【STM32H757XIH6 双核】IPC 进程间通信 —— OpenAMP 多核异构处理器间通信框架配置

1. 引言

此次使用的芯片为 STM32H757XIH6,工程采用 CM7 + CM4 双核结构。
本文主要达到以下目标:
1. 为 CM4 和 CM7 配置共同使用的 OpenAMP 共享内存;
2. 正确放置资源表并处理双核初始化顺序;
3. 创建 FreeRTOS 任务轮询 OpenAMP 消息;
4. 实现 CM7 向 CM4 发送消息,以及 CM4 接收后回复消息。

下一篇,将 CM7 printf 重定向到 OpenAMP 发送上:
【STM32H757XIH6 双核】IPC 进程间通信 —— CM7 printf 重定向到 OpenAMP 发送

2. OpenAMP 配置

2.1 配置 NVIC 中的 HSEM 中断

只有配置了 CM4 和 CM7 的 HSEM 中断,才能使能 OpenAMP。

CM4:
image

CM7:
image

3. MPU 配置

OpenAMP 资源共享使用的是 SRAM4(D3) 区域,配置如下:

/* Region1:DTCM — CPU 紧耦合,可 Cache,一般放栈/关键数据 */
memory_set_protection(MPU_REGION_NUMBER1,
                      0x20000000U,
                      MPU_REGION_SIZE_128KB,
                      0x00U,
                      MPU_TEX_LEVEL0,
                      MPU_REGION_FULL_ACCESS,
                      MPU_INSTRUCTION_ACCESS_ENABLE,
                      MPU_ACCESS_NOT_SHAREABLE,
                      MPU_ACCESS_CACHEABLE,
                      MPU_ACCESS_BUFFERABLE);

/* Region2:AXI SRAM — 大块应用数据,可 Cache */
memory_set_protection(MPU_REGION_NUMBER2,
                      0x24000000U,
                      MPU_REGION_SIZE_512KB,
                      0x00U,
                      MPU_TEX_LEVEL0,
                      MPU_REGION_FULL_ACCESS,
                      MPU_INSTRUCTION_ACCESS_ENABLE,
                      MPU_ACCESS_NOT_SHAREABLE,
                      MPU_ACCESS_CACHEABLE,
                      MPU_ACCESS_BUFFERABLE);

/* Region3:D2 SRAM — ETH DMA 描述符/RxTx 缓冲所在,必须非 Cache
 * TEX=1 + C=0 + B=0 → Normal non-cacheable,避免 CPU 与 DMA 看到不一致数据 */
memory_set_protection(MPU_REGION_NUMBER3,
                      0x30000000U,
                      MPU_REGION_SIZE_512KB,
                      0x00U,
                      MPU_TEX_LEVEL1,
                      MPU_REGION_FULL_ACCESS,
                      MPU_INSTRUCTION_ACCESS_ENABLE,
                      MPU_ACCESS_NOT_SHAREABLE,
                      MPU_ACCESS_NOT_CACHEABLE,
                      MPU_ACCESS_NOT_BUFFERABLE);

/* Region4:SRAM4(D3)— OpenAMP resource_table/SHM,必须非 Cache + Shareable */
memory_set_protection(MPU_REGION_NUMBER4,
                      0x38000000U,
                      MPU_REGION_SIZE_64KB,
                      0x00U,
                      MPU_TEX_LEVEL1,
                      MPU_REGION_FULL_ACCESS,
                      MPU_INSTRUCTION_ACCESS_DISABLE,
                      MPU_ACCESS_SHAREABLE,
                      MPU_ACCESS_NOT_CACHEABLE,
                      MPU_ACCESS_NOT_BUFFERABLE);

/* Region5:FMC 外设窗口 — Device 属性,关 Cache */
memory_set_protection(MPU_REGION_NUMBER5,
                      0x60000000U,
                      MPU_REGION_SIZE_64MB,
                      0x00U,
                      MPU_TEX_LEVEL0,
                      MPU_REGION_FULL_ACCESS,
                      MPU_INSTRUCTION_ACCESS_ENABLE,
                      MPU_ACCESS_NOT_SHAREABLE,
                      MPU_ACCESS_NOT_CACHEABLE,
                      MPU_ACCESS_NOT_BUFFERABLE);

/* Region6:SDRAM(LCD 帧缓冲等)— 允许 Cache;改屏后需 Clean/Invalidate
 *(见 ltdc_framebuffer_sync) */
memory_set_protection(MPU_REGION_NUMBER6,
                      0xD0000000U,
                      MPU_REGION_SIZE_32MB,
                      0x00U,
                      MPU_TEX_LEVEL0,
                      MPU_REGION_FULL_ACCESS,
                      MPU_INSTRUCTION_ACCESS_ENABLE,
                      MPU_ACCESS_NOT_SHAREABLE,
                      MPU_ACCESS_CACHEABLE,
                      MPU_ACCESS_BUFFERABLE);

/* Region7:QSPI 映射 — 关 Cache 且禁止执行,防止误把外设当代码跑 */
memory_set_protection(MPU_REGION_NUMBER7,
                      0x80000000U,
                      MPU_REGION_SIZE_256MB,
                      0x00U,
                      MPU_TEX_LEVEL0,
                      MPU_REGION_FULL_ACCESS,
                      MPU_INSTRUCTION_ACCESS_DISABLE,
                      MPU_ACCESS_NOT_SHAREABLE,
                      MPU_ACCESS_NOT_CACHEABLE,
                      MPU_ACCESS_NOT_BUFFERABLE);

4. 初始化 OpenAMP

4.1 CM4 部分

#define RPMSG_SERVICE_NAME "IPC"

static struct rpmsg_endpoint s_ept;

/* 接收回调函数 */
static int cm4_rx_callback(struct rpmsg_endpoint *rp_chnl, 
                       void *data, 
                       size_t len, 
                       uint32_t src, 
                       void *priv)
{
  char msg[64];
  memset(msg, 0, sizeof(msg));

  (void)src;
  (void)priv;

  if (len >=sizeof(msg))
  {
    len = sizeof(msg) - 1;
  }

  memcpy(msg, data, len);
  msg[len] = '\0';

  printf("CM4: Received message: %s\n", msg);

  if (is_rpmsg_ept_ready(rp_chnl))
  {
    const char reply[] = "Hello, from CM4!";
    rpmsg_send(rp_chnl, reply, strlen(reply));
  }

  return RPMSG_SUCCESS;
}

/* 初始化函数 */
void app_ipc_cm4_init(void)
{
  OPENAMP_init_ept(&s_ept);
  if (MX_OPENAMP_Init(RPMSG_REMOTE, NULL) != 0)
  {
    Error_Handler();
  }
  if (OPENAMP_create_endpoint(&s_ept,
                              RPMSG_SERVICE_NAME,
                              RPMSG_ADDR_ANY,
                              cm4_rx_callback,
                              NULL) != 0)
  {
    Error_Handler();
  }
}

4.2 CM7 部分

#define RPMSG_SERVICE_NAME "IPC"

static struct rpmsg_endpoint s_ept;

/* 发送函数 */
void app_ipc_cm7_send(void)
{
  OPENAMP_Wait_EndPointready(&s_ept);
  const char message[] = "hello from CM7";
  if (rpmsg_send(&s_ept, message, sizeof(message)) != 0)
  {
    Error_Handler();
  }
}

/* 接收回调函数(这里用不上)*/
static int cm7_rx_callback(struct rpmsg_endpoint *ept,
                           void *data,
                           size_t len,
                           uint32_t src,
                           void *priv)
{
  char message[64];

  (void)ept;
  (void)src;
  (void)priv;

  return RPMSG_SUCCESS;
}

/* 初始化函数 */
void app_ipc_cm7_init(void)
{
  OPENAMP_init_ept(&s_ept);
  if (MX_OPENAMP_Init(RPMSG_MASTER, NULL) != 0)
  {
    Error_Handler();
  }
  if (OPENAMP_create_endpoint(&s_ept,
                              RPMSG_SERVICE_NAME,
                              RPMSG_ADDR_ANY,
                              cm7_rx_callback,
                              NULL) != 0)
  {
    Error_Handler();
  }
  OPENAMP_Wait_EndPointready(&s_ept);
  app_ipc_cm7_send();
}

5. OpenAMP 任务

5.1 CM4 部分

/* FreeRTOS 初始化 */
void MX_FREERTOS_Init(void) {
  BaseType_t xReturn = pdPASS;
  xReturn = xTaskCreate((TaskFunction_t)OpenAMP_task,
                        (char *)"OpenAMP_task",
                        (uint16_t)256,
                        (void *)NULL,
                        (uint8_t)1,
                        (TaskHandle_t *)NULL);
  if (xReturn != pdPASS)
  {
    return;
  }
}

/* OpenAMP 任务 */
void OpenAMP_task(void *argument)
{
  (void)argument;

  for (;;)
  {
    OPENAMP_check_for_message();
    osDelay(1);
  }
}

5.1 CM7 部分

/* FreeRTOS 初始化 */
void MX_FREERTOS_Init(void) {
  BaseType_t xReturn = pdPASS;
  xReturn = xTaskCreate((TaskFunction_t)OpenAMP_task,
                        (char *)"OpenAMP_task",
                        (uint16_t)256,
                        (void *)NULL,
                        (uint8_t)1,
                        (TaskHandle_t *)NULL);
  if (xReturn != pdPASS)
  {
    return;
  }
}

/* OpenAMP 任务 */
void OpenAMP_Task(void *argument)
{
  for (;;)
  {
    OPENAMP_check_for_message();
    osDelay(1000);
  }
}

6. 链接脚本中加入 OPEN_AMP_SHMEM 区域与符号

6.1 CM4 部分

stm32h757xx_flash_CM4.ld 文件
第一部分:

/* Specify the memory areas */
MEMORY
{
FLASH (rx)      : ORIGIN = 0x08100000, LENGTH = 1024K
RAM (xrw)      : ORIGIN = 0x10000000, LENGTH = 288K
OPEN_AMP_SHMEM (xrw) : ORIGIN = 0x38000400, LENGTH = 63K  // 此处加入
}
/* Highest address of the user mode stack */
_estack = 0x10048000;    /* end of RAM */
__OPENAMP_region_start__  = ORIGIN(OPEN_AMP_SHMEM);  // 此处加入
__OPENAMP_region_end__    = ORIGIN(OPEN_AMP_SHMEM) + LENGTH(OPEN_AMP_SHMEM);  // 此处加入

第二部分:
image

  .resource_table ORIGIN(OPEN_AMP_SHMEM) (NOLOAD) :
  {
    . = ALIGN(4);
    KEEP(*(.resource_table))
    . = ALIGN(4);
  } >OPEN_AMP_SHMEM

6.2 CM7 部分

stm32h757xx_flash_CM7.ld 文件
第一部分:

/* Specify the memory areas */
MEMORY
{
FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 1024K
RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 128K
ITCMRAM (xrw)      : ORIGIN = 0x00000000, LENGTH = 64K
OPEN_AMP_SHMEM (xrw) : ORIGIN = 0x38000400, LENGTH = 63K  // 此处加入
}
/* Highest address of the user mode stack */
_estack = 0x20020000;    /* end of RAM */
__OPENAMP_region_start__  = ORIGIN(OPEN_AMP_SHMEM);  // 此处加入
__OPENAMP_region_end__    = ORIGIN(OPEN_AMP_SHMEM) + LENGTH(OPEN_AMP_SHMEM);  // 此处加入

第二部分:
image

  .resource_table ORIGIN(OPEN_AMP_SHMEM) (NOLOAD) :
  {
    . = ALIGN(4);
    KEEP(*(.resource_table))
    . = ALIGN(4);
  } >OPEN_AMP_SHMEM

7. OpenAMPconfig.h 配置

CM4 和 CM7 同样位置同样修改为如下:
image

#define VRING_RX_ADDRESS        (SHM_START_ADDRESS + 0x100)
#define VRING_TX_ADDRESS        (SHM_START_ADDRESS + 0x500)
#define VRING_BUFF_ADDRESS      (SHM_START_ADDRESS + 0x900)

8. rsc_table.c 中增加数据保护

CM4 和 CM7 同样位置同样修改为如下:
image

__sync_synchronize();

9. openamp.c 回调函数增加主动处理消息

此处修改是为了避免,由于双核 OpenAMP 启动时序的问题导致 CM7 的第一次 Name Service 通知在 CM4 准备好之前已经发送,随后 CM4 的 OpenAMP 没有再次触发处理的问题。

CM4 和 CM7 同样位置同样修改为如下:
image

/* 启动阶段即使 HSEM 通知丢失,也主动处理已到达的消息。 */
rproc_virtio_notified(rvdev.vdev, VRING1_ID);

10. 测试打印结果

由于只有 CM4 配置了串口,所以只能由 CM4 进行打印,最主要关注最下面一句消息:

CM4: Received message: hello from CM7

说明 CM7 已经成功通过 OpenAMP 的框架向 CM4 发送了一条消息。
image

博客导航

博客导航

posted @ 2026-09-02 15:22  膝盖中箭卫兵  阅读(20)  评论(0)    收藏  举报
ORCID iD icon https://orcid.org/0000-0001-5102-772X