赞
踩
UART(Universal Asynchronous Receiver/Transmitter)串口通信是一种简单的串行通信协议,常用的通信速率9600bite/s、19200bite/s、115200bite/s等,
图中TXD:发送数据线;RXD:接收数据线
一个完整的数据帧如下所示。
数据传输中接收方RX初始电平为1,当1变为0时候代表起始位,传输数据位以字节为单位,一次只能传输一字节,先发送低位再高位,发送频率由波特率来约定,RX与TX的波特率应该一致。
1.IP核解读
UART IP核外部接口分别为RX、TX以及Interrupt。其中RX为接收端,外部数据经RX控制模块接收数据到RX FIFO中,然后通过AXI-lite接口将数据读出;TX为发送端,数据经AXI-lite接口将发送的数据写入到TX FIFO,然后发送到外部接口。我们要做的就是编写AXI-lite界面代码,控制IP核的读取及写入,内部数据的串并或并串转换的帧格式如第一章中所示(代码实现可参考后续章节中TX_TB模块以及RX_TB模块)。
若要写入IP核数据,需要先写地址H04,然后再写数据,若要读取外部数据,即RX FIFO数据,需要将读取地址写成H00,TX FIFO及RX FIFO虽然接口为32bit,但是仅低8bit为有效数据,其余为预留。
同理若想读取IP核状态,需要将读地址改为H08,H08寄存器各个数值代表含义如下图所示。
2.新建工程
3.打开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 );
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
其中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
3.仿真结果展示:
①IP核写仿真:
②IP核读仿真
UART内容相对基础,注意写好AXI-lite接口代码就可以,本文基于vivado软件中UART IP完成了开发。文中罗列了一些基本的概念和设计的流程供大家参考,有问题可联系signal10_d@163.com
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。