FPGA初始——UART通信

今天我们开始FPGA最初的小工程:如何使用板卡实现简单的UART通信。(结尾送源码)
作者:Trustintruth
来源:https://zhuanlan.zhihu.com/p/94285361

这次我们用最白话来讲,首先来看UART是什么。他并不是一个实际的物体,而是一种协议。就好比两个人说话,必须要以一种两个人都能懂的方式来交流,这种方式也就是协议。UART是一种串行发送协议。一位一位的发送数据就需要一个控制发送节拍的,例如我们在踢正步的时候需要喊“121”,而在我们的FPGA设计中这个喊121的不再是教官,而是时钟。

时钟信号就是像这样的脉冲信号,我们在时钟的每个上升沿时发送数据,接收时也使用同样用相同的频率的时钟接收,收发就可以解决。在发送时我们常说波特率,波特率就是一秒钟发送多少个数据,也就是波特率就是波特率的频率。常用的波特率就是9600/115200等。

但是我们如何确定发送部分开始发送了呢?我们规定在未发送时数据位置于高位,当数据开始发送(数据有效)我们先将数据位拉低,再来接收数据位。这样接收端就可以检测下降沿来判断是否开始发送。

检测下降沿可以把数据位打一拍,

然后取(\~in1)&in2就可以检测到了。

基本概念就是这么多,就下来我们来做设计。首先我们使用的FPGA板卡都会有自带的晶振,也就是系统时钟,但是我们在做设计的时候需要用的时钟是和波特率有关,为了得到和波特率有关的时钟(达到对应时钟频率)我们需要分频,这里推荐使用PLL,但是由于设计很小,对频率要求不高,门控时钟分频也可以。

发送时如何控制发送阶段呢?这里我们使用状态机,状态转移:

状态0:开始阶段,检测下降沿,如果没检测到保持0状态,如果检测到转移到1;

状态1\~8:发送当前位,一次跳转下一状态

状态9:发送结束信号,信号拉高

状态10:结束,跳转0状态

顶层就不写了,都是实例化



BPS_CLK模块
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    22:39:01 05/02/2017 
// Design Name: 
// Module Name:    uart_bps 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////

module uart_bps(
                     input clk,
                     input rst_n,
                     input cnt_start,
                     output bps_sig
    );


    reg [12:0]cnt_bps;

    parameter bps_t = 13'd5207;

    always@(posedge clk or negedge rst_n)
    begin
       if(!rst_n)
          cnt_bps <= 13'd0;
       else if(cnt_bps == bps_t)
          cnt_bps <= 13'd0;
       else if(cnt_start)
          cnt_bps <= cnt_bps + 1'b1;
       else 
          cnt_bps <= 1'b0;
    end

    assign bps_sig = (cnt_bps ==  13'd2604) ? 1'b1 : 1'b0;

endmodule
sentdata模块
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    22:40:00 05/02/2017 
// Design Name: 
// Module Name:    uart_sentdata 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////

module uart_sentdata(
                             input clk,
                             input rst_n,
                             input [7:0]tx_data,
                             input tx_enable,
                             input bps_sig,
                             output reg tx,
                             output reg tx_done
    );

    reg [3:0]stata;

    always@(posedge clk or negedge rst_n)
    begin
       if(!rst_n)
       begin
          stata <= 4'd0;
          tx <= 1'b1;
          tx_done <= 1'b0;
       end
       else 
       begin
          case(stata)
          0: if(tx_enable & bps_sig)
             begin
                stata <= stata + 1'b1;
                tx <= 1'b0;
             end
             else
             begin
                stata <= stata;
                tx <= 1'b1;
             end
           1,2,3,4,5,6,7,8: if(bps_sig)
                            begin
                               tx <= tx_data[stata - 1'b1];
                               stata <= stata + 1'b1;
                            end
                            else
                            begin
                               stata <= stata;
                               tx <= tx;
                            end
           9,10: if(bps_sig)
                 begin
                    stata <= stata + 1'b1;
                    tx <= 1'b1;
                 end
           11: begin
                  stata <= stata + 1'b1;
                  tx_done <= 1'b1;
               end
           12: begin
                  stata <= 1'b0;
                  tx_done <= 1'b0;
               end
           endcase
       end
    end

endmodule

推荐阅读

  • 从 IP 开始,学习数字逻辑:DataMover 进阶篇(二)
  • 从 IP 开始,学习数字逻辑:DataMover 进阶篇

更多FPGA系列请关注专栏FPGA的逻辑

发表评论

邮箱地址不会被公开。 必填项已用*标注