• FPGA 串口FIFO回环实验(show ahead模式)


    RTL视图

     工作流程:

    (1)、当uart_rxd模块检测到rxd_din信号上有下降沿时,启动uart_rxd计数器器,并准备接收数据,当收完一个完整字节时,产生data_out_vld ,用于通知FIFO准备开始写入FIFO

    (2)、当FIFO收到din_vld有效信号时,先检测FIFO是否满,不满的就开始写使能,当FIFO成功写入数据之后, empty置0,表示FIFO不为空,可以利用这个条件来控制读使能。

        assign wrreq = full? 1'b0 : din_vld;   //检测FIFO是否满,如果不满,就将din_vld信号给写使能

    (3)、当FIFO写入数据之后,且empty 不为空了,这个时候可以考虑去读fifo中的数据,读出的数据在发送出去之前,还得检查发送模块是否就绪txd_rdy

        assign rdreq = (empty == 0) && (din_rdy == 1); //读使能之前,同时判断fifo 是否为空, 且发送模块是否准备就绪

    (4)、FIFO读使能之后,数据传给uart_txd模块,在发送期间,禁止读下一个数据,否则发送数据紊乱。 只能发送完一个字节后,再继续读下一个字节,这样循环操作

    时序:

    (1)、uart_rxd模块检测下降沿

     (2)、写FIFO 读FIFO时序

    注意几个地方同步:

    (1)、写使能和有待写入的有效数据必须保持在同一拍,如果不在同一拍,可以将其中一个在打一拍,这样就能保持同步

    (2)、由于用的是show - ahead模式,所以读使能和读出的有效数据也是在同一拍,此时应该将数据取走。也就是后面 “在发送期间,进行数据锁存,确保在发送期间数据不改变”

     

    (3)串口发送时序

    normal 和lshow-ahead模式:

      (1)、normal模式,在读使能后,下一拍才把数据送到q上。

      (2)、show-ahead模式,在读使能有效期间,FIFO就已经把第一个数据送到了q上,也就是说“读使能”和第一个效数据“q” 保持在同一拍

     uart_rxd.v

      1 module uart_rxd(
      2                     clk,
      3                     rst_n,
      4                     rxd_din,
      5 //                    rxd_din_vld,
      6                     rxd_data_out,
      7                     data_out_vld
      8                 );
      9         
     10 parameter DATA_W        = 8;
     11 parameter BAUD_RATE     = 434;
     12 
     13 input clk;
     14 input rst_n;
     15 input rxd_din;
     16 wire  rxd_din_vld;
     17 
     18 output [DATA_W-1: 0]    rxd_data_out /* synthesis keep*/;
     19 output data_out_vld;
     20 
     21 wire add_cnt0;
     22 wire end_cnt0;
     23 
     24 wire add_cnt1;
     25 wire end_cnt1;
     26 
     27 wire rxd_sig_neg;
     28 
     29 reg rxd_din_0;
     30 reg rxd_din_1;
     31 reg rxd_din_2;
     32 reg rxd_din_3;
     33 always @(posedge clk or negedge rst_n)begin
     34     if(!rst_n)begin
     35         rxd_din_0 <= 1;
     36         rxd_din_1 <= 1;
     37         rxd_din_2 <= 1;
     38         rxd_din_3 <= 1;
     39     end
     40     else begin
     41         rxd_din_0 <= rxd_din;
     42         rxd_din_1 <= rxd_din_0;
     43         rxd_din_2 <= rxd_din_1;
     44         rxd_din_3 <= rxd_din_2;
     45     end
     46 end
     47 
     48 assign rxd_sig_neg = (rxd_din_2 == 0) && (rxd_din_3 == 1);
     49 
     50 assign rxd_din_vld = 1;
     51 
     52 reg cnt0_vld;
     53 always @(posedge clk or negedge rst_n)begin
     54     if(!rst_n)begin
     55         cnt0_vld <= 0;
     56     end
     57     else if(rxd_sig_neg && rxd_din_vld)begin
     58         cnt0_vld <= 1;
     59     end
     60     else if(end_cnt1)begin
     61         cnt0_vld <= 0;
     62     end
     63 end
     64 
     65 reg [8:0] cnt0;
     66 always @(posedge clk or negedge rst_n)begin
     67     if(!rst_n)begin
     68         cnt0 <= 0;
     69     end
     70     else if(add_cnt0)begin
     71         if(end_cnt0)begin
     72             cnt0 <= 0;
     73         end
     74         else begin
     75             cnt0 <= cnt0 + 1;
     76         end
     77     end
     78 end
     79 
     80 assign add_cnt0 = cnt0_vld == 1;
     81 assign end_cnt0 = add_cnt0 && cnt0 == BAUD_RATE - 1;
     82 
     83 reg [3:0] cnt1;
     84 always @(posedge clk or negedge rst_n)begin
     85     if(!rst_n)begin
     86         cnt1 <= 0;
     87     end
     88     else if(add_cnt1)begin
     89         if(end_cnt1)begin
     90             cnt1 <= 0;
     91         end
     92         else begin
     93             cnt1 <= cnt1 + 1;
     94         end
     95     end
     96 end
     97 
     98 assign add_cnt1 = end_cnt0;
     99 assign end_cnt1 = add_cnt1 && cnt1 == (DATA_W + 1 + 1) - 1;  //数据位宽+起始位+停止位
    100 
    101 reg [DATA_W-1:0] data_temp;
    102 always @(posedge clk or negedge rst_n)begin
    103     if(!rst_n)begin
    104         data_temp <= 0;
    105     end
    106     else if(add_cnt0 && cnt0 == ((BAUD_RATE>>1)-1) && cnt1 >= 1 && cnt1 < DATA_W+1)begin
    107         data_temp[cnt1-1] <= rxd_din_2;
    108     end
    109 end
    110 
    111 reg [DATA_W-1:0] rxd_data_out;
    112 always @(posedge clk or negedge rst_n)begin
    113     if(!rst_n)begin
    114         rxd_data_out <= 1;
    115     end
    116     else if(end_cnt1)begin
    117         rxd_data_out <= data_temp;
    118     end
    119 end
    120 
    121 reg data_out_vld;
    122 always @(posedge clk or negedge rst_n)begin
    123     if(!rst_n)begin
    124         data_out_vld <= 0;
    125     end
    126     else if(end_cnt1)begin
    127         data_out_vld <= 1;  //收满一个字节后,表示一个有效的完整字节
    128     end
    129     else begin
    130         data_out_vld <= 0;
    131     end
    132 end
    133 
    134 endmodule
    View Code

    control_fifo.v

     1 module control_fifo(
     2                         clk,
     3                         rst_n,
     4                         din_vld,
     5                         fifo_data_din,
     6                         din_rdy,//下游模块准备好信号
     7                         dout_vld, //通知下游模块准备收数据
     8                         fifo_data_dout
     9 );
    10 parameter DATA_WRW    = 8;
    11 input clk;
    12 input rst_n;
    13 input din_vld;
    14 input [DATA_WRW-1:0] fifo_data_din;
    15 input din_rdy;
    16 
    17 output dout_vld;
    18 output[DATA_WRW-1:0] fifo_data_dout;
    19 
    20 wire rdreq;
    21 wire wrreq;
    22 wire [DATA_WRW-1:0] q/* synthesis keep*/;
    23 wire [7:0]usedw;
    24 my_fifo    my_fifo_inst (
    25                         .clock ( clk ),
    26                         .data  ( fifo_data_din ),
    27                         .rdreq ( rdreq ),
    28                         .wrreq ( wrreq ),
    29                         .empty ( empty ),
    30                         .full  ( full),
    31                         .q     ( q ),
    32                         .usedw ( usedw)
    33     );
    34     
    35 assign wrreq = full? 1'b0 : din_vld;
    36 
    37 assign rdreq = (empty == 0) && (din_rdy == 1);
    38 
    39 reg [DATA_WRW-1:0] fifo_data_dout;
    40 always @(posedge clk or negedge rst_n)begin
    41     if(!rst_n)begin
    42         fifo_data_dout <= 0;
    43     end
    44     else begin
    45         fifo_data_dout <= q;
    46     end
    47 end
    48 
    49 reg dout_vld;
    50 always @(posedge clk or negedge rst_n)begin
    51     if(!rst_n)begin
    52         dout_vld <= 0;
    53     end
    54     else begin
    55         dout_vld <= rdreq;
    56     end
    57 end
    58 
    59 endmodule
    View Code

    uart_txd.v

      1 module uart_txd(
      2                     clk,
      3                     rst_n,
      4                     txd_din_vld,
      5                     data_din,
      6                     txd_rdy,
      7                     txd_dout
      8                 );
      9                 
     10 parameter DATA_W    = 8;
     11 parameter BAUD_RATE    = 54;
     12 
     13 input clk;
     14 input rst_n;
     15 input txd_din_vld;
     16 input [DATA_W-1:0]data_din;
     17 
     18 output txd_rdy;
     19 output txd_dout;
     20 
     21 wire add_cnt0/* synthesis keep*/;
     22 wire end_cnt0/* synthesis keep*/;
     23 
     24 wire add_cnt1;
     25 wire end_cnt1;
     26 
     27 wire [10-1:0]data_temp;
     28 
     29 reg cnt0_vld;
     30 always @(posedge clk or negedge rst_n)begin
     31     if(!rst_n)begin
     32         cnt0_vld <= 0;
     33     end
     34     else if(txd_din_vld)begin
     35         cnt0_vld <= 1;
     36     end
     37     else if(end_cnt1)begin
     38         cnt0_vld <= 0;
     39     end
     40 end
     41 
     42 reg [8:0] cnt0;
     43 always @(posedge clk or negedge rst_n)begin
     44     if(!rst_n)begin
     45         cnt0 <= 0;
     46     end
     47     else if(add_cnt0)begin
     48         if(end_cnt0)begin
     49             cnt0 <= 0;
     50         end
     51         else begin
     52             cnt0 <= cnt0 + 1;
     53         end
     54     end
     55 end
     56 
     57 assign add_cnt0 = cnt0_vld == 1;
     58 assign end_cnt0 = add_cnt0 && cnt0 == BAUD_RATE - 1;
     59 
     60 reg [3:0] cnt1;
     61 always @(posedge clk or negedge rst_n)begin
     62     if(!rst_n)begin
     63         cnt1 <= 0;
     64     end
     65     else if(add_cnt1)begin
     66         if(end_cnt1)begin
     67             cnt1 <= 0;
     68         end
     69         else begin
     70             cnt1 <= cnt1 + 1;
     71         end
     72     end
     73 end
     74 
     75 assign add_cnt1 = end_cnt0;
     76 assign end_cnt1 = add_cnt1 && cnt1 == (DATA_W + 1 + 1) - 1;  //数据位宽+起始位+停止位
     77 
     78 reg[DATA_W-1 : 0] data_buf;
     79 always @(posedge clk or negedge rst_n)begin
     80     if(!rst_n)begin
     81         data_buf <= 0;
     82     end
     83     else if(txd_din_vld)begin  //在检测FIFO输出的有效信号时,把数据进行锁存,避免在发送过程中,data_buf 数据发生变化
     84         data_buf <= data_din;
     85     end
     86 end
     87 
     88 assign data_temp = {1'b1, data_buf, 1'b0};  // 停止位 + 8bit数据 + 起始位, 低位先发
     89 
     90 reg txd_dout;
     91 always @(posedge clk or negedge rst_n)begin
     92     if(!rst_n)begin
     93         txd_dout <= 1;
     94     end
     95     else if(add_cnt0 && cnt0 == 0 && cnt1 >=0 && cnt1 < (DATA_W + 1 + 1))begin
     96         txd_dout <= data_temp[cnt1];
     97     end
     98 end
     99 
    100 assign txd_rdy = cnt0_vld ?  1'b0: 1'b1;
    101 
    102 endmodule
    View Code

    fifo_top.v

     1 module fifo_top(
     2                     clk,
     3                     rst_n,
     4                     rxd_din,
     5                     txd_dout
     6 );
     7 
     8 parameter DATA_W        = 8;
     9 parameter BAUD_RATE     = 54; //54 = 921600  ; 434 = 115200
    10 
    11 input clk;
    12 input rst_n;
    13 input rxd_din;
    14 
    15 output txd_dout;
    16 
    17 wire [DATA_W-1:0]    rxd_data_out;
    18 wire [DATA_W-1:0]    fifo_data_dout;
    19 wire                data_out_vld;
    20 wire                txd_rdy;
    21 wire                 txd_dout;
    22 
    23 uart_rxd #(.DATA_W(DATA_W),.BAUD_RATE(BAUD_RATE))    u1_rxd(
    24                                                             .clk            (clk),
    25                                                             .rst_n            (rst_n),
    26                                                             .rxd_din        (rxd_din),
    27 //                                                            .rxd_din_vld    (txd_rdy),
    28                                                             .rxd_data_out    (rxd_data_out),
    29                                                             .data_out_vld    (data_out_vld)
    30                                                         );
    31                                                         
    32 uart_txd #(.DATA_W(DATA_W),.BAUD_RATE(BAUD_RATE))     u2_txd(
    33                                                             .clk(clk),
    34                                                             .rst_n(rst_n),
    35                                                             .txd_din_vld(txd_din_vld),
    36                                                             .data_din(fifo_data_dout),
    37                                                             .txd_rdy(txd_rdy),
    38                                                             .txd_dout(txd_dout)
    39                                                     );
    40 
    41 
    42 control_fifo #(.DATA_WRW(DATA_W))    u3_fifo(
    43                                                 .clk(clk),
    44                                                 .rst_n(rst_n),
    45                                                 .din_vld(data_out_vld),
    46                                                 .fifo_data_din(rxd_data_out),
    47                                                 .din_rdy(txd_rdy),                    //下游模块准备好信号
    48                                                 .dout_vld(txd_din_vld),             //通知下游模块准备收数据
    49                                                 .fifo_data_dout(fifo_data_dout)
    50                                             );
    51 
    52 endmodule
    View Code

    程序里的这段注释,有特定的含义,综合保持,/* synthesis keep*/:

    就是在SignalTap II中,一些信号被优化,导致添加到触发列表中显示的是红色状态,就没法准确查看仿真波形,所以一个这样的注释可以避免显示红色

     

     如果加了这个/* synthesis keep*/ 还是不好使,那么就在module ()信号列表里添加一个信号,

    比如

     module   control_fifo(

              .  

              .          

              data_temp,

              .

          );

    output   data_temp;

    wire  data_temp /* synthesis keep*/ ;

    不需要分配管脚,不影响结果,这样方便仿真抓时序

     如下图,列表中添加的txd_rdy信号处于 红色 ,这种状态出来的波形有可能是不对的,添加的信号必须保持 黑色 状态才行

    注意:

    txd_rdy控制信号有点问题,txd_rdy相对rdreq信号延迟了两拍,如果FIFO中一开始就有超过两个或两个以上的数据时,rdreq信号脉冲可能就不是保持一个时钟,有可能保持两个时钟周期,就意味着FIFO要读出两个数据,没有及时处理好的话,

    很可能就会丢一个数据。 rdreq信号是组合逻辑得到的

    assign rdreq = (empty == 0) && (din_rdy == 1);

    assign txd_rdy = cnt0_vld ?  1'b0: 1'b1; //这里写的条件不足,才导致延迟两拍

     

     正确确时序,txd_rdy应该读使能后下一拍就要拉低,如下图,这样才能保证每次读都是读一个字节

    在uart_txd.v里,修改这句代码,添加一个条件(cnt0_vld  || txd_din_vld )

    assign txd_rdy = (cnt0_vld  || txd_din_vld )?  1'b0: 1'b1;

     

      那为什么测试没有发现错误,那是因为写入和读出的速率都很慢,所以测试不出来,如果写入的数据多且快,读出时没控制好,就容易出现丢数据。

     

  • 相关阅读:
    人物-IT-张志东:张志东
    人物-IT-任正非:任正非
    人物-IT-张朝阳:张朝阳
    院校-清华大学:清华大学
    人物-丁磊:丁磊
    人物-李彦宏:李彦宏
    人物-IT-马云:马云
    inittab
    initlocation
    initdb
  • 原文地址:https://www.cnblogs.com/wen2376/p/15693691.html
Copyright © 2020-2023  润新知