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
[]


