2、常见总线协议(一):AMBA AHB总线协议详解、信号定义与传输时序

各位同学,今天我们来聊聊AMBA AHB总线。说实话,AHB是我在项目里打交道最多的总线之一。记得我刚入行那会儿,第一次接触AHB时被那一堆信号搞得晕头转向。后来做多了才发现,AHB的设计其实非常优雅——它把复杂的总线操作抽象成了几个核心阶段,理解了这个,你就抓住了它的精髓。

2.1 AHB总线概述

AHB,全称Advanced High-performance Bus,是ARM公司AMBA总线家族里的高性能选手。它主要用来连接高性能模块,比如CPU、DMA控制器、外部存储器接口这些。

我个人习惯把AHB想象成一个高速公路系统:

  • 主机(Master):就像路上的车,发起传输请求
  • 从机(Slave):就像目的地,响应传输请求
  • 仲裁器(Arbiter):就像交通警察,决定谁先走
  • 译码器(Decoder):就像导航,告诉你去哪个出口

为什么要搞这么复杂?你想想看,一个SoC里可能有十几个模块同时想访问内存,没有一套规则的话,那不乱套了?

核心特点:

  • 高性能:支持突发传输,一次地址可以传多笔数据
  • 流水线操作:地址阶段和数据阶段可以重叠
  • 多主机:支持多个总线主机,通过仲裁决定谁占用总线
  • 非三态实现:所有信号都是点到点连接,方便综合

2.2 信号定义详解

AHB的信号说多不多,说少不少。我建议你先把核心信号记住,其他的用到再查。下面这张表是我自己整理的,项目里经常用到。

信号名 方向 位宽 描述
HCLK 输入 1 总线时钟,所有信号都在HCLK上升沿采样
HRESETn 输入 1 复位信号,低电平有效
HADDR[31:0] 主机→从机 32 地址总线
HTRANS[1:0] 主机→从机 2 传输类型:00=IDLE, 01=BUSY, 10=NONSEQ, 11=SEQ
HWRITE 主机→从机 1 读写指示:1=写,0=读
HSIZE[2:0] 主机→从机 3 传输大小:000=8bit, 001=16bit, 010=32bit...
HBURST[2:0] 主机→从机 3 突发类型:000=单次, 001=INCR, 010=WRAP4...
HWDATA[31:0] 主机→从机 32 写数据总线
HRDATA[31:0] 从机→主机 32 读数据总线
HREADY 从机→主机 1 传输完成指示:1=完成,0=需要等待
HRESP[1:0] 从机→主机 2 传输响应:00=OKAY, 01=ERROR, 10=RETRY, 11=SPLIT
HSELx 译码器→从机 1 从机选择信号

我的小技巧:刚开始记不住信号?你就记住三组:地址相关(HADDR、HSIZE、HBURST)、数据相关(HWDATA、HRDATA)、控制相关(HTRANS、HWRITE、HREADY、HRESP)。分组记忆会轻松很多。

2.3 传输时序详解

AHB的传输分为两个阶段:地址阶段和数据阶段。地址阶段只占一个时钟周期,数据阶段可能需要多个周期(如果从机插入等待的话)。

嗯,这里要注意:地址阶段和数据阶段是流水线重叠的。也就是说,当前传输的数据阶段,和下一笔传输的地址阶段,发生在同一个时钟周期里。这样做的好处很明显——总线利用率更高。

2.3.1 基本读传输

先看一个最简单的单次读操作:

// 时序描述(伪代码)
// Cycle 1: 主机驱动地址和控制信号
HADDR   = 0x1000
HWRITE  = 0          // 读操作
HTRANS  = NONSEQ     // 新的一笔传输
HSIZE   = 010        // 32位传输

// Cycle 2: 从机返回数据
HRDATA  = 0xA5A5A5A5
HREADY  = 1          // 一次完成,无需等待

我在项目中遇到过一个问题:从机响应太慢,HREADY一直拉低,结果主机卡在那里动不了。后来查了协议才发现,从机最多只能插入16个等待周期,否则主机可能会超时。这个坑大家要注意。

2.3.2 基本写传输

写操作和读操作类似,但数据方向相反:

// Cycle 1: 地址阶段
HADDR   = 0x2000
HWRITE  = 1          // 写操作
HWDATA  = 0x12345678 // 写数据在地址阶段就准备好

// Cycle 2: 数据阶段
HREADY  = 1          // 写完成

曾经踩过的坑:写操作时,HWDATA必须在地址阶段的下一个时钟沿就准备好。有些新手会把HWDATA延迟一拍,结果数据对不上。记住:地址阶段之后紧跟着的就是数据阶段,没有缓冲时间。

2.3.3 突发传输

突发传输是AHB的亮点。一次地址,多笔数据,效率高很多。常见的突发类型有:

  • INCR4/INCR8/INCR16:递增突发,地址连续递增
  • WRAP4/WRAP8/WRAP16:回环突发,地址在边界处回绕
  • INCR:未指定长度的递增突发

举个例子,4拍的递增突发:

// 地址阶段(Cycle 1)
HADDR   = 0x1000
HBURST  = 011        // INCR4
HTRANS  = NONSEQ     // 第一拍

// 数据阶段 + 地址阶段重叠
// Cycle 2: 传第一笔数据,同时发第二笔地址
HRDATA  = D0
HADDR   = 0x1004     // 地址自动递增
HTRANS  = SEQ        // 后续传输

// Cycle 3: 传第二笔数据,同时发第三笔地址
HRDATA  = D1
HADDR   = 0x1008
HTRANS  = SEQ

// Cycle 4: 传第三笔数据,同时发第四笔地址
HRDATA  = D2
HADDR   = 0x100C
HTRANS  = SEQ

// Cycle 5: 传第四笔数据
HRDATA  = D3

你想想看,如果不用突发,4笔数据需要4个地址阶段+4个数据阶段=8个周期。用了突发,只需要1个地址阶段+4个数据阶段=5个周期。效率提升了将近一倍。

2.4 传输类型详解

HTRANS[1:0]这个信号很多人搞不清楚,我重点说一下:

HTRANS 类型 说明
00 IDLE 主机不占用总线,从机忽略地址和数据
01 BUSY 主机在突发传输中间插入空闲周期,地址保持
10 NONSEQ 新的一笔传输,地址与上一笔无关
11 SEQ 突发传输的后续拍,地址自动递增

重点提醒:BUSY状态只在突发传输中间使用。我曾经见过一个设计,在单次传输里插了BUSY,结果从机直接报错。协议里写得很清楚:BUSY只能出现在SEQ之后,而且地址必须保持不变。

2.5 响应信号HRESP

从机通过HRESP告诉主机传输结果。常见的响应有:

  • OKAY:传输成功,这是最常见的
  • ERROR:传输失败,比如访问了不存在的地址
  • RETRY:从机忙,请重试(不改变传输顺序)
  • SPLIT:从机忙,请重试(可以改变传输顺序)

我个人建议:除非你有特殊需求,否则尽量只用OKAY和ERROR。RETRY和SPLIT的实现比较复杂,容易引入死锁。我在一个项目里就吃过RETRY的亏——主机重试了三次都失败,最后超时复位了。

2.6 知识体系总览

下面这张图是我用SVG画的,把AHB的核心知识点串了起来。你可以把它当作复习提纲:

AMBA AHB 总线知识体系 总线架构 信号定义 传输时序 响应机制 主机(Master) / 从机(Slave) 仲裁器(Arbiter) 译码器(Decoder) 地址信号: HADDR, HSIZE 数据信号: HWDATA, HRDATA 控制信号: HWRITE, HTRANS 地址阶段 + 数据阶段 流水线重叠 突发传输: INCR / WRAP OKAY / ERROR RETRY / SPLIT HREADY 握手 核心要点总结 • 流水线操作:地址与数据阶段重叠,提高总线利用率 • 突发传输:一次地址多次数据,适合连续内存访问 • 从机控制:通过HREADY插入等待,通过HRESP报告状态

2.7 实战经验总结

最后,分享几个我在项目中积累的经验:

  1. 地址对齐很重要:32位传输时,地址必须4字节对齐。我曾经见过一个bug,HSIZE=010(32位)但HADDR=0x1001,结果从机返回的数据全是乱的。
  2. HREADY信号要小心处理:从机拉低HREADY时,所有信号必须保持稳定。我见过一个设计,HREADY拉低后地址还在变,结果数据全对不上。
  3. 突发长度别超限:INCR16最多16拍,WRAP4最多4拍。超限的话,从机可能直接报ERROR。
  4. 复位后先发IDLE:主机复位后,第一笔传输必须是IDLE,不能直接发NONSEQ。这是协议规定的,不遵守的话仲裁器可能不给你总线权限。

我的建议:如果你刚开始学AHB,先别急着看所有细节。把单次读写和INCR4突发搞明白,其他的都是变种。等你做了一两个IP集成项目后,自然就熟练了。

好了,AHB的内容就讲到这里。下一章我们会讲APB总线,那个比AHB简单多了,但应用场景完全不同。到时候再聊。


可可精品资料库