2. 开发环境搭建:硬件平台与工具链
做嵌入式驱动开发,环境搭建是第一道坎。说实话,我见过不少新手在这上面卡了一两天,最后发现是工具链版本不对。这一章咱们就把这些基础工作捋清楚。
2.1 硬件平台选型
目前主流的异构多核平台,我接触最多的是 STM32MP157 和 i.MX8M 系列。这两款芯片在工业产品和消费电子里都很常见。
| 特性 | STM32MP157 | i.MX8M Mini |
|---|---|---|
| 架构 | 单核/双核 Cortex-A7 + Cortex-M4 | 四核 Cortex-A53 + Cortex-M4 |
| 主频 | A7: 650MHz / M4: 209MHz | A53: 1.6GHz / M4: 400MHz |
| 核间通信 | Mailbox + RPMsg | Mailbox + RPMsg |
| 开发板 | STM32MP157C-DK2 | i.MX8M Mini EVK |
| 成本 | 较低 | 中等 |
我个人习惯用 STM32MP157 做教学,因为它的文档更全,社区资源也多。但如果你手头是 i.MX8M,原理完全一样,只是设备树和寄存器地址不同。
2.2 获取 Linux 内核源码
内核源码是驱动开发的根基。你想想看,没有源码,你怎么知道 Mailbox 驱动怎么注册的?
获取方式有两种:
- 从官方仓库克隆:
git clone https://github.com/STMicroelectronics/linux.git(以 ST 为例) - 下载 LTS 版本:
wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.xx.tar.xz
我建议用厂商维护的分支。为什么?因为厂商已经帮你适配好了设备树和驱动补丁。我自己踩过坑——用主线内核跑 STM32MP157,结果 Mailbox 驱动死活不工作,后来发现是时钟配置没对齐。
关键路径:
- 内核源码:
linux/drivers/mailbox/—— Mailbox 框架 - 内核源码:
linux/drivers/rpmsg/—— RPMsg 框架 - 设备树:
linux/arch/arm/boot/dts/stm32mp157*.dts
2.3 交叉编译工具链配置
交叉编译,说白了就是在 PC 上编译出能在 ARM 上跑的程序。这个环节最容易出问题的是版本不匹配。
以 STM32MP157 为例,我常用的工具链是 arm-linux-gnueabihf-:
# 下载 Linaro 工具链
wget https://releases.linaro.org/components/toolchain/binaries/latest-7/arm-linux-gnueabihf/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz
# 解压到 /opt
sudo tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz -C /opt/
# 设置环境变量
export PATH=/opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin:$PATH
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
FATAL: kernel too old,折腾了一天才发现是 glibc 版本冲突。
验证工具链是否生效:
arm-linux-gnueabihf-gcc --version
# 输出类似:arm-linux-gnueabihf-gcc (Linaro GCC 7.5-2019.12) 7.5.0
2.4 设备树基础
设备树(Device Tree)是 Linux 内核用来描述硬件信息的机制。对于异构多核通信,设备树里要声明 Mailbox 控制器、通道以及 RPMsg 相关的节点。
嗯,这里要注意:设备树不是 C 代码,它是一种树形结构文本,后缀是 .dts。
一个典型的 Mailbox 节点长这样:
/* stm32mp157.dtsi 中的 Mailbox 控制器 */
m4_mailbox: mailbox@4c001000 {
compatible = "st,stm32mp1-mailbox";
reg = <0x4c001000 0x400>;
interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&rcc 0 0>;
#mbox-cells = <2>;
status = "disabled";
};
这里 #mbox-cells = <2> 表示每个通道需要两个参数:通道 ID 和方向。我在项目中遇到过一个问题——忘记在板级 dts 里 status = "okay",结果 Mailbox 驱动根本没加载。
RPMsg 相关的设备树节点通常放在 m4_system_resources 或 reserved-memory 里:
reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
ranges;
m4_rsc_table: rsc-table@10044000 {
reg = <0x10044000 0x1000>;
no-map;
};
m4_vdev0_buffer: vdev0-buffer@10045000 {
reg = <0x10045000 0x4000>;
no-map;
};
};
no-map 属性。结果内核把这块内存映射了两次,导致 RPMsg 通信时数据错乱。记住:核间共享内存一定要加 no-map,告诉内核不要自己管理这块区域。
2.5 整体环境结构
下面这张图展示了开发环境的核心组件和它们之间的关系:
2.6 验证环境是否就绪
环境搭好之后,我习惯跑一个简单的测试:编译一个空的 Mailbox 驱动模块,确保工具链和内核源码能配合工作。
# 进入内核源码目录
cd linux
# 配置内核(使用厂商默认配置)
make stm32mp1_defconfig
# 编译设备树
make dtbs
# 编译内核模块
make modules
# 如果以上三步都通过,环境就基本就绪了
快速检查清单:
- ✅ 交叉编译器能输出版本信息
- ✅ 内核源码目录下有
drivers/mailbox/和drivers/rpmsg/ - ✅ 设备树文件包含 Mailbox 节点
- ✅ 板子能通过串口打印内核启动日志