FPGA|CPLD|ASIC论坛
直播中

刘宇

6年用户 23经验值
私信 关注
[问答]

FPGA驱动USB2.0芯片-FT245的问题

近期在处理一个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工作时钟,默认50MHz.
                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_u***,      //其他模块或器件从本模块读取来自USB接口的数据
                input                wire   [7:0] TX_data_to_u***,      //其他模块或器件向本模块写入发到USB接口的数据
                input   wire          [7:0]TX_data_to_u***1,
                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_u***;        //从USB接收数据
reg          [7:0]                data_to_u***;        //发送数据到USB
reg          [7:0]                data_to_u***_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_u***:8'bzz;
//******************************************************
//其他模块与本模块之间的数据交换
//******************************************************
always@(posedge sclk or negedge rst_n)//接收数据
if(!rst_n)
         RX_data_fm_u*** <= 8'h00;
else if(RD_Enable == 1'b1)
         RX_data_fm_u*** <= data_fm_u***;
// else
//         RX_data_fm_u*** <= 8'haf;
//////////////////////////////////         
always@(posedge sclk or negedge rst_n)//发送数据
if(!rst_n)
         data_to_u***_buffer <= 8'b00;
else
        begin
                if(WR_Enable == 1'b1)
                begin
                        if((start_signal==1'b1)&&(checktime_signal==1'b0))
                                begin
                                        data_to_u***_buffer <= TX_data_to_u***;
                                end
                        else if(checktime_signal==1'b1)
                                begin
                                        data_to_u***_buffer <= TX_data_to_u***1;
                                end
                        else
                                begin
                                        data_to_u***_buffer <= 8'b00;
                                end
                end
                else
                        begin
                                data_to_u***_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 产生读信号的下降沿140ns后读数据
                  data_fm_u***<=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_u***;
//                                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工作时钟,默认50MHz.
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_u*** <=data_to_u***_buffer;  //写一个字节到FIFO,data_to_u***_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)          //产生写信号的上升沿120ns后转到写状态1
//                                                                TX_state<=TX_state1;
//                                                end
//                                        TX_state1:
//                                                begin
//                                                        if(WR_time_cont==5'd6)               //产生写信号的上升沿140ns发送数据
//                                                                data_to_u*** <=data_to_u***_buffer;  //写一个字节到FIFO,data_to_u***_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

回帖(1)

alonggege

2019-8-7 17:38:19
不错,很好的经验分享,辛苦麻烦了,欠缺这方面的资料,非常感谢
举报

更多回帖

发帖
×
20
完善资料,
赚取积分