3. AXI总线协议详解:AXI4、AXI4-Lite、AXI4-Stream协议对比与实战波形解读
AXI总线,说白了就是Zynq里PS和PL之间沟通的“高速公路”。我刚开始接触Zynq时,总觉得协议细节太多,看着手册里那些时序图就头疼。后来调了几个项目,踩过坑,才慢慢摸到门道。今天咱们就把AXI的三种变体——AXI4、AXI4-Lite、AXI4-Stream——掰开揉碎,看看它们到底有什么区别,握手时序怎么玩,以及实战波形长什么样。
3.1 三种AXI协议的核心差异
先给个总览。这三种协议,其实是为不同场景设计的。你想想看,一个系统里既有CPU对寄存器的配置,又有高速数据流的搬运,还有大块内存的读写,用一种协议包打天下,效率肯定上不去。
| 特性 | AXI4 (Full) | AXI4-Lite | AXI4-Stream |
|---|---|---|---|
| 主要用途 | 高性能内存映射读写 | 寄存器配置、状态查询 | 高速数据流传输 |
| 地址/数据通道 | 分离的地址、读、写通道 | 分离的地址、读、写通道 | 无地址通道,只有数据通道 |
| 突发传输 | 支持,最多256拍 | 不支持,每次1拍 | 支持,无限拍 |
| 数据宽度 | 8/16/32/64/128/...1024 bit | 32 bit 固定 | 任意宽度,通常为8的倍数 |
| 握手信号 | VALID/READY + 通道间依赖 | VALID/READY + 通道间依赖 | VALID/READY,无通道依赖 |
| 典型场景 | DDR读写、大块数据搬运 | 控制寄存器、中断状态 | 视频流、以太网、DMA |
关键点:AXI4和AXI4-Lite都是“内存映射”协议,意味着每次传输都需要指定地址。AXI4-Stream则抛弃了地址,只关心数据流的顺序和有效性。这是本质区别。
3.2 握手时序分析:VALID/READY机制
三种协议都使用相同的握手方式——VALID和READY。这个机制,我习惯叫它“双方确认”。发送方拉高VALID,表示“我有数据/地址要给你”;接收方拉高READY,表示“我准备好接收了”。数据在VALID和READY同时为高的时钟沿被传输。
握手有五种可能的情况,但实际中常见三种:
- 情况A:发送方先准备好(VALID先高),等待接收方READY。这是最常见的,比如从机处理慢,需要等几个周期。
- 情况B:接收方先准备好(READY先高),等待发送方VALID。这通常发生在从机空闲时,提前告诉总线“我随时可以收”。
- 情况C:双方同时准备好。一拍完成,效率最高。
我的习惯:设计AXI从机时,我通常让READY信号在复位后默认拉高。这样只要主机一发VALID,数据就能立刻传输,减少等待周期。但要注意,如果从机内部FIFO快满了,必须及时拉低READY,防止数据溢出。
3.3 AXI4-Lite实战波形解读
AXI4-Lite最简单,咱们先看它。下面是一个写寄存器的波形片段:
// 写地址通道 (AW)
// 时钟上升沿采样
// 1. AWVALID 拉高,AWADDR = 0x4000_0000
// 2. AWREADY 拉高,地址在此时钟沿被接收
// 写数据通道 (W)
// 3. WVALID 拉高,WDATA = 0xDEAD_BEEF,WSTRB = 4'b1111
// 4. WREADY 拉高,数据在此时钟沿被接收
// 写响应通道 (B)
// 5. 从机处理完成后,BVALID 拉高,BRESP = 2'b00 (OKAY)
// 6. BREADY 拉高,响应被接收,一次写操作完成
注意,AXI4-Lite的写操作,地址和数据通道是独立的。主机可以先发地址,再发数据;也可以同时发。但响应通道必须等从机处理完才能返回。我在项目中遇到过一个问题:主机连续写两个寄存器,第二个写的地址发得太快,结果从机还没处理完第一个,导致地址通道被阻塞。后来我加了一个简单的状态机,确保每个写操作完成后才发起下一个。
3.4 AXI4-Stream实战波形解读
AXI4-Stream没有地址,只有数据通道,所以握手更简单。但多了几个辅助信号:
- TVALID / TREADY:标准握手,数据在两者同时为高时传输。
- TDATA:数据总线,宽度可变。
- TLAST:包结束标志,高电平表示当前是最后一个数据。
- TKEEP:字节使能,指示TDATA中哪些字节有效。
- TUSER:用户自定义信号,比如携带帧同步信息。
看一个视频数据流的波形:
// 假设TDATA宽度为64位,每个时钟传输8字节
// 1. TVALID 拉高,TDATA = 第一行像素数据
// 2. TREADY 拉高,数据被接收
// 3. 连续传输,TREADY 保持高,TVALID 保持高
// 4. 第1920个像素时,TLAST 拉高,表示一行结束
// 5. 下一拍,TVALID 可能拉低(行消隐期),TLAST 拉低
我曾经踩过的坑:设计AXI4-Stream DMA时,忘记处理TLAST信号。结果DMA不知道什么时候该结束传输,一直等下去,导致系统死锁。记住:对于包传输,TLAST是必须的,接收端必须根据TLAST来判断包边界。
3.5 AXI4 (Full) 实战波形解读
AXI4最复杂,支持突发传输。看一个读突发的例子:
// 读地址通道 (AR)
// 1. ARVALID 拉高,ARADDR = 0x8000_0000,ARLEN = 3 (4拍突发)
// 2. ARREADY 拉高,地址被接收
// 读数据通道 (R)
// 3. 从机返回第一个数据:RVALID 拉高,RDATA = data0,RLAST = 0
// 4. 主机RREADY 拉高,数据被接收
// 5. 第二个数据:RVALID 拉高,RDATA = data1,RLAST = 0
// 6. 第三个数据:RVALID 拉高,RDATA = data2,RLAST = 0
// 7. 第四个数据:RVALID 拉高,RDATA = data3,RLAST = 1 (最后一个)
// 8. 主机RREADY 拉高,读操作完成
注意,读数据通道的RLAST信号,在最后一个数据时拉高。主机必须检测这个信号,才知道突发结束。写操作类似,但多了写响应通道,每个写突发只需要一个响应。
3.6 三种协议的选择策略
在实际项目中,怎么选?我一般遵循这个原则:
- 配置类:用AXI4-Lite。比如控制寄存器、状态寄存器、中断使能。每次只读写一个地址,不需要突发。
- 数据流类:用AXI4-Stream。比如视频像素流、以太网包、ADC采样数据。没有地址开销,吞吐量最高。
- 内存类:用AXI4 Full。比如DDR读写、大块数据搬运。利用突发特性,减少地址传输次数。
性能调优提示:AXI4的突发长度不是越大越好。我测试过,在Zynq上,突发长度超过16拍后,DDR控制器的效率提升就不明显了。而且过长的突发会占用总线太久,影响其他从机的响应。一般建议突发长度设为8或16。
3.7 知识结构图:AXI协议体系
下面这张图,帮你理清三种协议的关系和适用场景:
3.7 实战中的避坑指南
最后,分享几个我在项目中积累的经验:
- AXI4-Lite的地址对齐:AXI4-Lite的地址必须是4字节对齐的,因为数据宽度固定为32位。如果你试图写一个非对齐地址,从机可能会返回SLVERR。我刚开始就犯过这个错,查了半天才发现地址写错了。
- AXI4-Stream的TKEEP信号:当数据宽度不是字节的整数倍时,TKEEP用来指示哪些字节有效。比如64位数据总线,但最后一个包只有3字节有效,TKEEP就应该是8'b00000111。很多初学者忽略这个信号,导致数据错位。
- AXI4的写响应:写操作完成后,必须等待写响应通道的BVALID。有些设计为了省事,直接忽略响应,这在调试时可能没问题,但生产环境中,如果从机返回错误,主机根本不知道。我建议所有写操作都检查BRESP。
- 握手超时:如果主机发出VALID后,从机一直不拉READY,总线就会死锁。设计时一定要加超时机制,比如计数器计数1000个时钟周期后,主动拉低VALID并报错。
调试小技巧:用ILA抓AXI波形时,别只抓数据信号。一定要抓VALID、READY、LAST这几个控制信号。很多时候,问题就出在握手时序上。比如READY一直为低,说明从机被卡住了;TLAST没拉高,说明包边界不对。