USB3.0 PHY方案(FT601Q)在 FPGA上的速率验证

一、背景

高通量在体神经信号采集系统,随着通道数增加、增加实时刺激需求等,采用以太网传输面临带宽极限,亟需一种更快的传输介质。

目前以太网的带宽极限:实测800Mbit/s左右,[移植并使用Iperf3测试ARM Linux网口带宽]https://www.cnblogs.com/dy-stairmed/p/18796116

在8port 30K采集速率下:16*64*2*8*30k = 491.5Mbit/s接近传输极限。

因此采用USB3.0 传输,理论传输带宽:5Gb/s。通过前期调研,目前USB3.0 PHY方案一般通过 FPGA实现。

二、硬件方案

FT601Q FIFO-USB3.0 Bridge,理论:400MB/s,连接至ZYNQ_PL端。

三、逻辑架构设计

  1. 系统框图

采用两个异步fifo实现多比特跨时钟域处理,将硬件接口转换为 FIFO的读写接口,后续可以根据应用调整为

AXI-STREAM接口。

2. 引脚定义:

3. 拟实现的读写时序

四、代码

  1. 驱动module

点击查看代码
/* 
 * file			: FT601Q.v
 * author		: D.y
 * date			: 2025-03-19
 * version		: v0.1
 * description	: usb3.0  FT601Q-QFN76 write and read control rtl.use 245 Synchronous FIFO mode.first release
				  use async fifo to deal with multi bit cross clock domain
				  actual test result: 380MB/s for read,340MB/s for write
 *
 */

module FT601Q(
input				clk,			//sysclk,50Mhz at least
input				rst_n,          //active low

//---------------FT601Q------------------
input				USB_CLK,		//FT601Q phy output clk, configure to 100MHz using FT600ChipConfigurationProgUtility_v1.3.0.2)
inout		[31:0]	USB_D,			//32bit data inout,I/O
inout		[3:0]	USB_BE,			//Byte Enable,active high,4'b1111 means using 4 Channel

input				USB_TXE,		//FT601Q-FIFO write enable?601Q-FIFO not full),active low
input				USB_RXF,		//FT601Q-FIFO read enable ?601Q-FIFO not empty),active low

output	reg			USB_OE,			//FT601Q Data Output Enable active low
output	reg			USB_RD,			//FT601Q-read  enable,active low
output	reg			USB_WR,			//FT601Q-write enable,active low

inout				USB_Wakeup,
//Suspend/Remote Wakeup pin by default Low when USB is active, high when USB is in suspend. 
//Application can drive this pin low in in USB suspend to generate a remote wakeup signal to the USB host.

output	reg			USB_RSTn,		//RESET_N,USB_EN,enable use
output				USB_SIWU,		//reserved,should pull-up
inout				USB_GPIO0,		//GPIO0 
inout				USB_GPIO1,		//GPIO1

//-------------FPGA Control------------------
input				wr_en,			//active high
input		[31:0]	wrdat,
output				full,

input				rd_en,			//active high
output		[31:0]	rddat,
output				empty
);

//-------------------------state define------------------------------
localparam	        RESET	=  8'h01;
localparam	        IDLE	=  8'h02;
localparam	        WRITE	=  8'h04;		//write fifo not empty,and USB_TXE keep low ,push data into USB
localparam	        READ	=  8'h08;		//USB_RXF keep low,and read fifo not full,read data to read fifo

//-------------------------signal define-----------------------------
reg		[7:0]	   state		= RESET;
reg		[7:0]	   next_state	= RESET;

wire			   w_fifo_full;
wire			   w_fifo_empty;
wire			   r_fifo_full;
wire			   r_fifo_empty;
reg				   w_fifo_rden		= 1'b0;
reg				   r_fifo_wren		= 1'b0;
wire			   fifo_rst;
reg		[7:0]	   rst_cnt			= 8'd0;

assign			   fifo_rst		    = ~rst_n;

//----------------------------iobuf---------------------------------
wire	[31:0]	USB_D_buf;
(* mark_debug = "true" *) reg			USB_D_link	= 1'b0;

assign	USB_D	= (USB_D_link)? USB_D_buf : 32'dz;
wire			GPIO0_buf;
wire			GPIO1_buf;
reg				GPIO_link	= 1'b0;
assign	        GPIO0_buf	= 1'b0;
assign	        GPIO1_buf	= 1'b0;
assign	        USB_GPIO0	= (GPIO_link)? GPIO0_buf : 1'bz;
assign	        USB_GPIO1	= (GPIO_link)? GPIO1_buf : 1'bz;

wire	[3:0]	USB_BE_buf;
reg				USB_BE_link	= 1'b0;
reg     [31:0]   USB_DATA;
reg              r_fifo_wren_r1;
assign	USB_BE_buf	= 4'b1111;
assign	USB_BE		= (USB_BE_link)? USB_BE_buf : 4'dz;

(* mark_debug = "true" *) wire [31:0] debug_data ;

//----------------------------logic---------------------------------
// for debud only
assign debug_data = USB_D;
//always @(posedge USB_CLK) begin
//	if(USB_BE_link)
//		debug_data <= USB_D;
//	else
//		debug_data <= 'd0;
//end

//-------------------------write fifo--------------------------------
//async FIFO     First Word Fall Through mode
fifo_generator_ft60x fifo_w(
	.rst		(fifo_rst),
	.wr_clk		(clk),
	.rd_clk		(USB_CLK),
	.din		(wrdat),
	.wr_en		(wr_en),
	.rd_en		(w_fifo_rden),
	.dout		(USB_D_buf),
	.full		(w_fifo_full),
	.empty		(w_fifo_empty)
);

//--------------------------read fifo--------------------------------
//always @(posedge USB_CLK or negedge rst_n) begin
//	if(~rst_n) begin
//		USB_DATA <= 'b0;
//		r_fifo_wren_r1 <= 1'b0;
//	end
//	else begin
//			USB_DATA <= USB_D;
//			r_fifo_wren_r1 <= r_fifo_wren;
//	end
//end
//异步FIFO
fifo_generator_ft60x fifo_r(
	.rst		(fifo_rst),
	.wr_clk		(USB_CLK),
	.rd_clk		(clk),
	.din		(USB_D),
	.wr_en		(r_fifo_wren),
	.rd_en		(rd_en),
	.dout		(rddat),
	.full		(r_fifo_full),
	.empty		(r_fifo_empty)
);

//-----------------------------FSM----------------------------------
always @(posedge clk or negedge rst_n) begin
	if(~rst_n) begin
		state		<= RESET;
		rst_cnt		<= 8'd0;
	end
	else begin
		state		<= next_state;

		if(rst_cnt < 8'd200) begin
			rst_cnt		<= rst_cnt + 1'b1;
		end
		else begin
			rst_cnt		<= rst_cnt;
		end
	end
end

always @(*) begin
	case(state)
	RESET: begin
		if(rst_cnt >= 8'd200) begin
			next_state	<= IDLE;
		end
		else begin
			next_state	<= RESET;
		end
	end
	IDLE: begin
		if((~USB_TXE) && (~w_fifo_empty)) begin
			next_state	<= WRITE;
		end
		else if((~USB_RXF) && (~r_fifo_full)) begin
			next_state	<= READ;
		end
		else begin
			next_state	<= IDLE;
		end
	end
	WRITE: begin
		if(USB_TXE || w_fifo_empty) begin
			next_state	<= IDLE;
		end
		else begin
			next_state	<= WRITE;
		end
	end
	READ: begin
		if(USB_RXF || r_fifo_full) begin
			next_state	<= IDLE;
		end
		else begin
			next_state	<= READ;
		end
	end
	default: begin
		next_state	<= IDLE;
	end
	endcase
end

//----------------------------Control--------------------------------
assign	full		= w_fifo_full;
assign	empty		= r_fifo_empty;
assign	USB_SIWU	= 1'b1;

always @(posedge clk) begin
	case(state)
	RESET: begin
		GPIO_link	<= 1'b1;
	end
	default: begin
		GPIO_link	<= 1'b0;
	end
	endcase
end

always @(*) begin
	case(state)
	RESET: begin
		USB_RSTn	<= 1'b0;
	end
	default: begin
		USB_RSTn	<= 1'b1;
	end
	endcase
end

always @(*) begin
	case(state)
	WRITE: begin
		USB_D_link	<= 1'b1;
	end
	default: begin
		USB_D_link	<= 1'b0;
	end
	endcase
end

// ------------USB FIFO write--------------
always @(*) begin
	case(state)
	WRITE: begin
		USB_BE_link		<= 1'b1;
		USB_WR			<= ((~USB_TXE) & (~w_fifo_empty))? 1'b0 : 1'b1;
		w_fifo_rden		<= ((~USB_TXE) & (~w_fifo_empty))? 1'b1 : 1'b0;
	end
	default: begin
		USB_BE_link		<= 1'b0;
		USB_WR			<= 1'b1;
		w_fifo_rden		<= 1'b0;
	end
	endcase
end

// ------------USB FIFO read---------------
always @(*) begin
	case(state)
	READ: begin
		USB_OE			<= ((~USB_RXF) & (~r_fifo_full))? 1'b0 : 1'b1;
		USB_RD			<= ((~USB_RXF) & (~r_fifo_full))? 1'b0 : 1'b1;
	end
	default: begin
		USB_OE			<= 1'b1;
		USB_RD			<= 1'b1;
	end
	endcase
end

always @(posedge USB_CLK) begin
	case(state)
	READ: begin
		r_fifo_wren		<= ((~USB_RXF) & (~r_fifo_full))? 1'b1 : 1'b0;
	end
	default: begin
		r_fifo_wren		<= 1'b0;
	end
	endcase
end

endmodule

2. ## 例化top:
点击查看代码
/* 
 * file			: top.v
 * author		: D.y
 * date			: 2025-03-19
 * version		: v0.1
 * description	: top module for FT601Q USB3.0 PHY
                  install FT601 MODULE,and generate sys_rst_n and system clk soure 100Mhz
 *
 */
module   top(
    input              sys_clk        ,                         // using outside 200M OSC
//    inout              GPIO_0_0_tri_io ,
//    inout              IIC_0_0_scl_io  ,
//    inout              IIC_0_0_sda_io  ,
//    output             MDIO_ETHERNET_0_0_mdc,
//     inout             MDIO_ETHERNET_0_0_mdio_io,
    //FT601
    input              USB_CLK         ,
    inout       [31:0] USB_D           ,
    inout		[3:0]  USB_BE          ,
    input              USB_TXE         ,
    input              USB_RXF         ,
    output		       USB_OE          ,
    output             USB_RD          ,
    output             USB_WR          ,
    inout              USB_Wake        ,
    output             USB_RSTn        ,
    output             USB_SIWU        ,
    inout              USB_GPIO_0      ,
    inout              USB_GPIO_1       
);




//wire define
wire                     clk_50M         ;
wire                     clk_200M_nRst   ;
wire                     pll_locked      ;
wire                     sys_rst_n       ;
wire                     empty           ;
wire                     fifo_full       ;
reg                      fifo_wr_en      ;
reg                      fifo_rd_en      ;
reg              [15:0]  test_data ='d0  ;
wire              [31:0]  loop_back_data ;
wire              [31:0]  rd_data        ;


// delay reset, active low
delayed_nReset  U_delayed_nReset
(
    .CLK(sys_clk),
    .nRst(clk_200M_nRst)
);

// mmcm for output 100Mhz sysclk
clk_wiz_0 my_clk_wiz_0
(
    // Clock out ports
    .clk_out1(clk_50M),     // output clk_out1
    // Status and control signals
    .reset(~clk_200M_nRst), // input reset
    .locked(pll_locked),       // output locked
   // Clock in ports
    .clk_in1(sys_clk)
);      // input clk_in1

assign  sys_rst_n   = pll_locked;

//my_block_design_wrapper  my_block_design_wrapper_ins
//   (
//      .MDIO_ETHERNET_0_0_mdc       (MDIO_ETHERNET_0_0_mdc)    ,
//      .MDIO_ETHERNET_0_0_mdio_io   (MDIO_ETHERNET_0_0_mdio_io)    ,
//     .GPIO_0_0_tri_io   (GPIO_0_0_tri_io),
//     .IIC_0_0_scl_io    (IIC_0_0_scl_io),
//     .IIC_0_0_sda_io    (IIC_0_0_sda_io),
//    .clk_out1_0  (clk_50M),
//    .locked_0    (pll_locked)
//    );


//-------------------------write data test-------------------------------
// USB_TXE is low , fifo write enable,and toggle data
always @(posedge clk_50M or negedge sys_rst_n) begin
    if(~sys_rst_n) begin
        fifo_wr_en <= 1'b0;
        test_data  <= 'd0;
    end
    else begin
        if(~USB_TXE) begin
            fifo_wr_en <= 1'b1;
            test_data <= test_data + 1'b1;
        end
        else begin
            fifo_wr_en <= 1'b0;
            test_data  <= 'd0;
        end
    end
end


//-------------------------read data test-------------------------------
//USB_RD is low ,fifo read enable,read data from fifo
always @(posedge USB_CLK or negedge sys_rst_n) begin
    if(~sys_rst_n) begin
        fifo_rd_en <= 1'b0;
    end
    else begin
        if(~USB_RXF) begin
            fifo_rd_en <= 1'b1;
        end
        else begin
            fifo_rd_en <= 1'b0;
        end
    end
end


FT601Q   FT601Q_ins
(
    .clk       (clk_50M)      ,	
    .rst_n     (sys_rst_n)    ,
    .USB_CLK   (USB_CLK)      ,
    .USB_D     (USB_D)        ,	
    .USB_BE    (USB_BE)       ,	
    .USB_TXE   (USB_TXE)      ,
    .USB_RXF   (USB_RXF)      ,
    .USB_OE    (USB_OE)       ,	
    .USB_RD    (USB_RD)       ,	
    .USB_WR    (USB_WR)       ,	
    .USB_Wakeup(USB_Wake)     ,
    .USB_RSTn  (USB_RSTn)     ,
    .USB_SIWU  (USB_SIWU)     ,
    .USB_GPIO0 (USB_GPIO_0)   ,
    .USB_GPIO1 (USB_GPIO_1)   ,
    .wr_en     (fifo_wr_en)    ,	
    .wrdat     ({test_data,test_data})     ,
    .full      (fifo_full)                 ,
    .rd_en     (fifo_rd_en)    ,	
    .rddat     (rd_data)       ,
    .empty     (empty     )
);

(* mark_debug = "true" *) wire [31:0] top_debug_data  = rd_data;
//fifo_generator_ft60x my_fifo_generator_ft60x (
//  .rst(~sys_rst_n),        // input wire rst
//  .wr_clk(USB_CLK),  // input wire wr_clk
//  .rd_clk(USB_CLK),  // input wire rd_clk
//  .din(rd_data),        // input wire [31 : 0] din
//  .wr_en(fifo_rd_en),    // input wire wr_en
//  .rd_en(fifo_wr_en),    // input wire rd_en
//  .dout(loop_back_data),      // output wire [31 : 0] dout
//  .full(),      // output wire full
//  .empty()    // output wire empty
//);


endmodule




五、测试过程

  1. 驱动安装(需要使用支持 USB3.0 的USB-TYPE B线缆,)


同时电脑的USB接口也需要支持USB3.0,带SS(Super Speed)标志

插入后,windows会自行安装设备驱动,通过设备管理器可以识别如下:

通过Vivado创建项目,并进行引脚约束,生成bitstream,烧录。

  1. 测试工具

使用官方提供的流测试工具:FT600DataStreamerDemoApp_v1.3.0.10

下载链接如下:

https://ftdichip.com/software-examples/ft600-601-software-examples-2/

六、测试结果

  1. 写速率(上位机---> FPGA****),382MB/s.

  1. 读速率(FPGA ---->上位机),344MB/s

需要使用支持 USB3.0 的USB-TYPE B线缆,

posted @ 2025-03-27 15:30  羊的第七章  阅读(884)  评论(0)    收藏  举报