【前言】
STM32H7双核MCU,双核的通信有好几种方式,此次采用OpenAMP来实现。
【STM32CubeMX图形化配置】
1、要配置OpenAPM,必须先使能HSEM的全局中断,才能使用能OpenAMP
2、接下来使能OPENAMP_M4与OPENAMP_M7,使用默认配置即可。

3、MPU设置
我们要实现OpenAMP交换数据,需要选择M7与M4可以共同访问的内存空间,根据数据手册SRAM4是可以共同访问的内存。

在M7内存中,我们需要配置SRAM4的MPU。

使用后需要重新生成代码。
【代码编写】
一、STM32H747_M7 在main.c中添加
1、添加变量以及函数声明
/* USER CODE BEGIN PTD */ #define RPMSG_CHAN_NAME "openamp_AHT20" /* USER CODE END PTD */
/* USER CODE BEGIN PM */ static volatile int message_received; static volatile int service_created; volatile unsigned int received_data_str; static struct rpmsg_endpoint rp_endpoint; static int rpmsg_recv_callback(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv); void service_destroy_cb(struct rpmsg_endpoint *ept); void new_service_cb(struct rpmsg_device *rdev, const char *name, uint32_t dest); /* USER CODE END PM */
2、实现回调函数
/* USER CODE BEGIN 4 */
AHT20_DataTypedef recv_aht_data = {0.0f, 0.0f};
static int rpmsg_recv_callback(struct rpmsg_endpoint *ept, void *data,
size_t len, uint32_t src, void *priv)
{
HAL_GPIO_WritePin(GPIOI, GPIO_PIN_12, GPIO_PIN_RESET);
if (len == sizeof(AHT20_DataTypedef)) {
// 将接收的数据拷贝到结构体(直接强转+赋值,或用 memcpy)
recv_aht_data = *(AHT20_DataTypedef *)data;
// 或用 memcpy(效果一致,更安全):
// memcpy(&recv_aht_data, data, sizeof(recv_aht_data));
message_received = 1; // 标记接收成功
// 可选:打印解析后的数据
// printf("Recv AHT20: Hum=%.2f %%RH, Temp=%.2f °C\r\n",
// recv_aht_data.humidity, recv_aht_data.temperature);
} else {
// 数据长度不匹配,标记失败
message_received = 0;
// printf("Recv Err: Len=%d (Need %d)\r\n", len, sizeof(AHT20_DataTypedef));
}
return 0;
}
void service_destroy_cb(struct rpmsg_endpoint *ept)
{
/* this function is called while remote endpoint as been destroyed, the
* service is no more available
*/
service_created = 0;
}
void new_service_cb(struct rpmsg_device *rdev, const char *name, uint32_t dest)
{
/* create a endpoint for rmpsg communication */
OPENAMP_create_endpoint(&rp_endpoint, name, dest, rpmsg_recv_callback,
service_destroy_cb);
service_created = 1;
}
/* USER CODE END 4 */3、创建一个任务:
/* USER CODE END Header_openAMP_task */
void openAMP_task(void *argument)
{
/* USER CODE BEGIN openAMP_task */
/* Infinite loop */
HAL_GPIO_WritePin(GPIOI, GPIO_PIN_12, GPIO_PIN_SET);
MAILBOX_Init();
/* Initialize the rpmsg endpoint to set default addresses to RPMSG_ADDR_ANY */
rpmsg_init_ept(&rp_endpoint, RPMSG_CHAN_NAME, RPMSG_ADDR_ANY, RPMSG_ADDR_ANY,
NULL, NULL);
/* Initialize OpenAmp and libmetal libraries */
if (MX_OPENAMP_Init(RPMSG_MASTER, new_service_cb)!= HAL_OK)
Error_Handler();
OPENAMP_Wait_EndPointready(&rp_endpoint);
for(;;)
{
while(service_created)
{
OPENAMP_check_for_message();
osDelay(1);
}
osDelay(1);
}
/* USER CODE END openAMP_task */
}4、修改STM32H747XIHX_FLASH.ld
/* Specify the memory areas */
MEMORY
{
FLASH (rx) : ORIGIN = 0x08100000, LENGTH = 1024K
RAM (xrw) : ORIGIN = 0x10000000, LENGTH = 288K
OPENAMP_RSC_TAB (xrw) : ORIGIN = 0x38000000, LENGTH = 1K
OPEN_AMP_SHMEM (xrw) : ORIGIN = 0x38000400, LENGTH = 63K
}
__OPENAMP_region_start__ = ORIGIN(OPEN_AMP_SHMEM);
__OPENAMP_region_end__ = ORIGIN(OPEN_AMP_SHMEM) + LENGTH(OPEN_AMP_SHMEM);在最后面添加:
.openamp_section (NOLOAD) : {
. = ABSOLUTE(0x38000000);
*(.resource_table)
} >OPENAMP_RSC_TAB AT > FLASH
.ARM.attributes 0 : { *(.ARM.attributes) }
}二、STM32H747_M4内核代码添加
修改app.c代码如下:
/*
* app.c
*
* Created on: Nov 15, 2025
* Author: liujianhua
*/
#include "app.h"
#include "stdio.h"
#include "AHT20.h"
#include "openamp.h"
#define RPMSG_CHAN_NAME "openamp_AHT20"
static volatile int message_received;
static volatile int service_created;
volatile unsigned int received_data_str;
static struct rpmsg_endpoint rp_endpoint;
static int rpmsg_recv_callback(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv);
void service_destroy_cb(struct rpmsg_endpoint *ept);
void new_service_cb(struct rpmsg_device *rdev, const char *name, uint32_t dest);
static int rpmsg_recv_callback(struct rpmsg_endpoint *ept, void *data,
size_t len, uint32_t src, void *priv)
{
// uint8_t cmd = *(uint8_t *)data;
message_received = *((unsigned int *) data);
printf("openamp recv data:%d",message_received);
return 0;
}
void Run(void)
{
float humidity = 0.0f, temperature = 0.0f;
AHT20_DataTypedef aht_data; // 定义结构体实例
AHT20_StatusTypeDef aht_status;
int status = 0;
MAILBOX_Init();
if(MX_OPENAMP_Init(RPMSG_REMOTE,NULL) != HAL_OK)
{
Error_Handler();
}
status = OPENAMP_create_endpoint(&rp_endpoint,
RPMSG_CHAN_NAME,
RPMSG_ADDR_ANY,
rpmsg_recv_callback,NULL);
if(status < 0)
{
Error_Handler();
}
// 1. 初始化AHT20
aht_status = AHT20_Init();
if (aht_status == AHT20_OK) {
printf("AHT20 Init Success!\r\n");
} else {
printf("AHT20 Init Fail! Code: %d\r\n", aht_status);
while (1); // 初始化失败,死循环
}
while(1)
{
aht_status = AHT20_ReadData(&humidity, &temperature);
if (aht_status == AHT20_OK) {
// 打印温湿度(保留2位小数)
printf("Humidity: %.2f %%RH | Temperature: %.2f\r\n",\
humidity, temperature);
} else {
// 打印错误信息
printf("Read Fail! Code: %d\r\n", aht_status);
}
// 2. 将温湿度赋值给结构体
aht_data.humidity = humidity;
aht_data.temperature = temperature;
int ret = rpmsg_send(&rp_endpoint, &aht_data, sizeof(aht_data));
if (ret < 0) {
printf("OpenAMP Send Fail! Ret: %d\r\n", ret);
} else {
printf("Send Success: Hum=%.2f, Temp=%.2f\r\n", aht_data.humidity, aht_data.temperature);
}
HAL_Delay(1000); // 1秒读取一次
}
}2、修改STM32H747XIHX_FLASH.ld
/* Specify the memory areas */
MEMORY
{
FLASH (rx) : ORIGIN = 0x08100000, LENGTH = 1024K
RAM (xrw) : ORIGIN = 0x10000000, LENGTH = 288K
OPENAMP_RSC_TAB (xrw) : ORIGIN = 0x38000000, LENGTH = 1K
OPEN_AMP_SHMEM (xrw) : ORIGIN = 0x38000400, LENGTH = 63K
}
__OPENAMP_region_start__ = ORIGIN(OPEN_AMP_SHMEM);
__OPENAMP_region_end__ = ORIGIN(OPEN_AMP_SHMEM) + LENGTH(OPEN_AMP_SHMEM);最文档最后面添加:
.openamp_section (NOLOAD) : {
. = ABSOLUTE(0x38000000);
*(.resource_table)
} >OPENAMP_RSC_TAB AT > FLASH
.ARM.attributes 0 : { *(.ARM.attributes) }
}【验证】
两个内核编译下载后,我们观察串口助手的打印日志

观察屏TouchGFX效果如下:

用手按下AHT20,观察温度变化:

可以看到动态的更了GUI显示。
【总结】
STM32H747的双核,M7内核主核高,GUI显示效果好,M4内核可以处理数据收发等,通过OpenAMP将数据同步给M7做显示,这样就各司其责。
【视频】
我要赚赏金
