4、总线协议基础:AMBA AHB/AXI协议简介、总线时序、读写操作流程
说到嵌入式系统,总线协议是个绕不开的话题。我刚开始做SoC设计那会儿,总觉得总线协议就是一堆时序图,看着就头疼。后来真正上手调了两次,才发现这东西说白了就是一套「握手规则」——谁先说话、谁先回应、数据怎么传,都约定好了。
今天咱们聊聊AMBA总线协议家族里最常用的两个成员:AHB和AXI。嗯,这两个你肯定会在项目中碰到。
4.1 为什么需要总线协议?
你想想看,一个芯片里可能有CPU、内存、外设、DMA控制器……这么多模块要互相通信。如果每个模块都自己搞一套通信方式,那设计就乱套了。总线协议就是给这些模块定了个「交通规则」。
AMBA(Advanced Microcontroller Bus Architecture)是ARM公司推出的总线标准。目前主流的就是AHB和AXI。我个人习惯把AHB看作「中速公路」,AXI则是「高速铁路」。
核心要点:总线协议定义了主设备(Master)和从设备(Slave)之间的通信方式。主设备发起请求,从设备响应请求。
4.2 AHB协议简介
AHB(Advanced High-performance Bus)是AMBA 2.0时代的主力。我在一个MCU项目里用过它,当时要挂接SRAM和Flash控制器,AHB完全够用。
4.2.1 AHB的主要特点
- 单周期地址/数据相位:地址阶段和数据阶段是分开的,但可以流水
- 支持突发传输:一次地址请求,后面连续传数据
- 最多16个主设备:通过仲裁器决定谁占用总线
- 三态总线:地址和数据共用一组总线
4.2.2 AHB的基本信号
| 信号名 | 方向 | 说明 |
|---|---|---|
| HCLK | 全局 | 总线时钟,所有操作同步于此 |
| HRESETn | 全局 | 复位信号,低有效 |
| HADDR[31:0] | Master→Slave | 地址总线 |
| HWDATA[31:0] | Master→Slave | 写数据总线 |
| HRDATA[31:0] | Slave→Master | 读数据总线 |
| HWRITE | Master→Slave | 写使能,1为写,0为读 |
| HSEL | Decoder→Slave | 从设备选择信号 |
| HREADY | Slave→Master | 传输完成信号,高有效 |
| HRESP[1:0] | Slave→Master | 传输响应:OKAY、ERROR、RETRY、SPLIT |
我的经验:调试AHB时,我最先看的就是HREADY信号。如果它一直拉低,说明从设备在「拖死」总线。我曾经遇到一个Flash控制器,读操作需要等待周期,结果HREADY没处理好,整个系统卡死。排查了整整一天……
4.2.3 AHB读写操作流程
AHB的读写操作分两个阶段:地址阶段和数据阶段。地址阶段只占一个时钟周期,数据阶段可能多个周期(如果从设备需要等待)。
单次读操作:
时钟周期: T1 T2 T3 T4
HCLK: ▁▁▂▂▁▁▂▂▁▁▂▂▁▁▂▂
HADDR: ── Addr ──────────
HWRITE: ── 0 ────────────
HRDATA: ────────── Data ──
HREADY: ── 1 ── 0 1 ──
你看,T1周期主设备发出地址,T2周期从设备拉低HREADY表示需要等待,T3周期数据才准备好。这就是典型的「等待周期」。
突发写操作:
时钟周期: T1 T2 T3 T4 T5
HCLK: ▁▁▂▂▁▁▂▂▁▁▂▂▁▁▂▂▁▁▂▂
HADDR: ── A1 ── A2 ── A3 ────
HWDATA: ────── D1 ── D2 ── D3
HWRITE: ── 1 ────────────────
HREADY: ── 1 ── 1 ── 1 ──
突发传输时,地址和数据可以流水。地址A1发出后,下一个周期就可以发地址A2,同时数据D1也出现在总线上。效率比单次传输高不少。
注意:AHB的突发长度是固定的,不能中途终止。我见过有人想用AHB做不定长传输,结果发现协议不支持,只能改用AXI。所以设计初期就要想清楚需求。
4.3 AXI协议简介
AXI(Advanced eXtensible Interface)是AMBA 3.0引入的,后来在AMBA 4.0和5.0中不断演进。说白了,AXI就是AHB的「升级版」——更快、更灵活、更适合高性能系统。
我记得第一次用AXI是在一个视频处理芯片上,数据吞吐量要求很高。AHB根本跑不动,换成AXI后问题就解决了。
4.3.1 AXI的主要特点
- 五个独立通道:读地址、读数据、写地址、写数据、写响应
- 全双工通信:读和写可以同时进行
- 乱序传输:支持Out-of-Order完成
- 支持非对齐传输:地址不需要对齐到数据宽度
- 突发长度可变:1到256次传输
4.3.2 AXI的通道结构
| 通道 | 信号组 | 方向 | 说明 |
|---|---|---|---|
| 读地址 | ARADDR, ARVALID, ARREADY | Master→Slave | 发起读请求 |
| 读数据 | RDATA, RRESP, RVALID, RREADY | Slave→Master | 返回读数据 |
| 写地址 | AWADDR, AWVALID, AWREADY | Master→Slave | 发起写请求 |
| 写数据 | WDATA, WSTRB, WVALID, WREADY | Master→Slave | 发送写数据 |
| 写响应 | BRESP, BVALID, BREADY | Slave→Master | 返回写完成状态 |
关键区别:AHB只有一套地址/数据总线,读写不能同时进行。AXI有五个独立通道,读和写可以「并行跑」。你想想看,这性能差距有多大。
4.3.3 AXI的握手机制
AXI每个通道都用VALID/READY握手。主设备拉高VALID表示数据有效,从设备拉高READY表示可以接收。两者都拉高时,传输发生。
这里有个小细节:VALID不能依赖READY。也就是说,主设备拉高VALID后,必须保持直到握手成功。但READY可以随时拉高拉低。嗯,这个设计是为了防止死锁。
// AXI握手示例(Verilog风格)
always @(posedge clk) begin
if (rst) begin
arvalid <= 1'b0;
araddr <= 32'b0;
end else begin
// 当ARREADY为高且ARVALID为高时,地址被接收
if (arvalid & arready) begin
arvalid <= 1'b0; // 传输完成,撤销请求
end else if (need_read) begin
arvalid <= 1'b1;
araddr <= read_addr;
end
end
end
避坑指南:我曾经在AXI接口上犯过一个低级错误——把VALID和READY的依赖关系搞反了。结果仿真时一切正常,上板后偶尔死机。后来发现是VALID在等待READY时才拉高,违反了协议规范。记住:VALID必须「主动拉高」,不能等READY。
4.3.4 AXI读写操作流程
读操作流程:
- 主设备在AR通道发出地址和突发信息
- 从设备接收后,开始准备数据
- 从设备在R通道返回数据,可以分多个周期
- 最后一个数据包带上RLAST信号
写操作流程:
- 主设备在AW通道发出地址
- 主设备在W通道发送数据,可以分多个周期
- 从设备接收完所有数据后,在B通道返回写响应
- 写响应表示数据已经写入,不是「准备写入」
你发现没有?AXI的读写流程是「解耦」的。地址和数据可以分开传输,甚至数据可以先于地址到达(只要从设备支持)。这种灵活性在高性能系统中非常有用。
4.4 AHB vs AXI:怎么选?
| 对比项 | AHB | AXI |
|---|---|---|
| 最大频率 | 中等(通常≤200MHz) | 高(可达1GHz+) |
| 并发能力 | 半双工 | 全双工 |
| 乱序支持 | 不支持 | 支持 |
| 接口复杂度 | 简单(约20个信号) | 复杂(约50个信号) |
| 典型应用 | MCU、低功耗设计 | 应用处理器、高速外设 |
我的建议:如果你的系统时钟低于100MHz,外设不多,用AHB就够了。如果要做高性能计算、视频处理、或者需要DMA频繁搬运数据,果断上AXI。别为了省事选AHB,后面性能不够再改架构,那代价就大了。
4.5 小结
总线协议这东西,光看文档是学不会的。我建议你找个开源的AHB或AXI接口代码,自己仿真跑一遍。看看波形,理解每个信号的变化。嗯,等你真正调通一次,就什么都明白了。
下一章咱们聊聊总线互联结构——怎么把多个主设备和从设备连起来,以及仲裁器、译码器这些「交通警察」是怎么工作的。