基于FX600Q芯片的USB3.0设计

概述

本来打算第一个例子做一些简单的语法操作,但是感觉那样太浪费我和同学们的时间,所以这个例子,我们来写USB 3.0芯片FX600Q的驱动代码。本次使用的硬件环境与软件环境如下:

FPGA开发板:米联客MA7035FA 100T版本
软件环境:vivado2019.1
上位机软件:米联客开发的上位机软件

这里说明一下,USB3.0协议的速度是5Gbps与PCIE2,0速度相同。但是FX600Q的速度因为引脚的限制只能达到200MB/s,这里如果想全部利用USB3.0的速度,需要使用FX601Q芯片,两个芯片的时序一模一样,只是FX601Q比FX600Q数据引脚数目多一半。

FX600Q芯片介绍

这里关于FX600Q芯片的介绍,不作为主要重点。芯片的内部结构如下:
在这里插入图片描述

我们只需要理解芯片与FPGA相连的引脚即可,这里以MA7035FA为例,FPGA与芯片的连接图如下:
在这里插入图片描述
这里对上面的引脚及其作用进行解释:
USBSS_D:数据信号;
USBSS_BE:数据信号的字节使能信号,BE1对应高字节,BE0对应低字节,为1的情况下对应的数据位有效;
USBSS_TEX:学习USB芯片,最简单的一种方式就是把USB芯片看成FPGA与PC机之间的FIFO,TEX信号为0时代表该FIFO还有空间可以供写入;
USBSS_REX:为0时代表该USB所代表的FIFO还有数据可供读出;
USBSS_OE:数据输出的使能信号,一般在FPGA读USB芯片时为0,写USB芯片时为1;
USBSS_RD:读使能信号,0为有效;
USBSS_WR:写使能信号,0为有效;
USBSS_SIWU:为0时增加一个额外的拉力,一般恒为0;
USBSS_CLK:数据读出和写入的随路时钟;
USBSS_EN:芯片使能信号,一般默认为1;
USBSS_WAKEUP:芯片上电信号,一般默认为1;
GPIO:芯片配置信号,一般默认2’b00;

FX600Q的读写时序

把TX600Q当成一个FIFO来操作,那么他的读写时序就非常简单,FPGA读TX600Q芯片的时序如下:
在这里插入图片描述
FPGA写TX600Q芯片的时序如下:
在这里插入图片描述

FPGA驱动代码

由FX600Q的读写时序与引脚的定义可以很容易的写出代码,这里我使用的代码风格是参考的开源骚客的风格,个人感觉特别简练与整齐,这里使用的软件工具为sublime需要的可以进群里面自取:

`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : [email protected]
// Website      : 
// Module Name  : top.v
// Create Time  : 2019-12-30 10:03:09
// Editor       : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date             By              Version                 Change Description
// -----------------------------------------------------------------------
// XXXX       zhangningning          1.0                        Original
//  
// *********************************************************************************


module top(
    input                       rst_n               ,
    output  wire                USBSS_EN            ,
    input                       sclk                ,
    inout           [15:0]      data                ,
    inout           [ 1:0]      be                  ,
    input                       rxf_n               ,
    input                       txf_n               ,
    output  reg                 oe_n                ,
    output  reg                 wr_n                ,
    output  wire                siwu_n              ,
    output  reg                 rd_n                ,
    output  wire                wakeup              ,
    output  wire    [ 1:0]      gpio            
);
 
//========================================================================================\
//**************Define Parameter and  Internal Signals**********************************
//========================================================================================/
parameter   IDLE        =       4'b0001             ;
parameter   JUDGE       =       4'b0010             ;
parameter   READ        =       4'b0100             ;
parameter   WRITE       =       4'b1000             ;

reg         [ 3:0]              state               ;
wire        [15:0]              data_in             ;
wire        [15:0]              data_out            ;
//wire        [ 1:0]              be_in               ;
//wire        [ 1:0]              be_out              ; 
wire                            fifo_wr             ;
wire                            almost_full         ;
wire                            fifo_rd             ;
wire                            almost_empty        ;


 
//========================================================================================\
//**************     Main      Code        **********************************
//========================================================================================/
assign      USBSS_EN    =       1'b1;
assign      wakeup      =       1'b1;
assign      siwu_n      =       1'b0;
assign      gpio        =       2'b00;    
assign      fifo_wr     =       (rd_n == 1'b0) && (rxf_n == 1'b0);
assign      data_in     =       (state == READ) ? data : 16'hzzzz;
assign      fifo_rd     =       (wr_n == 1'b0) && (txf_n == 1'b0);
assign      data        =       (state == WRITE) ? data_out : 16'hzzzz;
assign      be          =       (state == WRITE) ? 2'b11 : 2'bzz;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        state       <=          IDLE;
    else case(state)
        IDLE    :   state       <=          JUDGE;
        JUDGE   :   if(rxf_n == 1'b0 && almost_full == 1'b0)
                        state       <=          READ;
                    else if(txf_n == 1'b0 && almost_empty == 1'b0)
                        state       <=          WRITE;
                    else
                        state       <=          JUDGE;                        
        WRITE   :   if(txf_n == 1'b1)
                        state       <=          JUDGE;
                    else
                        state       <=          WRITE;                        
        READ    :   if(rxf_n == 1'b1)
                        state       <=          JUDGE;
                    else
                        state       <=          READ;
        default :   state       <=          IDLE;
    endcase

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        oe_n        <=          1'b1;     
    else if(state == READ && rxf_n == 1'b1)
        oe_n        <=          1'b1;
    else if(state == READ)
        oe_n        <=          1'b0;
    else
        oe_n        <=          oe_n;
        
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        rd_n        <=          1'b1;
    else if(state == READ && rxf_n == 1'b1)
        rd_n        <=          1'b1;
    else if(state == READ && oe_n == 1'b0)
        rd_n        <=          1'b0;
    else
        rd_n        <=          rd_n;

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        wr_n        <=          1'b1;
    else if(state == WRITE && txf_n == 1'b1)
        wr_n        <=          1'b1;
    else if(state == WRITE)
        wr_n        <=          1'b0;
    else
        wr_n        <=          wr_n;


      
        
fifo_generator_0 fifo_generator_0_inst (
  .clk              (sclk               ),                    // input wire clk
  .srst             (~rst_n             ),                  // input wire srst
  .din              (data_in            ),                    // input wire [15 : 0] din
  .wr_en            (fifo_wr            ),                // input wire wr_en
  .rd_en            (fifo_rd            ),                // input wire rd_en
  .dout             (data_out           ),                  // output wire [15 : 0] dout
  .full             (                   ),                  // output wire full
  .almost_full      (almost_full        ),    // output wire almost_full
  .empty            (                   ),                // output wire empty
  .almost_empty     (almost_empty       )  // output wire almost_empty
);


endmodule

如果只有驱动代码,那么调试起来与读起来都很麻烦,所以这里给出tb测试代码,测试代码写的就比较草了,如下:

`timescale 1ns / 1ps
`define  CLOCK      20
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : [email protected]
// Website      : 
// Module Name  : tb_top.v
// Create Time  : 2019-12-30 11:35:06
// Editor       : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date             By              Version                 Change Description
// -----------------------------------------------------------------------
// XXXX       zhangningning          1.0                        Original
//  
// *********************************************************************************

module tb_top;
reg                 rst_n               ;
reg                 sclk                ;
wire                USBSS_EN            ;
wire        [15:0]  data                ;
wire        [ 1:0]  be                  ;

reg         [15:0]  data_in             ;
reg                 rxf_n               ;
reg                 txf_n               ;
wire                oe_n                ;
wire                wr_n                ;
wire                siwu_n              ;
wire                rd_n                ;
wire                wakeup              ;
wire    [ 1:0]      gpio                ;      


initial begin
    rst_n       =           1'b0;
    sclk        <=          1'b0;
    rxf_n       =           1'b1;
    txf_n       =           1'b1;
    #(50*`CLOCK)
    rst_n       =           1'b1;
    #(50*`CLOCK)
    rxf_n       =           1'b0;
    #(100*`CLOCK)
    rxf_n       =           1'b1;
    #(100*`CLOCK)
    txf_n       =           1'b0;
    #(100*`CLOCK)
    txf_n       =           1'b1;
end
always     #(`CLOCK/2)         sclk        <=      ~sclk;

assign  data            =       (top_inst.state == 4'b0100) ? data_in : 16'hzzzz;
assign  be              =       (top_inst.state == 4'b0100) ? 2'd3 : 2'bzz;
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        data_in         <=          'd0;
    else if(top_inst.fifo_wr == 1'b1)
        data_in         <=          data_in + 1'b1;

top top_inst(
    .rst_n                      (rst_n                      ),
    .USBSS_EN                   (USBSS_EN                   ),
    .sclk                       (sclk                       ),
    .data                       (data                       ),
    .be                         (be                         ),
    .rxf_n                      (rxf_n                      ),
    .txf_n                      (txf_n                      ),
    .oe_n                       (oe_n                       ),
    .wr_n                       (wr_n                       ),
    .siwu_n                     (siwu_n                     ),
    .rd_n                       (rd_n                       ),
    .wakeup                     (wakeup                     ),
    .gpio                       (gpio                       )       
);
endmodule

个人感觉自己的代码风格还是很清爽的,该模块的功能是回环测试功能,至于FIFO的定义,自己在vivado中补充就行了。上位机软件这里不做讲述,需要的可以参考米联客的配套上位机(包括源码),也可以进群自取。

参考文献

[1] 米联客MA7035FA开发板配套资料

结束语

对文章有什么看法或者需要更近一步交流的同学,可以加入下面的群:
在这里插入图片描述

发布了14 篇原创文章 · 获赞 4 · 访问量 600

猜你喜欢

转载自blog.csdn.net/zhangningning1996/article/details/103825822