在FPGA开发中,UART通信是最基础也最常用的外设接口之一。Xilinx提供的AXI UART Lite IP核因其轻量级和易用性,成为许多嵌入式系统的首选方案。本文将基于Zynq-7000平台,从硬件设计到Linux驱动测试,详细介绍AXI UART Lite的完整开发流程。
我们使用的是Xilinx Zynq-7000系列中的XC7Z020CLG400-2芯片,这是Zynq家族中性价比极高的型号,具有:
在Vivado 2020.2开发环境中,我们创建了一个基于Processing System 7 (PS)的设计,通过AXI总线连接AXI UART Lite IP核。关键配置参数包括:
在Block Design中,主要组件包括:
UART的物理引脚通过PL侧的K14(RX)和M15(TX)引出,电平标准为LVCMOS33。在约束文件(XDC)中的定义如下:
tcl复制set_property -dict {PACKAGE_PIN K14 IOSTANDARD LVCMOS33} [get_ports uart2_rxd]
set_property -dict {PACKAGE_PIN M15 IOSTANDARD LVCMOS33} [get_ports uart2_txd]
裸机测试程序使用Xilinx提供的UART Lite驱动程序库(XUartLite),主要功能是实现数据回显。核心代码结构如下:
c复制#include "xparameters.h"
#include "xuartlite.h"
#include "xil_printf.h"
#include "sleep.h"
#define UART_DEVICE_ID XPAR_AXI_UARTLITE_0_DEVICE_ID
#define MAX_RECV_LEN 16
XUartLite UartInstance;
int main() {
int status;
u8 recv_buf[MAX_RECV_LEN];
u32 recv_len;
// 初始化UART
status = XUartLite_Initialize(&UartInstance, UART_DEVICE_ID);
if (status != XST_SUCCESS) {
xil_printf("UART Init Failed!\r\n");
return -1;
}
XUartLite_ResetFifos(&UartInstance);
while (1) {
recv_len = XUartLite_Recv(&UartInstance, recv_buf, MAX_RECV_LEN);
if (recv_len > 0) {
// 回显数据
for (u32 i = 0; i < recv_len; i++) {
XUartLite_SendByte(UartInstance.RegBaseAddress, recv_buf[i]);
}
}
usleep(1000);
}
return 0;
}
注意:AXI UART Lite的FIFO深度通常为16字节,超过此长度的数据需要分段处理。
无数据回显:
数据丢失:
初始化失败:
Petalinux工具会自动生成PL外设的设备树节点(pl.dtsi),关键内容如下:
dts复制axi_uartlite_0: serial@42c00000 {
clock-names = "ref_clk";
clocks = <&clkc 0>;
compatible = "xlnx,xps-uartlite-1.00.a";
current-speed = <115200>;
device_type = "serial";
interrupt-parent = <&intc>;
interrupts = <0 29 4>;
port-number = <1>;
reg = <0x42c00000 0x1000>;
xlnx,baudrate = <0x1c200>;
xlnx,data-bits = <0x8>;
xlnx,odd-parity = <0x0>;
xlnx,s-axi-aclk-freq-hz-d = "100.0";
xlnx,use-parity = <0x0>;
};
在Linux内核中需要确保以下配置已启用:
code复制Device Drivers --->
Character devices --->
Serial drivers --->
Xilinx UARTLITE serial port support
Console on Xilinx UARTLITE serial port
通过menuconfig的配置界面应如下图所示(图示略,实际需确认对应选项被选中)
系统启动后,UART设备通常注册为/dev/ttyULx(x为序号)。常用测试方法:
bash复制ls /dev/ttyUL*
bash复制# 发送数据
echo "test" > /dev/ttyUL1
# 接收数据(需要另一终端发送)
cat /dev/ttyUL1
bash复制stty -F /dev/ttyUL1 115200 cs8 -parenb -cstopb
bash复制minicom -D /dev/ttyUL1 -b 115200
在裸机程序中,可以通过修改为中断驱动提高效率:
c复制#include "xil_exception.h"
void Handler(void *CallBackRef, u32 Event, unsigned int EventData) {
if (Event == XUL_RECV_EVENT) {
u8 data = XUartLite_RecvByte(UartInstance.RegBaseAddress);
XUartLite_SendByte(UartInstance.RegBaseAddress, data);
}
}
int SetupInterrupt() {
Xil_ExceptionInit();
XUartLite_SetRecvHandler(&UartInstance, Handler, &UartInstance);
XUartLite_EnableInterrupt(&UartInstance);
Xil_ExceptionEnable();
return XST_SUCCESS;
}
AXI UART Lite的标准IP核不支持动态波特率调整,但可以通过修改IP核或软件实现:
如果需要开发自定义驱动,关键结构体包括:
c复制static struct uart_driver xuartlite_uart_driver;
static struct uart_ops xuartlite_ops;
static struct console xuartlite_console;
典型实现流程:
在工业控制等需要多串口的场景中,建议:
长期运行中发现的问题及解决方案:
bash复制echo 8 > /proc/sys/kernel/printk
dmesg | grep tty
bash复制stty -F /dev/ttyUL1 -a
bash复制cat /dev/urandom | hexdump -v -e '/1 "%02X\n"' | while read line; do echo -n $line | xxd -r -p > /dev/ttyUL1; done
通过本文详实的开发记录和问题解决方案,开发者可以快速掌握AXI UART Lite在Zynq平台上的全流程开发。这种轻量级串口解决方案虽然简单,但在工业控制、设备调试等场景中仍然具有不可替代的价值。