【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:

CM7:

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); // 此处加入
第二部分:

.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); // 此处加入
第二部分:

.resource_table ORIGIN(OPEN_AMP_SHMEM) (NOLOAD) :
{
. = ALIGN(4);
KEEP(*(.resource_table))
. = ALIGN(4);
} >OPEN_AMP_SHMEM
7. OpenAMPconfig.h 配置
CM4 和 CM7 同样位置同样修改为如下:

#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 同样位置同样修改为如下:

__sync_synchronize();
9. openamp.c 回调函数增加主动处理消息
此处修改是为了避免,由于双核 OpenAMP 启动时序的问题导致 CM7 的第一次 Name Service 通知在 CM4 准备好之前已经发送,随后 CM4 的 OpenAMP 没有再次触发处理的问题。
CM4 和 CM7 同样位置同样修改为如下:

/* 启动阶段即使 HSEM 通知丢失,也主动处理已到达的消息。 */
rproc_virtio_notified(rvdev.vdev, VRING1_ID);
10. 测试打印结果
由于只有 CM4 配置了串口,所以只能由 CM4 进行打印,最主要关注最下面一句消息:
CM4: Received message: hello from CM7
说明 CM7 已经成功通过 OpenAMP 的框架向 CM4 发送了一条消息。

博客导航
本文来自博客园,作者:膝盖中箭卫兵,转载请注明原文链接:https://www.cnblogs.com/Skyrim-sssuuu/p/22807285

浙公网安备 33010602011771号
https://orcid.org/0000-0001-5102-772X