双核通信机制:Mailbox、共享内存与IPC中断
双核项目里,最让人头疼的往往不是单个核的代码怎么写,而是两个核怎么「说话」。我刚开始做STM32H7双核开发时,就踩过一个大坑——两个核各自跑得飞快,但数据交换时莫名其妙丢包。查了三天,最后发现是通信机制没选对。
说白了,双核通信就三种路子:Mailbox邮箱、共享内存区、IPC中断同步。咱们一个一个说清楚。
Mailbox邮箱通信
Mailbox,你可以把它想象成一个「信箱」。一个核往里塞消息,另一个核来取。硬件上,STM32的Mailbox有8个深度,每个能放一个32位数据。
我个人习惯把Mailbox用在控制类消息上,比如「启动ADC采集」、「进入低功耗模式」这种短指令。为什么?因为它简单、快、不需要考虑互斥。
- 一次传32位数据,适合命令/状态码
- 硬件自带队列,不会丢消息
- 发送方不用等接收方处理完
来看一段实际代码。这是CM7核发送消息给CM4核:
// CM7核发送
void Mailbox_SendToCM4(uint32_t msg) {
// 等待邮箱有空位
while(HSEM->RLR[0] != 0);
// 写入消息并释放
HSEM->R[0] = msg;
HSEM->RLR[0] = 1; // 释放信号量
}
CM4核这边接收:
// CM4核接收(中断方式)
void HSEM_IRQHandler(void) {
uint32_t msg;
if(HSEM->MISR & (1 << 0)) {
msg = HSEM->R[0];
ProcessMessage(msg);
HSEM->ICR = (1 << 0); // 清中断
}
}
嗯,这里要注意:Mailbox的深度只有8。如果你连续发超过8条消息还没人取,就会阻塞。我在一个项目中就遇到过这种情况——CM7核疯狂发日志,CM4核处理不过来,结果CM7核卡死了。后来加了个超时机制才解决。
共享内存区设计
共享内存,说白了就是两个核都能访问同一块SRAM。适合传大数据,比如音频帧、图像数据、传感器批量数据。
但共享内存有个大问题:两个核同时写怎么办?你想想看,如果CM7正在写一个结构体,写到一半CM4来读了,读到的就是半残数据。
双缓冲的设计思路很简单:
- 准备两块缓冲区,A和B
- CM7写A时,CM4读B
- 写完后交换角色
代码实现大概这样:
// 共享内存结构体定义
typedef struct {
uint32_t flag; // 0: CM7写A, CM4读B; 1: 反之
uint8_t bufferA[1024];
uint8_t bufferB[1024];
} SharedMem_t;
// 放在DTCM或SRAM4中
__attribute__((section(".shared_ram")))
volatile SharedMem_t shared_mem;
写数据时:
// CM7核写数据
void WriteToShared(const uint8_t* data, uint32_t len) {
uint8_t* target;
if(shared_mem.flag == 0) {
target = shared_mem.bufferA;
} else {
target = shared_mem.bufferB;
}
memcpy(target, data, len);
// 写完后翻转flag
__DMB(); // 数据内存屏障,确保写完成
shared_mem.flag ^= 1;
}
IPC中断同步
Mailbox和共享内存解决了「怎么传数据」,但没解决「什么时候传」。IPC中断就是用来同步的——一个核发中断通知另一个核:「数据准备好了,快来取」。
STM32H7里,两个核之间可以通过HSEM(硬件信号量)触发中断。具体做法:
| 步骤 | CM7核操作 | CM4核操作 |
|---|---|---|
| 1 | 写数据到共享内存 | 等待中断 |
| 2 | 释放HSEM信号量 | 收到HSEM中断 |
| 3 | 继续做其他事 | 读取共享内存数据 |
| 4 | — | 处理完成后清中断 |
实际项目中,我通常把三种机制组合使用:
- Mailbox:传命令和状态码,比如「开始采集」、「采集完成」
- 共享内存:传批量数据,比如1024点ADC采样值
- IPC中断:通知对方数据已就绪
举个例子,一个数据采集系统的工作流:
- CM7通过Mailbox发「开始采集」给CM4
- CM4启动ADC,采集1024点,存入共享内存
- CM4发IPC中断给CM7,通知数据就绪
- CM7收到中断,从共享内存读数据
- CM7处理完,通过Mailbox发「采集完成」给CM4
这个流程里,每种机制各司其职,不会乱。
- Mailbox:短消息,深度8,硬件队列
- 共享内存:大数据,双缓冲,加volatile和内存屏障
- IPC中断:同步通知,配合HSEM使用
- 实际项目:三种组合用,别只用一种
下面这张图,把三种机制的关系画清楚了:
最后说一句:别想着只用一种机制搞定所有场景。Mailbox传大数据会堵死,共享内存不加同步会读脏数据,IPC中断没有数据载体就是空响。三种机制配合好,双核通信才能稳如老狗。