这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 综合技术 » 基础知识 » 【STM32H755】基于OpenAmp的双核通信

共1条 1/1 1 跳转至

【STM32H755】基于OpenAmp的双核通信

工程师
2025-09-07 20:28:13     打赏
前言

STM32H755以双核为他的特点。因此学会使用双核通信是一项基础,本篇学习如何实现基于OpenAmp的基础通信。

学习资料

1、官方的AN5617,他详细的阐述了基于STM32H7x5/H7x7系列的双核通信的原理以及多种实现方式。

2、B站的一个大佬的视频,详细的手把手教程大家如何实现。链接地址为:【STM32H745 】STM32 双核 CPU入门哔哩哔哩bilibili

3、官方的例程,在官方的stm32cube的H747中也有很多的教程。

【工程创建】

1、使用stm32cubeMX创建一个基于NUCLEO-H755的基础工程。

2、在NVIC中分别打开Cortex-m7以及cortex-m4的HSEM全局中断,如果不打开,那就配置不了OPENAMP

HSEM1中断配置HSEM1中断配置.png

3、使能OPENAMP_M4以及OPENAMP_M4,钩选enable后,配置保持因默认即可,系统将配置OPENAMP_M7为Master,而OPENAMP_M4为Slave

配置OPENAMP配置OPENAMP.png

4、配置Cortex-M7的MPU

OpenAMP是基于共享内存来传递数据的,因此,我们需要配置双核均可以访问的内存,选用SRAM4即地址0x3800000段,大小为64Kb,因为不需要Cache,配置如下图所示:

配置cortex-m7的MPU配置cortex-m7的MPU.png


4、然后配置时钟以及工程的其他选项。

5、生成基于MDK的工程,并使用keil打开。

【测试代码】

1、首先在.sct链接文件中最后添加内容:

   RW_OPENAMP_RSC_TAB 0x38000000 0x00000400 {
   *(.resource_table)
 }
 
 __OpenAMP_SHMEM__ 0x38000400 EMPTY 0xFC00 {} ; Shared Memory area used by OpenAMP
}

【注】如果使用IAR或stm32cubeIDE请参见AN5617的Table5进行对应的链接文件的修改。

2、首先编写cortex_m4的代码,打开m4的main.c,声明初始变量如下:

#define RPMSG_SEVICE_NAME "openamp_demo"  //RPMSG服务名称
static volatile int message_received;     //消息接收标志
static volatile int service_created;      //服务创建标志
static volatile char received_data[100];     //消息接收标志
static struct rpmsg_endpoint rp_endpoint;  //RPMSG端点结构体
static char data[100];                    //数据缓存

3、编写接收回调函数:

static int rpmsg_recv_callback(struct rpmsg_endpoint *ept, void *data,
        size_t len, uint32_t src, void *priv)
{
 memcpy((void*)received_data, data, len);
 received_data[len] = '\0';  // 确保字符串结束符
 message_received = 1;
 return 0;
}

4、编写接收消息函数:

/**
* @brief 接收消息函数
* @details 该函数用于等待并接收消息,当消息到达时返回
* @param 无参数
* @return 返回0表示成功接收到消息
*/
uint32_t receive_message(void)
{
 /* 等待消息到达 */
 while(message_received == 0)
 {
   OPENAMP_check_for_message();
 }
 /* 清除消息接收标志 */
 message_received = 0;
 return 0;
}

5、 OpenAMP 初始化代码

  if(MX_OPENAMP_Init(RPMSG_REMOTE,NULL) != HAL_OK)
 {
   Error_Handler();
 }

6、创建并注册一个通信端点

 status = OPENAMP_create_endpoint(&rp_endpoint, RPMSG_SEVICE_NAME,
                                 RPMSG_ADDR_ANY,
                                 rpmsg_recv_callback, NULL);
 if(status != 0)
 {
   Error_Handler();
 }

7、接下来就等待接收数据,如果接收到了就通过虚拟串口打印出来。

  receive_message();
 sprintf(data,"Received data: %d\n",receivied_data);
 HAL_UART_Transmit(&hcom_uart[COM1],(uint32_t *)data,strlen(data),1000);

8、最后我们可以注消OPENAMP

 OPENAMP_DeInit();

到此cortex_M4的代码编写完毕。

【cortex_M7代码】

打开cortex_M7的main.c编写代码如下:

1、同CM4的代码一下样,先创建基本参数:

#define RPMSG_SEVICE_NAME "openamp_demo"
uint32_t message = 1234;
static volatile int message_received;
static volatile int service_created;
volatile uint32_t receivied_data;
static struct rpmsg_endpoint rp_endpoint;

2、编写接收回调函数:

/**
* @brief RPMsg接收回调函数,当RPMsg端点接收到数据时被调用
*
* @param ept RPMsg端点结构体指针,表示接收数据的端点
* @param data 接收到的数据缓冲区指针
* @param len 接收到的数据长度
* @param src 数据来源地址
* @param priv 私有数据指针
*
* @return 0 表示处理成功
*/
static int rpmsg_recv_callback(struct rpmsg_endpoint *ept, void *data,
        size_t len, uint32_t src, void *priv)
{
 /* 从接收到的数据中提取第一个uint32_t值并保存到全局变量 */
 receivied_data = *((uint32_t *)data);
 /* 设置消息接收标志位,表示已接收到新消息 */
 message_received = 1;
 return 0;
}

3、服务销毁回调函数

/**
* @brief 服务销毁回调函数
*
* 当RPMSG端点服务被销毁时调用此回调函数,用于重置服务创建状态标志
*
* @param ept 指向RPMSG端点结构体的指针
*
* @return 无返回值
*/
void service_destroy_cb(struct rpmsg_endpoint *ept)
{
 /* 重置服务创建状态标志,表示服务已被销毁 */
 service_created = 0;
};

4、编写新服务回调函数,当检测到新服务时被调用

/**
* @brief 新服务回调函数,当检测到新服务时被调用
*
* @param rdev 指向rpmsg设备的指针
* @param name 服务名称字符串
* @param dest 目标地址
*
* 该函数负责创建新的端点并标记服务已创建状态
*/
void new_service_cb(struct rpmsg_endpoint *rdev, const char *name,
                   uint32_t dest)
{
 /* 创建新的RPMSG端点 */
 OPENAMP_create_endpoint(&rp_endpoint, name, dest, rpmsg_recv_callback, service_destroy_cb);
 /* 标记服务已创建 */
 service_created = 1;
}

5、接收消息函数

/**
* @brief 接收消息函数
* @details 该函数用于等待并接收消息,当有消息到达时返回
* @param 无参数
* @return uint32_t 返回0表示成功接收到消息
*/
uint32_t receive_message(void)
{
 /* 等待消息到达,当message_received标志为0时持续检查 */
 while(message_received == 0)
 {
   OPENAMP_check_for_message();
 }
 /* 清除消息接收标志,为下一次接收做准备 */
 message_received = 0;
 return 0;
}

6、服务销毁回调函数

/**
* @brief 服务销毁回调函数
*
* 当RPMsg端点被销毁时调用此回调函数,用于重置服务创建状态标志。
*
* @param ept 指向RPMsg端点结构的指针
*
* @return 无返回值
*/
void service_destroy_cbk(struct rpmsg_endpoint *ept)
{
 /* 重置服务创建标志,表示服务已被销毁 */
 service_created = 0;
}

7、接下来在main主函数中编写初始化邮箱、RPMsg结构,配置端点名称和服务地址,并初始化OPENAMP模块,等待RPMsg端点准备就绪后向Cortex_M4发送一条信息,然后就销毁OPENAMP。其代码如下,我生成的详细的注释:

  /* 初始化邮箱通信模块 */
 MAILBOX_Init();
 
 /* 初始化RPMsg端点结构体,配置端点名称和服务地址 */
 rpmsg_init_ept(&rp_endpoint, RPMSG_SEVICE_NAME, RPMSG_ADDR_ANY,
                 RPMSG_ADDR_ANY, NULL,NULL);
 
 /* 初始化OPENAMP模块,作为主设备运行,并注册新服务发现回调函数 */
 if((MX_OPENAMP_Init(RPMSG_MASTER,new_service_cb) != HAL_OK))
 {
   Error_Handler();
 }

 /* 等待RPMsg端点准备就绪 */
 OPENAMP_Wait_EndPointready(&rp_endpoint);
 
 /* 通过RPMsg端点发送消息到远程处理器 */
 status = OPENAMP_send(&rp_endpoint, (uint32_t *)msg, sizeof(msg));
 if(status < 0)
 {
   Error_Handler();
 }

 /* 持续检查消息,直到服务被销毁 */
 while (service_created )
 {
   OPENAMP_check_for_message();
 }
 
 /* 反初始化OPENAMP模块,释放资源 */
 OPENAMP_DeInit();

【测试效果】

分别把两个固件都下载进开发板,接上串口助手,就可以观察到串口成功打印出接收的信息:

实验效果实验效果.png

【官方给出的流程图】

openamp_exampleopenamp_example.png

【总结】

本章详细的通过工程如何配置,两个核的OPENAMP的配,以及详细的代码编写,等展示了如何实现两个核之间的通信。






关键词: STM32H755     OpenAmp     双核    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]