STM32MP157——Remoteproc和RPMsg

拆解STM32MP157的‘双系统’通信:OpenAMP框架下的Virtio、RPMsg与Remoteproc到底怎么工作的? 本文深入解析STM32MP157双核异构通信架构,详细探讨OpenAMP框架下的Virtio、RPMsg与Remoteproc工作原理。通过硬件中断、共享内存机制及环形缓冲区等技术,实现Linux与实时操作系统的高效协同,为工业控制和边缘计算提供可靠解决方案。 阅读详情
AI摘要

本文深入探讨STM32MP157的Remoteproc和RPMsg框架,讲解非对称多处理(AMP)在嵌入式领域的应用前景,以及如何在STM32MP157上实现多核通信,包括M4固件生成、Remoteproc框架使用、RPMsg框架实现A7与M4间的用户态和内核态通信。

优快云仅用于增加百度收录权重,排版未优化,日常不维护。请访问:www.hceng.cn 查看、评论。
本博文对应地址:https://hceng.cn/2020/05/09/STM32MP157%E2%80%94%E2%80%94Remoteproc%E5%92%8CRPMsg/#more

简单介绍基于STM32MP157的Remoteproc和RPMsg框架。

STM32MP1系列产品,是STM32进军Linux的首款微处理器,采用MCU+MPU的组合,集成两颗主频为650MHz的Cortex-A7应用处理器内核和一颗主频为209MHz的Cortex-M4微控制器内核。

非对称多处理Asymmetric Multiprocessing(AMP)虽然目前在嵌入式还不是主流,但未来肯定是趋势。将多媒体处理扔给专用的MCU,亦或将对控制延时敏感的传感器交给MCU实时控制,更多的组合给人更多的遐想。

对于非对称多核架构,不同的核心是如何启动运行,又是如何进行通信?这些疑惑在上手STM32MP157后,逐渐明朗,因此记录下笔记。

1.生成M4固件

在进行启动M4之前,需要先建立工程,生成M4固件,这里以点灯为例,简单说下创建STM32MP157的M4工程。

这里要M4点灯,涉及到资源的分配,资源分配如下图所示。

深蓝色的IP为A7独占,浅蓝色的IP为M4独占,竖线分割的IP为同一时刻只能一个占有,斜线分割的IP为任意时刻两者可以同时占用。 比如这里GPIO就为两者可以同时占用,在Linux中可以控制GPIO,同时M4也可控制GPIO。UART则为只能一个独占,分配给M4后,A7将不能控制。

支持STM32开发的集成开发环境有很多,国内熟知的有Keil MDK-ARM和IAR EWAR。这两个IDE都很好用,但它们都是商业软件,免费或评估版要么有器件型号限制,要么有程序容量限制。于是出现了免费的Eclipse+GNU GCC来搭建STM32开发环境,但搭建过程繁琐、版本差异大导致教程不统一,对新手很不友好。

STM32CubeIDE是ST公司基于Eclipse/CDT框架和GUN GCC工具链制作的免费IDE,并集成了STM32CubeMX。一个软件就可以实现STM32系列芯片的外围设备配置、代码生成、代码编辑、代码编译、在线调试,并且支持数百个Eclipse现有插件。

打开STM32CubeIDE,创建一个新的“STM32 Project”。

在弹出的STM32CubeMX,选择“STM32MP157A”,具体型号以自己使用的开发板为准。注意这里的“芯片资料区”,提供了该型号的芯片手册,不用再去网上找了。

再设置工程名字,打开STM32CubeMX的关联视图。

我使用的板子,LED灯接在PD13引脚上,因此这里把PD13设置为输出引脚。

需要注意,这里还要选中该引脚,右键弹出“Pin Reservation”,选择“Cortex-M4”,不然不会自动生成GPIO初始化代码。

最后,如图设置下GPIO的属性。

设置完后,在标签栏选择“Project”->“Generate Code”,即可自动生成相关初始化代码。默认的初始化代码如下图,需要注意的是“main.c”文件,在里面添加LED灯的控制逻辑。还有“stm32mp1xx_hal_gpio.c”,这个是hal库源码,从里面可知hal提供的GPIO相关操作函数,比如这里用到的HAL_GPIO_WritePin()。
{% codeblock lang:c %}
HAL_GPIO_WritePin(LED_BLUE_GPIO_Port, LED_BLUE_Pin, GPIO_PIN_SET);
HAL_Delay(1000);
HAL_GPIO_WritePin(LED_BLUE_GPIO_Port, LED_BLUE_Pin, GPIO_PIN_RESET);
HAL_Delay(1000);
{% endcodeblock %}

添加完LED的控制逻辑代码后,在标签栏选择“Project”->“Build Project”即可编译工程,得到GPIO_LED_CM4.elf。该文件就是M4的固件,包含Cortex-A7和Cortex-M4都可以访问的资源表(.resource_table)和LED的控制程序等。

在Linux里,使用readelf -a GPIO_LED_CM4.elf命令,可以获取ELF文件的更多信息。

2.Remoteproc框架

Remoteproc(Remote Processor Framework),主要作用就是对远程处理器的生命周期进行管理,即启动、停止远程处理器。
以STM32MP157为例,Cortex-A内核先启动,然后使用Linux RemoteProc框架进行加载Cortex-M4固件,启动M4内核。

ST官方提供的内核已经默认配置了Remoteproc驱动,进入系统后,首先将要运行的M4固件放在/lib/firmware/目录下,然后将固件名字写到/sys/class/remoteproc/remoteproc0/firmware,再操作/sys/class/remoteproc/remoteproc0/state启动、停止M4处理器。
{% codeblock lang:shell %}
[root@stm32mp157:~]# ls /lib/firmware/
DEMO_LED_CM4.elf
[root@stm32mp157:~]# echo GPIO_LED_CM4.elf > /sys/class/remoteproc/remoteproc0/firmware
[root@stm32mp157:~]# cat /sys/class/remoteproc/remoteproc0/state
offline
[root@stm32mp157:~]# echo start > /sys/class/remoteproc/remoteproc0/state
[22683.222322] remoteproc remoteproc0: powering up m4
[22683.229097] remoteproc remoteproc0: Booting fw image GPIO_LED_CM4.elf, size 1899976
[22683.235549] remoteproc remoteproc0: header-less resource table
[22683.241235] remoteproc remoteproc0: not resource table found for this firmware
[22683.248749] remoteproc remoteproc0: header-less resource table
[22683.254414] remoteproc remoteproc0: remote processor m4 is now up
[root@stm32mp157:~]# echo stop > /sys/class/remoteproc/remoteproc0/state
[22709.281733] remoteproc remoteproc0: warning: remote FW shutdown without ack
[22709.287325] remoteproc remoteproc0: stopped remote processor m4
{% endcodeblock %}

除了在Linux的用户态控制M4内核的生命周期,还能在Linux内核态使用API控制(参考linux-origin_master/Documentation/remoteproc.txt),甚至U-boot中控制。

3.RPMsg框架

Remoteproc框架实现了对远程处理器生命周期的管理,RPMsg框架(Remote Processor Messaging Framework)则是实现对远程处理器信息传递。
RPMsg是基于VirtIO的消息总线,它允许内核驱动程序与系统上可用的远程处理器进行通信,同时,驱动程序可以根据需要公开适当的用户空间接口(参考linux-origin_master/Documentation/rpmsg.txt)。

STM32MP1多核通信框架如下图。

消息服务基于共享内存,使用RPMsg和Virtio框架,RemoteProc框架则控制远程处理器生命周期。
信号通知(Mailbox)服务则基于内部IPCC(Inter-Processor communication controller),ST提供OpenAMP相关库。

这里列举两个示例:
第一个示例在Linux的用户态和M4通信,实现A7控制M4的灯,A7和M4的相互唤醒;
第二个示例则是在Linux的内核态创建一个简单的RPMsg客户端,实现A7和M4的大量数据传输。

3.1 用户态的通信

3.1.1 A7准备

ST官方提供的内核已经默认配置了RPMSG_TTY驱动,Linux这边就不需要做什么了。
STM32MP1多核消息通信应用接口框图如下,在RPMsg和Virtio框架创建一个面向用户态的/dev/ttyRPMSG接口,M4在OpenAMP上创建虚拟串口,两者最终效果像是串口透传。

3.1.2 M4准备

创建一个STM32工程,在STM32CubeMX里,依次配置GPIO用于LED、配置UART5用于M4打印、以及配置IPCC和OPENAMP用于通信。

注意配置IPCC时,需要在NVIC Settings选项卡里,将IPCC RX1 occupied interrupt和IPCC TX1 free interrupt
的使能勾选上,不然后面的OPENAMP的Activated始终为灰色,无法激活。

生成初始化代码后,在USER CODE BEGIN 0和USER CODE END 0之间添加printf的重定向函数,让UART5与printf绑定。
{% codeblock lang:c %}
/* USER CODE BEGIN 0 /
#ifdef GNUC
/
With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to ‘Yes’) calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE f)
#endif /
GNUC /
PUTCHAR_PROTOTYPE
{
/
Place your implementation of fputc here */
HAL_UART_Transmit(&huart5, (uint8_t )&ch, 1, HAL_MAX_DELAY);
return ch;
}
/
USER CODE END 0 */
{% endcodeblock %}

这里计划创建两个RPMsg tty通道,一个用来LED控制命令,一个用来传输唤醒命令。

  • 1.初始化两个RPMsg tty虚拟串口

{% codeblock lang:c %}
if (VIRT_UART_Init(&huart0) != VIRT_UART_OK) {
printf(“VIRT_UART_Init UART0 failed.\r\n”);
Error_Handler();
}

if (VIRT_UART_Init(&huart1) != VIRT_UART_OK) {
printf(“VIRT_UART_Init UART1 failed.\r\n”);
Error_Handler();
}
{% endcodeblock %}

  • 2.注册回调函数以按通道接收消息
    {% codeblock lang:c %}
    if(VIRT_UART_RegisterCallback(&huart0, VIRT_UART_RXCPLT_CB_ID, VIRT_UART0_RxCpltCallback) != VIRT_UART_OK)
    {
    Error_Handler();
    }

    if(VIRT_UART_RegisterCallback(&huart1, VIRT_UART_RXCPLT_CB_ID, VIRT_UART1_RxCpltCallback) != VIRT_UART_OK)
    {
    Error_Handler();
    }
    {% endcodeblock %}

  • 3.编写虚拟串口回调函数
    当RPMsg收到数据后,将调用该回调函数。在此函数里,需要将接收的数据复制到用户内存,并修改接收标志位,通知用户完成数据接收。
    {% codeblock lang:c %}
    /* USER CODE BEGIN 4 */
    void VIRT_UART0_RxCpltCallback(VIRT_UART_HandleTypeDef *huart)
    {
    printf(“Msg received on VIRTUAL UART0 channel: %s \n\r”, (char *) huart->pRxBuffPtr);

    /* copy received msg in a variable to sent it back to master processor in main infinite loop*/
    VirtUart0ChannelRxSize = huart->RxXferSize < MAX_BUFFER_SIZE? huart->RxXferSize : MAX_BUFFER_SIZE-1;
    memcpy(VirtUart0ChannelBuffRx, huart->pRxBuffPtr, VirtUart0ChannelRxSize);
    VirtUart0RxMsg = SET;
    }

void VIRT_UART1_RxCpltCallback(VIRT_UART_HandleTypeDef *huart)
{
printf(“Msg received on VIRTUAL UART1 channel: %s \n\r”, (char *) huart->pRxBuffPtr);

/* copy received msg in a variable to sent it back to master processor in main infinite loop*/
VirtUart1ChannelRxSize = huart->RxXferSize < MAX_BUFFER_SIZE? huart->RxXferSize : MAX_BUFFER_SIZE-1;
memcpy(VirtUart1ChannelBuffRx, huart->pRxBuffPtr, VirtUart1ChannelRxSize);
VirtUart1RxMsg = SET;

}
/* USER CODE END 4 */
{% endcodeblock %}

  • 4.主函数轮询RPMsg消息
    OPENAMP_check_for_message()查询MailBox状态。
    当收到数据时,VIRT_UARTx_RxCpltCallback()会保存好收到数

从零玩转STM32MP157:用Linux命令控制M4核的LED(OpenAMP+RPMsg实战) 本文详细介绍了如何在STM32MP157开发板上使用OpenAMP框架和RPMsg协议实现Linux系统(A7核)对M4核LED的精确控制。通过环境搭建、工程配置、实战编程和调试技巧的全流程讲解,帮助开发者掌握异核通信技术,适用于工业控制和物联网网关等场景。 阅读详情

相关推荐

多核异构核间通信-mailbox/RPMsg 介绍及实验

多核异构 mailbox RPMsg

liuxd3000的专栏 1万+

第十八节 多核异构核间通信–ipcc

基于STM32MP1Linux 驱动开发实战 多核异构核间通信–ipcc

picassocao的博客 4618

STM32MP157 异核通信

STM32MP157 异核通信

天道酬勤 1692

OpenAMP异构多核通信实战:从RPMsg原理到STM32MP157应用

在嵌入式系统设计中,异构多核处理器(如ARM Cortex-A与Cortex-M的组合)的协同工作已成为提升性能与能效的关键架构。这类系统的核心挑战在于处理器间通信(IPC),传统共享内存等方式在异构环境下往往存在效率与维护性问题。其技术原理在于通过标准化的抽象层,将复杂的底层内存管理、缓存一致性及中断同步等细节封装,为开发者提供清晰的API。这带来了显著的技术价值:它大幅降低了多核系统软件开发的复杂度,提升了代码的可移植性与系统可靠性。典型的应用场景包括工业网关、汽车电子及高端消费电子设备,其中实时核处理

weixin_30340819的博客 304

手把手教你用OpenRouter免费模型:从DeepSeek V3.1到Llama 3.3的实战指南

本文详细介绍了如何利用OpenRouter平台免费接入DeepSeek V3.1、Llama 3.3等53个AI模型,提供从账号注册到实战应用的完整指南。通过文本摘要、客服对话生成和代码生成等具体案例,帮助开发者高效利用免费模型资源,提升AI应用开发效率。

weixin_29258297的博客 3545

告别城市峡谷定位漂移:手把手教你用PSINS仿真INS/NHC/ODO组合导航(附代码获取)

本文详细解析了INS/NHC/ODO组合导航系统在城市峡谷环境中的应用,通过PSINS平台实现精准定位。文章涵盖核心原理、环境搭建、算法实现及性能优化,帮助开发者解决GNSS信号中断时的定位漂移问题,提升自动驾驶系统在复杂环境中的可靠性。

weixin_30329623的博客 429

MPC模型预测控制实战:从理论到代码实现(Python示例)

本文详细介绍了MPC模型预测控制的实战应用,从理论到Python代码实现。通过构建系统模型、预测方程、优化问题及约束处理,展示了如何实现一个完整的MPC控制器。文章还提供了水箱液位控制的应用案例,帮助读者掌握MPC在工业控制中的实际应用。

weixin_42653691的博客 457

空频、空时、空域、时域、频域抗干扰介绍

1、时域抗干扰:对时间域序列进行滤波,滤波系数h(n),采样序列不断进行输入与滤波系数卷积计算,得到响应输出;例如常用的FIR和IIR滤波器。 对于多窄带干扰噪声源和连续波干扰源有较好的处理效果,还可以解决多径问题; 可以通过在接收机前端处理中增加一个嵌入式块实现; 2、频域抗干扰:接收机不容易受到相对于接收机频带以外的强功率干扰; 通常为带通滤波和阻带滤波, 适用于窄带干扰噪声源,连续波干扰源以及较强的频带外干扰噪声源, 3、空域抗干扰:通过多个自适应天线按照特定组合成天线阵列,波束成形,针对

qq_43517907的博客 7299

2025反爬终极方案:Python破解Cloudflare v2行为指纹,设备伪装+轨迹模拟拦截率压至1%

Cloudflare v2的反爬逻辑越来越接近“人类行为识别”,单纯的技术破解已失效,核心竞争力变成“模拟真实用户的能力”。本文的终极方案本质是“全方位复刻人类行为”——从设备指纹到操作轨迹,从网络特征到交互模式,让爬虫成为“无法被区分的真实用户”。这套方案的优势是“通用性强”,不仅适用于Cloudflare v2,也能破解大多数高反爬网站(如小红书、知乎、跨境电商)的行为检测;且代码可直接复用,新手只需替换目标URL和数据提取逻辑,就能快速落地。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 2353

【Bug已解决】openclaw max turns reached / Tool calls exceeded limit — OpenClaw 最大轮次超限解决方案

OpenClaw 在执行过程中达到最大轮次限制任务未完成,本质是 --max-turns 设置过小或任务过于复杂。文中给出增加轮次、--continue 继续、分步执行等完整方案。

一键难忘的博客 5504

YOLO26改进 - C2PSA | C2PSA融合DiffAttention差分注意力:轻量级差分计算实现高效特征降噪,提升模型抗干扰能力

本文介绍了 DiffCLIP,一种将差分注意力机制集成到 CLIP 架构的视觉 - 语言模型,并将其应用于 YOLO26。差分注意力机制通过计算两个互补注意力分布的差值,抵消无关信息干扰。单头差分注意力将 Q 和 K 拆分,分别计算注意力分布后做差值融合;多头差分注意力则每个头独立执行差分操作后聚合输出。关键参数 λ 可动态调控噪声抵消强度。我们将 DiffAttention 代码集成到 YOLO26 中,替换原有模块。实验表明,改进后的 YOLO26 在图像 - 文本理解任务中表现出色。

魔改工程师的博客 601

µC/OS-II---任务就绪表

意思是:将变量OSRdyGrp中最低位为1的位数赋给y,那么,y就是最高优先级任务所在就绪表的行号,那么最高优先级的任务就在OSRdyGrp[y]行中,再根据。

weixin_45880844的博客 1649

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

上一篇: Buildroot笔记
hceng_blog
博客等级 码龄10年 263粉丝 53原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值