一.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核外部接口分别为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,资源获取
发表评论