FT8U245AM (FTDI社) の制御方法 VHDL

2002/07/31(更新日 )







FTDI社のFT8U245AMはUSB-001-FIFO等に搭載されております。このチップをFPGAで制御できるように詳しく解説します。Verilog-HDLについてはこちらをご覧下さい.

▼タイミングチャートの抜粋

■PC側からのデータを読み込む  -- リードサイクル

PCからUSB-001に文字を送るとFIFO(FT8U245AM)にデータ格納され、RXF#はLowになります。RD#を下げ、立ち上がりでFIFOは1つのデータが読まれたことを知ります。ここで、FIFOの中身が1文字しかなければ、RXF#はHIGHに戻ります。

D0..D7を読むタイミングはRD#の下がりからT3(30ns)、RD#が立ち上がりT4(10ns)の間が有効となります。
■PC側へデータを書き出す  -- ライトサイクル

TXE#がLowであれば、FIFO(FT8U245AM)にデータを出せるという意味です。

WRの立下りで、TXE#がT12(80ns)以上はHighになり、FIFOにデータが格納されます。FIFOのデータが満杯であれば、TXE#はHighのままです。

データはWRの立下り前からT9(20ns)、立下り後はT10(10ns)は出力すれば有効となります。


 次に上記のタイミングチャートより、リードサイクルとライトサイクルの状態遷移図を作成します。作成するのはFPGA内部のUSBの調停回路です。USB信号は双方向なので、リードとライトを同時に行うことはできません。また、USB FIFOやターゲットのモジュールに無制限にデータを送れないようにするために、Busy信号などを考慮しなくてはなりません。


▼リードサイクル

S0の時に、条件がRXF#=1つまり、PC側から何も送信されていないことを意味します。USB FIFO は空です。ここで、RXF#=0となれば、USB FIFOに文字があるという意味で、S1に移り、その時の状態をRD#<=0とします。ここではUSBからのデータを取込ません。タイミングチャートによれば、T3(30ns)となっているからです。

無条件にS2に移動します。S2で、RD#は下げたままで、USBからのデータを取込ます。

S3で、RD#<=1に戻します。ここで、ターゲットにリード信号を出します。これは、ターゲットのモジュールに対して、USBのデータの読み取りを知らせる信号です。


S0の時に、ターゲットからのライト要求(TG_WR=1)があれば、S1に移ります。S1のとき、ターゲットからのデータをレジスタに格納します。

TXE#=1
であれば、FIFOがフルなので、USB FIFOにデータを送ることはできません。条件がTXE#=0であれば、状態をS2に移します
このとき、データバスはFPGA内部からみて外側とします。データ線が双方向なので、方向には注意して下さい。

S3のとき、WR=0にします。データバスが外向きにして、S1でレジスタに格納したデータを出力します。WRの立下りでUSB FIFOはデータを取込みます。

 状態遷移図からVHDLを記述します。正論理と負論理には注意して下さい。状態遷移図をムーアマシンとして記述します。状態遷移図をHDLで記述する際には文法書等をを参照してください。

▼USB調停回路のダウンロード
 USB_ARBITER.vhd


▼USBデータの方向です。通常はハイインピーダンスにしておきます。
USB_DATA <= USB_DATA_REG when( DIR = '1') else "ZZZZZZZZ";

▼このモジュールが処理中であれば、BUSY信号を High にします。ステートマシンがライトとリード共にIDLE状態であれば、BUSYは Low です。
BUS_BUSY <= '0' when( WR_STATE="00" and RD_STATE="00" ) else '1';

▼念のため、D-FFを入れておきます。このとき、RXF#とTXE#を負論理から正論理に変えます。D-FFを入れなくても動作します。
process( CLK, RST ) begin
 if ( RST ='1') then
  RXF_REG <= '0';
  TXE_REG <= '0';
 elsif( CLK'event and CLK='1') then
  RXF_REG <= not RXF_N;
  TXE_REG <= not TXE_N;
 else
  NULL;
 end if;
end process;

▼リードサイクルのステートマシン
process( CLK, RST ) begin
 ▼リセットはシミュレーション時に初期値を代入するためでもあります。
 if ( RST ='1') then
  TG_DO <= "00000000";
  TG_RD <= '0';
  RD_N <= '1';
  RD_STATE <= S0;
 elsif( CLK'event and CLK='1') then
  case RD_STATE is
   when S0 =>
    ▼TG_READYとはターゲットの読み取り準備がOKという意味です。ライトサイクルと重ならないようにWR_STATE="00"としています。
    if( RXF_REG='1' and TG_READY='1' and WR_STATE="00") then
     ▼この状態はS1時のRD_Nです。つまり、次の状態を記述しています。
     RD_N <= '0';
     RD_STATE <= S1;
    else
     RD_STATE <= S0;
    end if;
   when S1 =>
    TG_DO <= USB_DATA;
    RD_STATE <= S2;
   when S2 =>
    RD_N <= '1';
    TG_RD <= '1';
    RD_STATE <= S3;
   when S3 =>
    TG_RD <= '0';
    RD_STATE <= S0;
   when others => RD_STATE <= S0;
  end case;
 end if;
end process;

▼ライトサイクル時のステートマシン
process( CLK, RST ) begin
 if( RST ='1') then
  WR <= '1';
  WR_STATE <= S0;
  DIR <= '0';
 elsif( CLK'event and CLK='1') then
  case WR_STATE is
   when S0 =>
    ▼ターゲットからのライト要求
    if( TG_WR='1') then
     USB_DATA_REG <= TG_DI;
     WR_STATE <= S1;
    else
     WR_STATE <= S0;
    end if;
   when S1 =>
    ▼FIFOに書込み可能 かつ リードサイクルと重ならない
    if( TXE_REG='1' and RD_STATE="00") then
     WR <= '1';
     DIR <='1';
     WR_STATE <= S2;
    else
     WR_STATE <= S1;
    end if;
   when S2 =>
    WR <= '0';
    DIR <= '1';
    WR_STATE <= S3;
   when S3 =>
    WR <= '1';
    DIR <= '0';
    WR_STATE <= S0;
   when others => WR_STATE <= S0;
  end case;
 end if;
end process;

エコー回路であれば、次のようなシミュレーション波形になります。
リードサイクル ライトサイクル


この調停回路を利用したエコー回路のページも御覧下さい。


メールでのご質問はこちらへどうぞ

HDLのホームページへ