在 NXP i.MX 95 上运行 Zephyr 实现非对称多核处理
概要
尽管大多数嵌入式软件应用针对单一微处理器或微控制器开发,但在某些特定场景下需要采用分布式架构。以汽车行业为例,不同子系统可能作为独立应用程序部署在分离的处理器上,例如负责发动机控制系统的嵌入式软件与防抱死制动系统应用就分别运行在不同的微控制器上。
医疗器械行业是嵌入式软件分布于多个微处理器的另一典型案例。例如,用户界面由一个微处理器实现,而负责患者交互的控制系统则位于另一个微控制器上。
可以看出,职责是根据功能划分的,而处理器则根据职责进行选择。例如,用户界面通常在基于 Linux 的系统上实现,这类系统专为类似 ARM Cortex-A 内核的处理器设计;而关键的嵌入式软件应用则采用实时操作系统(RTOS),这种系统最适合类似 ARM Cortex-R 或 Cortex-M 内核的处理器。
然而,若采用多处理器架构,处理器间的通信便至关重要。例如汽车行业就通过 CAN 总线实现这一功能。在医疗设备领域,各处理器可采用 UART、SPI 或 I2C 等通信协议进行交互,如下图所示:
然而,多个处理器分布在不同的芯片上会增加底层硬件、软件和固件的复杂性。这进而可能导致额外的开发和调试工作,从而影响产品的时间线和成本。
为了应对这种额外的复杂性,我们可以将多个处理器集成到同一块芯片上,如下图所示:
在上图中,ARM Cortex-A 和 ARM Cortex-M 内核被集成在同一块芯片上,称为系统级芯片(SoC)。SoC 将 CPU 内核与其他必要的控制器相结合,形成一个功能全面且强大的处理器。如图中显示,嵌入式软件的功能安全(FuSa)部分通过 Zephyr Project 实时操作系统在 ARM Cortex-M 内核上实现,而图形用户界面(GUI)则在 ARM Cortex-A 内核的 Linux 系统中运行。
该设计大幅缩短了硬件开发与调试时间。无需再管理多个独立处理器及电气和机械硬件互联,问题简化为围绕单个处理器的硬件设计。挑战也就主要转移到固件和软件层面,因为每个内核的嵌入式软件需要与其他内核的嵌入式软件建立通信机制。
在这篇博客文章中,我们将学习如何从运行于 ARM Cortex-A 核心的 Linux 内核加载运行于 ARM Cortex-M 核心上的固件。我们将以 Toradex Verdin iMX95 模块为例演示具体实现方法。
OpenAMP项目
Open Asymmetric Multi-Processing(OpenAMP)项目的设立旨在实现同一片上系统内不同核心之间的高效通信。该项目基于德州仪器早期将 Remoteproc 和 RPMsg 纳入 Linux 内核的工作成果发展而来:Remoteproc 使 Linux 内核能够管理远端处理器(remote processor)上的嵌入式软件生命周期,而 RPMsg 则实现了 Linux 内核与远端处理器固件间的通信。OpenAMP 项目将德州仪器的专有实现方法扩展为适用于各类系统的通用框架,标准化了 Linux 内核与基于实时操作系统(RTOS)的嵌入式应用间通信协议,并为希望利用其功能特性(如 RPMsg)的 RTOS 及裸机嵌入式应用提供了参考实现方案。
如前所述,Remoteproc 和 RPMsg 是 OpenAMP 项目的两大核心功能,它们使我们能够管理运行在同一 SoC 不同内核上的嵌入式软件。Remoteproc 负责将固件加载到远程处理器上,并启动和停止远程处理器的执行。在 Linux 系统中,Remoteproc 通常用于管理运行在 Cortex-M 等类似内核上的嵌入式软件生命周期。而 RPMsg 则负责支持运行在 Cortex-M 内核的嵌入式软件与运行 Cortex-A 内核的 Linux 系统之间的消息交换。
Toradex Verdin iMX95
Toradex Verdin iMX95 是一款基于 NXP iMX95 SoC 的高性能模块(SoM)。如下图所示,iMX95 SoC 包含三种不同类型的 ARM 核心架构:
ARM Cortex-A55 运行 Linux 操作系统,ARM Cortex-M7 负责执行实时固件,而 ARM Cortex-M33 则管理 Cortex-A55 和 Cortex-M7 的运行。
Zephyr Project RTOS
尽管“实时操作系统”是 Zephyr 项目 RTOS 的官方名称,但 “Zephyr” 远不止是一个 RTOS。它是一个完整的生态系统。虽然它确实包含了 RTOS 的典型功能和数据结构,如任务、信号量、互斥锁和消息队列,但它还拥有负责嵌入式系统其他重要功能的软件栈。例如,它包括:
用于控制和操作厂商特定硬件的驱动程序实现完整通信协议栈的软件,例如蓝牙低功耗(BLE)和WiFi实现整个子系统的模块,例如文件系统和引导加载程序
Zephyr 还支持来自众多厂商的 750 多款开发板,包括 Toradex Verdin iMX95。如果我们下载 Zephyr 代码库,可以看到在 boards/nxp/imx95_evk 目录下提供了对 iMX95 EVK 的支持,如下图所示:
Zephyr 借鉴了 Linux 内核的 Kconfig 和 Devicetree 功能,我们可以在上图中看到这一点。上图所示的 iMX95 EVK “device driver” 包含:
“board.c”, 负责初始板卡启动的C源代码“imx95_evk_mimx9596_m7.dts”, 用于告知 Zephyr 该板卡上存在哪些外设的 Devicetree 文件“Kconfig.imx95_evk”, 需要启用支持该板卡关键功能的 Kconfig 的选项集合
例如,如果我们打开“Kconfig.imx95_evk”文件(如下图所示),可以看到它启用了 iMX95 SoC 的 Kconfig 选项。该 Kconfg 选项随后会启用 SoC 所需的其他功能:
例如,Verdin iMX95的“device driver”位于 soc/nxp/imx/imx9/imx95 目录下,如下图所示:
同样的,“soc.c” 是负责初始 SoC 启动的 C 源代码,通过分析设备树中的相应节点,我们可以发现该 SoC 的 Kconfig 文件定义了 Flash 大小。
整合所有步骤
让我们演示如何为 iMX95 编译 Zephyr 应用程序,并从同一开发板上运行的 Cortex-A 内核加载 Zephyr 应用程序到 Cortex-M 内核。首先,我们可以按照 Zephyr入门指南(https://docs.zephyrproject.org/latest/develop/getting_started/index.html)中的步骤确保环境配置正确。
然后执行以下命令使用 West 工具获取 Zephyr 源代码:
$> west init -m https://github.com/mabembedded/zephyr.git $> west update
之后,我们可以执行以下命令为 Verdin iMX95 编译一个简单的“Hello World”应用程序:
$> west build -p -b imx95_evk/mimx9596/m7 samples/hello_world
然后,我们可以通过执行以下命令(确保将下方列出的 IP 地址替换为我们开发板的实际地址),将编译好的 ELF 格式二进制文件传输至运行在 iMX95 Cortex-A 内核上的 Linux 系统:
$> scp build/zephyr/zephyr.elf root@10.10.2.22:~/
随后,如果我们登录到 iMX95 设备,可以运行以下命令来指示 Linux 将 Zephyr ELF 二进制文件加载至 Verdin iMX95 的 Cortex-M7 核心上:
root@imx95-19x19-verdin:~# cd /sys/devices/platform/imx95-cm7/remoteproc/remoteproc1/ root@imx95-19x19-verdin:~# echo ~/zephyr.elf > firmware
最后,我们可以在 iMX95 Linux 控制台中输入以下命令来启动 Cortex-M7 核心:
root@imx95-19x19-verdin:~# echo start > state
我们可以在 iMX95 的 Cortex-M7 控制台上看到以下内容:
上述示例展示了 Linux 内核中 OpenAMP 项目的 Remoteproc 功能。
我们还可以通过如下所示的 openamp_rsc_table 示例应用程序,了解 Zephyr 中的 RPMsg 功能:
如上图所示,“imx95_evk_mimx9596_m7.conf” 包含了该应用启用的 Kconfig 选项。下图可见,此文件已启用相关的 OpenAmp 和 Mbox Kconfig 配置项:
该目录还包含一个 Devicetree “overlay”,用于为此特定应用定制开发板的 Devicetree。如下图所示,此覆盖层定义了 RPMsg 应用所需的功能,并引用了特定的硬件组件:
这些特性包括:
各个核心间用于交换数据的共享内存Linux内核通过资源表来识别远程处理器及固件支持的功能双核通信使用的邮箱机制
接下来演示如何编译并运行 RPMsg Zephyr 应用程序。首先执行以下命令进行编译:
$> west build -p -b imx95_evk/mimx9596/m7 samples/subsys/ipc/openamp_rsc_table
随后,我们可以按照之前概述的步骤将生成的 ELF 二进制文件从 Cortex-A55 上的 Linux 系统传输并加载到 Cortex-M7 中。在从 Linux 端启动 Cortex-M7 后,我们将在 Cortex-M7 的控制台上看到以下内容,这展示了从 Linux 端接收到的消息:
同样,如果观察 Cortex-A55 端的 Linux 内核日志,我们也能看到它通过 RPMsg 接收到了来自 Cortex-M7 上 Zephyr 应用程序的消息,如下所示:
总结
在本篇博客中,我们了解了利用 OpenAMP 项目特性简化嵌入式系统硬件设计的优势。探讨了 Toradex Verdin iMX95 开发板如何通过 SoC 上不同的 ARM 内核实现创新应用场景。实践演示了使用 Zephyr 实时操作系统快速构建 "Hello World" 示例程序,并从运行于 Cortex-A55 的 Linux 系统加载至 Verdin iMX95 的Cortex-M7 核心的全过程。最后,我们还完成了基于 RPMsg 协议的 Zephyr 应用程序编译、从 Linux 环境加载以及验证 Zephyr 与 Linux 之间消息交互的实验。

提交
HDMI 显示器热插拔对应显示应用启停测试
Yocto meta-toradex-security layer 创建加密数据分区应用说明
NXP iMX8MP ARM 平台多屏幕克隆显示测试
Yocto meta-toradex-security layer 创建独立数据分区
NXP iMX8MP ARM 平台 EMQX 部署测试