4. nRF54多核架构与Zephyr多核支持
nRF54H20 是 Nordic 首款面向高可靠、高实时场景的多核 SoC。它内部并不是“一个 Cortex-M33 加几个外设”的传统结构,而是由多个可独立运行固件的处理单元组成:应用核为 Arm Cortex-M33,配套的还有 RISC-V 协处理器(PPR、FLPR 等),以及负责安全与系统管理的 Secure Domain。理解这些核的定位、启动顺序和通信方式,是使用 Zephyr 开发 nRF54H20 的基础。
一、nRF54H20 的核布局与职责划分
从开发视角看,nRF54H20 中最常打交道的处理单元有三类:
- Application Core(Cortex-M33):主应用核,运行 Zephyr 主镜像,负责协议栈、业务逻辑、外设驱动与系统调度。它是开发者最常编写代码的目标核。
- PPR(Peripheral Processor RISC-V):外设协处理器,通常承担低层外设的实时处理、射频时序配合等任务,可由 Nordic 提供的固件或用户自定义固件驱动。
- FLPR(Fast Lightweight Processor RISC-V):轻量级 RISC-V 核,适合运行对时延敏感、逻辑简单但需要快速响应的任务,例如高速 GPIO 响应、传感器采样触发等。
这些核共享部分内存与外设资源,但各自有独立的指令空间和运行状态。它们之间不是主从轮询关系,而是通过 IPC、共享内存和中断协同工作。下图给出 nRF54H20 多核之间的资源与通信关系示意:
二、Zephyr 多核启动流程
在 nRF54H20 上,Zephyr 的启动并不是“一上电就跑 main”。上电后首先由 Secure Domain 执行安全启动流程,验证并加载各核固件。Application Core 的 Zephyr 镜像被加载后,从复位向量进入 Zephyr 的启动代码,依次完成:
- 早期架构初始化:设置栈、时钟、异常向量,完成 Cortex-M33 的 MPU/SAU 基础配置。
- SoC 与板级初始化:配置时钟树、电源域、引脚复用,并初始化 IPC、MBOX 等核间通信硬件。
- 驱动与子系统初始化:按 Zephyr 的 init 优先级依次初始化设备驱动、日志、内核对象。
- 启动从核:通过 IPC 或专用启动寄存器通知 PPR/FLPR 加载并运行各自固件,从核进入自己的 main 或任务循环。
- 进入主调度:Application Core 创建主线程与用户任务,内核开始调度。
需要特别注意的是,从核的固件通常独立编译、独立加载,Zephyr 主镜像只负责“启动它”和“与它通信”,并不把从核当作普通线程来调度。因此,多核任务管理的核心是划分职责与定义接口,而不是把所有逻辑塞进一个镜像。
三、核间通信(IPC)机制
nRF54H20 的核间通信主要依赖三类机制:
- 共享内存:多个核可访问同一块 SRAM 区域,用于传递数据缓冲区。需要约定好地址、长度、读写顺序和缓存一致性策略。
- IPC/MBOX 中断:一个核向另一个核发送事件通知,接收核在中断中处理消息。适合传递短消息、命令和完成通知。
- Zephyr IPC 服务:Zephyr 提供 IPC 服务框架,可在共享内存之上封装消息队列、信号量和回调,简化核间通信代码。
一个典型的通信流程是:Application Core 把命令写入共享内存缓冲区,然后通过 IPC 向 PPR 发送中断;PPR 在中断服务中读取命令、执行外设操作,完成后把结果写回共享内存,再通过 IPC 通知 Application Core。整个过程是异步的,双方通过消息 ID 和状态字段保证顺序与完整性。
四、在 Zephyr 中管理多核任务
在 Zephyr 中管理 nRF54H20 多核任务,通常遵循以下实践:
- 按实时性划分:硬实时、低时延任务放到 FLPR 或 PPR;复杂协议栈和业务逻辑留在 Cortex-M33。
- 接口先行:先定义核间消息格式(命令码、参数、返回码、缓冲区布局),再分别实现两端固件。
- 使用设备树描述:在 Zephyr 设备树中声明 IPC、MBOX、共享内存区域,使驱动和 IPC 服务能正确初始化。
- 同步与超时:核间调用应设置超时和错误返回,避免某一核异常导致另一核永久阻塞。
- 日志分离:各核日志通过独立通道输出,便于定位问题出在哪个核。
下面是一个简化的核间消息结构示例,用于 Application Core 向 PPR 发送“启动采样”命令:
/* 共享内存中的消息结构(示例) */
struct ipc_cmd {
uint16_t cmd_id; /* 0x01: 启动采样 */
uint16_t seq; /* 序号,用于匹配请求与响应 */
uint32_t param; /* 采样周期,单位 us */
uint32_t status; /* 0: 未处理, 1: 成功, 2: 失败 */
};
/* Application Core 侧发送 */
cmd->cmd_id = 0x01;
cmd->seq = ++g_seq;
cmd->param = 1000;
cmd->status = 0;
ipc_send(IPC_PPR, IPC_CMD_SAMPLE_START);
/* PPR 侧处理完成后回写 status 并通知 */
cmd->status = 1;
ipc_send(IPC_APP, IPC_CMD_SAMPLE_DONE);
这段代码的关键不在语法,而在于它体现了多核协作的基本约定:命令有编号、有参数、有状态、有完成通知。只要这个约定稳定,Application Core 和 RISC-V 协处理器就可以各自独立开发、独立测试,最后通过 IPC 联调。
总结来说,nRF54H20 的多核架构为 Zephyr 开发带来了更细的任务划分能力:Cortex-M33 负责系统与业务,RISC-V 协处理器负责实时与外设,Secure Domain 负责安全与启动。Zephyr 通过启动流程、设备树和 IPC 服务把这些核组织起来。掌握核间消息格式、共享内存约定和超时处理,是写出稳定多核应用的关键。