axi-uart
uart通信协议介绍
UART作为异步串行通信收发器,采用了对数据流进行全双工的双向传输的方法,即通过两条通路使发射器和接收器可以同时进行信息的发送与传输。
作为异步通信,uart将数据以字符为单位进行逐字传输,位与位之间因存在于同一个字符内,需要设定固有的时间间隔,也称为波特率。
从左至右为第n-1个字符,第n个字符以及第n+1个字符这三个字符间无需设定固有的时间间隔,而单个字符内存在特定功能的“位格式”。从左往右分别为起始位,数据位,校验位以及停止位,而图中字符之间还存在一位空闲位。
起始位:1bit,连接空闲位,当电平由高变低,则标志着数据传输的开始;
数据位:表示该字符中的有效数据,可以是5位,6位,7位或8位数据,其数据位数可通过代码设计或软硬件设备进行设置,数据位数据的传输需要从低位开始由低位到高位进行传输;
校验位:通过设置校验位来进行数据传输正确性的检验。
停止位:对应于起始位,为高电平有效,标志着数据传输的结束,其长度根据设计可以被设定为1位,1.5位或2位。
空闲位:与停止位相同为高电平有效,长期处于高电平,表示非工作模式下的状态,且其长度不固定。
官方FIFO改写成握手形式的FIFO
这里新建一个工程,然后在ip catalog中搜索FIFO Generator双击就可以生成了
配置参数 basic这里默认
read mode这里,standard fifo表示下表示控制命令来了,一个周期数据有效(有一拍的延时),这里选First Word Fall Through 表示控制命令来了,当前周期数据有效(没有延时)。FIFO宽度设定为8,深度设为64。
低电平异步复位模式
最后生成的GUI如下,点击OK生成ip核
可以看到这里的FIFO源码为vhdl写的,下面为部分代码,我们只需要将端口例化到自己的模块中。
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
LIBRARY fifo_generator_v13_2_4;
USE fifo_generator_v13_2_4.fifo_generator_v13_2_4;
ENTITY fifo_ff_8x64 IS
PORT (
clk : IN STD_LOGIC;
rst : IN STD_LOGIC;
din : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
wr_en : IN STD_LOGIC;
rd_en : IN STD_LOGIC;
dout : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
full : OUT STD_LOGIC;
empty : OUT STD_LOGIC;
wr_rst_busy : OUT STD_LOGIC;
rd_rst_busy : OUT STD_LOGIC
);
END fifo_ff_8x64;
握手形式的FIFO架构
例化FIFO到自己模块
`timescale 1ns / 1ps
module hs_fifo_8_64
(
input clk,
input rst_n,
input din_vld,
output din_rdy,
input [7:0]din,
output dout_vld,
input dout_rdy,
output [7:0]dout
);
wire fifo_full;
wire fifo_empty;
fifo_fw_8x64 u_fifo_fw_8x64
(
.clk(clk),
.rst(~rst_n),
.din(din),
.wr_en(din_vld&din_rdy), //
.rd_en(dout_vld&dout_rdy),
.dout(dout),
.full(fifo_full),
.empty(fifo_empty)
);
assign din_rdy=~fifo_full;
assign dout_vld=~fifo_empty;
endmodule
整体架构设计
testbench仿真没有问题
发送数据
接收数据
打包AXI_UART的IP核,如下
添加zynq7000ip核
配置 Bank电平标准,使能串口
DDR3的型号(根据自己开发板对应的DDR型号)
修改FCLK0改到100MHZ
添加刚才的ip核到soc平台,自动连线然后生成bit流
sdk代码
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xparameters.h"
#include "sleep.h"
volatile unsigned int *UART_BASE =(unsigned int*)XPAR_UART_MY_0_BASEADDR;
int main()
{
init_platform();
print("Hello World\n\r");
//设置输入模式并赋值
for(int i=0;i<40;i++)
{
*(unsigned int*)(UART_BASE+0)=i*4;
}
//打印输出
for(int i=0;i<40;i++)
{
xil_printf("%d : recv value == %d\r\n",i,*(unsigned int*)(XPAR_UART_MY_0_BASEADDR));
}
cleanup_platform();
return 0;
}
上板测试结果:
思考:这里留一个问题,为什么AXI-UART设计里要加FIFO?欢迎大家留言讨论,答案会在下期AXI-DMA中公布,谢谢大家关注和阅读!!!