APB 外设子系统集成:GPIO/UART/I2C/Timer 的地址映射、中断汇集与复位时钟接入
更新时间:2026-09-25。本篇是「集成电路大类 · 芯片设计 · 片上总线」序列的集成实战篇。协议本身建议先读 APB 总线时序与从机设计,桥怎么把 APB 挂到骨干见 AHB/APB 与桥接,寄存器表的入门概念见 寄存器表与地址解码。本篇不再重复两拍时序,只回答一个集成问题:把 GPIO、UART、I2C、Timer 这几块成熟 IP 真正拼成一个可被软件驱动的外设子系统,地址、中断、时钟、复位四条线分别怎么接,接完按什么清单验收。
本文要回答的问题
- 四个外设挂到同一条 APB 上,地址窗口怎么切,译码器放在哪、输出什么?
- 每个外设的寄存器块(register block)在 4KB 窗口里怎么摆,未分配地址访问会怎样?
- 各 IP 的中断输出怎么一路汇集到 PLIC/INTC,电平型和脉冲型中断在汇集时有什么差别?
- PCLK 从哪里来、PRESETn 怎么生成,跨时钟域的中断和 I2C 异步脚如何安全接入?
- 子系统集成完成后,有哪些必须逐项打勾的检查点?
一、子系统全景:四个外设 + 一座桥 + 一个中断控制器
先给出整体拓扑。一个典型的 APB 外设子系统由五部分构成:上游的 AXI/AHB-to-APB 桥(唯一的 APB 主机)、地址译码器、四个挂在 PCLK 域的外设 IP、中断汇集通路(PLIC 或简易 INTC),以及提供时钟与复位的 CGU/复位控制器。软件看到的是一片连续的内存映射地址,硬件上则是「桥广播地址、译码器点选一个从机」的结构。
读图抓三个要点。其一,译码器在逻辑上属于桥的一部分:多数桥 IP 内部就带一段可配置的地址译码区,外接时只需给每个从机配基址和窗口大小;也有把译码器独立做成 decoder IP 的做法,信号等价。其二,所有外设共用同一组 PADDR/PWDATA/PWRITE/PCLK,只有 PSELx 是每从机一根的点选线,读数据 PRDATA 则由各从机经 MUX 汇回桥。其三,中断方向与数据通路相反:外设把中断线汇到 PLIC,PLIC 仲裁后只向 CPU 输出一根(或一组)中断线加中断号,详见第三节。
四个外设的选择不是随意的。GPIO、UART、I2C、Timer 恰好覆盖了外设的四种典型形态:纯寄存器型(GPIO,读写引脚电平)、带时钟域的流式型(UART,片内波特时钟 + FIFO)、异步开漏型(I2C,外部时钟可由主机驱动)、自由计数型(Timer,计数器持续跑)。把这四类接通,其他 SPI、PWM、看门狗等都是同构复制。
二、地址映射:4KB 窗口、高位译码与 default slave
APB 外设子系统的地址规划遵循一条行业惯例:每个外设分配一个 4KB 对齐的窗口,哪怕它的寄存器只有十几个。4KB 不是浪费,而是给软件页表(典型页大小 4KB)、译码器简化(只译高位)和未来寄存器扩展留余量。假设桥的 APB 段基址为 0x4000_0000,四个外设的映射如下:
| 窗口 | 地址区间 | PSEL | 实际使用 |
|---|---|---|---|
| GPIO | 0x4000_0000 – 0x4000_0FFF | psel_gpio | 低地址 16B |
| UART | 0x4000_1000 – 0x4000_1FFF | psel_uart | 低地址 32B |
| I2C | 0x4000_2000 – 0x4000_2FFF | psel_i2c | 低地址 24B |
| Timer | 0x4000_3000 – 0x4000_3FFF | psel_timer | 低地址 32B |
| default slave | 其余 APB 段地址 | 无 | 回 PSLVERR |
译码逻辑本身简单到可以用一句话描述:PADDR[31:12](页号)与四个基址比较,命中则把对应的 PSELx 拉高,全部未命中则选 default slave。窗口内的低位地址 PADDR[11:0] 原样送给外设,由外设内部的寄存器译码处理。因为窗口固定 4KB,桥不需要任何可变掩码逻辑,综合后就是若干比较器,时序极好。
default slave 不是可选项。若一笔访问落在没有任何外设响应的空洞地址上,总线上没有任何从机驱动 PRDATA 和 PREADY,桥会永久停在 Access 相位等 PREADY——这就是 SoC 上常见的「写到保留地址系统死机」。default slave 的职责是被 PSEL 选中时在完成拍返回 PSLVERR=1、PRDATA 回 0,让软件收到异常而不是挂死。同理,窗口内寄存器未使用的地址也建议由外设自身译码为错误响应或读回 0,二选一但要在寄存器手册里写明。
地址规划阶段还要定下三条容易事后扯皮的细节:窗口是否允许 64KB 大窗口(某些 DMA/EMAC 需要,可单独配置);APB5 系统里 PPROT 的安全态如何划分——TrustZone 方案通常把 secure 和 non-secure 各开一段别名窗口,译码时同时看 PADDR 和 PPROT;字节使能 PSTRB 要原样送进外设,不允许在桥里按 32 位整字截断,否则 8 位寄存器会被相邻字节的写误伤。
三、寄存器块布局:偏移、位域与访问属性
进入一个窗口后,外设内部就是一块寄存器块。四个外设的寄存器写法高度一致,以 UART 为例给出典型布局(32 位对齐,偏移十六进制):
| 偏移 | 寄存器 | 主要位域 | 访问 |
|---|---|---|---|
| 0x00 | DATA | 收发数据字节、FIFO 空满标志 | RW/RC |
| 0x04 | CTRL | 使能、校验位、停止位 | RW |
| 0x08 | BAUDDIV | 波特率分频值 | RW |
| 0x0C | STATUS | TX 空、RX 满、帧错误 | RO/RC |
| 0x10 | IER | 各中断源使能位 | RW |
| 0x14 | IPR | 原始中断状态(未屏蔽) | RO |
集成时寄存器侧有四个必须统一的口径。第一,中断状态寄存器用「写 1 清零」(write-1-to-clear)而不是写 0 清零,避免读改写操作把新到的中断标志误清;清零语义要在 UVM 寄存器模型里对应 W1C 访问策略。第二,保留位(reserved bits)读出必须为 0、写入必须忽略,不能让保留位连到任何功能逻辑,这是后续做寄存器兼容扩展的前提。第三,复位值要逐寄存器在数据手册里列明,外设内部计数器、移位寄存器等不可见状态也要在 RTL 里保证被 PRESETn 清到确定态。第四,跨时钟取数的寄存器(如 UART 读 FIFO 计数、I2C 读外部状态)要在内部做同步,必要时拉低 PREADY 等待,软件侧表现为一次稍慢的 APB 读,功能不能出错。
GPIO 的寄存器块另含方向寄存器 DIR 和引脚复用选择,复用设计见 GPIO 引脚复用与 alt function;Timer 含重载值、当前计数和捕获/PWM 配置,见 Timer 输入捕获与 PWM。寄存器抽象层的 UVM 适配可对照 UVM 寄存器适配器。
四、中断汇集:从四根中断线到 PLIC 的一根线
每个外设内部都有若干中断源(UART 的 TX 空、RX 满、校验错;Timer 的计数到;I2C 的传输完成;GPIO 的引脚边沿),集成的标准做法是两级屏蔽:外设内部用 IER 寄存器做第一级使能,把未屏蔽的中断状态相或后输出一根电平中断线;PLIC 做第二级,负责优先级、中断号分配和软件 claim/complete。
PLIC 的 gateway 对每个中断号维护一个「待决」锁存:电平型中断在源有效时置位,软件完成处理、外设状态位被清零后自动撤销;RISC-V PLIC 的完整 gateway 与 claim/complete 机制见 RISC-V PLIC gateway 与 claim。用 PLIC 时,外设输出统一做成高电平有效,不要输出脉冲——PLIC gateway 能可靠锁存电平,窄脉冲却可能在两次采样之间漏掉。
不用 PLIC 的极简系统用一个 INTC 寄存器块代替:一组中断状态位 + 一组使能位,输出相或后直连 CPU 的一根中断线,软件进 ISR 后读状态寄存器查号。这种「线或 + 状态寄存器」结构与 PLIC 的区别要清楚:INTC 没有硬件优先级和自动 claim,中断风暴时软件要自己防重入。更灵活的汇集(唤醒、合并、路由到不同核)见 事件路由器与中断聚合器,中断合并降频见 中断合并 interrupt coalescing。
汇集接线有三条硬规则。其一,中断线必须在 PCLK 域生成:I2C 的开漏脚、GPIO 外部输入是异步信号,先双触发器同步、再参与中断逻辑,否则亚稳态会制造幻影中断;同步与消抖见 GPIO 同步与消抖。其二,外设中断线在 PRESETn 期间必须为低,不能复位一拉就误触发。其三,唤醒场景(CPU 睡眠、PCLK 可停)要确认中断源接到了始终上电的唤醒域,否则中断自己随时钟一起停掉,系统永远醒不来。
五、时钟与复位接入:同源、同步释放、域隔离
时钟侧,四个外设的 APB 寄存器接口全部由同一个 PCLK 驱动,PCLK 来自 CGU 的分频输出,常等于或慢于骨干时钟。外设内部的功能时钟分三种处理:UART 的波特率时钟在 IP 内由 PCLK 再分频,不引入新时钟根;I2C 需要可被外部主机驱动的 SCL 采样逻辑,属异步输入,按 CDC 处理而非接自由时钟;Timer 直接用 PCLK 计数,若需要低功耗节拍可切到 RTC 时钟,切换点要在 IP 内做安全处理。CGU 的配置与时钟拓扑见 SoC 时钟控制器 CGU。
复位侧,桥和四个外设共用 PRESETn,低有效、异步断言、同步释放。复位树的典型接法如下:
PRESETn 释放必须在 PCLK 沿上同步并送到所有外设,保证各 IP 在同一拍离开复位,否则一个外设已开始发请求、另一个还在复位态,总线和中断线上会出现协议外的组合。复位同步器的标准结构见 复位同步器:异步断言同步释放,复位设计总则见 复位设计,系统级复位源(POR/WDT/软复位)的组织见 系统复位控制器。
两条域隔离红线集成时必查。第一,若子系统内存在独立时钟域(低功耗 UART、RTC Timer),跨域信号必须走握手或同步器,复位释放顺序要可验证,这属于 RDC 检查范围,见 RDC 复位域穿越。第二,调试复位(JTAG 系统复位)和软复位不能误清正在被 APB 访问的外设:软复位通常只复位功能逻辑、保持 APB 接口可访问,便于软件重新初始化,具体复位范围要在复位矩阵表里逐 IP 标注。
六、子系统集成检查清单
把前五个节的要点收成一份可直接照做的验收清单,分四组,全部打勾才算集成完成。
| 组别 | 检查项 |
|---|---|
| 地址 | 四窗口均 4KB 对齐、不重叠;PSEL 为 one-hot;空洞地址有 default slave 回 PSLVERR;窗口内保留偏移读 0/报错;PSTRB 与 PPROT 透传 |
| 寄存器 | 偏移与手册一致;状态位 W1C;保留位读 0 写忽略;每个寄存器有确定复位值;跨时钟读值已同步 |
| 中断 | 外设统一电平高有效;异步输入先双触发同步;PRESETn 期间中断为低;PLIC 中断号与 dts/头文件编号一致;唤醒源在常驻域 |
| 时钟复位 | 所有 APB 接口同源 PCLK;PRESETn 异步断言同步释放;复位释放各 IP 同拍;CDC/RDC 有同步与约束;软复位范围已标注 |
最后三项验证环境建议:用 SVA 绑定 PSEL one-hot、「PSEL 与 PREADY 完成沿唯一」等总线性质;做一张「地址 → PSEL → 寄存器 → 中断号」的全映射表,用定向用例逐行覆盖;子系统级 UVM 环境里把四个外设的功能 VIP 挂到真实引脚上(I2C 用开漏模型、UART 回环、GPIO 注入边沿),跑「配置—触发—中断—claim—清状态」的完整软件式序列。任何一项只靠波形肉眼放行,回片后都会以软件工单的形式还回来。
这一篇在知识体系里的位置
协议细节回 APB 总线时序与从机设计;桥的内部结构见 AHB/APB 与桥接;中断深入读 RISC-V PLIC gateway 与 claim 与 事件路由器与中断聚合器;外设本身见 GPIO 同步与消抖、UART 波特率与 FIFO、I2C 主控与开漏、Timer 输入捕获与 PWM;时钟复位底座见 SoC 时钟控制器 CGU 和 系统复位控制器。
总结
APB 外设子系统的集成就是接好四条线:地址线上桥内译码器按 4KB 对齐窗口把 PADDR 高位译成一根 PSELx、空洞由 default slave 回 PSLVERR;中断线上各外设经内部 IER 输出统一的高电平线、异步脚先同步,再汇到 PLIC 按中断号仲裁 claim;时钟线全子系统同源 PCLK、功能时钟在 IP 内分频或按 CDC 处理;复位线共用异步断言同步释放的 PRESETn 并保证各 IP 同拍退出复位——最后按地址、寄存器、中断、时钟复位四组清单逐项打勾,用全映射表和「配置到中断清除」完整序列完成子系统验收。