PAYATHON 2026

RP2040 上的 SVC 中断为何不能通过跳转表控制 LED?

数据小许

结论

SVC 指令编码和跳转表索引的基本思路合理。需要重点检查 install_svc_isr:它从 VTOR 读取向量表地址后,直接把 svc_isr 地址写入 SVC 表项。如果向量表位于 Flash,就不能像写普通 RAM 那样修改表项,处理程序也无法按预期安装。应先确认 VTOR 指向的内存区域,再将向量表复制到符合对齐要求的可写 SRAM,把 VTOR 指向副本,然后修改副本中的 SVC 表项。

检查并安装 SVC 向量

SVC 是 Cortex-M 的异常号 11,对应的向量表偏移为 11 * 4 = 0x2C,与代码中的 SVC_ISR_OFFSET 一致。需要确认的是表项所在的内存是否可写。ldr r1, [r2] 能读出地址,并不能说明该地址指向 RAM。

安装前检查以下事项:

  1. 读取 VTOR,确认当前向量表基址及其映射区域。
  2. 将完整向量表复制到符合 VTOR 对齐要求的 SRAM 区域。
  3. 将 VTOR 更新为 SRAM 副本的地址,再将 svc_isr 写入偏移 0x2C 的表项。
  4. 确认写入的处理程序地址是有效的 Thumb 函数地址,且没有覆盖其他异常或中断向量。

如果工程运行环境或 SDK 已负责管理异常向量表,应使用其提供的安装方式,避免直接修改正在使用的表。

再检查异常处理流程

SVC 异常进入处理程序时,硬件会压入包含 r0-r3、r12、lr、pc 和 xPSR 的基本栈帧。代码随后执行 push {lr},因此从当前 sp 读取压入的 pc 时,偏移 0x1C 与这两部分栈空间相符。对于 16 位 Thumb svc 指令,代码从压入的返回 pc 减去 2,再读取一个字节来取得 SVC immediate。

跳转到表项后,可以用 bx r1 明确执行间接分支,并确认表中保存的是有效的 Thumb 函数地址:

ldr r1, [r1, r0]
bx r1

SVC_MAX_INSTRS 为 1,配合 bhi svc_done 会接受编号 0 和 1,与两项跳转表相匹配。编号无效时,处理程序会跳到 svc_done,恢复保存的异常返回值。

分步定位

先暂时绕过跳转表,在 svc_isr 入口设置断点,或切换一个已知可用的 GPIO,确认执行 svc #0 后能否进入处理程序。如果没有进入,先检查向量表安装和 VTOR。进入处理程序后,再确认读取到的 SVC immediate 是否分别为 0 和 1,以及表项读出的地址是否对应 svc_num0、svc_num1。最后单独验证 GPIO 初始化和 asm_gpio_put,排查 LED 引脚或板卡配置问题。

当前代码假设板载 LED 接在 GPIO 25。使用其他型号的板卡时,也应核对 LED 的实际连接方式和引脚。代码中的 svc #0、svc #1 及立即数提取方式,适用于这里使用的 16 位 Thumb SVC 指令。

备注:内容仅供参考。