3. RPMsg开发环境搭建:硬件选型与软件栈部署

搭建RPMsg开发环境,说白了就是两件事:选对板子,配好软件栈。我这些年经手过TI OMAP、NXP i.MX、Xilinx Zynq三个主流平台,每个平台的坑都不太一样。今天咱们就把环境搭建的每一步拆开揉碎,讲清楚。

3.1 硬件平台选型与对比

选硬件平台,核心看三点:核间通信硬件机制、Linux对 remoteproc 的支持成熟度、OpenAMP 官方适配情况。下面这张表是我自己整理的对比,帮你快速决策。

平台 主控架构 核间通信硬件 Linux remoteproc OpenAMP 适配 我的推荐场景
TI OMAP (如 AM5728) 双核 A15 + 双核 M4 Mailbox + 共享内存 主线支持完善 官方参考实现 入门学习、原型验证
NXP i.MX (如 i.MX8M) A53 + M4/M7 MU (Messaging Unit) + TCM/SRAM BSP 支持,主线稍滞后 NXP 维护分支 工业产品、量产项目
Xilinx Zynq (如 Zynq-7000) A9 + FPGA 软核 IPI (Inter-Processor Interrupt) + OCM 主线支持,需配置 Xilinx 定制版 FPGA 加速 + 核间通信
我的建议: 如果你是第一次接触RPMsg,优先选TI OMAP AM5728 EVM。为什么?因为它的文档最全,社区例子最多,遇到问题容易搜到答案。我当年带团队做第一个RPMsg项目,就是拿AM5728起步的,省了不少弯路。

3.2 软件环境全景图

在动手之前,先搞清楚整个软件栈长什么样。我画了一张结构图,帮你建立全局视角。

RPMsg 开发环境软件栈全景 Linux 侧 (A核) Linux Kernel (remoteproc + rpmsg) OpenAMP Linux 用户态库 应用层 (echo_test / 自定义) RTOS 侧 (M核) FreeRTOS / NuttX / 裸机 OpenAMP RTOS 端库 RPMsg 固件 (资源表 + 通信) 硬件层 共享内存 (DDR/TCM/OCM) + 核间中断 (Mailbox/MU/IPI) RPMsg 通道 构建工具链 Yocto / Buildroot / CMake + 交叉编译器 关键:Linux 端和 RTOS 端的资源表必须完全对齐! 共享内存基地址、大小、vring 数量、名称必须一致

3.3 Linux 内核配置步骤

内核配置是环境搭建中最容易出问题的一环。我见过太多人编译出来的内核没有开启 remoteproc 和 rpmsg,结果板子死活跑不起来。下面是我验证过的配置清单。

3.3.1 必须开启的内核选项

Device Drivers  --->
  [*] Remoteproc drivers  --->
    <*>   TI OMAP remoteproc support
    <*>   NXP i.MX remoteproc support
    <*>   Xilinx Zynq remoteproc support
  [*] Rpmsg drivers  --->
    <*>   Rpmsg virtio transport driver
    <*>   Rpmsg character device interface
    <*>   Rpmsg raw endpoint driver
    [*]   Rpmsg namespace support
我曾经踩过的坑: 有一次给 i.MX8M 编译内核,忘了开 RPMSG_CHAR,结果用户态程序调用 open("/dev/rpmsg0") 一直返回 -1。查了两天才发现是内核配置漏了。所以我的习惯是:每次改完配置,先 grep 一下 .config 文件,确认关键选项是 y 或 m。

3.3.2 设备树配置要点

设备树里要描述清楚三件事:共享内存区域、核间中断、remoteproc 实例。以 i.MX8M 为例:

&imx8mp_m4 {
  memory-region = <&vdev0buffer>, <&vdev0vring0>, <&vdev0vring1>;
  mbox-names = "tx", "rx";
  mboxes = <&mu 0 1>, <&mu 1 1>;
  status = "okay";
};

reserved-memory {
  vdev0buffer: vdev0buffer@94200000 {
    compatible = "shared-dma-pool";
    reg = <0x0 0x94200000 0x0 0x100000>;
    no-map;
  };
  vdev0vring0: vdev0vring0@94300000 {
    reg = <0x0 0x94300000 0x0 0x8000>;
    no-map;
  };
  vdev0vring1: vdev0vring1@94308000 {
    reg = <0x0 0x94308000 0x0 0x8000>;
    no-map;
  };
};
注意: 共享内存的地址范围必须和 RTOS 端固件里的资源表完全一致。我习惯把地址定义写在一个头文件里,Linux 设备树和 RTOS 端都引用同一个头文件,从源头避免不一致。

3.4 OpenAMP 库的获取与编译

OpenAMP 库分两套:一套跑在 Linux 用户态,一套跑在 RTOS 端。两套代码都在同一个仓库里,但编译方式完全不同。

3.4.1 获取源码

git clone https://github.com/OpenAMP/open-amp.git
cd open-amp
git checkout v2022.10  # 我推荐用这个稳定版本

3.4.2 Linux 端编译

Linux 端用 CMake 交叉编译。假设你的交叉编译器是 aarch64-linux-gnu-gcc:

mkdir build && cd build
cmake .. \
  -DCMAKE_TOOLCHAIN_FILE=../cmake/arm-gcc.cmake \
  -DCMAKE_INSTALL_PREFIX=/usr/local/openamp \
  -DWITH_APPS=ON \
  -DWITH_PROXY=ON
make -j4
sudo make install

3.4.3 RTOS 端编译

RTOS 端通常用厂商提供的 SDK 编译。以 NXP i.MX8M 的 FreeRTOS 为例:

# 设置 SDK 环境
source /opt/fsl-imx-wayland/5.10-hardknott/environment-setup-aarch64-poky-linux

# 进入 OpenAMP 的 RTOS 示例目录
cd open-amp/apps/examples/echo_test

# 编译 M4 固件
make PLATFORM=imx8mp CROSS_COMPILE=arm-none-eabi-

关键点: RTOS 端编译出来的 .elf 文件,就是你要加载到 M4 核上运行的固件。Linux 端通过 remoteproc 框架把这个固件加载到 M4 核的 TCM 或 DDR 里,然后启动 M4 核。

3.5 常见编译与部署问题

环境搭建过程中,下面这几个问题我几乎每次培训都会遇到。我把它们列出来,你遇到了直接对照排查。

问题现象 根因 解决方案
insmod remoteproc.ko 报错 -ENODEV 设备树中 remoteproc 节点 status 为 disabled 检查设备树,确保 status = "okay"
加载 M4 固件时卡在 "Waiting for remote processor..." 共享内存地址在 Linux 和 RTOS 端不一致 对比两端的 resource_table 定义,确保地址完全一致
open("/dev/rpmsg0") 返回 -1 内核未开启 RPMSG_CHAR 或 rpmsg_raw 驱动 检查 .config,确认 CONFIG_RPMSG_CHAR=y
echo_test 收发数据超时 vring 数量或大小不匹配 检查两端 VRING_NUM 和 VRING_SIZE 定义
M4 固件加载后立即崩溃 固件链接地址与加载地址不一致 检查 M4 固件的链接脚本,确保 .text 段放在正确的 TCM 或 DDR 地址
我曾经遇到最隐蔽的一个问题: 在 Zynq 平台上,Linux 端和 RTOS 端用的共享内存基地址明明一样,但就是通信失败。后来发现是 Linux 端的页表映射把共享内存区域映射成了不可缓存的,而 RTOS 端默认用了缓存。两边缓存策略不一致,导致数据一致性问题。解决方案是在设备树里给共享内存区域加上 no-map 和 no-cache 属性。

3.6 快速验证:跑通第一个 echo_test

环境搭好之后,用 OpenAMP 自带的 echo_test 做快速验证。这是最直接的"hello world"。

3.6.1 启动 M4 固件

# 加载 remoteproc 驱动
modprobe remoteproc_ti

# 加载 M4 固件
echo -n "echo_test.elf" > /sys/class/remoteproc/remoteproc0/firmware
echo start > /sys/class/remoteproc/remoteproc0/state

3.6.2 运行 Linux 端 echo_test

# 运行用户态测试程序
./echo_test -p 1 -n 100

# 预期输出:
# Sending 100 messages of size 512 bytes
# Received 100 messages
# Average round-trip time: 45 us

如果看到这个输出,恭喜你,环境搭建成功了!

一个小技巧: 如果 echo_test 跑通了,但延迟数据异常大(比如几百微秒),先别急着调优。检查一下 Linux 内核的 CPU 调频策略,把它设成 performance 模式:echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor。我遇到过好几次,延迟大其实只是 CPU 降频了。

3.7 本章小结

环境搭建这一步,说白了就是三板斧:选对硬件、配好内核、对齐资源表。只要这三件事做对了,RPMsg 通信就能跑起来。后面章节我们会深入调试方法和性能优化,但前提是环境得先搭稳。嗯,动手试试吧,有问题随时翻回这一章对照排查。