読者です 読者をやめる 読者になる 読者になる

guruguru123’s diary

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

AD9851ドライブ用データをRS232C通信を用いてPCから選択

そろそろ外部でデータ生成をして、それをRAMに格納して順次読み出し、AD9851をドライブする。といったものを作っていきたい。

今回は、PCからデータを受け渡す機構として、以前も出てきたRS232Cを使って試したいと思う。いきなりデータ生成まで作るのは大変なので、今日はとりあえずRS232Cのブロックを組み込んで、前回の状態選択の入力をPCから行えるものをつくってみた。

状態が5つしかないので、wを0、r1を1、r2を2、r3を3、r4を4のキーを押すことによって指定するようにした。0,1,2,3,4はアスキーコードの16進でX'30'、X'31'、X'32'、X'33、'X'34'であるので、それらが入力されたら指定された状態へ、それ以外の入力は待機状態のままになる。今回もPC側からの入力にはTera_Termを用いた。

とりあえず組んで、書き込みをしたところ、またリクエスト信号が立ち上がりっぱなしになっていたようだ。そこを修正したら、正しい出力が確認できた。

AD9851へのドライブ信号を外部入力から選択

前回、AD9851を100MHzでドライブすることができたため、今回は外部入力から状態遷移(4データのRAMへの書き込み、それぞれのデータの読み出し)を行えるように組み替えた。I/Oポートにそれぞれのリクエスト信号に対応する5つのピンを設け、それをグラウンドから5Vにして、状態を選択するようにした。わかりづらいが、以下の図のようにPapilio上部5本の緑の信号線が各リクエスト信号になっており、そこに今はどこにも刺さっていない黄色い5V電圧ピンを接続して、状態指定を行う。これにより、外部入力からAD9851へのドライブ信号の選択が行えた。

f:id:guruguru123:20170523104534j:plain

AD9851へW_CLKの周波数を上げてドライブ

32MHzの周期を3.125nsだと一桁勘違いしていたため(本当は31.25ns)前回はW_CLKを分周して用いていた。そこで、今回は全ブロックを32MHzで動作するものを作成した。

また、これが動作したため、DCMを用いて、W_CLKの周波数を上げてAD9851へドライブするものを試した。今回は50MHzと100MHzで動作させた。100MHzでも問題なく動作することが確認できた。

AD9851へのドライブ(2)

前回のAD9851への書き込み信号が連続して出力されてしまう問題(waitの状態に移行してくれない)の解決策が思い浮かばなかったため、問題を洗い出すためにシミュレーションをしてみた。以下がその結果。f:id:guruguru123:20170510161150p:plain

すると、シミュレーション上ではstate_nがいったん書き込みが終わると、次のリクエスト信号まで一定の値を保持しており、waitの状態を保っていることがわかる。これより、リクエスト信号に何らかの問題があると考えた。

 

リクエスト信号の生成は以下のように行っていた。見直してみたら、これでは0.5秒間リクエスト信号が'1'のまま保持されてしまうことに気がついた。また、RAMに対するリクエスト信号もここで生成しているため、RAMは動作をしているが、これも見直しが必要であると考えた。

process (clk,state_con,counter) begin
if clk' event and clk = '1' then
if counter = 8000000 then
counter <= (others => '0');
if state_con = "00001" then
state_con <= "00010";
elsif state_con = "00011" then
state_con <= "00100";
elsif state_con = "00101" then
state_con <= "00110";
elsif state_con = "00111" then
state_con <= "01000";
elsif state_con = "01001" then
state_con <= "00000";
else
state_con <= state_con+ '1';
end if;
else
counter <= counter + '1';
end if;
end if;
end process;

OUTPUT: process(state_con) begin
ram_req_w <= '0';
ram_req_r1 <= '0';
ram_req_r2 <= '0';
ram_req_r3 <= '0';
ram_req_r4 <= '0';
dds_req <= '0';
case state_con is
when "00001" =>
ram_req_w <= '1';
dds_req <= '0';
when "00011" =>
ram_req_r1 <= '1';
dds_req <= '1';
when "00101" =>
ram_req_r2 <= '1';
dds_req <= '1';
when "00111" =>
ram_req_r3 <= '1';
dds_req <= '1';
when "01001" =>
ram_req_r4 <= '1';
dds_req <= '1';
when others =>
null;
end case;
end process;

 

リクエストが'1'のとき状態遷移が始まるようにしているため、これでは繰り返し出力されてしまう。そこで以下のように変更した(変更無しの部分は省略)

process (clk,state_con,counter) begin
if clk' event and clk = '1' then
if state_con = "0001" then
state_con <= "0010";
elsif state_con = "0011" then
state_con <= "0100";
elsif state_con = "0101" then
state_con <= "0110";
elsif state_con = "0111" then
state_con <= "1000";
elsif state_con = "1001" then
state_con <= "0000";
end if;

if counter = 8000000 then
counter <= (others => '0');
state_con <= state_con+ '1';
else
counter <= counter + '1';
end if;
end if;
end process;

すると繰り返しがなくなったが、RAMからのデータ読み出しが行われなくなってしまった。これは、データ読み出しから出力の遅延をうまく組み込めていなかったことが原因であった。32bitデータ読み出しの出力にイネーブルをつけていたが、これを外して解決した。

変更前data_out <= data_o1 when r_o = '1' else     変更後data_out<= data_o;
         (others => '-') when r_o = '0';

 

これらを改善してFPGAに書き込みを行ったところ、AD9851の出力が時間変化していることが確認できた。

このAD9851の出力の変更を外部スイッチなどから行えるようにしていきたい。

AD9851のドライブ

前回のエラー文中に

PIN "clk_gen/clkout1_buf.O" CLOCK_DEDICATED_ROUTE = FALSE;

を制約ファイルに入れるとエラーからワーニングに移るとあったため、試してみた。すると、出ていたエラーが消え、以下のようなワーニングに移った。

Pack:1653 - At least one timing constraint is impossible to meet because component delays alone exceed the constraint.

Place:1137 - This design is not guaranteed to be routable!

Par:468 - Your design did not meet timing.

タイミングが合ってないとか出ている気がするが、ビットファイルが生成できたためとりあえず書き込みを行った。各制御ピンの出力の様子を以前と同じようにLabToolで信号取得をした。以下がそのキャプチャ。

f:id:guruguru123:20170508144620p:plain

緑の矢印の間がAD9851へのドライブ信号の1サイクルである。W_CLKが乱れているように見えるのはサンプルレートが40MHzだからであろう。取得した信号を見ていくと、赤い丸で囲まれたような不要な信号が立ち上がってしまっていることがわかる。また、ひとつの32bitの周波数データに対してAD9851へ一度書き込みをするように作ったつもりであったが、連続して書き込みが行われていることがわかる。

また、DCMを用いてAD9851制御ブロック用のクロック生成をやめて、32MHzを使って動かすことにした。

AD9851駆動回路の追加(DCM)

DCM構成の段階でBUFGをつなぐかどうかのチェックがあったため、今回構成したDCMのVHDLの記述を参照してみた。すると、内部にIBUFGとBUFGがすでにあったため、前回のエラーが発生していたようだ。

そこでIBUFG,BUFGの記述を削除し、32MHzのクロック信号をDCMへ入力し、DCMの出力を25MHz,32MHzとして、これらを用いることにした。論理合成、Translateは通ったが、今度はMapで以下のようなエラーが出た。

ERROR:Place:1205 - This design contains a global buffer instance,
ERROR:Place:1136 - This design contains a global buffer instance,
ERROR:Pack:1654 - The timing-driven placement phase encountered an error.

どうやら25MHzクロックをw_clkの出力として用いていることが問題らしい。w_clkの外部出力部分をコメントアウトしてみると、ビットファイル生成まで行えた。次回はw_clkをどうするのかを考えていく。

ad9851駆動回路の追加

RAMコントローラが問題なく動いたため、AD9851の駆動用の回路を追加していく。ベースは以前作成したZPUinoに追加した回路。AD9851用の書き込みクロックであるW_CLKは、最小パルス幅が3.5nsであり、以前作成したものでは、カウンタを作ってそれでクロックの代わりにしていた。今回はDCMを用いてW_CLKの生成を行いたいと考えた。

f:id:guruguru123:20170418181830p:plain

さっそくcore-generatorでDCMを作成しくみこんでみた。生成するクロックの周波数は25MHz。論理合成を行ったところ次のようなエラーが出た。

ERROR:Xst:2035 - Port <clk> has illegal connections. This port is connected to an input buffer and other components.

バッファとコンポーネントが並列につながっているからダメらしい。正直この辺は勉強不足で知識が足りないので、改善策を探していきたい。とりあえず並列にならないようにバッファを入れてみた。

IBUFG_inst : IBUFG
port map (
O => clk_i, -- 1-bit output: Clock buffer output
I => clk -- 1-bit input: Clock buffer input
);

そうすると論理合成は通過した、がTranslateで引っかかった。

ERROR:NgdBuild:770 - IBUFG 'IBUFG_inst' and IBUFG 'clk_25/clkin1_buf' on net
'clk_i' are lined up in series. Buffers of the same direction cannot be
placed in series.
ERROR:NgdBuild:462 - input pad net 'clk_i' drives multiple buffers:

複数のバッファが直列に接続されているとこれが出るらしい。そういえばDCMでバッファ入れるとか入れないとかいう項目が会った気がする。今回はここまでにして、次回はこれの改善からはじめる。