近期在处理一个USB2.0通信的问题,采用FPGA主控,FT245为USB芯片,Verilog编程控制。FT245有RD和WR两个读写控制端,RXF和TXE两个USB芯片工作状态反馈端。数据读操作很少,目前没问题;数据写量稍大,发送是从fifo模块发送的,先存,存到7296后停止,然后发,一次228个,分32次发完,然后发现漏数的问题,而且漏数不固定。首先我认为FPGA生成的时序本身应该是可以信任的,所以应该是编程本身的问题。我的思路是:通过控制程序中的一个写使能寄存器保证1M的发送时钟。WR端常低,写使能在1M的周期中给3/5的高电平。在写使能为高的情况下,判断TXE为低后,等待一段时间后开始将WR端置高,然后在置低。等待时间和发送时间通过一个计数器计数。时间都是超过说明书里的最小值的。我不了解这里怎么出问题了,有大神能给个参考设计或者修改思路吗,谢谢。程序是网上找然后修改的,clk为50M,如下:
`timescale 1ns/1ps
module FT245test(
//系统信号
input sclk, //sclk为FPGA工作时钟,默认100MHz.
input rst_n, //异步复位信号,低有效.
//FPGA和FT245MB间的USB接口
input USB_RXF,
input USB_TXE,
output reg USB_RD,
output reg USB_WR,
inout tri [7:0] USB_DATA, //USB和FPGA间的双向数据库总线
//模块内部和其他模块或器件间的接口
output reg [7:0] RX_data_fm_usb, //其他模块或器件从本模块读取来自USB接口的数据
input wire [7:0] TX_data_to_usb, //其他模块或器件向本模块写入发到USB接口的数据
input wire [7:0]TX_data_to_usb1,
input wire RD_Enable, //其他模块或器件从本模块读取来自USB接口数据的读使能,高有效
input wire WR_Enable, //其他模块或器件向本模块写入发到USB接口数据的写使能,高有效
output reg USB_busy, //USB接口忙/空闲状态信号,高为忙碌,低为空闲
input wire start_signal,//启动信号
input wire checktime_signal//读取积分时间信号
); //处于读状态时,由忙碌状态变为空闲状表示上一个数据开始有效
//******************************************************
//内部寄存器定义
reg [7:0] data_fm_usb; //从USB接收数据
reg [7:0] data_to_usb; //发送数据到USB
reg [7:0] data_to_usb_buffer; //发送缓冲寄存器
reg [4:0] RD_time_cont; //读等待时间计数器
reg [4:0] WR_time_cont; //写等待时间计数器
parameter RX_state0 = 2'b01; //读状态0
parameter RX_state1 = 2'b10; //读状态1
parameter TX_state0 = 2'b01; //写状态0
parameter TX_state1 = 2'b10; //写状态1
reg [1:0] RX_state; //读状态
reg [1:0] TX_state; //写状态
//******************************************************
//本模块与FT245B间的数据总线
//******************************************************
assign USB_DATA=(USB_WR==1'b1)?data_to_usb:8'bzz;
//******************************************************
//其他模块与本模块之间的数据交换
//******************************************************
always@(posedge sclk or negedge rst_n)//接收数据
if(!rst_n)
RX_data_fm_usb <= 8'h00;
else if(RD_Enable == 1'b1)
RX_data_fm_usb <= data_fm_usb;
// else
// RX_data_fm_usb <= 8'haf;
//////////////////////////////////
always@(posedge sclk or negedge rst_n)//发送数据
if(!rst_n)
data_to_usb_buffer <= 8'b00;
else
begin
if(WR_Enable == 1'b1)
begin
if((start_signal==1'b1)&&(checktime_signal==1'b0))
begin
data_to_usb_buffer <= TX_data_to_usb;
end
else if(checktime_signal==1'b1)
begin
data_to_usb_buffer <= TX_data_to_usb1;
end
else
begin
data_to_usb_buffer <= 8'b00;
end
end
else
begin
data_to_usb_buffer <= 8'b00;
end
end
//******************************************************
//USB接口忙/空闲状态信号USB_busy处理
//******************************************************
always@(posedge sclk or negedge rst_n)
if(!rst_n)
USB_busy<=1'b0; //状态机复位到空闲
else if((USB_RXF==1'b0 && RD_Enable == 1'b1)||(USB_TXE==1'b0 && WR_Enable==1'b1))
USB_busy<=1'b1; //状态机忙碌
else
USB_busy<=1'b0; //状态机空闲
//******************************************************
//读/写FT254BM相关等待时间计数
//******************************************************
always@(posedge sclk or negedge rst_n)
if(!rst_n)
RD_time_cont<=8'b0;
else if(USB_RD==1'b0) //读使能到来开始计数.
RD_time_cont<=RD_time_cont + 1'b1;
else if(USB_RXF == 1'b1) //USB_RXF == 1'b1//RD_time_cont == 5'd5 //USB_RXF没拉高之前不允许有其他跨读(写)操作
RD_time_cont<=8'b0;
//******************************************************
always@(posedge sclk or negedge rst_n)
if(!rst_n)
WR_time_cont<=8'b0;
else if(USB_WR==1'b1) //写使能到来开始计数.
WR_time_cont<=WR_time_cont + 1'b1;
else if(USB_TXE == 1'b1) //USB_TXE没拉高之前不允许有其他跨读(写)操作
WR_time_cont<=8'b0;
//******************************************************
//本模块读FT254BM状态机
//******************************************************
always@(posedge sclk or negedge rst_n) //sclk为FPGA工作时钟,默认50MHz.
if(!rst_n)
begin
RX_state<=RX_state0;
USB_RD <=1'b1;
end
else if(USB_RXF==1'b0 && RD_Enable == 1'b1) //RD_Enable 高有效
begin
case(RX_state)
RX_state0:
begin
if(RD_time_cont==8'b0)
USB_RD<=1'b0; //产生读信号的下降沿
else if(RD_time_cont==8'd5) //2|产生读信号的下降沿120ns后转到读状态1
RX_state<=RX_state1;
end
RX_state1:
begin
if((RD_time_cont>=8'd6)&&(RD_time_cont<8'd27)) //3|13|RD_time_cont==5'd3 产生读信号的下降沿60ns后读数据
data_fm_usb<=USB_DATA; //读FT245BM芯片FIFO的当前字节
else if(RD_time_cont==8'd27)
USB_RD<=1'b1;
end
endcase
end
else
begin
RX_state<=RX_state0;
USB_RD<=1'b1;
end
//reg [7:0] rev_data[0:8];
//reg [3:0] rev_cnt;
//parameter total2=9;
//
//always @(posedge sclk or negedge rst_n)
// if(!rst_n)
// begin
// $readmemb("test.txt",rev_data);
// //idata=0;
// rev_cnt=4'd0;
// end
// else
// begin
// if(crc_cnt1==total)
// begin
// rev_cnt = 4'd0;
// end
// else
// begin
// rev_data[rev_cnt]=RX_data_fm_usb;
// rev_cnt=rev_cnt+ 1;
// end
// end
//
//
////启动和积分时间信号控制
//always @(posedge sclk or negedge rst_n)
// if(!rst_n)
// begin
// start_signal=1'b1;
// checktime_signal=1'b1;
// end
// else if(rev_data[4]==8'h1E)
// begin
// start_signal=1'b0;
// checktime_signal=1'b1;
// end
// else if(rev_data[4]==8'h41)
// begin
// start_signal=1'b1;
// checktime_signal=1'b0;
// end
// else
// begin
// start_signal=1'b1;
// checktime_signal=1'b1;
// end
//******************************************************
//本模块写FT254BM状态机
//******************************************************
always@(posedge sclk or negedge rst_n) //sclk为FPGA工作时钟,默认100MHz.
if(!rst_n)
begin
TX_state<=TX_state0;
USB_WR <=1'b0;
end
else
begin
if(USB_TXE==1'b0 && WR_Enable==1'b1) //WR_Enable 高有效
begin
// if(start_signal==1'b1|)
// begin
case(TX_state)
TX_state0:
begin
if(WR_time_cont==8'b0)
USB_WR<=1'b1; //2|产生写信号的上升沿
else if(WR_time_cont==8'd5) //产生写信号的上升沿120ns后转到写状态1
TX_state<=TX_state1;
end
TX_state1:
begin
if((WR_time_cont>=8'd6)&&(WR_time_cont<8'd27)) //3|12(WR_time_cont>=5'd3)&&(WR_time_cont<5'd8) //产生写信号的上升沿60ns发送数据
data_to_usb <=data_to_usb_buffer; //写一个字节到FIFO,data_to_usb_buffer为发送缓冲寄存器
else if(WR_time_cont==8'd27)
USB_WR <=1'b0;
end
endcase
end
// else if(checktime_signal==1'b1)
// begin
// case(TX_state)
// TX_state0:
// begin
// if(WR_time_cont==5'b0)
// USB_WR<=1'b1; //产生写信号的上升沿
// else if(WR_time_cont==5'd5) //产生写信号的上升沿50ns后转到写状态1
// TX_state<=TX_state1;
// end
// TX_state1:
// begin
// if(WR_time_cont==5'd6) //产生写信号的上升沿60ns发送数据
// data_to_usb <=data_to_usb_buffer; //写一个字节到FIFO,data_to_usb_buffer为发送缓冲寄存器
// else if(WR_time_cont==5'd7) //USB_WR有效脉冲宽度最小为50ns,这里用70ns.
// USB_WR <=1'b0;
// end
// endcase
// end
// else
// begin
// TX_state<=TX_state0;
// USB_WR <=1'b0;
// end
// end
else
begin
TX_state<=TX_state0;
USB_WR <=1'b0;
end
end
endmodule |