news 2026/6/24 10:43:31

痞子衡嵌入式:大话双核i.MXRT1180之XIP应用里借助MU实现可靠Flash IAP的方法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
痞子衡嵌入式:大话双核i.MXRT1180之XIP应用里借助MU实现可靠Flash IAP的方法

一、双核通信的三种方法

因为今天这个话题涉及双核架构,有必要先简单和大家谈一谈双核间通信的三种方式及其优缺点,注意这里仅指双核间传递消息数据(侧重通知),而不涉及所谓信号量 semaphore 概念(侧重互斥,比如两个核抢同一个“硬件锁寄存器”,谁先抢到,谁就独占某个共享资源)。

1.1 共享内存

第一种方法就是最常见的共享内存,只要是两个核均能访问的 SRAM,Register 等均可以用作消息数据传递。比如定义如下结构体 g_sharedMsg 存储两个 msg 数据,core0 发出的消息存入 core0_msg,core1 发出消息存入 core1_msg,在两个核的工程链接文件里,均将 .shared_mem 段指向同一个物理地址即可(需要是 Non‑Cacheable 属性的内存,且是 4 字节对齐地址)。

// 对 ARM Cortex‑M 来说,4 字节对齐的 uint32_t 读写是原子的,不会出现“读到一半新、一半旧”的撕裂问题 typedef struct _shared_msg { uint32_t core0_msg; uint32_t core1_msg; } shared_msg_t; __attribute__((section(".shared_mem"))) volatile shared_msg_t g_sharedMsg;

这种方法的优点是非常通用,不依赖任何硬件,且消息数据量不限(取决于内存大小);缺点是消息数据需要内核以 polling 方式获取,消息交互实时性不高。

1.2 硬件MU模块

第二种方法就是借助专用于双核通信的 Messaging Unit (MU) 模块,这是一个硬件模块,双核 MCU 里一般都会有,其提供了中断驱动的消息传递机制。这种方法的优点是实时性最佳,消息交互通过中断驱动,不需要内核去 polling;缺点是依赖专用硬件模块,且消息寄存器数量有限,比如 RT1180 上 MU 一次最多传递 4 个 uint32_t 数据。

1.3 硬件通信模块

最后一种方法就是借助一般通信外设模块,比如 GPIO/UART/SPI/I2C 等,两个内核各控制一个通信外设,片外通过 pin 脚将两个外设相连。这种方法的优点是实时性也不错,消息交互也可通过通信外设自身中断驱动,并且消息数据量也不限;缺点是消耗硬件通信外设,且占用外部 pin 脚。

二、MU模块及其驱动简介

综合比较,本文选取了第二种方法即借助于片内专用 MU 模块实现双核通信,下面简单介绍一下 MU 模块的基本特性和驱动用法。RT1180 内部共有两个 MU 模块,每个 MU 内部包含两个子模块 MUA 和 MUB,分别对应主核 CM33 (Processor A)和从核 CM7 (Processor B),MUA 与 MUB 子模块之间通过内部总线相连。

每个 MUA/B 模块均提供了 4 个 32-bit 的消息寄存器(发送通过 TR0-3,接收通过 RR0-3)用于数据传递,以及相应的中断机制。比如当 Processor A 向 MUA_TR0 写入数据时,Processor B 可以通过 MUB_RR0 读取该数据,同时会触发 Processor B 的中断;反之亦然。

下面是一个基于 SDK v25.12 里 fsl_mu 驱动代码的简单示例,两个内核各自初始化自己的 MU 子模块,这里定义了两个 MU_CMD,通过 MUx_TR0/RR0 交互,CM7 先通过 MUB 发出 MU_CMD_ECHO 消息,CM33 通过 MUA 中断得到该消息后立刻返回 MU_CMD_ACK 消息,CM7 收到返回消息即结束。

#include "fsl_mu.h" typedef enum { MU_CMD_ECHO = 0xA5A50001, // CM7 -> CM33 MU_CMD_ACK = 0xA5A50002, // CM33 -> CM7 } mu_cmd_t; // 下列代码应用于 CM33 工程 void mc_cm33_init(void) { MU_Init(MU1_MUA); MU_EnableInterrupts(MU1_MUA, kMU_Rx0FullInterruptEnable); NVIC_EnableIRQ(MU1_IRQn); } void MU1_IRQHandler(void) { uint32_t flag = MU_GetStatusFlags(MU1_MUA); if ((flag & kMU_Rx0FullFlag) == kMU_Rx0FullFlag) { uint32_t msg = MU_ReceiveMsgNonBlocking(MU1_MUA, kMU_MsgReg0); if (msg == MU_CMD_ECHO) { MU_SendMsgNonBlocking(MU1_MUA, kMU_MsgReg0, MU_CMD_ACK); } } } // 下列代码应用于 CM7 工程 void mc_cm7_init(void) { MU_Init(MU1_MUB); MU_EnableInterrupts(MU1_MUB, kMU_Rx0FullInterruptEnable); NVIC_EnableIRQ(MU1_IRQn); MU_SendMsgNonBlocking(MU1_MUB, kMU_MsgReg0, MU_CMD_ECHO); } void MU1_IRQHandler(void) { uint32_t flag = MU_GetStatusFlags(MU1_MUB); if ((flag & kMU_Rx0FullFlag) == kMU_Rx0FullFlag) { uint32_t msg = MU_ReceiveMsgNonBlocking(MU1_MUB, kMU_MsgReg0); if (msg == MU_CMD_ACK) { // Do something } } }

三、双核管理驱动MCMGR用法

由于 MU 模块仅仅是最底层的裸消息数据传输,不带协议、不带缓冲、不带管理,这里不建议直接在应用程序里大量使用,因为代码易写错、维护成本高。NXP 官方提供了一个更高级的双核管理驱动 MCMGR(Multicore Manager),它是对 MU 模块的进一步封装,提供了更加便捷的双核通信接口。

我们将上一节里的代码示例实现用 MCMGR 驱动改写,这时候完全不用碰 MU 寄存器与驱动,代码变得更加清晰易读。MCMGR 驱动的核心是事件(Event)机制,每个事件都有一个 ID 类型和关联的回调函数,当一个核向另一个核发送事件时,接收端会触发相应的回调函数。

#include "mcmgr.h" #define MCMGR_EVENT_ECHO (1U) // CM7 -> CM33 #define MCMGR_EVENT_ACK (2U) // CM33 -> CM7 // 下列代码应用于 CM33 工程 void mc_cm33_init(void) { (void)MCMGR_Init(); MCMGR_RegisterEvent( kMCMGR_RemoteApplicationEvent, cm33_mc_cb, NULL); } static void cm33_mc_cb(mcmgr_core_t coreNum, uint16_t eventData, void *context) { if (eventData == MCMGR_EVENT_ECHO) { MCMGR_TriggerEvent(kMCMGR_Core1, kMCMGR_RemoteApplicationEvent, MCMGR_EVENT_ACK); } } // 下列代码应用于 CM7 工程 void mc_cm7_init(void) { (void)MCMGR_Init(); MCMGR_RegisterEvent( kMCMGR_RemoteApplicationEvent, cm7_mc_cb, NULL); MCMGR_TriggerEvent(kMCMGR_Core0, kMCMGR_RemoteApplicationEvent, MCMGR_EVENT_ECHO); } static void cm7_mc_cb(mcmgr_core_t coreNum, uint16_t eventData, void *context) { if (eventData == MCMGR_EVENT_ACK) { // Do something } }

MCMGR 驱动一共定义了 9 种不同类型的事件,其中 kMCMGR_RemoteApplicationEvent 是用于用户自定义跨核事件的唯一正确类型。

typedef enum _mcmgr_event_type_t { kMCMGR_RemoteCoreUpEvent = 1, // 内部事件,核状态管理 kMCMGR_RemoteCoreDownEvent, // 内部事件,核状态管理 kMCMGR_RemoteExceptionEvent, // 内部事件 kMCMGR_StartupDataEvent, // 启动数据 kMCMGR_FeedStartupDataEvent, kMCMGR_RemoteRPMsgEvent, // RPMsg 专用,IPC kMCMGR_RemoteApplicationEvent, // 唯一用户事件 kMCMGR_FreeRtosMessageBuffersEvent, // 系统用,Buffer 回收 kMCMGR_EventTableLength } mcmgr_event_type_t;

四、XIP应用里实现Flash IAP的方法

前面铺垫了那么多,看到这里相信你肯定已经对这个客户需求如何解决有了答案,其实也不复杂。我们可以直接基于 SDK multicore_examples/hello_world 例程来修改实现,该例程 CM33 是 XIP,CM7 在 ITCM 执行,跟客户情况一致,我们只需要在此基础上加上 MCMGR 和 IAP 代码,核心思想是 CM7 做 Flash IAP 之前必须先给 CM33 发 notify 消息让其跳转到 RAM 里驻留等待(脱离 XIP),得到 CM33 发来的 ready 消息时,CM7 才能真正开始做 Flash IAP,等 IAP 结束 CM7 再通知 CM33 重返 XIP。

这里最大的注意点是 CM33 端 RAM 驻留函数设计与 FlexSPI 状态清理,还有就是因为要保留 MU 中断接收 CM7 来的消息,因此不能简单粗暴地关全局中断,CM33 端需要将中断向量表以及使能的中断的服务程序代码全部重定向到 RAM 中。

CM7 端: > MCMGR_EVENT_FLASH_IAP_NOTIFY:通知CM33即将做IAP < MCMGR_EVENT_FLASH_IAP_READY:得到来自CM33的ready信号后开始做IAP > MCMGR_EVENT_FLASH_IAP_PASS:IAP成功后返回结果给CM33 > MCMGR_EVENT_FLASH_IAP_FAIL:IAP失败后返回结果给CM33 CM33 端: < MCMGR_EVENT_FLASH_IAP_NOTIFY:当接收到来自CM7的notify信号后,清除FLEXSPI cache等待bus idle > MCMGR_EVENT_FLASH_IAP_READY:此时已驻留进RAM loop中,给CM7发ready信号 < MCMGR_EVENT_FLASH_IAP_PASS:得到来自CM7的IAP成功结果,直接重返XIP < MCMGR_EVENT_FLASH_IAP_FAIL:得到来自CM7的IAP失败结果,需重新初始化FLEXSPI重返XIP(TBD)
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/24 10:40:16

光伏储能设备工业模块电源怎么选?三大选型技术要点

一、引言&#xff1a;忽视模块电源选型&#xff0c;光伏储能项目批量故障频发当下光伏储能行业规模化落地提速&#xff0c;工商业储能柜、户用光储一体机、集中式储能 PCS 配套电路&#xff0c;均离不开模块电源、电源模块完成高低压隔离、辅助供电、信号采集转换。大量硬件工程…

作者头像 李华
网站建设 2026/6/24 10:30:24

审批链路卡死?低代码重构政务数字化底层效率

当下政务数字化转型早已告别“有无之争”&#xff0c;进入“优劣之辩”。全国绝大多数政务部门已完成线上系统搭建、线下流程迁移、数字化平台上线等基础建设&#xff0c;但行业普遍陷入表层数字化、底层低效化的尴尬困境。从基层街道办到省市直属部门&#xff0c;普遍存在一个…

作者头像 李华
网站建设 2026/6/24 10:25:55

10分钟精通:KH Coder免费文本挖掘工具实战指南

10分钟精通&#xff1a;KH Coder免费文本挖掘工具实战指南 【免费下载链接】khcoder KH Coder: for Quantitative Content Analysis or Text Mining 项目地址: https://gitcode.com/gh_mirrors/kh/khcoder 面对海量文本数据时&#xff0c;你是否感到无从下手&#xff1f…

作者头像 李华
网站建设 2026/6/24 10:22:47

3D Web 开发实战:Three.js 场景构建与 GPU 渲染性能优化的工程化路径

3D Web 开发实战&#xff1a;Three.js 场景构建与 GPU 渲染性能优化的工程化路径一、3D Web 的性能悬崖&#xff1a;从 60fps 到卡死只差一个模型 浏览器里跑 3D 场景&#xff0c;听起来很酷&#xff0c;做起来很痛苦。一个 10 万面的模型在桌面端流畅运行&#xff0c;在移动端…

作者头像 李华