guruguru123’s diary

かなり雑な作業日記です。

SDRAM動作の確認とADコンバータドライブ用ブロックの作成

前回AD9851の基準クロックをPapilioから供給すると言っていたが、あれは勘違いで実際にはAD9851基板に乗っている30MHz水晶発振器のクロックを6逓倍して180MHzを基準クロックとして用いている。そのため、w_clkは100MHzを供給しても問題ない。というか以前にAD9851ドライブプログラムを、w_clkを100Mhzでの動作試験をしたことを忘れていた。

W_CLKも100MHzにしたところで動作させると、どうも思ったとおりにAD9851の出力が出ない。おそらく高周波になっているため、配線が問題なのだろうとは思うがSDRAMが100MHzでも動作しているか確認することにした。

確認方法はSDRAMから読み出したデータをRS232CでPC上に表示させる。確認してみると、なぜだか0番目に2MHzのデータ、というようにアドレスとデータが一つずつずれている。

(データの書き込みはアドレスの0番目から1MHz,1番目に2MHz...,9番目に10MHzと格納している)

これでは一応SDRAMは動作しているといえるが、正しく動いているとはいえない。

この原因として、SDRAMへの書き込み、読み出しのリクエストのタイミングとデータの動機のタイミングのずれが考えられる。そこでRS232C通信の制御ブロックをSDRAMコントローラと同様なステートマシンとして記述しなおしてみた。すると、きちんと0番目に1MHzが書き込まれており、ずれが無くなった。

f:id:guruguru123:20171116221949p:plain上の画像を見ると16bitで10文字の40bitデータが10個SDRAMからの出力され、以下の各40bitデータと一致するため正しいことがわかる。

1Mhz :X"01016c16c1"; 2MHz :X"0102d82d82"; 3MHz :X"0104444444";
4MHZ:X"0105b05b05"; 5MHz:X"01071c71c7"; 6MHz: X"0108888888";
7MHz:X"0109f49f49"; 8MHz:X"010b60b60b"; 9MHz:X"010ccccccc";
10MHz:X"010e38e38e";

AD9851の出力波形も正しく出ていた。

これと平行してADコンバータドライブ用ブロックも作成した。内容はほとんどAD9851ドライブブロックと同じである。詳しい中身は次回書く。記述が終わったので、次回ADコンバータを実際に動かしてみる。

SDRAMのバースト動作(3)

前回はただaddr?とでるだけだったので、とりあえず"start_addr?”と"stop_addr?"と表示するようにした。これで開始と停止アドレスを指定できるようになった。

アドレスの指定はとりあえずbankを1ビット、rowを1ビット、colを1ビットで指定する。

ここまでは動作クロックが32MHzであるので、DCMをもちいて100MHzにして動作させていく。しかし、AD9851は基準クロック32MHzを6逓倍して使って180MHzとして使っていたため、これをどうしようか悩みどころだ。(AD9851のクロック上限は180MHz)

今回はとりあえずAD9851の基準クロックはそのままで、SDRAMRS232Cブロックだけ100MHzで動作させていく。

DCMで100MHzと32MHzのクロックを生成し、制約ファイルに以前のように

PIN "CLK_GEN/clkout1_buf.O" CLOCK_DEDICATED_ROUTE = FALSE;
PIN "CLK_GEN/clkout2_buf.O" CLOCK_DEDICATED_ROUTE = FALSE;

と書き込んでエラーをWARNINGへと移行させた。

WARNINGを見てみると、100MHzのSDRAMのクロック源としての外部出力に関してPlace:1206とPlace:1137が出ていた。これは生成したクロックがそのまま出力されており、遅延やスキューを発生させるとかいてある(たぶん)。回避方法として、出力DDR(ODDR2)を用いることで、これを回避できると指示が書いてある。試してみるとWARNINGが消えて、問題なく外部出力が行えている。

しかし、AD9851のW_CLKとして用いている32MHzの方は依然としてWARNINGに残っている(Place:1137)ので、これを改善していきたい。

 

SDRAMのバースト動作(2)

AD9851を高速にドライブするために、SDRAMに蓄えられているデータを連続で読み出してAD9851へドライブする機構を作成する。

今回もバースト長は4で、64ビットで一つのデータとして扱う。

今回はあらかじめSDRAMに10個の64ビットデータを蓄えておき、それを読み出していく。10個のデータはreqwのコマンドを送ることで書き込まれる。

読み出し方は、reqrのコマンドを受け付けた後、PCに"addr?"と出力させ、スタートアドレスを入力、その後また"addr?"と出るので、ストップアドレスを入力する。このとき、スタートアドレスはストップアドレスより小さくなければならない。これは、アドレスをインクリメントして、次々データを読み出しているためである。

動作させたところ、スタートからストップまで問題なく出力され、出力を維持することが確認できた。これを改良して、指定した範囲をループしてのドライブなどの動作を行えるようにしていく。

SDRAMのバースト動作:バースト長4

バースト長2でSDRAMの動作が確認できたため、これをAD9851用の周波数チューニングワードとして駆動してみた。位相は固定。問題なく動作することが確認できた。

 

次にSDRAMをバースト長4で動作させてみた。アドレス指定は、カラムアドレスの下位2bitを自動的にインクリメントすることにより行われる。今回は下位2bitを"00"としたため、"00"→"01"→"10"→"11"となる。データは16×4で64bit用意する。

64bit書き込めるが、AD9851に必要なのは40bitであるため残りの24bitには適当なデータを入れておく。下位40bitをAD9851用データとして動作させた。

書き込んだ40bitデータに対して、AD9851が正しく動作していることが確認できた。

次は何か40bitデータを自動で100個くらい作るものを用意して、SDRAMへ書き込み、それらを連続してAD9851へドライブするものを作りたい。

SDRAMのバースト動作

前回はバースト長1でSDRAMを動作させた。今回はSDRAMにバースト動作をさせてみた。テストのためバースト長は2で動作させた。

変更点はモード設定用レジスタの下位3bitとライト、リードステート。

カラムアドレスの下位1bitを自動でインクリメントしてくれるため、カラムアドレス8bitを指定して、ライトの場合は一つカラムアドレスを指定して、書き込むデータをタイミング良くDQ線へ出力。リードの場合も同様に一つカラムアドレスを指定して、読み出すデータをDQ線からタイミング良く取り出すだけだ。

f:id:guruguru123:20171024191736p:plain

前回と同じコマンドで32bitデータの書き込み、読み出しを行った。32bitを16進数で8文字としてみているため、以下のような出力結果になっている。rew1,rew2により書き込んだ8文字がrer1,rer2で正しく出力されている。

f:id:guruguru123:20171024193027p:plain

 バースト長4でも動きそうなので、次回試してみたい。バースト長4が動いたらそれを使ってDDSを駆動したい。

SDRAMコントローラの作成とRS232C通信ブロックとの接続

 以前SDRAMコントローラを作ろうとして失敗、その代わりにFPGA内部RAMを使っていた。しかし、SerDesを用いてAD9851用の大量データを蓄えるとなると容量が明らかに足りない。そこで改めてSDRAMコントローラを作成することにした。

今回はZPUinoのソースにあるSDRAMコントローラを参考に作成していった。

以前も書いたが、PapilioProに乗っているSDRAMはMT48LC4M16A2。4バンクでロウアドレス12bit、カラムアドレス8bitで指定し、1アドレスに16bit格納できる。なぜかPapilio Pro上のSpaltan6の配線図を見るとアドレス信号線が13本出ているため、このうち使わない13bit目は'0'としておく。

AD9851チューニングワードは40biであり、おそらく40bitに何ビットか情報を加えることになるため、16bitでは足りない。参考にするソースでは32bitを1セットにするためにカラムアドレスの下位1bitを使って実現していた。今回は練習として、このソースと同じく32bitを格納するとした。

SDRAMコントローラの記述が終わったので、前回使った、コマンド受付用RS232C通信ブロックを書き直した。確認用としてコマンドはrew1,rew2で書き込み、rer1,rer2で読み出しを行うとした。格納する32bitはキーボードから入力する。

rew1,rew2:このコマンドw受け付けた後、データが32bitになるまでデータを受け付 ける。32bitになったらreq_writeを立ち上げ、アドレスを有効にする。

rer1,rer2:このコマンドを受け付けたとき、req_readを立ち上げ、アドレスを指定する。このまま読み出し完了信号(data_validのアサート)を待つ。信号が来たらRS232C通信にてデータをPCへ送る。

動作テストを行ったところ、32bitが正常に書き込み、読み出しができた。

これをSetDesと連携して使って行きたい。

RS232C通信を用いてDDSへデータの書き込み

前回はTeraTermからFPGAへコマンドを送り、wdでデータを保持、rdでデータを返した。今回はこれを使ってRS232C通信を用いてFPGAへコマンドの送信と、コマンドによってDDS用のデータの受信、DDSへのデータのドライブを行った。

DDS用の40bitデータはアスキーコードで10文字とし、これを16進数に変換して用いる。まずはじめにこの変換機構を作成した。複雑なことはせず、受信した8bitのアスキーコードをただcase文で判定し、用意しておいた40bitのレジスタに4bitずつ入れていくだけ。RS232C送信用の変換(16進数からアスキー)も作ったため記述量が多くなってしまったが、データ確認に必要なのでしょうがない。

変換機構ができたので、前に作ったDDSドライブ用のコンポーネントと組み合わせてみた。今回のコマンドは今後複数のDDSを扱うことを見越して、40bit受信をDDS1、DDSへのドライブをout1とした。

試しに手打ちでTeraTermから40bitデータを送って見たところDDSの駆動が確認できた。

今回はDCMをいれずにクロックは32MHのまま作ったが、周波数を上げて動作確認を行いたい。また、LabVIEWをインターフェースとして周波数・位相を制御するといったものができつつあるため、そちらと連携させていきたい。