zoukankan      html  css  js  c++  java
  • 实验2:基于FPGA + adc7928 + FIFO 缓冲8通道数据 + 通过串口打印到PC机 (串口采样8位通用模式)

    RTL视图:

    此次修改了串口模块,和FIFO控制模块。

    串口模块:以后遇到FIFO位宽不管是8位 或 16位 或 32位 ,串口模块都可以通用,而不需要根据FIFO的位宽再做相应更改。输入的data_in位宽定义的是8位, 上个“实验1”中data_in是定义16位宽,要连续发送两个8位数据,可参考上一篇文章。

    FIFO模块:增加了一个计数器,控制取数据,fifo 读出一个数据是16bit的,而串口一次只能发8位,所以,在读出数据之前,就得把fifo上的数据取走,只有取走发出去之后,才能读fifo中的一下个数据。FIFO增加了异步清除,在做仿真抓时序时,

          按住复位按键,将FIFO数据清空,这样可以触发抓到第一个数据波形,要不然老是触发到快满时的波形,和串口打印的数据就不好对比了。(串口发送效率变慢了,很容易触发usedw>250条件)

    串口模块代码:

      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  || txd_din_vld )?  1'b0: 1'b1;
    101 
    102 endmodule
    View Code

    fifo模块代码:

     1 module control_fifo(
     2                         clk,
     3                         rst_n,
     4                         din_vld,
     5                         fifo_data_din,
     6                         din_rdy,//下游模块准备好信号
     7                         fifo_dout_vld, //通知下游模块准备收数据
     8                         fifo_data_dout,
     9                         fifo_full_flag
    10 );
    11 parameter DATA_WRW    = 16;
    12 input clk;
    13 input rst_n;
    14 input din_vld;
    15 input [DATA_WRW-1:0] fifo_data_din;
    16 input din_rdy;
    17 
    18 output fifo_dout_vld;
    19 output[8-1:0] fifo_data_dout;
    20 output fifo_full_flag;
    21 
    22 reg  fifo_full_flag;
    23 wire rdreq;
    24 reg  wrreq;
    25 wire [DATA_WRW-1:0] q/* synthesis keep*/;
    26 wire [7:0]usedw/* synthesis keep*/;
    27 wire add_cnt0;
    28 wire end_cnt0;
    29 my_fifo    my_fifo_inst (
    30                         .aclr ( ~rst_n ),
    31                         .clock ( clk ),
    32                         .data  ( fifo_data_din ),
    33                         .rdreq ( rdreq ),
    34                         .wrreq ( wrreq ),
    35                         .empty ( empty ),
    36                         .full  ( full),
    37                         .q     ( q ),
    38                         .usedw ( usedw)
    39     );
    40     
    41 //assign wrreq = full? 1'b0 : din_vld;
    42 
    43 always @(*)begin
    44     if(usedw >= 250)begin
    45         wrreq = 0;
    46         fifo_full_flag = 0;
    47     end
    48     else begin
    49         wrreq = din_vld;
    50         fifo_full_flag = 1;
    51     end
    52         
    53 end
    54 
    55 reg [0:0] cnt0;
    56 always @(posedge clk or negedge rst_n)begin
    57     if(!rst_n)begin
    58         cnt0 <= 0;
    59     end
    60     else if(add_cnt0)begin
    61         if(end_cnt0)begin
    62             cnt0 <= 0;
    63         end
    64         else begin
    65             cnt0 <= cnt0 + 1;
    66         end
    67     end
    68 end
    69 
    70 assign add_cnt0 = (empty == 0) && (din_rdy == 1);
    71 assign end_cnt0 = add_cnt0 && cnt0 == 2-1;
    72 
    73 assign rdreq = end_cnt0;
    74 
    75 reg [8-1:0] fifo_data_dout;
    76 always @(posedge clk or negedge rst_n)begin
    77     if(!rst_n)begin
    78         fifo_data_dout <= 0;
    79     end
    80     else if(add_cnt0 && cnt0 >=0 && cnt0 < 2)begin
    81         fifo_data_dout <= q[16-1-8*cnt0 -:8];
    82     end
    83 end
    84 
    85 reg fifo_dout_vld;
    86 always @(posedge clk or negedge rst_n)begin
    87     if(!rst_n)begin
    88         fifo_dout_vld <= 0;
    89     end
    90     else begin
    91         fifo_dout_vld <= add_cnt0;
    92     end
    93 end
    94 
    95 endmodule
    View Code

    仿真时序和串口数据对比,结果数据也是对的,没有丢数据

     

     时序说明:在读使能有效之前,就得将FIFO 总线上q的数据分两次进行发送,一次发送8bit (先高8bit,在发低8bit)。FIFO是用的是show-ahead模式,在读使能有效的同时,数据已经在输出总线上了,也就是FIFO的q。

    注意几个信号:

    (1)、din_rdy 有效高电平只能保持一个时钟周期,否则读出的FIFO数据将会丢失。如果din_rdy 有效信号保持两个时钟周期就得查该问题出在哪。

    (2)、rdreq  读使能有效电平也只能保持一个时钟周期,一旦连续保持两个时钟周期,FIFO的数据肯定会丢,记住串口发送很慢很慢,你得等等,让我发完才行

    (3)、强调,写使能 和 要写的数据 必须保持在同一拍,如果不在同一拍上,可采用D触发器进行延时达到保持在同一拍。

    (4)、强调, 读使能有效期间,q有效数据也是在同一拍上,所以不能通过时序逻辑判断rdreq 信号读数据,得用组合逻辑。在有效之前,就可以先发高8bit数据。也只能保持一个时钟周期。

    记住这些要点,可以帮助你快速定位问题。

    错误写法:

    alwaya @(posedge clk or negedge rst_n )begin

      if()

      else if(rdreq==1)

         data <= q;

    end

    正确写法用组合逻辑:assign rdreq =  *** ;

     

     ad7928模块:(代码未改动,和实验1 代码一样)

      1 module ad7928(
      2                 clk,
      3                 rst_n,
      4                 adc_dout,
      5                 adc_cs,
      6                 adc_sclk,
      7                 adc_din,
      8                 din_vld,
      9                 adc_dout_vld,
     10                 adc_data_out
     11 );
     12 
     13 parameter WRITE     = 1'b1    ;
     14 parameter SEQ       = 1'b0    ;
     15 parameter PM1        = 1'b1    ;
     16 parameter PM0        = 1'b1    ;
     17 parameter SHADOW    = 1'b0    ;
     18 parameter RANGE        = 1'b0    ;
     19 parameter CODING    = 1'b1    ;
     20 parameter ADDRES    = 3'b010;
     21 
     22 input                 clk        ;
     23 input                 rst_n    ;
     24 input                 adc_dout;
     25 input                 din_vld ;
     26 
     27 output                 adc_cs    ;
     28 output                 adc_sclk;
     29 output                 adc_din    ;
     30 output                 adc_dout_vld;
     31 output [16-1:0]     adc_data_out;
     32 
     33 wire add_cnt0;
     34 wire end_cnt0;
     35 
     36 wire add_cnt1;
     37 wire end_cnt1;
     38 
     39 wire add_cnt2;
     40 wire end_cnt2;
     41 
     42 wire [15:0]    data;
     43 
     44 reg [2:0] cnt0;
     45 always @(posedge clk or negedge rst_n)begin
     46     if(!rst_n)begin
     47         cnt0 <= 0; 
     48     end
     49     else if(add_cnt0)begin
     50         if(end_cnt0)begin
     51             cnt0 <= 0;
     52         end
     53         else begin
     54             cnt0 <= cnt0 + 1;
     55         end
     56     end
     57 end
     58 
     59 assign add_cnt0 = din_vld;
     60 assign end_cnt0 = add_cnt0 && cnt0 == 4-1;
     61 
     62 
     63 reg [4:0] cnt1;
     64 always @(posedge clk or negedge rst_n)begin
     65     if(!rst_n)begin
     66         cnt1 <= 0; 
     67     end
     68     else if(add_cnt1)begin
     69         if(end_cnt1)begin
     70             cnt1 <= 0;
     71         end
     72         else begin
     73             cnt1 <= cnt1 + 1;
     74         end
     75     end
     76 end
     77 
     78 assign add_cnt1 = end_cnt0;
     79 assign end_cnt1 = add_cnt1 && cnt1 == 17-1;
     80 
     81 reg [3:0] cnt2;
     82 always @(posedge clk or negedge rst_n)begin
     83     if(!rst_n)begin
     84         cnt2 <= 0; 
     85     end
     86     else if(add_cnt2)begin
     87         if(end_cnt2)begin
     88             cnt2 <= 0;
     89         end
     90         else begin
     91             cnt2 <= cnt2 + 1;
     92         end
     93     end
     94 end
     95 
     96 assign add_cnt2 = end_cnt1;
     97 assign end_cnt2 = add_cnt2 && cnt2 == 8-1;
     98 
     99 
    100 reg adc_sclk;
    101 always @(posedge clk or negedge rst_n)begin
    102     if(!rst_n)begin
    103         adc_sclk <= 1;
    104     end
    105     else if(add_cnt0 && cnt0 >= 2 && cnt0 < 4)begin
    106         adc_sclk <= 0;
    107     end
    108     else if(add_cnt0 && cnt0 >= 0 && cnt0 < 2)begin
    109         adc_sclk <= 1;
    110     end
    111 end
    112 
    113 reg adc_cs;
    114 always @(posedge clk or negedge rst_n)begin
    115     if(!rst_n)begin
    116         adc_cs <= 1;
    117     end
    118     else if(add_cnt0 && cnt0 == 2-1 && cnt1 == 1-1)begin
    119         adc_cs <= 0;
    120     end
    121     else if(add_cnt0 && cnt0 == 2-1 && cnt1 == 17-1)begin
    122         adc_cs <= 1;
    123     end
    124 end
    125 
    126 reg [2:0] channel_sel;
    127 always @(posedge clk or negedge rst_n)begin
    128     if(!rst_n)begin
    129         channel_sel <= 3'b000;
    130     end
    131     else begin
    132         case(cnt2)
    133             0        :    channel_sel <= 3'b000;
    134             1        :    channel_sel <= 3'b001;
    135             2        :    channel_sel <= 3'b010;
    136             3        :    channel_sel <= 3'b011;
    137             4        :    channel_sel <= 3'b100;
    138             5        :    channel_sel <= 3'b101;
    139             6        :    channel_sel <= 3'b110;
    140             7        :    channel_sel <= 3'b111;
    141             default :     channel_sel <= 3'b000;
    142         endcase
    143     end
    144 end 
    145 
    146 reg adc_din;  //给ADC送数据,进行通道切换
    147 always @(posedge clk or negedge rst_n)begin
    148     if(!rst_n)begin
    149         adc_din <= 1;
    150     end
    151     else if(add_cnt0 && cnt0 == 2-1 && cnt1 >=0 && cnt1 < 16)begin
    152         adc_din = data[15-cnt1];
    153     end
    154 end
    155 
    156 assign data = {WRITE, SEQ, 1'b0, channel_sel, PM1, PM0, SHADOW, 1'b0, RANGE, CODING, 4'b0000};
    157 
    158 reg [16-1:0] data_temp; //从ADC上读数据
    159 always @(posedge clk or negedge rst_n)begin
    160     if(!rst_n)begin
    161         data_temp <= 15'b000_0000_0000_0000;
    162     end
    163     else if(add_cnt0 && cnt0 == 3-1 && cnt1 >= 0 && cnt1 < 16)begin
    164         data_temp[15-cnt1] <= adc_dout;
    165     end
    166 end
    167 
    168 reg [16-1:0] adc_data_out;  //将收到的完整数据进行锁存
    169 always @(posedge clk or negedge rst_n)begin
    170     if(!rst_n)begin
    171         adc_data_out <= 0;
    172     end
    173     else if(end_cnt1)begin
    174         adc_data_out <= data_temp;
    175     end
    176 end
    177 
    178 reg adc_dout_vld;  //数据有效时,同时产生一个有效标志
    179 always @(posedge clk or negedge rst_n)begin
    180     if(!rst_n)begin
    181         adc_dout_vld <= 0;
    182     end
    183     else if(end_cnt1)begin
    184         adc_dout_vld <= 1;
    185     end
    186     else begin
    187         adc_dout_vld <= 0;
    188     end
    189 end
    190 
    191 endmodule
    View Code

    ad7928_fifo_top模块:(做了位宽修改)

     1 module ad7928_fifo_top(
     2                         clk,
     3                         rst_n,
     4                         adc_dout,
     5                         
     6                         adc_cs,
     7                         adc_sclk,
     8                         adc_din,
     9                         txd_dout
    10 );
    11 
    12 input                 clk;
    13 input                 rst_n;
    14 input                 adc_dout;
    15 
    16 output                 adc_cs;
    17 output                 adc_sclk;
    18 output              adc_din;
    19 output                 txd_dout;
    20 
    21 wire  [8-1 : 0]        fifo_data_dout;
    22 wire  [16-1 : 0]    adc_data_out;
    23 wire                 adc_dout_vld;
    24 wire                txd_rdy;
    25 wire                 fifo_dout_vld;
    26 wire                 fifo_full_flag;
    27 
    28 ad7928                u1_adc(
    29                                     .clk            (clk),
    30                                     .rst_n            (rst_n),
    31                                     .adc_dout        (adc_dout),
    32                                     .adc_cs            (adc_cs),
    33                                     .adc_sclk        (adc_sclk),
    34                                     .adc_din        (adc_din),
    35                                     .din_vld        (fifo_full_flag),
    36                                     .adc_dout_vld    (adc_dout_vld),
    37                                     .adc_data_out    (adc_data_out)
    38                     );
    39                     
    40 control_fifo        u2_fifo(
    41                                     .clk(clk),
    42                                     .rst_n(rst_n),
    43                                     .din_vld(adc_dout_vld),
    44                                     .fifo_data_din(adc_data_out),
    45                                     .din_rdy(txd_rdy),//下游模块准备好信号
    46                                     .fifo_dout_vld(fifo_dout_vld), //通知下游模块准备收数据
    47                                     .fifo_data_dout(fifo_data_dout),
    48                                     .fifo_full_flag(fifo_full_flag)
    49 );
    50 
    51 uart_txd            u3_uart_txd(
    52                                     .clk(clk),
    53                                     .rst_n(rst_n),
    54                                     .txd_din_vld(fifo_dout_vld),
    55                                     .data_din(fifo_data_dout),
    56                                     .txd_rdy(txd_rdy),
    57                                     .txd_dout(txd_dout)
    58                     );
    59                     
    60 endmodule 
    View Code

    实验1 和 实验2 差别:

     实验1:

      优点 :写代码简单,好控制,不需要将FIFO 16位宽的数据进行拆分发,效率会更高。

      缺点: 不同位宽的FIFO,串口发送模块要做相应的更改,通用性不强。

     实验2: 

      优点:通用性好,不同位宽的FIFO,只需对FIFO控制模块进行更改,串口发送模块不需要做任何更改。

           缺点:需要额外增加计数器,控制FIFO数据,将数据拆分发送,效率慢。

    代码中可以改进的地方:

    adc_sclk信号赋值,代码中用的范围赋值,可以更改为在某个点进行赋值

    在某个点对adc_sclk进行赋值:

    重复的条件可以另起一个变量名代替,如adc_cs信号,尽量简化代码,不要有冗余代码

  • 相关阅读:
    30-语言入门-30-分数加减法
    29-语言入门-29-两点距离
    bootstrapcss3触屏滑块轮播图
    input输入样式,动画
    HTML5夜空烟花绽放动画效果
    精美留言、评论框,带微博表情
    Sublime Text 3汉化中文版
    直播英国脱欧各国反应?谁将是最大赢家?
    品牌关键字的重要性?是什么呢
    网站收录之网络推广
  • 原文地址:https://www.cnblogs.com/wen2376/p/15730864.html
Copyright © 2011-2022 走看看