FT600とFPGA間でデータの送受信を行いましたので、ご参考に手順をお示しします。
FT600は「Multi-Channel FIFO」と「245 Synchronous FIFO」という、ふたつの動作モードを選択できます。今回の実験ではMulti-Channel FIFOモード(以後、MultiChモード)を使用してFPGAとデータ通信してみました。
通信条件などは下記の通りです。
- Write/Read Pipe = 1
- FIFO Clock = 100MHz
- 受信はCallback割り込みを使用
FT600用API(D3XX)に関しては公式の資料を参考してください。 AN_379 - D3XX Programmers Guide
通信タイミング(プロトコル)についてはFT600のデータシートを参照してください。 F600/FT601 Series - SuperSpeed USB3.0 ICs
1.ハンドルの取得
FT_Create()によりハンドルを取得します。今回はシリアルナンバーでOPENしました。(Flag = FT_OPEN_BY_SERIAL_NUMBER)。
問題がなければFT_OKが返ります。
FT_Create(serialNumber, FT_OPEN_BY_SERIAL_NUMBER, &this->ftHandle);
デバイスのシリアルナンバーは下記のように取得します。
char serialNumber[16]; FT_ListDevices((PVOID)dwDeviceIndex, serialNumber, FT_LIST_BY_INDEX | FT_OPEN_BY_SERIAL_NUMBER);
2.動作モードの変更(チップ情報の書き換え)
FT600のコンフィギュレーションを設定します。書き込みの前に、元となるデータを取得しておきます。
FT_60XCONFIGURATION chipConfig; FT_GetChipConfiguration(ftHandle, &chipConfig);
Multi-Chモードで動作させるための値を設定し書き戻します。
chipConfig.FIFOMode = CONFIGURATION_FIFO_MODE_600; chipConfig.ChannelConfig = CONFIGURATION_CHANNEL_CONFIG_1; chipConfig.FIFOClock = CONFIGURATION_FIFO_CLK_100; chipConfig.OptionalFeatureSupport |= CONFIGURATION_OPTIONAL_FEATURE_ENABLENOTIFICATIONMESSAGE_INCH1; chipConfig.OptionalFeatureSupport |= CONFIGURATION_OPTIONAL_FEATURE_DISABLEUNDERRUN_INCH1; FT_SetChipConfiguration(ftHandle, &chipConfig);
書き込み後はチップの再起動のため一度ポートを閉じます。
FT_Close(ftHandle); WaitSec(5); //5秒待ち
3.Multi-Channel FIFO mode のProtocolについて
Multi-Chモードでは送受信FIFOの状態がData[15:8]を使用して示されます。この時Data[7:0]はHi-Zです。
Data | FIFO | Channel |
---|---|---|
15 | OUT | 4 |
14 | OUT | 3 |
13 | OUT | 2 |
12 | OUT | 1 |
11 | IN | 4 |
10 | IN | 3 |
9 | IN | 2 |
8 | IN | 1 |
今回の実験ではChannel = 1を使用していますので、OUT channel 1 FIFOにデータがある場合Data[12] = 0 となります。IN channel 1 FIFOが受信可能状態である場合Data[8] = 0となります。
各FIFOのフラグを検出後、マスタ(FPGA)はWR信号を下げつつコマンドを応答します。コマンドはData[7:0]とBE[1:0]で返します。定義は下記の通りです。
Data[12] = 0 検出後にデータを取り出す場合(Master Read)、コマンドとしてBEに00bを、Data[7:0]に0001bを出力しWRを下げます。
(Data[31:16], BE[3:2]はFT600には在りません)
コマンド応答後、FT600よりRXF = 0 をもってデータが出力されます。TXEも上記のタイミングでFT600から出力されますので使用可能です。
Data[8] = 0 となっている場合にはコマンドBE=01b、Data[7:0]=0001b & WR = 0としてFPGAからデータを送信できます。 (Master Write)
コマンド応答後、FT600よりRXF = 0 をもってデータが受信されます。TXEも上記のタイミングでFT600から出力されますので使用可能です。
なお、Data[8] = 0 が出力されるにはモード設定時に行った下記の設定が必要です。
chipConfig.OptionalFeatureSupport |= CONFIGURATION_OPTIONAL_FEATURE_ENABLENOTIFICATIONMESSAGE_INCH1;
3.データ送信 (FT600→FPGA)
FT_WritePipe()よりデータを送信します。
Write Pipe Channel 1より出力しますので第2引数のPipeID (Endpoint) には0x02を指定します。
送信の完了を待ちますので第6引数のOverlappedにはNULLを指定しておきます。Overlapを使用すると非同期動作を行えます。つまりFT_WritePipe関数がデータの送信完了を待ちません。このときの返り値は"FT_IO_PENDING"となります。今回はNULLとしていますので送信完了まで関数から返りません。
FT_WritePipe(ftHandle, 0x02, buff, 10, &bytesTransferred, NULL);
FPGA側での受信波形を示します。FT600から出力した5WordのデータをFPGAで正常に受信できています。
FPGA受信用のHDLコード例を下記にお示しします。clk周波数 = FIFO clock x2 (立上同期)です。
library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; entity H_FT600_MULTI_RX_V1 is port ( clk : in std_logic; reset : in std_logic; act : in std_logic; txe : in std_logic; rxf : in std_logic; wr : out std_logic; data : inout std_logic_vector(15 downto 0); be : inout std_logic_vector(1 downto 0); data_rcv : out std_logic_vector(15 downto 0); data_len : out std_logic_vector(15 downto 0) ); end entity; architecture rtl of H_FT600_MULTI_RX_V1 is -- Build an enumerated type for the state machine type state_type is (idle,s0,s1,s2,s3,s4,s5,s6,d0,d1,e0,e1); signal state : state_type; signal data_r : std_logic_vector(15 downto 0); signal rcv_len : std_logic_vector(15 downto 0); begin process (clk, reset) begin if reset = '1' then state <= idle; wr <= '1'; be <= (others=>'Z'); data <= (others=>'Z'); data_r <= X"0000"; rcv_len <= X"0000"; elsif (rising_edge(clk)) then data_rcv <= data_r; data_len <= rcv_len; case state is when idle => if data(12) = '0' and act = '1' then be <= "00"; data(7 downto 0) <= X"01"; wr <= '0'; rcv_len <= X"0000"; state <= s0; else be <= (others=>'Z'); data <= (others=>'Z'); state <= idle; end if; --------------------------------------------- when s0 => state <= s1; --------------------------------------------- when s1 => state <= s2; --------------------------------------------- when s2 => be <= (others=>'Z'); data <= (others=>'Z'); state <= s3; --------------------------------------------- when s3 => state <= s4; --------------------------------------------- when s4 => state <= s5; --------------------------------------------- when s5 => state <= s6; --------------------------------------------- when s6 => state <= d0; --------------------------------------------- when d0 => state <= d1; --------------------------------------------- when d1 => if rxf = '0' then data_r <= data; rcv_len <= rcv_len + 1; state <= d0; else state <= e0; end if; --------------------------------------------- when e0 => state <= e1; --------------------------------------------- when e1 => wr <= '1'; state <= idle; --------------------------------------------- end case; ------------------------------------------ end if; end process; end rtl;
5.データの受信 (FPGA→FT600)
FT_ReadPipe()によりデータを受信します。
受信割り込みを使用しますのでHandle取得後にCallback関数を登録しておきます。
FT_SetNotificationCallback(this->ftHandle, NotificationCallback, &myContext);
NotificationCallbackはFT_NOTIFICATION_CALLBACK型で下記のように定義されています。
typedef VOID(*FT_NOTIFICATION_CALLBACK)(PVOID pvCallbackContext, E_FT_NOTIFICATION_CALLBACK_TYPE eCallbackType, PVOID pvCallbackInfo);
Callback関数内では引数を使用して受信用の関数を呼びます。ucEndpointNoには0x82が入っています。cntはグローバル定義のユーザコンテキストです(内容自由)。
enum _E_FT_NOTIFICATION_CALLBACK_TYPE type = eCallbackType; if(type == E_FT_NOTIFICATION_CALLBACK_TYPE_DATA){ FT_NOTIFICATION_CALLBACK_INFO_DATA *info = (FT_NOTIFICATION_CALLBACK_INFO_DATA*)pvCallbackInfo; ReadPipe(info->ucEndpointNo, cnt->buff, info->ulRecvNotificationLength); }
Callback関数から呼ぶ受信用関数は下記のようにしました。Overlapを使用し、受信完了を非同期で待っています。
int __fastcall TFt600::ReadPipe(unsigned char pipeId, BYTE *buff, int bytes) { int result = 0; ULONG bytesRead; ULONG bytesToRead = bytes; OVERLAPPED overlappedRead = {0}; if(FT_InitializeOverlapped(ftHandle, &overlappedRead) == FT_OK){ ftStatus = FT_ReadPipe(ftHandle, pipeId, buff, bytesToRead, &bytesRead, &overlappedRead); if(ftStatus == FT_IO_PENDING){ while(1){ ftStatus = FT_GetOverlappedResult(ftHandle, &overlappedRead, &bytesRead, false); if(ftStatus == FT_IO_INCOMPLETE){ continue; }else if(ftStatus != FT_OK){ AddMemo(String().sprintf(_T("ReadPipe()::FT_GetOverlappedResult. (0x%X)"), ftStatus)); break; }else{ //ftStatus == FT_OK result = 1; break; } } } if(result != 0) return result; //---------------------------------------- if(FT_ReleaseOverlapped(ftHandle, &overlappedRead) != FT_OK){ AddMemo("Error, ReadPipe()::FT_ReleaseOverlapped"); result = -1; } }else{ AddMemo("Error, ReadPipe()::FT_InitializeOverlapped"); } return result; }
FPGA側での送信波形をお示しします。
FPGA受信用のHDLコード例をお示しします。clk周波数 = FIFO clock x2 (立上同期)です。データはAsciiのインクリメントデータを出力しています。
library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; entity H_FT600_MULTI_TX_V2 is port ( clk : in std_logic; reset : in std_logic; start : in std_logic; sending : out std_logic; txe : in std_logic; rxf : in std_logic; wr : out std_logic; data : inout std_logic_vector(15 downto 0); be : inout std_logic_vector(1 downto 0); send_len : in std_logic_vector(15 downto 0) ); end entity; architecture rtl of H_FT600_MULTI_TX_V2 is -- Build an enumerated type for the state machine type state_type is (idle,s0,s1,s2,s3,s4,d0,d1,e0,e1); signal state : state_type; signal data_r : std_logic_vector(15 downto 0); signal send_len_r : std_logic_vector(15 downto 0); begin process (clk, reset, rxf, start) begin if reset = '1' then sending <= '0'; state <= idle; wr <= '1'; be <= (others=>'Z'); data <= (others=>'Z'); data_r <= X"4141"; send_len_r <= X"0000"; elsif (rising_edge(clk)) then dbg_data <= data_r; case state is when idle => if start = '0' then send_len_r <= X"000D"; data_r <= X"4241"; sending <= '1'; state <= s0; else sending <= '0'; state <= idle; end if; --------------------------------------------- when s0 => if data(8) = '0' then be <= "01"; data (15 downto 8) <= (others=>'Z'); data(7 downto 0) <= X"01"; wr <= '0'; state <= s1; else be <= (others=>'Z'); data <= (others=>'Z'); wr <= '1'; state <= s0; end if; --------------------------------------------- when s1 => state <= s2; --------------------------------------------- when s2 => state <= s3; --------------------------------------------- when s3 => if txe = '1' then data <= (others=>'Z'); state <= s4; else state <= s3; end if; --------------------------------------------- when s4 => be <= "11"; data <= data_r; state <= d0; --------------------------------------------- when d0 => if rxf = '0' then be <= "11"; data <= data_r; data_r <= data_r + X"0202"; send_len_r <= send_len_r - 1; state <= d1; else be <= (others=>'Z'); data <= (others=>'Z'); wr <= '1'; state <= e0; -- RX FIFO IS FULL end if; --------------------------------------------- when d1 => if send_len_r /= X"0000" then be <= "11"; data <= data_r; state <= d0; else be <= (others=>'Z'); data <= (others=>'Z'); wr <= '1'; state <= e0; end if; --------------------------------------------- when e0 => if send_len_r /= X"0000" then state <= s0; else state <= e1; -- DATA SEND COMPLETE sending <= '0'; end if; --------------------------------------------- when e1 => if start = '1' then state <= idle; else state <= e1; end if; --------------------------------------------- end case; ------------------------------------------ end if; end process; end rtl;
お問い合わせについて
ご不明な点や間違いなどありましたらご連絡ください。
弊社では、FPGAそのものの使い方や開発ツールの使い方などは、サポートしておりませんので予めご了承ください。
[kw] 2018-04-26 TEC-FPGA EDA-009 FTDI USB3.0 FT600 Multi-Channel-FIFO
[]