双核 MCU 的协作架构:RP2040 的 SIO、中断与事件信号全解析

处理器子系统

RP2040 处理器子系统由两个 Arm Cortex-M0+ 处理器组成------每个处理器都有其标准的内部 Arm CPU 外设以及用于 GPIO 访问和核心间通信的外部外设。

图 2.11 RP2040 处理器子系统架构框图

上图是 RP2040 双核处理器的 "工作连接框架"------ 它明确了两个 Cortex-M0 + 核心(Core0、Core1)与芯片其他模块、外部设备的通信方式,是双核协同工作的基础支撑结构,核心通信接口的作用如下:

  • ​独立 AHB-Lite 总线接口:​每个核心都有专属的 32 位 AHB-Lite 总线,这是它们访问内存、外设的 "专属主干道"------ 比如 Core0 读取 SRAM 程序、Core1 配置 UART 外设,都是通过各自的总线连到总线互联结构(Bus Fabric)。独立总线的设计,避免了双核访问资源时的 "抢路拥堵",保证了代码、数据的高效读写。

  • SIO 块与 IOPORT:高速 GPIO 访问 + 双核协作 SIO 是专门服务于双核的 "高速接口块",每个核心通过 IOPORT 连接到 SIO:

    • 一方面,它提供对 GPIO 的 "高速、无延迟访问"------ 相比通过总线访问 GPIO,这种方式响应更快、时序更稳定(比如快速控制 LED 闪烁时,能保证精准的节奏);
    • 另一方面,SIO 也负责双核之间的 "Events(事件)通信",让 Core0 和 Core1 能互相发送信号(比如 Core0 完成数据采集后,发事件通知 Core1 进行处理),实现双核协作。
  • 中断系统:突发任务的分工响应外设(如传感器触发、串口收数据)会产生中断信号,这些信号会被路由到两个核心的 NVIC(中断控制器)------RP2040 的 26 个系统级中断可以分配给任意一个核心处理,比如把 "串口收数据" 的中断分给 Core0,"传感器触发" 的中断分给 Core1,让双核能分工响应突发任务,提升系统的实时性。

  • SWD 调试总线:外部调试的统一入口外部调试器通过 "multi-drop(多节点)" 的串行线调试总线,同时连接两个核心的 DAP 模块 ------ 这意味着可以从外部调试主机同时访问、调试 Core0 和 Core1,比如程序运行出错时,能同时查看两个核心的运行状态,精准定位双核协作中的问题。

    接下来,我们对这些关键部分进行一一介绍。

1.Single-cycle IO block (SIO)

SIO 是 RP2040 双核处理器的'高速协作工具箱'------ ​它借助 Cortex-M0 + 的 IOPORT 辅助总线,实现'单周期(极快)'的操作​,专门解决'双核之间快速传数据''抢共享资源''高速控制 GPIO'这些对速度、定时要求高的任务,是双核高效协作的核心支撑模块。

SIO 的本质是基于 IOPORT 辅助总线的 "快速通道模块" :IOPORT 是 Cortex-M0 + 的专用快速总线端口,对应 0xd0000000 开头的地址段,用普通读写指令就能访问,且 SIO 不连接主系统总线,只走这个快速通道 ------ 这保证了 SIO 的读写操作都能在 1 个周期内完成,速度快、定时精准。

SIO 的具体结构如下所示:

图 2.12 RP2040 Single-cycle IO(SIO)模块架构框图

SIO 是利用 Cortex-M0 的辅助总线 IOPORT 进行 32B 访问的,目的就是为了节约访问时间,做一些高速计算任务,也可以用于两个核心之间的通信。

IOPORT 是 Cortex-M0+ 上的一个辅助总线端口,它可以执行快速的 32 位读取和写操作。

处理器使用正常负载和存储指令访问他们的 IOPORT,指向特殊的 IOPORT 地址段 0xd0000000...0xdfffffff。SIO 显示为 IOPORT 空间中的内存映射硬件。

SIO 为每个处理器的 IOPORT 都有一个专用的总线接口。由于其严格的定时要求,SIO 没有连接到主系统总线。它只能由处理器或调试器通过处理器调试端口进行访问。

SIO 的读写操作均为 1 个周期完成,包括以下几个单元:

  • ​双核心 FIFO:​ 用于在两个核心之间传递数据、消息或有序事件
    • 其中一个 fifo 只能由核心 0 编写,并由核心 1 读取
    • 另一个只能由核心 1 编写,并由核心 0 读取
  • ​CPUID:​用于识别目前工作核心,寄存器 CPUID 是 IOPORT 空间中的第一个寄存器。当访问此地址时,核心 0 读取值为 0,而核心 1 读取值为 1。软件确定它在哪个核心上运行是在初始引导过程中检查的:两个核心同时开始运行,核心 1 进入深度睡眠状态,核心 0 继续执行主引导序列。
  • ​硬件 Mutex 锁:​ 可用于管理对共享软件资源的互斥访问,软件通过以下操作之一与每个自旋锁进行交互
    • 读取:即获取锁
    • 写入:释放锁
  • 硬件除法以及内插器
  • IO 共享访问控制

2.中断

中断是 RP2040 处理'突发任务'的核心机制 ------ 比如定时器到点、串口收到数据、传感器触发信号时,不能等核心'忙完手头的活'再处理,这时候中断会'打断'核心当前的操作,优先处理紧急任务。而 NVIC(嵌套向量中断控制器)是每个核心的'中断调度员',负责管理中断的优先级和执行顺序,下面结合表和规则讲清楚它的逻辑:

每个核心(Core0 和 Core1)都有独立的 NVIC(相当于专属的 "中断调度员"),它能接收 32 个中断信号,但 RP2040 只用到了前 26 个(IRQ0~25),剩下的 IRQ26~31 是预留的(也能强制触发)。当外设(如定时器、UART)触发紧急任务时,会向对应的 IRQ 发送信号,NVIC 再调度核心处理。

在 RP2040 上,只有较低的 26 个 IRQ 信号被连接在 NVIC 上,而 IRQs 26 到 31 没有绑定。通过在 NVIC ISPR 寄存器中写入位 26 到 31,核心仍然可以被强制输入相关的中断处理程序。

RP2040 的中断向量表如下,这个表是 "IRQ 的任务清单",每个 IRQ 编号对应一个具体的 "紧急任务来源":

图 2.13 RP2040 中断源与 IRQ 映射表

比如 IRQ0 对应 "定时器 0 的 IRQ"(定时器 0 到点了)、IRQ20 对应 "UART0 的 IRQ"(UART0 收到数据了)。核心看到 IRQ 编号,就能立刻知道是哪个外设发的 "紧急呼叫",进而调用对应的处理程序。

当多个 IRQ 同时触发时,核心会按 "紧急程度" 依次处理,优先级分两层判断:

  • NVIC 动态优先级 :通过寄存器可以给每个 IRQ 设 4 个优先级(0~3),数字越小紧急程度越高(比如 0 级是最高优先级,会优先于 1 级处理);
  • IRQ 编号优先级 :如果两个 IRQ 的 NVIC 优先级相同,就看 IRQ 编号 ------编号越小紧急程度越高(比如 IRQ0 的优先级高于 IRQ1)。

在硬件中支持嵌套中断:一个低优先级的中断可以被一个高优先级的中断(或另一个异常,如硬故障)抢占,一旦高优先级的异常完成,低优先级的中断将恢复。这种 "插队" 机制,能保证最紧急的任务始终被优先响应。

3.事件信号

先明确核心概念:

  • 事件信号​:是一种轻量级的 "唤醒 / 通知信号",和中断的区别在于:中断是 "打断核心当前的工作" 去处理紧急任务,而事件主要是 "唤醒处于睡眠状态的核心",或 "给另一个核心发通知",不会主动打断核心的运行。

  • WFE 指令​:全称 Wait For Event(等待事件),核心执行这个指令后会进入睡眠状态,暂停工作,直到有事件或中断到来时才被唤醒。

  • SEV 指令​:全称 Send Event(发送事件),核心执行这个指令可以主动生成一个事件信号,用来通知或唤醒其他核心。

    在 RP2040 中,事件信号是​双核协作与低功耗休眠的关键机制​,逻辑如下:

  • 双核间的事件互通:

    • RP2040 的两个核心(Core0、Core1)之间的事件信号是 "交叉连接" 的 ------ 比如 Core0 执行 SEV 指令发送事件,这个事件会被 Core1 接收到;反之 Core1 发的事件也能被 Core0 接收。
    • 这种设计的作用是 "双核间的轻量通知":比如 Core0 完成数据采集后,发一个事件唤醒处于睡眠状态的 Core1,让它继续处理数据,既避免了核心空等浪费算力,又比用中断通知更轻量化。
  • 低功耗休眠的实现:

    • 当核心执行 WFE(或 WFI,等待中断)指令进入睡眠状态后,核心的内部时钟门会关闭,不再消耗额外电量;如果两个核心都进入睡眠状态,且 DMA 也处于非活动状态,整个 RP2040 会进入 "全局休眠",同时关闭未使用模块的时钟,进一步降低功耗。
    • 而唤醒的触发条件很灵活:无论是另一个核心发的事件,还是外设触发的中断,都能让核心(或整个芯片)从休眠中唤醒,恢复工作 ------ 这在需要低功耗的场景(比如电池供电的设备)中非常实用。

4.调试

在了解调试结构之前,先明确几个核心概念:

  • SWD(串行线调试​:是一种仅用 2 根线(SWCLK 时钟线、SWDIO 数据线)的调试接口,是外部调试器(比如电脑端的调试工具)与芯片内部模块通信的 "通道",用来实现程序下载、调试等操作。

  • DAP(调试访问端口​:是芯片内部的 "调试入口",每个核心(Core0、Core1)对应一个 DAP(DAP_0、DAP_1),外部调试器通过 DAP 可以访问核心的运行状态、控制核心执行。

  • SWD 多节点仲裁器​:相当于调试通信的 "交通调度员"------ 外部调试器只有 1 个 SWD 接口,却要连 2 个核心的 DAP 和备用救援端口,仲裁器负责分配通信资源,避免多个调试入口抢信号。

  • Rescue DP(救援调试端口 ​:是调试的 "安全出口"------ 当正常 DAP 调试失效(比如核心卡死)时,可通过这个备用端口恢复调试功能。

    图 2.15 RP2040 SWD 串行线调试架构框图

    这个图是 RP2040 的​调试通信架构​,它实现了 "外部调试器对双核的统一控制 + 调试可靠性保障",核心逻辑如下:

  • ​SWD 接口的基础通信:​外部调试器通过 SWCLK/SWDIO 两根线连接到芯片的 IO 模块,再接入 SWD 多节点仲裁器 ------ 这是调试器与芯片内部的唯一通信通道,建议最高用 24MHz 频率,保证通信稳定。

  • ​调试资源的调度(仲裁器的作用):​因为芯片内部有 2 个核心的 DAP(DAP_0 对应 Core0、DAP_1 对应 Core1)和 1 个 Rescue DP,而调试器只有 1 个 SWD 接口,仲裁器会根据调试需求,把通信分配给对应的端口:

    • 要调试 Core0,分配给 DAP_0;
    • 要调试 Core1,分配给 DAP_1;
    • 正常调试失效时,分配给 Rescue DP。这样能避免多个调试入口抢信号,保证通信有序。
  • SWD 调试的核心功能通过这个架构,外部调试器可以完成:

    • 向芯片的 SRAM 或外部闪存加载程序(固件);
    • 查看 / 修改核心的运行状态(比如寄存器值);
    • 控制核心执行:让核心运行、停止、单步执行代码,还能设置断点(让核心执行到指定代码处暂停)。
  • Rescue DP 的 "救援" 保障 当正常 DAP 调试因为核心卡死、配置错误等原因无法使用时,Rescue DP 可以作为备用入口,通过 pam_restart 信号恢复调试功能 ------ 这是防止芯片因调试故障 "变砖" 的安全机制。