3、硬件平台选型:多核处理器(Cortex-A+Cortex-M)、内存分区与共享、中断控制器(GIC)配置
好,咱们进入第三章。这一章聊的是硬件选型,说白了就是「你打算拿什么芯片来跑这套混合系统」。我个人习惯是,先定硬件再写软件,因为硬件决定了你的天花板在哪里。
RTOS 和 Linux 要共存,最直接的办法就是找一颗「大小核」芯片——大核跑 Linux,小核跑 RTOS。Cortex-A 系列负责复杂逻辑、网络协议、文件系统;Cortex-M 系列负责实时控制、传感器采集、中断响应。嗯,这里要注意,不是随便拿两颗核就能拼在一起用的。
3.1 多核处理器选型:Cortex-A + Cortex-M 的搭配逻辑
我在项目中遇到过不少团队,上来就选了个四核 A53 的芯片,结果发现 RTOS 那侧的中断延迟根本压不下去。为什么?因为 A 核天生为高性能设计,Cache 大、流水线深,中断响应路径长。而 M 核呢?它就是为了实时而生的,中断延迟可以做到几十个时钟周期。
所以我的建议是:
- 主控核(Linux 侧):Cortex-A7、A53、A55 都行。功耗低,生态好。我个人偏爱 A55,性价比高。
- 实时核(RTOS 侧):Cortex-M4、M7、M33。M7 性能强,M33 带 TrustZone,适合安全场景。
- 通信核(可选):有些芯片会带一个 M0 专门做核间通信,省心。
你想想看,如果让 A 核去处理一个 10kHz 的 PWM 中断,那 Linux 的调度延迟会让你崩溃。而 M 核处理这个,就像喝水一样简单。
关键点:A 核跑 Linux 做「大脑」,M 核跑 RTOS 做「手脚」。两者分工明确,别让 A 核干实时活。
3.2 内存分区与共享:怎么分才不打架?
内存问题,是混合部署里最容易踩坑的地方。我记得第一次做这个方案时,Linux 和 RTOS 共用了一段内存,结果 Linux 那边一个 DMA 操作直接把 RTOS 的任务栈给覆盖了……嗯,从那以后我再也不敢乱分内存了。
我的做法是这样的:
- 物理隔离:在芯片的 Memory Map 里,把内存分成两块区域。Linux 独占一块,RTOS 独占一块。互不干扰。
- 共享区域:划出一小块(比如 64KB 或 256KB)作为共享内存,专门用来做核间通信。
- Cache 一致性:这是个大坑。A 核有 Cache,M 核没有(或者有但很小)。如果共享内存被 A 核写入了,但数据还在 Cache 里没刷出去,M 核读到的就是脏数据。
避坑指南:我曾经在共享内存上吃过亏。后来强制在共享内存区域关闭 A 核的 Cache,或者每次读写后手动 flush。虽然性能有点损失,但数据安全第一。
下面是一个典型的内存分区表,你可以参考:
| 区域 | 起始地址 | 大小 | 用途 | 谁在用 |
|---|---|---|---|---|
| Linux 内存 | 0x8000_0000 | 512MB | Linux 内核、用户态程序 | Cortex-A |
| RTOS 内存 | 0xA000_0000 | 64MB | RTOS 内核、任务栈、中断向量表 | Cortex-M |
| 共享内存 | 0xA400_0000 | 64KB | 核间通信、消息队列、状态标志 | 双核共享 |
| 保留区域 | 0xA401_0000 | 剩余 | 调试、日志、异常处理 | 双核共享 |
说白了,内存分区就是「分家过日子」。Linux 和 RTOS 各住各的,只在客厅(共享内存)里碰头。这样谁也不会打扰谁。
3.3 中断控制器(GIC)配置:别让中断跑错核
GIC(Generic Interrupt Controller)是 ARM 体系里管理中断的核心部件。在混合部署场景下,GIC 的配置直接决定了你的实时性能。
我见过有人把所有的中断都配给了 A 核,结果 M 核那边闲得发慌,A 核却被中断淹没了。这其实是个设计失误。
我的配置原则是:
- 实时中断(比如电机控制、传感器触发)→ 分配给 M 核。M 核响应快,没有 Linux 调度干扰。
- 复杂中断(比如网络包到达、USB 热插拔)→ 分配给 A 核。这些中断需要 Linux 的协议栈来处理。
- 核间中断(IPI)→ 用于两个核之间的同步。比如 M 核发一个 IPI 告诉 A 核「数据准备好了」。
GIC 的配置代码,我一般放在 Bootloader 里做。下面是一个简化的配置示例:
// 伪代码:GIC 中断路由配置
// 将 IRQ 42(电机编码器中断)路由到 Cortex-M 核
GICD_SetTarget(42, TARGET_M_CORE);
// 将 IRQ 55(以太网中断)路由到 Cortex-A 核
GICD_SetTarget(55, TARGET_A_CORE);
// 配置核间中断(IPI)
GICD_SetTarget(IPI_IRQ, TARGET_BOTH_CORES);
警告:GIC 的寄存器操作是全局的。A 核和 M 核都能访问 GIC 的配置寄存器。如果不加锁,两个核同时修改中断路由,会导致系统崩溃。我建议只在启动阶段由 Bootloader 统一配置,运行期间不要动。
另外,GIC 的优先级分组也要注意。A 核那边 Linux 可能会把中断优先级调来调去,但 M 核这边需要固定的优先级。我的做法是:M 核的中断优先级全部设为最高,确保实时任务不会被 Linux 侧的中断抢占。
嗯,这里还有一个细节:GIC 的亲和性(Affinity)。你可以把某个中断绑定到特定的 CPU 核上。比如让所有 M 核的中断只发给 M 核,别让 A 核收到。这样能减少不必要的核间切换。
3.4 小结:选型就是做取舍
硬件平台选型,说白了就是一场权衡。你要性能,就得接受功耗;你要实时,就得接受 Linux 那边少用点核。我个人经验是:
- 先确定你的实时任务有多「实时」——是微秒级还是毫秒级?
- 再确定你的 Linux 任务有多「重」——是跑 GUI 还是跑数据库?
- 最后根据这两个需求,选一颗合适的 A+M 芯片。
别贪心。一颗芯片解决所有问题,那是理想。现实中,我们都是在有限资源下做最优解。
下一章,我们会聊聊核间通信的具体实现——怎么让 Linux 和 RTOS 高效地「对话」。到时候我会分享一个我踩过的坑,关于共享内存的死锁问题……嗯,那是个有趣的故事。