如图可以看到,FPGA端产生批量数据通过SlaveFIFO接口发送到FX3,直到FX3的多个FIFO通道都写满了.然后FX3中的数据可以通过USB3.0口快速的传输给电脑.本篇文章讲述的就是如何按照一定的时序将数据写入Slave FIFO中.
开发板:我用的是特权hsc开发板
FX3工具:下载安装可以参考这个网址:https://blog.csdn.net/zhang_ze1234/article/details/99654170
好了,准备工作做好之后就可以开始写代码了,本实例使用Verilog 编写
输入输出定义:
module usb_controller(
input clk, //100MHz
input rst_n,
//FX3 Slave FIFO接口
input fx3_flaga,
input fx3_flagb,
input fx3_flagc, //ctl[9]
input fx3_flagd, //ctl[8]
//output fx3_pclk, //Slave FIFO同步时钟信号
output reg fx3_slcs_n, //Slave FIFO片选信号,低电平有效
output reg fx3_slwr_n, //Slave FIFO写使能信号,低电平有效
output reg fx3_slrd_n, //Slave FIFO读使能信号,低电平有效
output reg fx3_sloe_n, //Slave FIFO输出使能信号,低电平有效
output reg fx3_pktend_n, //包结束信号
output reg[1:0] fx3_a, //操作FIFO地址
inout[31:0] fx3_db //数据
);
//寄存器和参数定义
reg[9:0] num; //数据寄存器
reg[3:0] delaycnt; //计数器
reg[3:0] fxstate; //状态寄存器
parameter FXS_REST = 4'd0;
parameter FXS_IDLE = 4'd1;
parameter FXS_WRIT = 4'd5;
parameter FXS_WSOP = 4'd6;
//定时读写操作状态机
always @(posedge clk or negedge rst_n)
if(!rst_n) fxstate <= FXS_REST;
else begin
case(fxstate)
FXS_REST: begin
fxstate <= FXS_IDLE;
end
FXS_IDLE: begin
if( fx3_flaga) fxstate <= FXS_WRIT; //如果fx_3_flaga为高电平时,Slave FIFO为空,可以写数据
else fxstate <= FXS_IDLE;
end
FXS_WRIT: begin
if(num >= 10'd256) fxstate <= FXS_WSOP;
else fxstate <= FXS_WRIT;
end
FXS_WSOP: begin
if(delaycnt >= 4'd4) fxstate <= FXS_IDLE;
else fxstate <= FXS_WSOP;
end
default: fxstate <= FXS_IDLE;
endcase
end
//数据计数器,用于产生读写时序
always @(posedge clk or negedge rst_n)
if(!rst_n) num <= 10'd0;
else if(fxstate == FXS_WRIT) num <= num+1'b1; //Slave FIFO写操作
else num <= 10'd0;
//6个clock的延时计数器
always @(posedge clk or negedge rst_n)
if(!rst_n) delaycnt <= 4'd0;
else if(fxstate == FXS_WSOP) delaycnt <= delaycnt+1'b1;
else delaycnt <= 4'd0;
//FX3 Slave FIFO控制信号时序产生
parameter FX3_ON = 1'b0;
parameter FX3_OFF = 1'b1;
always @(posedge clk or negedge rst_n)
if(!rst_n) begin
fx3_slcs_n <= FX3_OFF; //Slave FIFO片选信号,低电平有效
fx3_slwr_n <= FX3_OFF; //Slave FIFO写使能信号,低电平有效
fx3_slrd_n <= FX3_OFF; //Slave FIFO读使能信号,低电平有效
fx3_sloe_n <= FX3_OFF; //Slave FIFO输出使能信号,低电平有效
fx3_pktend_n <= FX3_OFF; //包结束信号
fx3_a <= 2'b00; //操作FIFO地址
end
else if(fxstate == FXS_IDLE) begin
fx3_slcs_n <= FX3_OFF; //Slave FIFO片选信号,低电平有效
fx3_slwr_n <= FX3_OFF; //Slave FIFO写使能信号,低电平有效
fx3_slrd_n <= FX3_OFF; //Slave FIFO读使能信号,低电平有效
fx3_sloe_n <= FX3_OFF; //Slave FIFO输出使能信号,低电平有效
fx3_pktend_n <= FX3_OFF; //包结束信号
fx3_a <= 2'b00; //写数据
end
else if(fxstate == FXS_WRIT) begin
if(num == 10'd0) begin //cs = 0; addr = 2'b00;wr = 0;
fx3_slcs_n <= FX3_ON; //Slave FIFO片选信号,低电平有效
fx3_slwr_n <= FX3_ON; //Slave FIFO写使能信号,低电平有效
fx3_slrd_n <= FX3_OFF; //Slave FIFO读使能信号,低电平有效
fx3_sloe_n <= FX3_OFF; //Slave FIFO输出使能信号,低电平有效
fx3_pktend_n <= FX3_OFF; //包结束信号
fx3_a <= 2'b00; //FIFO读地址
end
else if(num == 10'd255) begin //fx3_pktend_n =0
fx3_slcs_n <= FX3_ON; //Slave FIFO片选信号,低电平有效
fx3_slwr_n <= FX3_ON; //Slave FIFO写使能信号,低电平有效
fx3_slrd_n <= FX3_OFF; //Slave FIFO读使能信号,低电平有效
fx3_sloe_n <= FX3_OFF; //Slave FIFO输出使能信号,低电平有效
fx3_pktend_n <= FX3_ON; //包结束信号
fx3_a <= 2'b00; //FIFO读地址
end
else if(num == 10'd256) begin //cs = 0; addr = 2'b00;
fx3_slcs_n <= FX3_OFF; //Slave FIFO片选信号,低电平有效
fx3_slwr_n <= FX3_OFF; //Slave FIFO写使能信号,低电平有效
fx3_slrd_n <= FX3_OFF; //Slave FIFO读使能信号,低电平有效
fx3_sloe_n <= FX3_OFF; //Slave FIFO输出使能信号,低电平有效
fx3_pktend_n <= FX3_OFF; //包结束信号
fx3_a <= 2'b00; //FIFO读地址
end
end
else if(fxstate == FXS_WSOP) begin
fx3_slcs_n <= FX3_OFF; //Slave FIFO片选信号,低电平有效
fx3_slwr_n <= FX3_OFF; //Slave FIFO写使能信号,低电平有效
fx3_slrd_n <= FX3_OFF; //Slave FIFO读使能信号,低电平有效
fx3_sloe_n <= FX3_OFF; //Slave FIFO输出使能信号,低电平有效
fx3_pktend_n <= FX3_OFF; //包结束信号
fx3_a <= 2'b00; //操作FIFO地址
end
else begin
fx3_slcs_n <= FX3_OFF; //Slave FIFO片选信号,低电平有效
fx3_slwr_n <= FX3_OFF; //Slave FIFO写使能信号,低电平有效
fx3_slrd_n <= FX3_OFF; //Slave FIFO读使能信号,低电平有效
fx3_sloe_n <= FX3_OFF; //Slave FIFO输出使能信号,低电平有效
fx3_pktend_n <= FX3_OFF; //包结束信号
end
产生数据写入Slave FIFO中
reg[31:0] fx3_wdb; //FX3写数据寄存器
always @(posedge clk or negedge rst_n)
if(!rst_n) fx3_wdb <= 32'd0;
else if((fxstate == FXS_WRIT) && (num < 10'd256)) fx3_wdb <= fx3_wdb+1'b1;
assign fx3_db = fx3_wdb; //FX3数据总线方向控制
到这里代码就写完了,数据已经可以放入Slave FIFO中了
下面我们来解释一下这段代码.
该段代码的主要功能是检测FX3的SlaveFIFO是否为空,并且不断的写入数据帧。
功能框图如图所示。FX3读写状态机一旦检测到FX3的SlaveFIFO为空,则进入FX3数据写入的状态,写入新的数据帧到FX3的FIFO中。
FX3读写状态机的状态迁移图如下
我们可以看到上电状态为FXS_REST ,随后就进入FXS_IDLE状态,判断SlaveFIFO是否为空,可以写入数据,若可以则进入FXS_WRIT状态写数据到FX3的SlaveFIFO中,接着进入FXS_WSOP状态停留一个时钟周期,最后回到FXS_IDLE状态,如此反复.