当前位置:   article > 正文

【FPGA】xilinx Vivado UART IP核使用_在vivado实现uart ip设计

在vivado实现uart ip设计

一.UART通信协议

UART(Universal Asynchronous Receiver/Transmitter)串口通信是一种简单的串行通信协议,常用的通信速率9600bite/s、19200bite/s、115200bite/s等,
串口连接图
图中TXD:发送数据线;RXD:接收数据线

一个完整的数据帧如下所示。
一个完整数据帧数据传输中接收方RX初始电平为1,当1变为0时候代表起始位,传输数据位以字节为单位,一次只能传输一字节,先发送低位再高位,发送频率由波特率来约定,RX与TX的波特率应该一致。

二.UART IP核使用

1.IP核解读
UART IP核内部框图UART IP核外部接口分别为RX、TX以及Interrupt。其中RX为接收端,外部数据经RX控制模块接收数据到RX FIFO中,然后通过AXI-lite接口将数据读出;TX为发送端,数据经AXI-lite接口将发送的数据写入到TX FIFO,然后发送到外部接口。我们要做的就是编写AXI-lite界面代码,控制IP核的读取及写入,内部数据的串并或并串转换的帧格式如第一章中所示(代码实现可参考后续章节中TX_TB模块以及RX_TB模块)。
UART IP核内部寄存器值若要写入IP核数据,需要先写地址H04,然后再写数据,若要读取外部数据,即RX FIFO数据,需要将读取地址写成H00,TX FIFO及RX FIFO虽然接口为32bit,但是仅低8bit为有效数据,其余为预留。
RX FIFOTX FIFO

同理若想读取IP核状态,需要将读地址改为H08,H08寄存器各个数值代表含义如下图所示。
H08状态寄存器各个数值含义
2.新建工程
3.打开IP核界面,
UART IP核分别选择系统时钟,波特率、传输的数据位宽以及奇偶校验,本次选择时钟100MHz,波特率9600bps,数据位宽8bit,不使用奇偶校验。
4.打开例化文件,如下所示,对IP核进行例化,

axi_uartlite_0 your_instance_name (
  .s_axi_aclk(s_axi_aclk),        // input wire s_axi_aclk
  .s_axi_aresetn(s_axi_aresetn),  // input wire s_axi_aresetn
  .interrupt(interrupt),          // output wire interrupt
  .s_axi_awaddr(s_axi_awaddr),    // input wire [3 : 0] s_axi_awaddr
  .s_axi_awvalid(s_axi_awvalid),  // input wire s_axi_awvalid
  .s_axi_awready(s_axi_awready),  // output wire s_axi_awready
  .s_axi_wdata(s_axi_wdata),      // input wire [31 : 0] s_axi_wdata
  .s_axi_wstrb(s_axi_wstrb),      // input wire [3 : 0] s_axi_wstrb
  .s_axi_wvalid(s_axi_wvalid),    // input wire s_axi_wvalid
  .s_axi_wready(s_axi_wready),    // output wire s_axi_wready
  .s_axi_bresp(s_axi_bresp),      // output wire [1 : 0] s_axi_bresp
  .s_axi_bvalid(s_axi_bvalid),    // output wire s_axi_bvalid
  .s_axi_bready(s_axi_bready),    // input wire s_axi_bready
  .s_axi_araddr(s_axi_araddr),    // input wire [3 : 0] s_axi_araddr
  .s_axi_arvalid(s_axi_arvalid),  // input wire s_axi_arvalid
  .s_axi_arready(s_axi_arready),  // output wire s_axi_arready
  .s_axi_rdata(s_axi_rdata),      // output wire [31 : 0] s_axi_rdata
  .s_axi_rresp(s_axi_rresp),      // output wire [1 : 0] s_axi_rresp
  .s_axi_rvalid(s_axi_rvalid),    // output wire s_axi_rvalid
  .s_axi_rready(s_axi_rready),    // input wire s_axi_rready
  .rx(rx),                        // input wire rx
  .tx(tx)                        // output wire tx
);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

vivado中UART IP核采用AXI4-lite连接协议,关于AXI4协议的说明可以参考我写的这篇文章:

5.生成代码:顶层文件:

module uart_top(

    input m_axi_aclk_100M,
    input m_axi_aresetn,
    input START,
    
    input uart_rx,
    
    output uart_tx

    );
  
  
 
wire interrupt; 

//clock
//wire m_axi_aclk_100M;
//wire m_axi_aresetn;
//write addr        
wire[3:0] m_axi_awaddr;   
wire  m_axi_awvalid; 
wire m_axi_awready;
//write data
wire[31:0] m_axi_wdata;     
wire[3:0]  m_axi_wstrb;     
wire  m_axi_wvalid;    
wire m_axi_wready;
//write response 
wire[1:0] m_axi_bresp;     
wire      m_axi_bvalid;   
wire       m_axi_bready; 
//read addr  
wire[3:0] m_axi_araddr;   
wire      m_axi_arvalid;  
wire     m_axi_arready; 
//read response
wire[31:0] m_axi_rdata;      
wire[1:0]  m_axi_rresp;     
wire m_axi_rvalid;    
wire  m_axi_rready;  
///ststus signal
wire ERROR;
                     
        


m_axi_uartlite_0 u_m_axi_uartlite_0(

.m_axi_aclk(m_axi_aclk_100M),
.m_axi_aresetn(m_axi_aresetn),
//.interrupt(interrupt),
.INIT_AXI_TXN(START||interrupt),

//写地址
.m_axi_awaddr(m_axi_awaddr),    // input wire [3 : 0] s_axi_awaddr
.m_axi_awvalid(m_axi_awvalid),  // input wire s_axi_awvalid
.m_axi_awready(m_axi_awready),  // output wire s_axi_awready
//写数据
.m_axi_wdata(m_axi_wdata),      // input wire [31 : 0] s_axi_wdata
.m_axi_wstrb(m_axi_wstrb),      // input wire [3 : 0] s_axi_wstrb,写选通
.m_axi_wvalid(m_axi_wvalid),    // input wire s_axi_wvalid
.m_axi_wready(m_axi_wready),    // output wire s_axi_wready
//写响应
.m_axi_bresp(m_axi_bresp),      // output wire [1 : 0] s_axi_bresp
.m_axi_bvalid(m_axi_bvalid),    // output wire s_axi_bvalid
.m_axi_bready(m_axi_bready),    // input wire s_axi_bready
//读地址
.m_axi_araddr(m_axi_araddr),    // input wire [3 : 0] s_axi_araddr
.m_axi_arvalid(m_axi_arvalid),  // input wire s_axi_arvalid
.m_axi_arready(m_axi_arready),  // output wire s_axi_arready
//读数据
.m_axi_rdata(m_axi_rdata),      // output wire [31 : 0] s_axi_rdata
.m_axi_rresp(m_axi_rresp),      // output wire [1 : 0] s_axi_rresp
.m_axi_rvalid(m_axi_rvalid),    // output wire s_axi_rvalid
.m_axi_rready(m_axi_rready),    // input wire s_axi_rready
.ERROR(ERROR)

    );
 
    


axi_uartlite_0 u_axi_uartlite_0 (
  .s_axi_aclk(m_axi_aclk_100M),        // input wire s_axi_aclk
  .s_axi_aresetn(m_axi_aresetn),  // input wire s_axi_aresetn
  .interrupt(interrupt),          // output wire interrupt
  //写地址
  .s_axi_awaddr(m_axi_awaddr),    // input wire [3 : 0] s_axi_awaddr
  .s_axi_awvalid(m_axi_awvalid),  // input wire s_axi_awvalid
  .s_axi_awready(m_axi_awready),  // output wire s_axi_awready
  //写数据
  .s_axi_wdata(m_axi_wdata),      // input wire [31 : 0] s_axi_wdata
  .s_axi_wstrb(m_axi_wstrb),      // input wire [3 : 0] s_axi_wstrb
  .s_axi_wvalid(m_axi_wvalid),    // input wire s_axi_wvalid
  .s_axi_wready(m_axi_wready),    // output wire s_axi_wready
  //写响应
  .s_axi_bresp(m_axi_bresp),      // output wire [1 : 0] s_axi_bresp
  .s_axi_bvalid(m_axi_bvalid),    // output wire s_axi_bvalid
  .s_axi_bready(m_axi_bready),    // input wire s_axi_bready
  //读地址
  .s_axi_araddr(m_axi_araddr),    // input wire [3 : 0] s_axi_araddr
  .s_axi_arvalid(m_axi_arvalid),  // input wire s_axi_arvalid
  .s_axi_arready(m_axi_arready),  // output wire s_axi_arready
  //读数据
  .s_axi_rdata(m_axi_rdata),      // output wire [31 : 0] s_axi_rdata
  .s_axi_rresp(m_axi_rresp),      // output wire [1 : 0] s_axi_rresp
  .s_axi_rvalid(m_axi_rvalid),    // output wire s_axi_rvalid
  .s_axi_rready(m_axi_rready),    // input wire s_axi_rready
  //对外接口
  .rx(uart_rx),                        // input wire rx
  .tx(uart_tx)                        // output wire tx
);    
 
 
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116

其中m_axi_uartlite_0 模块为uart IP提供数据、地址以及读写时序信号,axi-lite的读写时序可以看我的另一篇博客

三.仿真

1.方案:方案框图如下所示。
仿真测试方案框图
编写RX_TB模块接收UART IP核的TX数据,观测RX_TB模块中接收到的数据是否与发送一致;编写TX_TB模块发送数据,然后在UART IP核观测接收到数据与TX_TB模块发送的数据是否一致。

2.编写tb代码。将UART IP核、uart_top顶层文件以及uart_rx_tb、uart_tx_tb作为仿真模块,在uart IP核读取数据之前,需要保证IP核内部的RX FIFO有数据,所以tx_start 需要早于IP核start。

module uart_top_tb(
    );

parameter FREQ = 100_000_000;//100MHz
parameter FREQ_PER = 5;//100MHz
parameter C_BAUDRATE = 9600;//
parameter RATIO = FREQ/C_BAUDRATE;//10416
parameter COUNT = RATIO/2;//5208

reg sys_clk;
reg rst;
wire s_axi_aclk;
wire s_axi_aresetn;
wire m_axi_aclk_100M;
wire m_axi_aresetn;

wire rxd;
wire[7:0] rx_data    ;
wire rx_data_vld;

wire txd;
wire w_axi_rvalid;
wire START;
wire tx_start;
reg[18:0] cnt_start;
                       
      
initial 
    begin
        sys_clk = 0;
        rst = 1;
        #100;
        rst = 0;           
    end
        
always #FREQ_PER  sys_clk=~sys_clk; //100MHz时钟   

assign s_axi_aclk = sys_clk;
assign s_axi_aresetn = ~rst;


clk_wiz_0 u_clk_wiz_0
 (
  // Clock out ports
  .clk_out1(m_axi_aclk_100M),     // output clk_out1
  // Status and control signals
  .reset(rst), // input reset
  .locked(m_axi_aresetn),       // output locked
 // Clock in ports
  .clk_in1(s_axi_aclk));      // input clk_in1  



always @(posedge m_axi_aclk_100M or negedge m_axi_aresetn)
    if(!m_axi_aresetn)
        cnt_start <= 19'd0;
    else if(cnt_start == 19'd354244)
        cnt_start <= 19'd354244;
    else
        cnt_start <= cnt_start + 1'b1; 

assign START = (cnt_start == 19'd354244)? 1'b1:1'b0;
assign tx_start = (cnt_start == 19'd187588)? 1'b1:1'b0;

uart_rx_tb
#(
    .RATIO(RATIO),
    .BSP_COUNT(COUNT)
)
 u_uart_rx_tb(
    .clk  (m_axi_aclk_100M)       ,
    .rst_n(m_axi_aresetn)       ,
    
    .rxd(rxd)         ,//接收数据
 
    .rx_data     (rx_data),//串转并后的8bit数据
    .rx_data_vld (rx_data_vld) //串转并后的数据有效标志信号
 
);    

uart_tx_tb 
#(
    .RATIO(RATIO),
    .BSP_COUNT(COUNT)
)
u_uart_tx_tb(
    .clk  (m_axi_aclk_100M  )      ,
    .rst_n(m_axi_aresetn)      ,
 
    .tx_din    (8'h8a)  ,//数据输入
    .tx_din_vld(tx_start)  ,//数据有效
 
    .txd(txd)
);


uart_top u_uart_top(

    .m_axi_aclk_100M(m_axi_aclk_100M),
    .m_axi_aresetn(m_axi_aresetn),
    .START(START),
    
    .uart_rx(txd),
    .uart_tx(rxd)

    );



   

//axi_uartlite_1 u_axi_uartlite_1 (
//  .s_axi_aclk(s_axi_aclk),        // input wire s_axi_aclk
//  .s_axi_aresetn(s_axi_aresetn),  // input wire s_axi_aresetn
//  .interrupt(interrupt),          // output wire interrupt
//  .s_axi_awaddr(s_axi_awaddr),    // input wire [3 : 0] s_axi_awaddr
//  .s_axi_awvalid(s_axi_awvalid),  // input wire s_axi_awvalid
//  .s_axi_awready(s_axi_awready),  // output wire s_axi_awready
//  .s_axi_wdata(s_axi_wdata),      // input wire [31 : 0] s_axi_wdata
//  .s_axi_wstrb(s_axi_wstrb),      // input wire [3 : 0] s_axi_wstrb
//  .s_axi_wvalid(s_axi_wvalid),    // input wire s_axi_wvalid
//  .s_axi_wready(s_axi_wready),    // output wire s_axi_wready
//  .s_axi_bresp(s_axi_bresp),      // output wire [1 : 0] s_axi_bresp
//  .s_axi_bvalid(s_axi_bvalid),    // output wire s_axi_bvalid
//  .s_axi_bready(s_axi_bready),    // input wire s_axi_bready
//  .s_axi_araddr(s_axi_araddr),    // input wire [3 : 0] s_axi_araddr
//  .s_axi_arvalid(s_axi_arvalid),  // input wire s_axi_arvalid
//  .s_axi_arready(s_axi_arready),  // output wire s_axi_arready
//  .s_axi_rdata(s_axi_rdata),      // output wire [31 : 0] s_axi_rdata
//  .s_axi_rresp(s_axi_rresp),      // output wire [1 : 0] s_axi_rresp
//  .s_axi_rvalid(s_axi_rvalid),    // output wire s_axi_rvalid
//  .s_axi_rready(s_axi_rready),    // input wire s_axi_rready
//  .rx(rx),                        // input wire rx
//  .tx(tx)                        // output wire tx
//);

         
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138

3.仿真结果展示:
①IP核写仿真:

IP核写仿真②IP核读仿真
IP核读仿真

总结

UART内容相对基础,注意写好AXI-lite接口代码就可以,本文基于vivado软件中UART IP完成了开发。文中罗列了一些基本的概念和设计的流程供大家参考,有问题可联系signal10_d@163.com,资源获取点击这里

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/651166
推荐阅读
相关标签
  

闽ICP备14008679号