2010年12月31日金曜日

当面の予定

 目標としては、今年中には完成させるつもりでしたが、実際は大晦日になっても半分も実現できていない状況となっています。当初案より大分変わってしまっているのもありますが、FPGAの論理設計とデバッグ、基盤の部品選定、調達作業には、やはり結構時間がかかりそれが大きいかなと思います。

 今後の当面の予定として、下記を早期に実現させたいと思います。

 ・SDRAMバッファモードの組み込み
    現在、回路作成、コーディング中 1/9あたりには動かしたい。

 ・TOS 192kで接続
    SCD-XE600は192kでしか出力してくれないので早めになんとかしたいので

 ・DSD受信回路/送信回路
    受信回路自体はできたので、SDRAMバッファモードでBuffaloIIにつなぎこんで鳴らしてみたい。
    エレアトさんのブログを見て"ベートーヴェン/交響曲第6番ヘ長調
    作品69 「田園」・「エグモント」序曲作品84 [SACD Hybrid + DVD-ROM]"も発注したので、
    5.6448MHzもできれば。

 ・I2S-LVDS-HDMI入手

    IO基盤の作成はまだまだかかりそうなので、Fidelix I2S-LVDS-HDMIをCaprice-I2Sとの接続用に入手

 ・mbed I2C制御とPC通信手段   
    BuffaloIIとFPGAの制御の制御ができるように

 ・FPGAのI2C受信回路
    そろそろスイッチだけでは、制御しきれなくなってきたので



  MR-1
 直接は関係ないですが、Korgの1bitモバイルレコーダーMR-1が結構安売りしているので、ポチってしまいました。

  FLAC
 それからPCMについては、基本waveファイルで保存していましたが、管理が面倒になってきたのでFLACに移行させようかと考え中。(システム構成図を修正)

 それでは、良いお年を...

2010年12月29日水曜日

DSD Phase Modulation Mode 受信回路

 DSD Phase Modulation ModeのデータをBCKを使用せずに、DSDdataのエッジを利用して受信しSignalTapIIにキャプチャする回路の回路図とSystemVerilogのコードです。片チャネル分。
 この回路をベースにI2S、ADAT、S/PDIF受信回路にDSD受信機能として統合する予定。片チャネル分のため、2回路化、L/Rの多重処理が追加で必要になります。現在サンプリングクロックとして98.3040MHzを使用していますが、90.3168MHzに変更します。

     DSD Phase Modulation Mode 受信回路構成


DSD Phase Modulation Mode 受信回路 SystemVerilogコード
   

`timescale 1ns/1ns
module DSD_capture(

  input  wire          m_clk,                 //sampling clock 98MHz
  input  wire          resetN,        
 
  input  logic         dsd_in,                //DSD_L or DSD_R input
 
  output logic         dsd_out,               //DSD monitor out
  output logic         dsd_alt_out,           //DSD monitor out alt
 
  output logic         cap_clk,               //SignalTapII capture sampling clock
  output logic         dsd_cmp,               //DSD and DSD alt inv compare
  output logic         dsd_5apat              //5A5A5A5A pattern match
);

 logic [3:0]  sdata_input_shift;
 logic     edge_detect;

 logic [5:0]   dsd_inc_word_time = 6'h0;
 logic     fw_window_clr;
 logic     fw_window;
 logic     hw_window;
 logic     fw_edge_det_flg;
 logic     fw_edge_det;
 logic     fw_edge_nodet;
 logic     hw_edge_det_flg;
 logic     hw_edge_nodet;

 logic    bit_clk;
 logic    bit_clk_mask;
 logic    alt_bit_clk;
 logic    alt_bit_clk_mask;

 logic    cmp_ini_flag;

 logic [31:0] dsd_data;
 logic [31:0] dsd_data_alt;

 logic [4:0]    capture_counter;

 
 enum {synclos=0,presync1 =1,presync2 =2,presync3 =3,presync4 =4, sync =5, fwprtect =6 } State, NextState;
 

//// dsd input section ////  
//shift_adat_input :
   always_ff @(posedge m_clk)
      sdata_input_shift <= {sdata_input_shift[2:0] , dsd_in};

// detect_adat_sync :
   always_ff @(posedge m_clk)begin
      if ((sdata_input_shift[2:1]==2'b01) || (sdata_input_shift[2:1]==2'b10))
         edge_detect <= 1'b1;
      else
         edge_detect <= 1'b0;
   end

   always_ff @(posedge m_clk)begin
      if (edge_detect==1'b1 && State == synclos)   dsd_inc_word_time <= '0;
      else if(edge_detect==1'b1 && fw_window == 1) dsd_inc_word_time <= '0;
      else                                         dsd_inc_word_time <= dsd_inc_word_time + 1;
   end

// edge detect window
   assign fw_window_clr = (dsd_inc_word_time==6'd02)  || (dsd_inc_word_time==6'd37) ;
   always_ff @(posedge m_clk)begin
      if (dsd_inc_word_time==6'd32)      fw_window <= '1;
      else if(fw_window_clr)             fw_window <= '0;
   end

   always_ff @(posedge m_clk)begin
      if (dsd_inc_word_time==6'd15)      hw_window <= '1;
      else if(dsd_inc_word_time==6'd20)  hw_window <= '0;
   end

// fw_edge_det & hw_edge_det
   always_ff @(posedge m_clk)begin
      if (fw_window && edge_detect)      fw_edge_det_flg <= '1;
      else if(fw_window_clr)             fw_edge_det_flg <= '0;
   end

   always_ff @(posedge m_clk)begin
      if (fw_edge_det_flg && fw_window_clr)   fw_edge_det <= '1;
      else                                    fw_edge_det <= '0;
   end
 
   always_ff @(posedge m_clk)begin
      if (! fw_edge_det_flg && fw_window_clr) fw_edge_nodet <= '1;
      else                                    fw_edge_nodet <= '0;
   end
 
 
   always_ff @(posedge m_clk)begin
      if (hw_window && edge_detect)      hw_edge_det_flg  <= '1;
      else if(dsd_inc_word_time==6'd20)  hw_edge_det_flg  <= '0;
   end

   always_ff @(posedge m_clk)begin
      if (! hw_edge_det_flg && dsd_inc_word_time==6'd20) hw_edge_nodet <= '1;
      else                                               hw_edge_nodet <= '0;
   end

// Sync State Control
   always_ff @(posedge m_clk, negedge resetN )begin
         if(!resetN)                                            State <= synclos;
         else if(m_clk=='1)                                     State <= NextState;
      end           

   always_comb begin
      case (State)
         synclos:begin
                if(hw_edge_nodet)                               NextState = presync1;
                else                                            NextState = synclos;
            end
         presync1:begin
                if(fw_edge_det)                                 NextState = presync2;
                else if(fw_edge_nodet)                          NextState = synclos;
                else                                            NextState = presync1;
            end
         presync2:begin
                if(fw_edge_det)                                 NextState = presync3;
                else if(fw_edge_nodet)                          NextState = synclos;
                else                                            NextState = presync2;
            end
         presync3:begin
                if(fw_edge_det)                                 NextState = presync4;
                else if(fw_edge_nodet)                          NextState = synclos;
                else                                            NextState = presync3;
            end
         presync4:begin
                if(fw_edge_det)                                 NextState = sync;
                else if(fw_edge_nodet)                          NextState = synclos;
                else                                            NextState = presync4;
            end
         sync:begin
                if(fw_edge_nodet)                               NextState = fwprtect;
                else                                            NextState = sync;
            end
         fwprtect:begin
                if(fw_edge_nodet)                               NextState = synclos;
                else if(fw_edge_det)                            NextState = sync;
                else                                            NextState = fwprtect;
            end
      endcase
   end


//bit_clk gen :
   always_ff @(posedge m_clk)begin
      if (dsd_inc_word_time==6'd26 && bit_clk == 1'b0 && bit_clk_mask == 1'b0)
               bit_clk  <=  1'b1;
            else
               bit_clk  <=  1'b0;
   end

   always_ff @(posedge m_clk)begin
      bit_clk_mask  <= bit_clk;
   end

   always_ff @(posedge m_clk)begin
      if (dsd_inc_word_time==6'd09 && alt_bit_clk == 1'b0 && alt_bit_clk_mask == 1'b0)
               alt_bit_clk  <=  1'b1;
            else
               alt_bit_clk  <=  1'b0;
   end

   always_ff @(posedge m_clk)begin
      alt_bit_clk_mask  <= alt_bit_clk;
   end


//dsd data s/p
   always_ff @(posedge m_clk)begin
      if(bit_clk)  dsd_data <= {dsd_data[30:0],sdata_input_shift[2]};
   end

   assign dsd_out = dsd_data[31] ;
  
   always_ff @(posedge m_clk)begin
      if(alt_bit_clk)  dsd_data_alt <= {dsd_data_alt[30:0], !sdata_input_shift[2]};
   end

   assign dsd_alt_out = dsd_data_alt[31] ;
  
//clk_counter
   always_ff @(posedge m_clk)begin
      if(dsd_data == 32'h5a5a5a5a && cmp_ini_flag) capture_counter <= 5'h0;
      else if (bit_clk)                            capture_counter <= capture_counter + 1;
   end

   always_ff @(posedge m_clk)begin
      if(State == presync4)                             cmp_ini_flag <= 1'b1;
      else if (dsd_data == 32'h5a5a5a5a && cmp_ini_flag)cmp_ini_flag <= 1'b0;
   end

//signaltap clk gen
   always_ff @(posedge m_clk)begin
      if(capture_counter == 5'd00 && hw_window) cap_clk <= 1'b1;
      else                                      cap_clk <= 1'b0;
   end

//compare dsd & alt_dad data
   always_ff @(posedge m_clk)begin
      if(capture_counter == 5'd00 && hw_window)begin
         if(dsd_data == dsd_data_alt) dsd_cmp <= 1'b1;
         else                         dsd_cmp <= 1'b0;
      end
   end

//detect dsd data 5a5a5a5a pattern

   always_ff @(posedge m_clk)begin
      if(capture_counter == 5'd00 && hw_window)begin
         if(dsd_data == 32'h5a5a5a5a) dsd_5apat <= 1'b1;
         else                         dsd_5apat <= 1'b0;
      end
   end


endmodule

DSDデータのキャプチャ2

 DSDデータの32bit中のHigh('1')の数を計数する機能を追加してSignalTapIIでキャプチャしてみました。
 
前回、まだ無音区間と考えた32bit中のHの数は、15,16,17bitのいずれかで占めている区間ですが、もしかするとすでに曲が始まっている部分にあたるかもしれません。
 というのは、どうも曲中でも、小音量部では、15,16,17bitが大勢を占めている可能性がありそうだからです。

 初めて”5A5A5A5A"パターン以外が出現したポイント(ほぼ中央の点線部)
(******set_bitnumが32bit中のH bitの数)


Hの個数がはじめて17個が出現したポイント
(左半分はすべて16個(10h))

 上のタイムチャートとしたのタイムチャートは別々に採取したものですが、前回の結果からすると多分上の右半分と下の左半分は、一部は重複している部分になるはずです。
 下のタイムチャートの右半分は、16bitが多数を占めた状態で15,16,17bitのみで構成されています。

32bit中の"H"の個数ですが、どうも演奏中になっても14~18個のパターンしかほとんど出てこない区間のあるソースもあるようです。意外と振れ幅が小さいようで、確認した中では最小は8個、最大は21個ですが、14~18個ぐらいが大部分を占めているように見えます。

32bit中、Hのbit数が9個のキャプチャパターン(点線部)

 無音区間の判別はなかなか難しいのかもしれません。移動平均フィルタをかければ見えてくるのかな?

2010年12月26日日曜日

DSDデータのキャプチャ

 DSDデータの受信回路を作成し、SignalTapIIでキャプチャしてみました。




上から
  1. State:5=同期確立中
  2. DSD受信データ(サンプリングクロックのほうが荒い為意味なし)
  3. ポジ側データを32bitパラレル化
  4. ネガ側データの反転を32bitパラレル化
  5. H:ポジ側とネガ側が一致 L:不一致
  6. H:"5A5A5A5A"パターン L:"5A5A5A5A"パターン以外
     DSDデータキャプチャ波形("5A5A5A5A"パターン以外初出部分)


 大体のところは、すでに某サイトで確認されていますので、追加情報的なところをあげてみます。

 実施手順
 ・同じディスクを①停止=>再生と②ポーズ=>再生の各々2セットをキャプチャ(片チャネルのみ)
 ・トリガ条件"5A5A5A5A"パターンか否かを常時監視し、"5A5A5A5A"のパターン出現でキャプチャ開始
 ・トリガ前512×32bit トリガ後3584×32bitのデータをキャプチャ
 ・cvsファイルにexportし、Excel上で編集・解析

 結果からわかること
 ・DSD Phase Modulation Modeのポジ側(前側)データとネガ側(後側)データの反転したものを比較し不一致がないかを検出する回路をつけたが、すべて一致した。
 これより、適当なジャンパーではあるが、伝送エラーは発生していないとほぼ断定できる。
 
 ・大体5A5A5A5A"以外初出から2500word(4byte)ぐらいのところで4つのキャプチャデータパターンが一致。なぜか32bit整列で比較しているのにすべて一致するという結果に、プレイヤー内では32bitあるいはそれ以上のbit処理であるためと推測する。

 ・5A5A5A5A"以外初出から4つのデータが一致するまでのword数には24word位のばらつきがみられた。もしかするとスタートボタンを押したときとピックアップの位置などが影響しているのかも?
 
 ・キャプチャした4096wordすべてのwordで32bit中の1の数は、15,16,17のいずれか。
  内訳は、15個:314、16個:3463 17個:320 
  ローパスをかければ直流。つまりキャプチャした部分はすべてまだ無音区間。


 曲間の区切りを検出するには、32bit中の1の個数を移動平均フィルタをかけ、閾値以上が検出される前n wordとかがよさそうです。

    キャプチャデータ 5A5A5A5Aパターン以外初出部

2010年12月25日土曜日

1万円を切るロジアナ ZEROPLUS LAP-C(16032)

 こんなに安いロジアナがあるんですねえ。
 秋月では¥9800 ZEROPLUS LAP-C16032 16chロジックアナライザ(100MHz,32k)




 こちらの情報だと、64kbit/chのひとつ上位機種と中身は同じで、何だかxxしてます。

 標準で、UART, I2C、SPI、7SegLEDのプロトコルをサポートし、2つほどいくつかあるプロトコルから無料で選択できるそうで、[ Digital Audio ]としては、AC97, HD Audio, I2S, PCM, S/PDIF, STBus が選択可能です。ちょっとそそられます。

 32kbit/chしかメモリがなく、SignalTap IIと どっこいどっこいともいえる点が微妙です。
 高い機種になると、メモリ容量が大きくなっていき、チャネル数が増えたり、サンプリング周波数も高速になったりしていきますが、値段が跳ね上がります。

 
 SignalTap IIをロジアナ代わりに使うとなると、準備に色々めんどくさいこともありますが、手間をかければ複雑なトリガ条件も論理で組めます。
 
 今まで知りませんでしたが、キャプチャしたデータをcvsファイルへExportもできます。

 また、現在確認しようとしてる、DSD Phase Modulation Modeをシリアルではなく、8bitや32bitパラレルで見ようとなると、サポートプロトコル外のためLAP-Cでは、難しいのではないかと思われます。今回については、シリアルでデータを観測しても何が何だか状態なので、とりあえずSignalTapIIでキャプチャでいきます。そのうち買っちゃいそうですけど... 

2010年12月23日木曜日

DSD BCK/DSD_L(R)波形 2

 一昨日にアップした波形、あまりに鈍りすぎでしたが、プローブのInput Capacitanceの影響が大きかったようです。×10にして再測定したのが、下記の波形です。
 やはり結構鈍っていますが、大分ましです。エレアトさんのブログでは、ダンピングに470Ωと以上に大きい値の抵抗値が入っているようで、これを47Ωに替えれば、かなり急峻になるようです。集合チップ抵抗で交換するのはちょっと大変そうなのでできれば手を出したくありませんが....



 BCK(上)とDSD_L(R)(下)(infinite persistence mode)


 
 再生停止時のBCK(上)とDSD_L(R)(下)

2010年12月22日水曜日

DSD Phase Modulation Mode

 DSD Phase Modulation Modeですが、データの周波数が倍になるためタイミングは厳しくなります。といってもたかだか2.8Mbit/s程度なのでクロック波形がきれいであれば問題ではないはずですが...

 見方を変えると、必ずエッジが存在するため、BCKなしでもデータが再生できることに気がつきます。S/PDIFやADAT等と同様にBCKなしでも受信可能です。


 しかも、BCLKネガエッジ側のDSD_L(R)データは、ポジエッジ側の反転データであるため、ポジ側とネガ側の反転データが一致するかどうかで、誤り検出として使用できるかもしれません。
 
 誤り検出として使えるかは、コードバイオレーションがないことが前提となります。たとえばS/PDIFの場合は、PreambleのX/Y/Zcode時は、"1"は"10"または"01"に0は"11"または"00"にエンコードするルールに反するコードを使用して実現しています。

 DSD Phase Modulation Modeもこのようなコードバイオレーションを用いていなければ誤り検出に使用できると思われます。

 また、BCKを用いて受信したデータと、上記のBCLKを用いないで受信したデータをコンペアすることによっても、完璧ではありませんが、データ誤りの検出方法として利用できることが期待でいます。

 
 BCKが鈍っていることを考えると、BCKを用いない受信回路の方が、確実にデータを受信できるのではないかと思われます。というか、今のBCK波形ではまともに受信できるか非常に怪しい。
 ということで受信キャプチャは、先ずはBCKを用いずデータエッジを利用してデータを受信する方法でやってみようと思います。 

 またFPGAとしては、BCKを用いないほうが、もうひとつメリットがあります。
 S/PDIF、ADAT、I2S、DSDなどの受信回路を共通回路化する場合、モードによってクロックを切り替えることは、できれば避けたいので、BCKを使用せずに受信できるのはありがたい。