4. AXI总线基础:AXI4、AXI4-Lite、AXI4-Stream协议介绍
做Zynq图像处理,绕不开AXI总线。说白了,AXI就是ARM和FPGA之间沟通的桥梁。我刚开始接触Zynq时,总觉得AXI协议很复杂,各种通道、握手信号看得眼花缭乱。后来踩了几个坑,才慢慢摸清楚门道。
今天咱们就把AXI总线的基础掰开揉碎讲清楚。你想想看,图像数据在PL和PS之间跑来跑去,没有一套可靠的协议怎么行?
4.1 三种AXI协议,各司其职
AXI家族有三个兄弟:AXI4、AXI4-Lite、AXI4-Stream。它们各有各的脾气,用错了地方就会出问题。
| 协议类型 | 特点 | 典型应用场景 | 数据宽度 |
|---|---|---|---|
| AXI4 | 高性能、突发传输、地址映射 | DDR读写、大块数据搬运 | 32/64/128/256/512位 |
| AXI4-Lite | 轻量级、单次传输、地址映射 | 寄存器配置、控制状态读取 | 32位固定 |
| AXI4-Stream | 无地址、连续流、低延迟 | 视频流、音频流、数据管道 | 任意宽度 |
我个人习惯把AXI4比作卡车运输——一次拉很多货,但需要知道目的地。AXI4-Lite就像骑自行车送快递,一次只送一件,但灵活。AXI4-Stream呢?它像流水线上的传送带,东西来了就走,不需要地址。
核心要点:图像处理流水线中,像素数据走AXI4-Stream,寄存器配置走AXI4-Lite,帧缓存走AXI4。这个分工要记牢。
4.2 握手信号与时序
AXI的握手机制,说白了就是「你说你准备好了,我说我准备好了,然后咱们开始干」。这个机制靠的是VALID和READY两个信号。
为什么会这样设计?因为总线上的主设备和从设备速度可能不一样。主设备准备好了,从设备可能还在忙。这时候就需要握手来协调。
4.2.1 三种握手方式
- VALID先有效:主设备先拉高VALID,等待从设备拉高READY。这种方式主设备比较主动。
- READY先有效:从设备先拉高READY,等待主设备拉高VALID。从设备提前告诉主设备「我准备好了」。
- 同时有效:VALID和READY在同一时钟沿都拉高,一拍完成传输。这是最高效的方式。
嗯,这里要注意:数据只在VALID和READY同时为高的时钟沿传输。如果其中一个没准备好,就得等。
我的经验:写AXI从设备时,我习惯让从设备先拉高READY,这样主设备来了数据就能直接传,减少等待周期。但要注意,READY不能依赖VALID,否则可能死锁。
4.2.2 时序图示例
咱们用SVG画一个典型的AXI写通道握手时序。这个图展示了写地址、写数据和写响应三个通道的交互。
你看这个时序图,T0时刻AWVALID拉高,但AWREADY还没准备好。直到T2时刻AWREADY才拉高,这时候地址才传过去。写数据通道也是类似,WVALID和WREADY在T2到T4之间握手完成。最后写响应BVALID在T4返回。
避坑指南:我曾经在一个项目中,从设备的READY信号依赖了主设备的VALID信号,结果形成了组合逻辑环路。仿真时没问题,上板就跑飞了。记住:READY不能组合逻辑依赖VALID,要用寄存器打一拍。
4.3 AXI4-Stream协议详解
图像处理流水线中,AXI4-Stream用得最多。它没有地址通道,只有数据通道,说白了就是一根管子,数据从一头流进去,从另一头流出来。
AXI4-Stream的关键信号就几个:
- TVALID:主设备告诉从设备「数据有效了」
- TREADY:从设备告诉主设备「我准备好了」
- TDATA:数据总线,宽度可以自定义
- TLAST:包结束标志,告诉接收方「这是最后一个数据」
- TUSER:用户自定义信号,比如帧同步、行同步
- TKEEP:字节使能,用于非对齐传输
嗯,这里有个关键点:TLAST信号在图像处理中特别重要。一帧图像传输完时,TLAST要拉高,告诉下游模块「帧结束了」。我见过有人忘了拉TLAST,结果图像一直卡在那里,显示不出来。
4.3.1 图像数据流结构
咱们用SVG画一个典型的图像数据流结构,看看像素怎么在AXI4-Stream上跑。
你看这个结构,一帧图像由多行组成。每行传输时TUSER信号拉高表示行开始,TLAST在最后一行拉高表示帧结束。这种结构在VDMA(Video Direct Memory Access)中非常常见。
4.4 AXI VIP仿真验证
写完了AXI接口的RTL代码,怎么验证对不对?手动写testbench太痛苦了。Xilinx提供了AXI Verification IP(VIP),专门用来做AXI总线的仿真验证。
我个人习惯用AXI VIP做三件事:
- 主设备仿真:用VIP模拟ARM端发起读写事务
- 从设备仿真:用VIP模拟外设响应主设备请求
- 协议检查:VIP会自动检查时序违规,比如握手超时、数据冲突
4.4.1 AXI VIP的基本用法
下面是一个简单的AXI4-Lite VIP配置示例,用于验证寄存器读写:
// 在testbench中实例化AXI VIP
axi_vip_0 #(
.C_AXI4_LITE_DATA_WIDTH(32),
.C_AXI4_LITE_ADDR_WIDTH(32)
) u_axi_vip (
.aclk(clk),
.aresetn(rst_n),
.m_axi_awaddr(m_axi_awaddr),
.m_axi_awvalid(m_axi_awvalid),
.m_axi_awready(m_axi_awready),
.m_axi_wdata(m_axi_wdata),
.m_axi_wvalid(m_axi_wvalid),
.m_axi_wready(m_axi_wready),
.m_axi_bresp(m_axi_bresp),
.m_axi_bvalid(m_axi_bvalid),
.m_axi_bready(m_axi_bready),
.m_axi_araddr(m_axi_araddr),
.m_axi_arvalid(m_axi_arvalid),
.m_axi_arready(m_axi_arready),
.m_axi_rdata(m_axi_rdata),
.m_axi_rvalid(m_axi_rvalid),
.m_axi_rready(m_axi_rready)
);
// 发起一次写事务
initial begin
@(posedge rst_n);
#100;
// 写地址 0x1000,数据 0xA5A5A5A5
u_axi_vip.master_0.write(32'h00001000, 32'hA5A5A5A5);
// 读地址 0x1000,验证数据
u_axi_vip.master_0.read(32'h00001000, data);
$display("Read data: 0x%08h", data);
end
我的经验:用AXI VIP做仿真时,一定要打开协议检查功能。它会在仿真日志中打印出所有违规信息,比如「写地址通道握手超时」之类的。我曾经靠这个功能抓到了一个地址对齐的bug,省了三天调试时间。
4.4.2 仿真验证的常见问题
做AXI仿真时,有几个坑我踩过,分享给你:
- 复位时序:复位释放后,至少要等几个时钟周期再发起事务。VIP默认有复位等待时间,但自己写的testbench容易忽略。
- 突发长度:AXI4支持1-256拍的突发传输。但有些从设备不支持长突发,仿真时要注意配置匹配。
- 数据对齐:32位总线访问32位地址没问题,但如果是64位总线访问非64位对齐地址,就要小心了。
避坑指南:我曾经在仿真中遇到一个诡异现象——写数据明明成功了,但读回来的数据不对。后来发现是VIP的写响应通道和读数据通道共用了同一个变量,导致数据被覆盖了。记住:每个通道的变量要独立声明。
4.5 本章小结
AXI总线是Zynq图像处理流水线的血管。AXI4负责大块数据搬运,AXI4-Lite负责寄存器配置,AXI4-Stream负责像素流传输。握手信号VALID和READY是协调主从设备的关键。仿真验证时,AXI VIP能帮我们省不少力气。
嗯,这些基础概念搞清楚了,后面咱们讲VDMA、讲图像处理IP核时,你就不会觉得吃力了。记住一句话:AXI总线不难,难的是把时序搞对。多仿真、多验证,慢慢就熟练了。