AXI UART Lite是Xilinx提供的一款轻量级串行通信控制器IP核,它完美地桥接了AXI4-Lite总线协议与UART串行通信协议。作为一名长期从事FPGA开发的工程师,我发现这个IP核在资源受限的嵌入式系统中特别实用。它最大的优势在于既保留了AXI总线的标准化接口,又实现了UART通信的简洁性。
这个IP核支持全双工通信模式,意味着它可以同时进行数据的发送和接收。在实际项目中,我经常用它来实现FPGA与PC、传感器或其他外设的通信。它内置的16字节深度FIFO缓冲区是个很贴心的设计,可以有效减少CPU的中断频率,提高系统整体效率。
注意:虽然叫做"Lite",但这个IP核的功能并不简陋。它支持5-8位数据宽度、可选的奇偶校验,以及从110bps到921600bps的多种标准波特率,完全能满足大多数应用场景的需求。
AXI UART Lite的内部架构非常清晰,主要由以下几个关键模块组成:
AXI4-Lite从机接口:这是IP核与系统总线通信的桥梁。它负责处理来自主设备的读写请求,并将这些请求转换为对内部寄存器的操作。在我的项目中,这个接口通常连接到MicroBlaze处理器或Zynq的PS部分。
寄存器组:包括控制寄存器(CTRL_REG)、状态寄存器(STAT_REG)、发送FIFO和接收FIFO。这些寄存器是软件与硬件交互的窗口。
UART控制模块:这是IP核的核心部分,包含:
IP核的接口信号可以分为三类:
系统信号:
AXI4-Lite接口信号:
这部分遵循标准的AXI4-Lite协议,包括:
UART物理接口信号:
AXI UART Lite通过四个32位寄存器进行控制,地址偏移如下:
| 地址偏移 | 寄存器名 | 访问权限 | 描述 |
|---|---|---|---|
| 0x00 | Rx FIFO | 只读 | 接收数据FIFO |
| 0x04 | Tx FIFO | 只写 | 发送数据FIFO |
| 0x08 | STAT_REG | 只读 | 状态寄存器 |
| 0x0C | CTRL_REG | 只写 | 控制寄存器 |
接收FIFO是一个16字节深的先进先出缓冲区。当UART接收到完整的一个字节后,会自动将其存入接收FIFO。软件通过读取这个寄存器来获取接收到的数据。
重要提示:尝试读取空FIFO会导致SLVERR总线错误。在实际编程中,一定要先检查STAT_REG的Rx FIFO Valid Data位(bit 0)是否为1。
发送FIFO同样为16字节深度。软件将要发送的数据写入这个寄存器,UART控制器会自动从FIFO中取出数据并串行发送。
常见错误:向已满的发送FIFO写入数据也会导致SLVERR错误。写入前应检查STAT_REG的Tx FIFO Full位(bit 3)。
CTRL_REG用于控制IP核的基本功能:
| 位 | 名称 | 描述 |
|---|---|---|
| 4 | Enable Intr | 1=使能中断,0=禁止中断 |
| 1 | Rst Rx FIFO | 写1清除接收FIFO(自动清零) |
| 0 | Rst Tx FIFO | 写1清除发送FIFO(自动清零) |
| 其他 | Reserved | 保留位,应写0 |
STAT_REG反映了IP核的当前状态:
| 位 | 名称 | 描述 |
|---|---|---|
| 7 | Parity Error | 奇偶校验错误(读取后自动清零) |
| 6 | Frame Error | 帧错误(停止位不正确,读取后自动清零) |
| 5 | Overrun Error | 溢出错误(新数据到达但FIFO已满,读取后自动清零) |
| 4 | Intr Enabled | 当前中断使能状态(反映CTRL_REG的Enable Intr位) |
| 3 | Tx FIFO Full | 发送FIFO满标志 |
| 2 | Tx FIFO Empty | 发送FIFO空标志 |
| 1 | Rx FIFO Full | 接收FIFO满标志 |
| 0 | Rx FIFO Valid | 接收FIFO中有有效数据(非空) |
在Vivado IP Integrator中添加AXI UART Lite IP时,需要配置以下参数:
AXI CLK Frequency (MHz):系统时钟频率,用于波特率计算。这个值必须与实际使用的时钟频率一致,否则会导致波特率不准确。
Baud Rate:支持的波特率范围从110bps到921600bps。Vivado会自动检查所选波特率是否能在给定的系统时钟频率下实现,并显示误差百分比。
Data Bits:可选择5、6、7或8位数据长度。大多数现代设备使用8位数据。
Parity:奇偶校验选项:
Use External XIN:如果选择使用外部时钟输入,则需要连接额外的时钟引脚。
AXI UART Lite的所有操作都同步于s_axi_aclk时钟信号。在实际设计中,我通常将这个时钟连接到与处理器相同的时钟域,以避免跨时钟域问题。
复位信号s_axi_aresetn是低电平有效的异步复位。复位时:
经验分享:虽然复位是异步的,但建议在释放复位时与时钟上升沿对齐,以避免潜在的亚稳态问题。
正确的初始化流程如下:
复位后,首先清除FIFO:
根据需要配置中断:
检查STAT_REG确认IP核状态:
发送数据的典型代码如下(伪代码):
c复制// 等待发送FIFO有空间
while (STAT_REG & TX_FIFO_FULL_MASK);
// 写入要发送的数据
TX_FIFO = data_to_send;
对于高效的数据发送,可以采用以下优化策略:
接收数据的典型代码如下(伪代码):
c复制// 检查是否有数据可读
if (STAT_REG & RX_FIFO_VALID_MASK) {
// 读取接收到的数据
received_data = RX_FIFO;
// 检查错误标志
if (STAT_REG & (PARITY_ERROR_MASK | FRAME_ERROR_MASK | OVERRUN_ERROR_MASK)) {
// 错误处理
}
}
性能提示:对于高速通信,建议使用中断方式处理接收数据,避免轮询带来的CPU开销。
当使能中断后,IP核会在以下情况下产生中断:
中断服务程序应遵循以下流程:
c复制void UART_ISR(void) {
// 读取状态寄存器确定中断源
uint32_t status = STAT_REG;
// 处理接收中断
if (status & RX_FIFO_VALID_MASK) {
while (status & RX_FIFO_VALID_MASK) {
uint8_t data = RX_FIFO;
// 处理接收到的数据
status = STAT_REG; // 重新读取状态
}
}
// 处理发送中断
if (status & TX_FIFO_EMPTY_MASK) {
// 填充更多数据到发送FIFO
}
}
波特率发生器是通过对系统时钟进行分频实现的。在选择系统时钟频率时,应考虑目标波特率的整除关系。例如:
这种误差通常可以接受。但如果误差超过3%,可能会导致通信不可靠。
接收侧:
发送侧:
无数据收发:
数据错误:
FIFO相关问题:
对于高速通信(>115200bps),建议:
对于低功耗应用:
虽然AXI UART Lite是一个轻量级IP核,但我们仍然可以通过一些技巧扩展其功能:
可以在应用层实现XON/XOFF流控协议:
c复制#define XON 0x11
#define XOFF 0x13
void send_with_flow_control(uint8_t *data, uint32_t length) {
for (uint32_t i = 0; i < length; i++) {
// 检查接收到的流控字符
if (STAT_REG & RX_FIFO_VALID_MASK) {
uint8_t c = RX_FIFO;
if (c == XOFF) {
while (1) {
if (STAT_REG & RX_FIFO_VALID_MASK) {
c = RX_FIFO;
if (c == XON) break;
}
}
}
}
// 发送数据
while (STAT_REG & TX_FIFO_FULL_MASK);
TX_FIFO = data[i];
}
}
可以在UART基础上实现更高级的协议,如简单的数据包格式:
code复制[开始标志][长度][数据][校验和]
在需要多个UART接口的系统中,可以实例化多个AXI UART Lite IP核,并通过统一的驱动层进行管理:
c复制struct uart_instance {
uint32_t base_addr;
// 其他实例特定数据
};
void uart_send(struct uart_instance *uart, uint8_t data) {
while (REG_READ(uart->base_addr + STAT_REG_OFFSET) & TX_FIFO_FULL_MASK);
REG_WRITE(uart->base_addr + TX_FIFO_OFFSET, data);
}
ILA集成逻辑分析仪:
Vivado仿真:
逻辑分析仪:
串口调试助手:
c复制void print_uart_status(uint32_t base_addr) {
printf("STAT_REG: 0x%08X\n", REG_READ(base_addr + STAT_REG_OFFSET));
printf("CTRL_REG: 0x%08X\n", REG_READ(base_addr + CTRL_REG_OFFSET));
// 其他调试信息
}
虽然AXI UART Lite非常实用,但在某些场景下可能需要考虑其他方案:
| 特性 | AXI UART Lite | AXI UART 16550 |
|---|---|---|
| FIFO深度 | 16字节 | 16/64/128字节(可配置) |
| 波特率范围 | 标准值 | 更灵活的范围 |
| 流控支持 | 无 | 硬件流控(RTS/CTS) |
| 中断类型 | 简单中断 | 更丰富的中断类型 |
| 资源占用 | 较少 | 较多 |
选择建议:
也可以完全用RTL实现UART功能,优势是:
但缺点也很明显:
在一个基于Zynq的项目中,我使用AXI UART Lite实现了调试控制台:
这个实现非常稳定,即使在复杂的系统中也能可靠工作。
在另一个工业传感器项目中,AXI UART Lite用于:
项目运行一年多来,没有出现任何通信问题。
AXI UART Lite的资源占用非常低,以下是在Artix-7器件上的典型资源使用:
| 资源类型 | 使用量 |
|---|---|
| LUT | ~200 |
| FF | ~150 |
| BRAM | 0 |
相比之下,AXI UART 16550可能需要2-3倍的资源。因此,在资源受限的设计中,AXI UART Lite是更经济的选择。
AXI UART Lite的驱动可以相对容易地移植到不同操作系统:
需要注意PG142文档版本的差异:
在实际项目中,我总是明确记录使用的IP核版本号,以避免后续维护时的混淆。
输入验证:
错误处理:
访问控制:
虽然AXI UART Lite已经很完善,但在实际项目中,我还会考虑以下扩展:
DMA支持:
添加简单的DMA功能,减少CPU在大量数据传输时的开销。
自适应波特率:
实现波特率自动检测功能,提高灵活性。
更丰富的诊断功能:
增加错误统计、性能监测等高级功能。
经过多个项目的实践,我认为AXI UART Lite是Xilinx FPGA设计中串口通信的最佳选择之一。它的优势在于:
在实际使用中,我有几点深刻体会:
最后分享一个小技巧:在设计初期,我通常会实现一个简单的回环测试功能(将TX连接到RX),这能快速验证IP核的基本功能是否正确工作。这个习惯帮我节省了不少调试时间。