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-AP 挂载在 AHB 总线上 特性 • 支持 32/64 位地址空间 • 地址自动递增模式灵活 • 支持非对齐访问 • 适用于 SoC 内部调试 • 访问速度较快 • 配置相对简单 特性 • 遵循 AHB 协议规范 • 支持 AHB 突发传输 • 地址递增模式固定 • 适用于 AHB 总线调试 • 访问速度取决于 AHB 时钟 • 配置与 AHB 协议绑定 实际项目中,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 寄存器,看看它支持哪些传输大小和地址递增模式。这样能避免很多不必要的调试。