加入星计划,您可以享受以下权益:

  • 创作内容快速变现
  • 行业影响力扩散
  • 作品版权保护
  • 300W+ 专业用户
  • 1.5W+ 优质创作者
  • 5000+ 长期合作伙伴
立即加入
  • 正文
  • 推荐器件
  • 相关推荐
  • 电子产业图谱
申请入驻 产业图谱

FPGA零基础学习之Vivado-UART驱动教程

2023/07/23
2592
阅读需 18 分钟
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

作者:李西锐  校对:陆辉

大侠好,欢迎来到FPGA技术江湖。本系列将带来FPGA的系统性学习,从最基本的数字电路基础开始,最详细操作步骤,最直白的言语描述,手把手的“傻瓜式”讲解,让电子、信息、通信类专业学生、初入职场小白及打算进阶提升的职业开发者都可以有系统性学习的机会。

系统性的掌握技术开发以及相关要求,对个人就业以及职业发展都有着潜在的帮助,希望对大家有所帮助。本次带来Vivado系列,UART驱动教程。话不多说,上货。

UART 驱动教程

UART即通用异步收发器,是一种通用串行数据总线,用于异步通信。该总线为双向通信,可以实现数据的接收与发送。

数据传输过程中,我们需要解释一下串行通信。假设现在我们传输数据的双方为A和B,每次传输8bit数据,这8bit的数据在传输时按照A与B之间的连线分为串行通信和并行通信。串行通信即A与B之间仅有一根数据线,在传输数据时需要一次发送1bit,总共发送8次。并行通信即A与B之间有8根线,传输数据时,将8bit数据通过8根线一起传输,这样一次就可以全部传输完成。

数据传输时,接收方和发送方使用的时钟不是同一个时钟域,这也就是异步传输

在通信双方传输数据之前,需要通过串口线进行连接,然后再传输数据,常用的串口线为DB9接口,但是由于这种接口体积大,不易携带等缺点而慢慢淘汰。我们在B04的开发板上使用到的是一个USB转串口的芯片,这样我们的MINI USB接口不仅可以给开发板供电,还可以进行串口数据传输。芯片为CP2102(USB <-->UART(LVCMOS/LVTTL)),对于开发者来说,就不需要关注电平标准了。

芯片电路图如图所示:

在电路图中我们可以发现,串口接口只有两根数据线,分别为RXD和TXD。那么在进行通信之前,我们需要先了解一下串口的传输规则。

在发送者没有发送数据时,接收方如果一直接收数据,那就会导致数据出错,所以,接收方在接收数据时需要有标志信号,然后启动接收。在我们的串口协议中是这样规定的:

1、空闲态数据线上为高电平

2、发送数据时,先发送起始位,逻辑电平为低。

3、起始位结束之后,发送8bit数据,从低位开始传输。

4、数据传输完毕,是1bit的校验位,采用奇偶校验法。(可不使用)

5、停止位,为高电平,可以是1bit、1.5bit或者2bit。

那么我们清楚了数据传输规则之后,我们还需要明白一个内容,那就是1bit数据的时间长度。在算这个时间之前,我们需要了解一下波特率。波特率的单位是bit/s,也就是1秒时间内,传输的bit数。我们串口常用的波特率有9600、14400、19200等等。这个波特率是传输数据的双方,提前规定好的。那么在同一速度下传输数据,就会简单很多。那么根据波特率我们可以计算出来1bit数据的时长为104166ns。在清楚这些之后,接下来我们做一个回环测试。

首先我们先新建一个工程:

选好代码存放位置,修改工程名字为uart。

选择我们的芯片型号:XC7A35TFGG484-2。

新建好工程后,开始新建文件写代码。

点击OK,顶层文件新建完成,后续各个模块新建方式相同。接收代码如下:

1   module uart_rx(2     3     input     wire           clk,4     input     wire           rst_n,5     input     wire           RXD,6     output     reg    [7:0]       data,7     output     reg           wr_en8   );9 10    parameter t = 5208;1112    reg     [14:0]      cnt;13    reg             flag;14    reg             rxd_r, rxd_rr;15    wire             rx_en;16    reg     [3:0]      num;17    reg     [7:0]      data_r;18    19    always @ (posedge clk) rxd_r <= RXD;20    always @ (posedge clk) rxd_rr <= rxd_r;21    22    assign rx_en = (~rxd_r) & rxd_rr;23    24    always @ (posedge clk, negedge rst_n)25    begin26      if(rst_n == 1'b0)27        cnt <= 15'd0;28      else if(flag)29        begin30          if(cnt == t - 1)31            cnt <= 15'd0;32          else33            cnt <= cnt + 1'b1;34        end35      else36        cnt <= 15'd0;37    end38    39    always @ (posedge clk, negedge rst_n)40    begin41      if(rst_n == 1'b0)42        flag <= 1'b0;43      else if(rx_en)44        flag <= 1'b1;45      else if(num == 4'd10)46        flag <= 1'b0;47      else48        flag <= flag;49    end50    51    always @ (posedge clk, negedge rst_n)52    begin53      if(rst_n == 1'b0)54        num <= 4'd0;55      else if(cnt == t / 2 - 1)56        num <= num + 1'b1;57      else if(num == 4'd10)58        num <= 4'd0;59      else60        num <= num;61    end62    63    always @ (posedge clk, negedge rst_n)64    begin65      if(rst_n == 1'b0)66        begin67          data_r <= 8'd0;68          data <= 8'd0;69        end70      else if(cnt == t / 2 - 1)71        case(num)72          4'd0  :  ;73          4'd1  :  data_r[0] <= rxd_rr;74          4'd2  :  data_r[1] <= rxd_rr;75          4'd3  :  data_r[2] <= rxd_rr;76          4'd4  :  data_r[3] <= rxd_rr;77          4'd5  :  data_r[4] <= rxd_rr;78          4'd6  :  data_r[5] <= rxd_rr;79          4'd7  :  data_r[6] <= rxd_rr;80          4'd8  :  data_r[7] <= rxd_rr;81          4'd9  :  data <= data_r;82          default  :  data <= data;83        endcase84    end85    86    always @ (posedge clk, negedge rst_n)87    begin88      if(rst_n == 1'b0)89        wr_en <= 1'b0;90      else if(num == 4'd10)91        wr_en <= 1'b1;92      else93        wr_en <= 1'b0;94    end9596  endmodule

 

发送数据时,跟接收基本类似,按照数据格式发送数据,代码如下:

1   module uart_tx(2     3     input   wire             clk,4     input   wire             rst_n,5     input   wire             empty,6     input   wire     [7:0]      data,7     output   wire             rd_en,8     output   reg              TXD9   );10    11    parameter t = 5208;1213    reg     [14:0]      cnt;14    reg             flag;15    reg     [3:0]      num;16    17    18    always @ (posedge clk, negedge rst_n)19    begin20      if(rst_n == 1'b0)21        cnt <= 15'd0;22      else if(flag)23        begin24          if(cnt == t - 1)25            cnt <= 15'd0;26          else27            cnt <= cnt + 1'b1;28        end29      else30        cnt <= 15'd0;31    end32    33    always @ (posedge clk, negedge rst_n)34    begin35      if(rst_n == 1'b0)36        flag <= 1'b0;37      else if(empty == 1'b0)38        flag <= 1'b1;39      else if(num == 4'd10)40        flag <= 1'b0;41      else42        flag <= flag;43    end44    45    always @ (posedge clk, negedge rst_n)46    begin47      if(rst_n == 1'b0)48        num <= 4'd0;49      else if(cnt == t / 2 - 1)50        num <= num + 1'b1;51      else if(num == 4'd10)52        num <= 4'd0;53      else54        num <= num;55    end56    57    assign rd_en = (num == 4'd0 && cnt == 15'd1) ? 1'b1 : 1'b0;58    59    always @ (posedge clk, negedge rst_n)60    begin61      if(rst_n == 1'b0)62        TXD <= 1'b1;63      else if(cnt == t / 2 - 1)64        case(num)65          4'd0  :  TXD <= 1'b0;66          4'd1  :  TXD <= data[0];67          4'd2  :  TXD <= data[1];68          4'd3  :  TXD <= data[2];69          4'd4  :  TXD <= data[3];70          4'd5  :  TXD <= data[4];71          4'd6  :  TXD <= data[5];72          4'd7  :  TXD <= data[6];73          4'd8  :  TXD <= data[7];74          4'd9  :  TXD <= 1'b1;75          default  :  TXD <= 1'b1;76        endcase77    end7879  endmodule

其中读使能我们只需在数据发送前将数据读出即可。

在做完两个模块之后,我们还需要使用一个FIFO来做数据缓存,FIFO配置参数如下:

我们使用异步FIFO,深度选择2048,位宽为8,复位信号暂时不使用。

生成FIFO后,将各个模块例化到顶层当中,代码如下:

1   module uart(2     3     input   wire           clk,4     input   wire           rst_n,5     input   wire           RXD,6     output   wire           TXD7   );8 9     wire     [7:0]    rx_data;10    wire           wr_en;11    wire           rd_en;12    wire     [7:0]    tx_data;13    wire           empty;14    15    uart_rx uart_rx_inst(16    17    .clk        (clk  ),18    .rst_n        (rst_n),19    .RXD        (RXD  ),20    .data        (rx_data),21    .wr_en        (wr_en)22  );23    24    fifo fifo_inst (25    .wr_clk(clk),  // input wire wr_clk26    .rd_clk(clk),  // input wire rd_clk27    .din(rx_data),        // input wire [7 : 0] din28    .wr_en(wr_en),    // input wire wr_en29    .rd_en(rd_en),    // input wire rd_en30    .dout(tx_data),      // output wire [7 : 0] dout31    .full(),      // output wire full32    .empty(empty)    // output wire empty33  );34    35    uart_tx uart_tx_inst(36    37    .clk        (clk  ),38    .rst_n        (rst_n  ),39    .empty        (empty  ),40    .data        (tx_data),41    .rd_en        (rd_en  ),42    .TXD        (TXD  )43  );4445  endmodule

 

功能部分写完之后,我们写一个仿真进行逻辑验证,写仿真时,我们按照数据顺序模拟给值,每1bit持续104166ns的时间。代码如下:

1   `timescale 1ns / 1ps2 3   module uart_tb;4 5     reg            clk;6     reg            rst_n;7     reg            RXD;8     wire           TXD;9 10    initial begin11      clk = 0;12      rst_n = 0;13      RXD = 1;14      #105;15      rst_n = 1;16      17      #1000;18      RXD = 0;19      #104166;20      21      RXD = 1;22      #104166;23      RXD = 0;24      #104166;25      RXD = 1;26      #104166;27      RXD = 0;28      #104166;29      RXD = 1;30      #104166;31      RXD = 0;32      #104166;33      RXD = 0;34      #104166;35      RXD = 1;36      #104166;37      38      RXD = 1;39      #104166;40      41      #5000;42      $stop;43    end44    45    always #10 clk = ~clk;46    47    uart uart_inst(48    49    .clk      (clk  ),50    .rst_n      (rst_n  ),51    .RXD      (RXD  ),52    .TXD      (TXD  )53  );54    55  endmodule

打开仿真波形:

如图,我们可以看到,当我们的接收模块接收到数据时,会将数据写入FIFO,FIFO中有数据时,发送模块就会将数据读出并发送,仿真现象正确。

下板现象:

我们随便写入几个数据,会发现我们的发送模块和接收模块的数据完全一致,即接收和发送正常。

 

推荐器件

更多器件
器件型号 数量 器件厂商 器件描述 数据手册 ECAD模型 风险等级 参考价格 更多信息
A3P250-FGG256 1 Microsemi Corporation Field Programmable Gate Array, 6144 CLBs, 250000 Gates, 350MHz, CMOS, PBGA256, 17 X 17 MM, 1.60 MM HEIGHT, 1 MM PITCH, GREEN, FBGA-256
$96.5 查看
EP4CE40F23C7N 1 Altera Corporation Field Programmable Gate Array, 2475 CLBs, 472.5MHz, 39600-Cell, PBGA484, 23 X 23 MM, 1 MM PITCH, LEAD FREE, FBGA-484
$640.28 查看
EPM570T100I5N 1 Altera Corporation Flash PLD, 8.7ns, 440-Cell, CMOS, PQFP100, 16 X 16 MM, 0.50 MM PITCH, LEAD FREE, TQFP-100

ECAD模型

下载ECAD模型
$21.73 查看

相关推荐

电子产业图谱

任何技术的学习就好比一个江湖,对于每一位侠客都需要不断的历练,从初入江湖的小白到归隐山林的隐世高人,需要不断的自我感悟自己修炼,让我们一起仗剑闯FPGA乃至更大的江湖。