3、调试访问端口(DAP)配置
调试访问端口,简称 DAP。它是 ARM 调试架构里连接调试器和芯片内部的总线接口。说白了,它就是一把钥匙,帮你打开芯片内部世界的大门。
我刚开始接触 ARM 调试时,总觉得 DAP 就是个寄存器集合,没什么好研究的。直到有一次,我在一个量产项目中遇到了芯片死活连不上调试器的问题。折腾了两天,最后发现是 DP 的 IDCODE 寄存器读回来的值不对——芯片根本没进入正确的调试模式。嗯,从那以后,我再也不敢小看 DAP 的配置了。
核心要点:DAP 由两部分组成——DP(Debug Port)和 AP(Access Port)。DP 负责物理连接,AP 负责总线访问。两者配合,才能完成调试。
3.1 DP(Debug Port)寄存器详解
DP 是调试端口,它直接和调试器打交道。ARMv8 架构里,DP 通过 SWD(Serial Wire Debug)或 JTAG 接口与外部通信。我个人习惯用 SWD,因为它只需要两根线,布线简单。
DP 的寄存器不多,但每个都很关键。我整理了一张表,方便你对照查阅:
| 寄存器名称 | 地址偏移 | 访问类型 | 功能描述 |
|---|---|---|---|
| IDCODE | 0x00 | 只读 | 芯片标识码,用于识别厂商和型号 |
| CTRL/STAT | 0x04 | 读写 | 控制 DP 状态,启动调试会话 |
| SELECT | 0x08 | 读写 | 选择当前使用的 AP 和寄存器组 |
| RDBUFF | 0x0C | 只读 | 读取缓冲区,用于连续读取数据 |
| WCR | 0x04(扩展) | 读写 | 线缆配置寄存器,调整时序参数 |
这里我要重点说一下 CTRL/STAT 寄存器。它的第 0 位是 CDBGPWRUPREQ,用来请求调试电源。你想想看,如果芯片处于低功耗模式,调试器必须先唤醒它。我曾经遇到过一个问题:芯片进入深度睡眠后,调试器怎么都连不上。后来发现是 CTRL/STAT 寄存器里的电源请求位没置对。
我的经验:初始化 DP 时,建议先读 IDCODE 确认芯片型号,再写 CTRL/STAT 请求电源。顺序搞反了,可能会卡在电源请求阶段。
3.2 AP(Access Port)寄存器详解
AP 是访问端口,它负责把 DP 收到的请求转换成总线操作。ARMv8 里最常见的 AP 是 MEM-AP,它直接挂载在系统总线上。
AP 的寄存器结构比 DP 复杂一些。每个 AP 都有自己的寄存器组,通过 DP 的 SELECT 寄存器来切换。我列一下 MEM-AP 的核心寄存器:
- CSW(Control/Status Word):控制传输大小、地址递增模式、保护位等。地址偏移 0x00。
- TAR(Transfer Address Register):存放要访问的目标地址。地址偏移 0x04。
- DRW(Data Read/Write):数据读写寄存器。地址偏移 0x0C。
- BD0~BD3(Banked Data Registers):分块数据寄存器,用于高效传输。地址偏移 0x10~0x1C。
- CFG(Configuration Register):配置寄存器,描述 AP 的能力。地址偏移 0xF4。
- BASE(Base Address Register):调试组件的基地址。地址偏移 0xF8。
这里有个容易踩坑的地方:TAR 寄存器。它支持地址自动递增模式,但递增的步长由 CSW 里的 AddrInc 字段控制。如果你设置成 32 位递增,但实际访问的是 8 位数据,那地址就会跳错。我有个同事就因为这个,读内存数据时总是少读几个字节,排查了半天。
注意:AP 的寄存器访问必须通过 DP 的 SELECT 寄存器来选通。SELECT 寄存器的 APSEL 字段选择 AP,APBANKSEL 字段选择 AP 内部的寄存器组。忘记设置 SELECT,读回来的数据全是 0。
3.3 MEM-AP 与 AHB-AP 的区别
这个问题,很多初学者都会问。其实,MEM-AP 和 AHB-AP 都是访问端口的实现,但它们的应用场景不同。
我画了一张对比图,帮你理清思路:
说白了,MEM-AP 是一个抽象层,它不关心底层总线是什么。你配置好地址和传输大小,它就能帮你读写数据。而 AHB-AP 是 MEM-AP 的一个具体实现,它专门针对 AHB 总线做了优化。
我举个例子。在一个 Cortex-A72 的调试项目中,我用了 MEM-AP 来访问 DDR 内存。MEM-AP 的地址自动递增功能让我能连续读取一大块数据,效率很高。但如果我要调试 AHB 总线上的外设,比如 GPIO 或 UART,用 AHB-AP 会更直接,因为它能利用 AHB 的突发传输特性。
选择建议:
- 如果你要访问系统内存(DDR、SRAM),用 MEM-AP。
- 如果你要调试 AHB 总线上的外设,用 AHB-AP。
- 如果芯片只实现了 MEM-AP,那它也能访问 AHB 总线,只是效率稍低。
最后,我分享一个避坑指南。我曾经在一个项目中,用 MEM-AP 去读一个 AHB 外设的寄存器。读回来的数据总是错的。后来发现,那个外设要求 16 位对齐访问,而 MEM-AP 默认是 32 位访问。解决办法是修改 CSW 寄存器的 Size 字段,把传输大小改成 16 位。
小技巧:配置 MEM-AP 时,先读 CFG 寄存器,看看它支持哪些传输大小和地址递增模式。这样能避免很多不必要的调试。