1. 项目背景与核心价值
在嵌入式Linux开发中,UART(通用异步收发传输器)作为最基础的外设接口之一,承担着系统调试、设备通信等关键任务。AXI UART Lite是Xilinx FPGA平台上基于AXI4-Lite总线协议的轻量级UART控制器IP核,相比传统UART具有总线标准化、时钟域隔离等优势。本次测试的目标是在Linux环境下验证AXI UART Lite的完整功能链路,包括驱动加载、设备节点生成、数据传输稳定性等关键环节。
实际工程中,我们经常遇到这样的场景:当Zynq SoC需要与传感器模组或调试终端通信时,PL端实现的AXI UART Lite需要与PS端的Linux系统无缝配合。但官方文档往往只提供基础配置说明,缺乏实际环境下的完整测试方案。这就是为什么需要这样一篇从实战角度出发的测试指南。
2. 测试环境搭建
2.1 硬件准备清单
- Xilinx Zynq-7000开发板(如ZC706)
- USB转UART调试器(推荐FT232RL芯片方案)
- 杜邦线若干(注意线长不超过20cm以降低干扰)
- 示波器(可选,用于信号质量分析)
关键细节:USB转UART的电压电平必须与开发板UART接口匹配(通常为3.3V),错误使用5V电平可能损坏FPGA引脚。
2.2 Vivado工程配置
在Block Design中添加AXI UART Lite IP核时,需要特别注意以下参数配置:
tcl复制set_property -dict [list \
CONFIG.C_BAUDRATE {115200} \
CONFIG.C_DATA_BITS {8} \
CONFIG.C_USE_PARITY {0} \
CONFIG.C_ODD_PARITY {0} \
CONFIG.C_FLOW_CONTROL {0} \
] [get_bd_cells axi_uartlite_0]
波特率设置需与后续Linux终端配置保持一致。若需要硬件流控,需同时启用RTS/CTS信号线连接。
2.3 设备树关键配置
Linux内核需要通过设备树获取UART硬件信息。典型配置如下:
dts复制axi_uartlite_0: serial@42c00000 {
compatible = "xlnx,xps-uartlite-1.00.a";
reg = <0x42c00000 0x10000>;
interrupt-parent = <&intc>;
interrupts = <0 29 1>;
clock-frequency = <100000000>;
current-speed = <115200>;
device_type = "serial";
port-number = <1>; // 对应ttyUL1设备节点
};
特别注意port-number的取值逻辑:
- 0 → ttyUL0
- 1 → ttyUL1
- 以此类推
3. Linux驱动加载验证
3.1 内核驱动编译
确保内核配置已启用UART Lite驱动:
bash复制make menuconfig
路径:Device Drivers → Character devices → Serial drivers → Xilinx uartlite serial port support
编译后查看驱动是否正常加载:
bash复制dmesg | grep uartlite
[ 3.456789] xuartlite 42c00000.serial: uartlite at MMIO 0x42c00000 (irq = 29) is a 0
3.2 设备节点检查
成功加载后应在/dev目录下看到对应设备:
bash复制ls -l /dev/ttyUL*
crw-rw---- 1 root dialout 241, 0 Apr 10 10:00 /dev/ttyUL1
权限问题常导致测试失败,建议将用户加入dialout组:
bash复制sudo usermod -aG dialout $USER
4. 全功能测试方案
4.1 回环测试(Loopback Test)
硬件连接:将UART的TX与RX引脚短接
测试命令:
bash复制stty -F /dev/ttyUL1 115200 cs8 -cstopb -parenb
cat /dev/ttyUL1 & # 后台接收
echo "AXI UART Test" > /dev/ttyUL1
预期看到终端输出相同字符串。若出现乱码,需检查:
- 波特率偏差(用示波器测量实际波特率)
- 时钟域交叉问题(确认AXI总线与UART时钟比≤16:1)
4.2 压力测试
使用dd命令进行大数据量传输:
bash复制dd if=/dev/urandom of=/dev/ttyUL1 bs=1K count=100
同时在接收端统计:
bash复制cat /dev/ttyUL1 | pv -b > /dev/null
正常应达到持续115200bps速率,误码率低于1e-6。若出现数据丢失,建议:
- 减小DMA缓冲区(修改驱动中的XLUARTLITE_RX_FIFO_DEPTH)
- 增加中断响应优先级
4.3 多线程并发测试
编写测试脚本模拟多线程访问:
python复制import threading
def uart_thread(num):
with open(f'/dev/ttyUL1', 'w+') as f:
f.write(f"Thread {num} test\n")
print(f.read(50))
for i in range(5):
threading.Thread(target=uart_thread, args=(i,)).start()
观察是否出现数据交叉或线程阻塞。AXI UART Lite的硬件FIFO深度通常为16字节,超过此容量需要软件流控配合。
5. 性能优化技巧
5.1 中断响应优化
修改驱动中的中断处理函数(xuartlite.c):
c复制static irqreturn_t xuartlite_interrupt(int irq, void *dev_id)
{
/* 原始处理逻辑 */
return IRQ_HANDLED;
}
建议添加:
c复制static irqreturn_t xuartlite_interrupt(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
/* 精简处理流程 */
spin_unlock_irqrestore(&port->lock, flags);
return IRQ_WAKE_THREAD; // 耗时操作移交线程
}
5.2 DMA配置(PL端修改)
对于高速应用(>1Mbps),建议在Vivado中启用DMA引擎:
- 添加AXI DMA IP核
- 连接UART Lite的FIFO接口到DMA的AXI Stream端口
- 在驱动中实现scatter-gather传输
6. 典型问题排查指南
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 无/dev/ttyUL*节点 | 驱动未加载/设备树错误 | 检查dmesg输出,确认reg地址匹配 |
| 能发送但接收不到数据 | 引脚分配错误/电平不匹配 | 用示波器检查TX/RX信号 |
| 大数据量传输丢失 | FIFO溢出/中断延迟 | 减小传输块大小或启用DMA |
| 波特率不稳定 | 时钟分频误差 | 重新计算CLK_FREQ参数 |
7. 进阶测试场景
7.1 与系统console共用
如需将ttyUL1作为系统console,需修改bootargs:
bash复制setenv bootargs "console=ttyUL1,115200 root=/dev/mmcblk0p2 rw earlyprintk"
此时需特别注意:
- 确保UART在Linux内核初始化前已完成配置
- 早期printk可能丢失,建议配合JTAG调试
7.2 热插拔支持
实现udev规则自动配置权限:
bash复制# /etc/udev/rules.d/99-uart.rules
KERNEL=="ttyUL[0-9]*", MODE="0666", GROUP="dialout"
重新加载规则:
bash复制sudo udevadm control --reload-rules
sudo udevadm trigger
在实际项目中,AXI UART Lite的稳定性直接关系到整个系统的可靠性。我曾遇到过因时钟域异步导致的偶发数据错误,最终通过在Vivado中约束跨时钟域路径(set_false_path)解决。建议在量产前至少进行72小时持续传输测试,这对工业级应用尤为重要。