Here is a demo of measuring transfer rate of FTDI's USB3.0 bridge IC FT600 using an EDA-009.
EDA-009 is an FPGA board which has Altera's CycloneV and FT600 on its credit-card size board.

Transfer rate of FT600 can be calculated as 200MB/s by its 16 bit data width and 100 MHz transfer frequency. An app acts actual trasfer tests and here is a result:

  • Transmit : 195MB/s (average)
  • Receive : 180MB/s (average)


Click to see all

Please refer to below for more details.

Set up

This test was done with settings below.

  • FT600 bus protocol : 245 FIFO at 100MHz
  • Transfered data amount  : 0.1MB (104858 Byte) to 50MB, 500 points in 0.1MB step
  • Number of trials : 100
  • D3XX device driver version : v1.1.0.0
  • Test board : EDA-009
Transmit Rate

Periods are timed between after writing data to the FT600 and asserting of complete signal by an API. The FPGA receives data wasting off of them.
Here is a part of codes of application.

	OVERLAPPED vOverlappedWrite = {0};
	vOverlappedWrite.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

	ftStatus = FT_WritePipe(ftHandle, 0x02, buff, bytesToWrite, &bytesTransferred, &vOverlappedWrite);
	if (ftStatus == FT_IO_PENDING)
	{
		// Poll until all data requested ulBytesToWrite is sent
		do
		{
			// FT_GetOverlappedResult will return FT_IO_INCOMPLETE if not yet finish
			ftStatus  =  FT_GetOverlappedResult(ftHandle, &vOverlappedWrite,  &bytesTransferred, FALSE);
			if (ftStatus == FT_IO_INCOMPLETE)
			{
				//AddReport(String().sprintf(_T("FT_IO_INCOMPLETE (%d)"), num_incomp));
				AttachReport(".");
				num_incomp++;
				continue;
			}
			else if(ftStatus != FT_OK)
			{
				AddReport(String().sprintf(_T("WritePipeAsync()::FT_GetOverlappedResult. (0x%X)"), ftStatus));
				CloseHandle(vOverlappedWrite.hEvent);
				return -1;
			}
			else //if (ftStatus == FT_OK)
			{
				break;
			}
		}
		while (1);
	}
	CloseHandle(vOverlappedWrite.hEvent);

Here is a state machine of the FPGA which receives data from the FT600. The clk is 200MHz. This state machine also write data to the FPGA internal FIFO memory.

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity H_FT600_S245_RX_V3 is

 port
 (
  clk    : in std_logic;
  reset  : in std_logic;
  act    : in std_logic;
  
  rcv_cmp : out std_logic;
  rcv_length : out std_logic_vector(15 downto 0);
  fifo_data : out std_logic_vector(15 downto 0);
  fifo_wrreq : out std_logic;
  
  be     : in std_logic_vector(1 downto 0);
  rxf    : in std_logic;
  oe     : out std_logic;
  rd     : out std_logic; 
  data   : in std_logic_vector(15 downto 0)
 );

end entity;

architecture rtl of H_FT600_S245_RX_V3 is

   -- Build an enumerated type for the state machine
   type state_type is (idle,s0,s1,s2,s3,s4,s5,s6,t0,t1,e0,e1);
   signal state : state_type;
   signal rcv_length_reg : std_logic_vector(15 downto 0);
   signal rxf_r : std_logic;
   signal oe_r  : std_logic;
   signal rd_r  : std_logic; 

begin

   rcv_length <= rcv_length_reg;

   process (clk, reset, rxf, act)
   begin
   if reset = '1' then
      state <= idle;
      oe <= '1';
      rd <= '1';
      rcv_cmp <= '0';
      rcv_length_reg <= X"0000";
      oe_r <= '1';
      rd_r <= '1';
      fifo_wrreq <= '0';
   elsif (rising_edge(clk)) then
   
      rxf_r <= rxf;
      oe <= oe_r;
      rd <= rd_r;
   
      case state is
         when idle =>
            rcv_length_reg <= X"0000";
            rcv_cmp <= '0';
            fifo_data <= X"BEEF";
            fifo_wrreq <= '0';
            oe_r <= '1';
            rd_r <= '1';
            if rxf_r = '0' and act = '1' then
               state <= s0;
            else
               state <= idle;
            end if;
         when s0 =>
            state <= s1;
         when s1 =>
            state <= s2;
         when s2 =>
            oe_r <= '0';
            state <= s3;
         when s3 =>
            state <= s4;
         when s4 =>
            rd_r <= '0';
            state <= s5;
         when s5 =>
            state <= s6;
         when s6 =>
            state <= t0;
         ---------------------------------------
         when t0 =>
            if rxf_r = '0' then
               fifo_data <= data;
               fifo_wrreq <= '1';
               oe_r <= '0';
               rd_r <= '0';
               rcv_length_reg <= rcv_length_reg + 1;
               state <= t1;
            else
               fifo_data <= X"DEAD";
               fifo_wrreq <= '0';
               oe_r <= '1';
               rd_r <= '1';
               rcv_length_reg <= rcv_length_reg;
               state <= e0;
            end if;
         when t1 =>
            state <= t0;
         ---------------------------------------
         when e0 =>
            rcv_cmp <= '1';
            state <= e1;
         when e1 =>
            rcv_cmp <= '0';
            state <= idle;
      end case;
   end if;
   end process;
end rtl;

An graph of transmit rate is here. It gets closer to 195MB.

The FT600 suspended transmitting after sending some blocks of data.  In this test, it asserted a RXF signal after sending 0x200, 0x400, 0x600 or 0x800 amount of data words. Period of the suspends are not fixed and around from 16 to 2186 clocks.
It did not suspend transmitting within 0x200 data words. This number is same as the FT600's internal output buffer size.

Waveform by SignalTap

Click to see all

Receive Rate

Periods are timed between requesting to receive data to the FT600 and being informed of completion.
Here is a part of codes of application.

	overlappedRead.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);

	if(FT_InitializeOverlapped(ftHandle, &overlappedRead) == FT_OK)
	{
		ftStatus = FT_ReadPipe(ftHandle, 0x82, buff, bytesToRead, &bytesRead, &overlappedRead);

		if(ftStatus == FT_IO_PENDING){
			while(1){
				ftStatus = FT_GetOverlappedResult(ftHandle, &overlappedRead, &bytesRead, FALSE);
				if(ftStatus == FT_IO_INCOMPLETE){
					//AddReport(String().sprintf(_T("FT_IO_INCOMPLETE (%d)"), num_incomp));
					AttachReport(".");
					num_incomp++;
					continue;
				}else if(ftStatus != FT_OK){
					AddReport(String().sprintf(_T("ReadPipe()::FT_GetOverlappedResult. (0x%X)"), ftStatus));
					CloseHandle(overlappedRead.hEvent);
					break;
				}else{ //ftStatus == FT_OK
					result = 0;
					break;
				}
			}
		}
		//----------------------------------------

		if(FT_ReleaseOverlapped(ftHandle, &overlappedRead) != FT_OK){
			AddReport("Error, ReadPipeAsync()::FT_ReleaseOverlapped");
			result = -1;
		}
	}else{
		AddReport("Error, ReadPipeAsync()::FT_InitializeOverlapped");
	}
	CloseHandle(overlappedRead.hEvent);

 

Here is a state machine of the FPGA which transmits  data to the FT600. The clk is 200MHz. This state machine also reads data from internal FIFO memory.

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity H_FT600_S245_TX_V6 is

 port
 (
  clk    : in std_logic;
  reset  : in std_logic;
  act    : in std_logic;
  
  fifo_data : in std_logic_vector(15 downto 0);
  fifo_rdreq : out std_logic;
  fifo_empty : in std_logic;

  be     : inout std_logic_vector(1 downto 0);
  txe    : in std_logic;
  wr     : out std_logic; 
  data   : inout std_logic_vector(15 downto 0);
  dbg_data   : out std_logic_vector(15 downto 0)
 );

end entity;

architecture rtl of H_FT600_S245_TX_V6 is

   -- Build an enumerated type for the state machine
   type state_type is (idle,s0,s1,s2,t0,t1,e0);
   signal state : state_type;
   signal fifo_rdreq_w : std_logic;
   signal txe_r : std_logic;
   signal wr_r : std_logic;

begin

   fifo_rdreq <= fifo_rdreq_w and not txe;

   process (clk, reset, txe, fifo_data)
   begin
   if reset = '1' then
      state <= idle;
      be <= (others=>'Z');
      data <= (others=>'Z'); 
      dbg_data <= X"0000";
      wr <= '1';
      wr_r <= '1';
      fifo_rdreq_w <= '0';
   elsif (rising_edge(clk)) then
   
   txe_r <= txe;
   wr <= wr_r;
   
   case state is
      when idle =>
         wr_r <= '1';
         data <= (others=>'Z');
         be <= (others=>'Z');
         fifo_rdreq_w <= '0';
         if txe_r = '0' and act = '1' then
            state <= s0;
         else
            state <= idle;
         end if;
      ---------------------------------------------
      when s0 =>
         state <= s1;
      when s1 =>
         fifo_rdreq_w <= '1';
         state <= s2; 
      when s2 =>
         wr_r <= '0';
         state <= t0;
      --------------------------------------
      when t0 =>
         if txe_r = '0' then
            fifo_rdreq_w <= '1';
            wr_r <= '0';
            data <= fifo_data;
            be <= "11";
            dbg_data <= fifo_data;
            state <= t1;
         else
            fifo_rdreq_w <= '0';
            wr_r <= '1';
            data <= (others=>'Z');
            be <= (others=>'Z');
            dbg_data <= X"EEEE";
            state <= e0;
         end if;
      when t1 =>
         state <= t0;
      ----------------------------
      when e0 =>
         state <= idle;
   end case;
   ------------------------------------------
   end if;
   end process;
end rtl;

 

An graph of receive rate is here. It gets closer to 180MB.

The FT600 suspended receiving data after getting 4096 Bytes by asserting an TXE signal. This number is equal to FT600 internal buffer.

Waveform by SignalTap

Click to see all

 

Contact us

We hope you find this demonstration informative.
Please let us know if you notice any mistakes.

Please be forewarned that we do not offer sample design files.


[kw] FT600 EDA-009 EDX-009 USB-106


[ ]

© HuMANDATA LTD. - Intel (Altera) & Xilinx FPGA Boards manufacturer in Japan - 2017 Sitemap