明德扬吴老师 发表于 2020-4-15 10:08:23

【至简案例系列】基于USB3.0的数据通信设计-一位研三学生学习FPGA的点滴感悟

基于USB3.0的数据通信
                                                                                                                                                    作者:小Q      作为一个即将毕业但由于疫情不能回校的研三学生的独白。。。。。。真正和FPGA打交道应该是刚读研一的时候,不知道市场上什么资料好,可能和刚开始学习FPGA的同学们一样,主要心态是想快速掌握这门技术,经过一番调查选择了潘老师的《手把手教你学FPGA设计》,终于被大道至简的至简设计法所打败了。
1. 为什么大道至简好用且方便

      由于书中讲解详细且区域划分鲜明,过多赘述不必多说,就像潘老师所说过那样,学好FPGA最重要就是状态机和计数器,记住,这是重点,要考的!!!其实刚开始我没认为这两项多么重要,哈哈哈,但是随着工程代码量的不断增大以及对时序等要求的不断增强,愈发觉得基础才能决定上层建筑。而反观三段式或四段式状态机代码清晰,结构分明,你所需要做的只是添砖加瓦,也就是你自己的状态,因为地基已经为你搭好了。再说计数器,应该说没有什么说的了,抬手就写,因为代码放在那了啊,只需要添加你的加一和结束条件就可以了啊!!!现在想想当初的我为什么要特立独行!!!导致在仿真阶段浪费好多时间。
2. USB3.0数据通信

      最近写的代码(也不是最近了,大约在过年回家之前)是关于USB3.0数据通信的,这里多说几句,板子前期是购买的,后来自己设计的。代码部分是卖家提供(具体名称不方便透露,因为我不是挑事的人,哈哈哈),但是真的是他的代码太繁琐以及太不易搞懂且移植性太差了,但比较好的是我自己写也不浪费什么事情,我将USB3.0的状态分为读,写,空闲三个,然后根据三段式顺利写好属于自己的代码。源代码在下面,哈哈哈,如果可以的话请不要乱发或者帮我打码,毕竟毕业论文里还在用。并且家里电脑真的是什么软件都没安装,我就用记事本复制过来的。
2.1. USB3.0控制模块参考代码


信号类型位宽意义
clk输入1时钟信号
pclk_in输入1USB芯片复位信号
rst_n输入1复位信号,低电平有效
flag_a输入1USB芯片标志位,控制写状态
flag_b输入1USB芯片标志位,控制写状态
flag_c输入1USB芯片标志位,控制读状态
flag_d输入1USB芯片标志位,控制读状态
pclk输出1USB芯片复位信号
slcs输出1USB芯片片选信号
sloe输出1USB芯片控制信号
slrd输出1USB芯片读状态选择信号
slwr输出1USB芯片写状态选择信号
pktend输出1USB芯片数据包信号
fifo_addr输出2USB芯片数据读取方向控制信号
usb_data双向32USB3.0数据
cmd_flag输出1USB传输数据标志位
cmd_data输出32USB传输数据


moduleUSB_command(      input                   clk,      input                   pclk_in,      input                   rst_n,      //usb      input                   flag_a,      input                   flag_b,      input                   flag_c,      input                   flag_d,outputwirepclk                            ,outputwireslcs                            ,outputreg             sloe                            ,outputregslrd                            ,outputregslwr                            ,outputwirepktend                        ,outputreg   [ 1: 0]   fifo_addr                     ,inoutwire   usb_data                        ,outputregcmd_flag                        ,outputwire   cmd_data                                    ); parameter   IDLE            =   4'b0001                         ;parameter   WRITE         =   4'b0010                         ;parameter   READ            =   4'b0100                         ;reg   [ 3: 0]               state_c /*synthesis preserve*/;reg   [ 3: 0]               state_n /*synthesis preserve*/;//cntreg                  cnt                           ;wire                            add_cnt;wire                            end_cnt; reg                  rd_cnt                        ;reg                  rd_data_len                     ;regwr_trig                         ;//写触发 assignslcs      =   1'b0;assignpclk      =   pclk_in;assignpktend      =   1'b1;assignusb_data    =   (!slwr) ? usb_write_data : 32'dz;wireusb_write_data ; //state_calways@(posedgeclk or negedgerst_n)begin    if(!rst_n)beginstate_c<= IDLE;    end    else beginstate_c<= state_n;    endend //state_nalways@(*)begin    case(state_c)IDLE:beginif(flag_a&&flag_b&&wr_trig)beginstate_n = WRITE;            end            else if(flag_c&&flag_d)beginstate_n = READ;                                          end            else beginstate_n = state_c;                                          end      endWRITE:begin            if(flag_b == 1'b0)begin //写满state_n = IDLE;            end            else beginstate_n = state_c;            end      endREAD:begin            if(flag_d == 1'b0)begin //读空state_n = IDLE;            end            else beginstate_n = state_c;            end      enddefault:beginstate_n = IDLE;      endendcaseend //fifo_addralways@(posedgeclk or negedgerst_n)beginif(rst_n == 1'b0)beginfifo_addr<=2'b00;      sloe      <=1'b1;    end    else if(state_c==READ)beginfifo_addr<=2'b11;      sloe      <=1'b0;    end    else beginfifo_addr<=2'b00;      sloe      <=1'b1;    endend //slwr 输出信号,用时序逻辑好点always@(posedgeclk or negedgerst_n)beginif(rst_n == 1'b0)beginslwr<=1'b1;    end    else if(state_c==WRITE)beginslwr<=1'b0;    end    else beginslwr<=1'b1;    endend //slrdalways@(posedgeclk or negedgerst_n)beginif(rst_n == 1'b0)beginslrd<=1'b1;    end    else if(state_c==READ)beginslrd<=1'b0;    end    else beginslrd<=1'b1;    endend //rd_cntalways@(posedgeclk or negedgerst_n)beginif(rst_n == 1'b0)beginrd_cnt<=16'd0;    end    else if(slrd)beginrd_cnt<=16'd0;    end    else beginrd_cnt<=rd_cnt + 1'b1;    endend //rd_data_lenalways@(posedgeclk or negedgerst_n)beginif(rst_n == 1'b0)beginrd_data_len<=16'd0;    end    else if(rd_cnt == 16'd3)beginrd_data_len<=usb_data + 16'd3;     endend //cmd_flagalways@(posedgeclk or negedgerst_n)beginif(rst_n == 1'b0)begincmd_flag<=1'b0;    end    else if(rd_cnt == 16'd3)begincmd_flag<=1'b1;    end    else if(rd_cnt == rd_data_len)begincmd_flag<=1'b0;    endend assigncmd_data   =   usb_data ;//将cmd_flag与cmd_data配合使用                                  //cntalways @(posedgeclk or negedgerst_n)begin    if(!rst_n)begincnt<= 0;    end    else if(add_cnt)begin      if(end_cnt)cnt<= 0;      else cnt<= cnt + 1;    end    else begincnt<= 0;    endend assignadd_cnt   =       state_c==WRITE;       assignend_cnt   =       add_cnt&&cnt == 4096-1;   //测试用的计数数据 //wr_trigalways@(posedgeclk or negedgerst_n)beginif(rst_n == 1'b0)beginwr_trig<=1'b0;    end    else if(cmd_flag&&cmd_data == 32'h11111111)beginwr_trig<=1'b1;    end    //else if(slwr == 1'b0)begin //开始写的时候,将wr_trig拉低          //wr_trig<=1'b0;    //endend //fifo 读请求regfifo_rdeq;always@(posedgeclk or negedgerst_n)beginif(rst_n == 1'b0)beginfifo_rdeq<=1'b0;                end    else if(flag_a )begin                        fifo_rdeq<=1'b1;          end    else fifo_rdeq<= 1'b1;end //fifo 写请求regfifo_wdeq;always@(posedgeclk or negedgerst_n)beginif(rst_n == 1'b0)beginfifo_wdeq<=1'b0;    end    else if(flag_c)beginfifo_wdeq<=1'b1;    end    else fifo_wdeq<= 1'b1;end //FIFO fifo      fifo_inst (            .clock (clk),      .data ( cnt ),      .rdreq ( fifo_rdeq ),      .wrreq ( fifo_wdeq ),      .q ( usb_write_data )      ); Endmodule

2.2. 明德扬的signaltap教程及仿真验证

       这里还得感谢明德扬的signaltap教程,因为USB通信的数据线为32根,因此调试阶段使用modelsim真的不太好用,所以根据明德扬所讲的signaltap教程,我很容易的实现了抓图,分析出代码问题,并且我自己的体会,signaltap真的就像现实的示波器啊!!!好处自己去钻研吧。下面是抓图,通过抓图分析数据简直不要太快!!
3. 结论

         最后,祝福明德扬越来越好,大道至简,受益匪浅。愿桃李不言下自成蹊,终其教育,无外乎传道授业解惑,古有孔丘弟三千,愿今师者百树人。

页: [1]
查看完整版本: 【至简案例系列】基于USB3.0的数据通信设计-一位研三学生学习FPGA的点滴感悟