引言

随着物联网与边缘计算的发展,单核 MCU 在复杂任务处理与低功耗要求之间常陷入两难。STM32H7 系列(如 STM32H745/755)采用 Cortex-M4(主核,高性能)与 Cortex-M0+(从核,低功耗)的双核架构,通过高效的通信机制实现任务分工。本文将聚焦于双核通信的核心——IPC(Inter-Processor Communication),从硬件原理到代码实现,助你快速上手。

一、双核架构概览

STM32H7 双核 MCU 内部集成两个独立内核:

  • Cortex-M4:主核,运行复杂算法(如 AI、DSP),主频可达 480MHz。
  • Cortex-M0+:从核,处理低功耗任务(如传感器采集、通信协议),主频 240MHz。

两核共享外设(如 GPIO、ADC)和内存(SRAM),但各自拥有独立的中断控制器(NVIC)。协同工作的核心在于通信机制,主要包括:

  • 硬件邮箱(Mailbox):用于发送短消息和中断触发。
  • 共享内存(Shared SRAM):用于大数据交换。
  • 信号量(Semaphore):通过硬件互斥保证数据一致性。

二、通信机制原理

1. 硬件邮箱(HSEM)

硬件信号量(HSEM)模块提供 32 个互斥信号量,用于保护共享资源。每个信号量可被任一核获取/释放,支持中断通知。

2. 共享内存

双核通过 AHB 总线矩阵访问共享 SRAM(如 D1 域 SRAM)。为避免冲突,需使用 HSEM 进行互斥访问。

3. 核间中断(IPCC)

IPCC(Inter-Processor Communication Controller)提供双向通道,每个通道有发送/接收寄存器,可触发对方核的中断,实现事件同步。

三、配置步骤(以 STM32H745 为例)

1. 硬件连接

  • 使用 STM32H745 开发板,两核均连接调试器(SWD 多核调试)。
  • 确保电源稳定,共享 SRAM 区域在链接脚本中分配。

2. 软件初始化流程

  1. 使能时钟:RCC 中使能 HSEM 和 IPCC 时钟。
  2. 配置共享内存:在链接脚本中定义共享 SRAM 段(如 SHARED_SRAM)。
  3. 初始化 HSEM:设置信号量初始值。
  4. 配置 IPCC:使能通道,注册中断回调。
  5. 启动双核:主核通过 HAL_HSEM_FastTake 控制从核启动。

四、完整代码示例

以下代码演示主核(M4)与从核(M0+)通过共享内存和 HSEM 交换数据,并通过 IPCC 触发中断。

主核代码(M4)

/* main.c - M4 内核 */
#include "stm32h7xx_hal.h"

/* 共享内存区域,定义在链接脚本中 */
#define SHARED_ADDR 0x30040000
volatile uint32_t *shared_data = (uint32_t *)SHARED_ADDR;

void IPCC_IRQHandler(void)
{
    HAL_IPCC_IRQHandler();
    // 处理从核发来的数据
    uint32_t val = *shared_data;
    // 释放信号量
    HAL_HSEM_Release(HSEM_ID_0, 0);
}

int main(void)
{
    HAL_Init();
    __HAL_RCC_HSEM_CLK_ENABLE();
    __HAL_RCC_IPCC_CLK_ENABLE();

    // 初始化 HSEM
    HAL_HSEM_Init();
    // 获取信号量,保护共享内存
    HAL_HSEM_FastTake(HSEM_ID_0);
    *shared_data = 0x1234;
    HAL_HSEM_Release(HSEM_ID_0, 0);

    // 配置 IPCC 通道
    HAL_IPCC_Init();
    HAL_IPCC_ActivateNotification(IPCC_CHANNEL_1, IPCC_FLAG_RX);
    HAL_NVIC_EnableIRQ(IPCC_IRQn);

    // 启动从核(通过 HSEM 触发)
    HAL_HSEM_FastTake(HSEM_ID_1);
    // 从核复位释放
    HAL_RCC_EnableCSS(); // 示例,实际使用复位控制

    while(1)
    {
        // 主循环
    }
}

从核代码(M0+)

/* main.c - M0+ 内核 */
#include "stm32h7xx_hal.h"

#define SHARED_ADDR 0x30040000
volatile uint32_t *shared_data = (uint32_t *)SHARED_ADDR;

void IPCC_IRQHandler(void)
{
    HAL_IPCC_IRQHandler();
    // 读取共享数据
    uint32_t val = *shared_data;
    // 处理数据...
    // 发送响应
    *shared_data = val + 1;
    // 触发主核中断
    HAL_IPCC_Notify(IPCC_CHANNEL_1);
}

int main(void)
{
    HAL_Init();
    __HAL_RCC_HSEM_CLK_ENABLE();
    __HAL_RCC_IPCC_CLK_ENABLE();

    HAL_HSEM_Init();
    HAL_IPCC_Init();
    HAL_IPCC_ActivateNotification(IPCC_CHANNEL_1, IPCC_FLAG_RX);
    HAL_NVIC_EnableIRQ(IPCC_IRQn);

    while(1)
    {
        // 低功耗任务
        __WFI();
    }
}

链接脚本片段(共享内存)

/* 在 .ld 文件中添加 */
SHARED_SRAM (xrw) : ORIGIN = 0x30040000, LENGTH = 16K

五、注意事项

  • 内存一致性:双核访问共享内存时,需使用 HSEM 互斥,避免数据竞争。
  • 中断优先级:IPCC 中断优先级应合理设置,避免死锁。
  • 启动顺序:主核必须确保从核复位释放后再通信,否则可能崩溃。
  • 调试技巧:使用多核调试器(如 ST-Link 的 multi-core 支持)分别观察两核状态。
  • 功耗优化:从核在空闲时进入 WFI,由 IPCC 唤醒,降低功耗。

六、总结

STM32 双核架构通过 HSEM、共享内存和 IPCC 实现了高效、安全的核间通信。开发者需理解硬件机制,并合理设计数据流与同步策略。本文提供的示例可作为基础模板,实际项目中可根据需求扩展为消息队列或环形缓冲区。掌握双核协同,将显著提升系统性能与灵活性。