I.MX RT1170双核学习(1):双核通信之MU消息单元详解

在I.MX RT1170中,它有CM7和CM4核,而消息单元(MU)模块使SoC内的两个处理器能够通过MU接口传递消息以进行通信和协调。

文章目录

  • 1 MU特性
  • 2 功能描述
  • 3 MU通信实例
    • 3.1 轮训实现多核通信
      • 3.1.1 MU_SetFlags和MU_GetFlags
      • 3.1.2 MU_SendMsg和MU_ReceiveMsg
      • 3.1.3 调试从核注意事项
    • 3.2 中断实现多核通信

1 MU特性

MU包括以下特性:

  • 通过中断或轮询进行的消息控制
    • 中断也可用于从低功耗模式唤醒另一处理器
    • 允许一个处理器使用中断向另一个处理器发出信号
  • 对称的处理器接口,每一侧支持以下功能:
    • 四个通用中断请求,在另一核中反映
    • 三个通用标志,在另一核中反映
    • 四个带有可屏蔽中断的接收寄存器
    • 四个带有可屏蔽中断的发送寄存器
  • 由于CM7和CM4可能使用不同的时钟,MU需要确保在传递消息时两侧的访问是同步的,以避免数据传输或通信中的时序问题。
    • MU通过使用两组对应的寄存器来实现这种同步,以确保消息的正确传递和处理。
      在这里插入图片描述

2 功能描述

主要特性描述描述
处理器间中断CM7和CM4各有12个中断源,用于向另一处理器发出信号。这些中断可用于RX/TX事件的通知和处理器间的通用信号。
MU复位处理器A可通过其对应的控制寄存器(ACR)中的控制位(MUR)对整个MU进行复位。MUR位是自清零位。
核间状态和控制通信MU提供了一种方式,使两个核能够使用两个处理器的状态和控制寄存器进行通信。一个核的状态寄存器反映了另一个核的状态。控制寄存器用于控制操作,例如启用中断和向另一处理器发送中断。
核间同步消息传输通过同步机制更新两个核各自的传输和接收满标志实现。注意更新其中一个核的寄存器后,被另一个核接收到的过程存在延迟。
直接访问共享内存和避免冲突MU在两个核都提供了4个传输寄存器和4个接收寄存器。同时,两个核可以直接访问SoC的共享内存资源。为了访问共享内存的冲突(互斥),可以使用MU的中断和传输接收寄存器解决这个问题。
支持双核不同频率的时钟MU模块的核心是事件控制机制,MU制定了事件更新延迟,用于同步MU两侧的访问,因为两个核可以使用不同的时钟。
内存映射寄存器MU连接在双核各自的外设总线上

3 MU通信实例

MU向双核都提供了32位的状态和控制寄存器,用于控制操作(如中断、复位)以及检查另一侧的状态。对于消息传递,MU在两个处理器都提供了4个32位的只写传输寄存器和4个32位的只读接收寄存器。这些寄存器用于彼此发送消息,它们可以使用MU任一侧的控制和状态寄存器中提供的3个通用标志位进行控制。

通过MU,一个核可以传递一个32位的消息给另一个核,同时触发对方的中断。MU支持4个双向的通道:
在这里插入图片描述
下面通过SDK中的代码来看一下MU模块如何使用

3.1 轮训实现多核通信

这里以SDK中的evkmimxrt1170_mu_polling_core为例进行分析,它实现以下功能:

  1. core 0通过MU模块以轮询模式向core 1发送消息。
  2. core 1通过轮询模式将消息回发给core 0。
  3. core 0通过轮询模式接收来自core 1发送的消息。

这里core 0为CM7(主核),core 1为CM4(从核)。主核使用的MU模块成为MUA,从核使用的MU模块为MUB。

主从核实现:

下面一步步分析一下主从核代码的执行过程。

3.1.1 MU_SetFlags和MU_GetFlags

先来看一下初始化过程:

主核代码流程从核代码流程
初始化主核MU时钟:MU_Init(MUA)-
从CM7启动CM4核:设置向量表,复位等:APP_BootCore1()-
等待从核准备好:while (BOOT_FLAG != MU_GetFlags(MUA))初始化从核MU时钟:MU_Init(MUB)
-设置主核Flag指示从核已经运行:MU_SetFlags(MUB, BOOT_FLAG);

MU_SetFlags

这里主核在启动从核后等待从核置位,而从核启动后则调用MU_SetFlags置位。下面来看一下这个函数:

void MU_SetFlags(MU_Type *base, uint32_t flags)
{while (0U != (base->SR & ((uint32_t)MU_SR_FUP_MASK))){}MU_SetFlagsNonBlocking(base, flags);
}static inline void MU_SetFlagsNonBlocking(MU_Type *base, uint32_t flags)
{uint32_t reg = base->CR;reg          = (reg & ~((MU_CR_GIRn_MASK | MU_CR_NMI_MASK) | MU_CR_Fn_MASK)) | MU_CR_Fn(flags);base->CR     = reg;
}

先来看一下最终调用的MU_SetFlagsNonBlocking函数:

#define MU_CR_GIRn_MASK                          (0xF0000U)
#define MU_CR_NMI_MASK                           0U
#define MU_CR_Fn_MASK                            (0x7U)
#define MU_CR_Fn(x)                              (((uint32_t)(((uint32_t)(x)) << 0)) & 7)
static inline void MU_SetFlagsNonBlocking(MU_Type *base, uint32_t flags)
{uint32_t reg = base->CR;reg          = (reg & ~((MU_CR_GIRn_MASK | MU_CR_NMI_MASK) | MU_CR_Fn_MASK)) | MU_CR_Fn(flags);base->CR     = reg;
}

这里将GIRnFn的位都清零了,然后根据flag的值再置Fn的位:

在这里插入图片描述

可以看到GIRn是用于中断通知MUA的,这里我们用的是轮询方式,所以清零。对于Fn位来说:

  • Fn的3位分别代表MUBMUA发送的不同标志
  • Fn位在MU重置(系统初始化或其它条件)的时候会清零,或者直接写000也能清零
  • MUA可以通过其SR寄存器的Fn位来获取MuB发送过来的标志

在这里插入图片描述

所以这里的MU_SetFlagsNonBlocking实际上就是置CR寄存器的Fn位。我们在程序中将其置为BOOT_FLAG,也就是三个标志位的最低位为1。

#define BOOT_FLAG 0x01U

另外在从核设置标志位之前,需要等待其MUB->SR寄存器的FUP标志位置0,来看一下这个位的定义:

在这里插入图片描述

也就是说如果之前MUB设置的标志位还没有update到MUA中,FUP为1,且此时修改CRFn位也是无效的,我们需要等待其自动清零后才能置标志位。

MU_GetFlags

#define MU_SR_Fn_MASK                            (0x7U)
#define MU_SR_Fn_SHIFT                           (0U)
static inline uint32_t MU_GetFlags(MU_Type *base)
{return (base->SR & MU_SR_Fn_MASK) >> MU_SR_Fn_SHIFT;
}

前面有提到MUA需要从SR寄存器的低三位获取MUB传来的标志位,这个函数就是获取SR的低三位。如果BOOT_FLAG相匹配,则程序继续往下执行。

3.1.2 MU_SendMsg和MU_ReceiveMsg

主核代码流程从核代码流程
发送消息给MUB:MU_SendMsg(MUA, kMU_MsgReg0, g_msgSend[i]);-
-接收MUA的消息:MU_ReceiveMsg(MUB, kMU_MsgReg0);
-回显收到的消息:MU_SendMsg(MUB, kMU_MsgReg0, g_msgRecv[i]);
MU_ReceiveMsg(MUA, kMU_MsgReg0);-

我们知道MU有4个双向的通信通道,这里就利用通道0进行主从核的通信:主核发从核收,然后从核回显信息给主核。

MU_SendMsg

void MU_SendMsg(MU_Type *base, uint32_t regIndex, uint32_t msg)
{while (0U == (base->SR & (((uint32_t)kMU_Tx0EmptyFlag) >> regIndex))){}base->TR[regIndex] = msg;
}typedef enum _mu_msg_reg_index  //regIndex的取值,对应4个通道
{kMU_MsgReg0 = 0,kMU_MsgReg1,kMU_MsgReg2,kMU_MsgReg3,
} mu_msg_reg_index_t;

发送之前我们需要等待对应MUSR寄存器的[23:20]位的TEn(发送寄存器空)标志,四个位就对应四个通道。当消息发送到另一核后,该位会置0,当该位置1时,表示我们可以继续发送数据了。

在这里插入图片描述

  • 上图为MUA寄存器的说明,MUB类似

接着我们只要将数据写入TR寄存器即可,四个通道各有一个32位的TR寄存器:

在这里插入图片描述

来看一下MUA中的TR0寄存器的说明,TR1~TR3类似:

在这里插入图片描述

  • 写入MUATR0寄存器的数据会反映在MUBRR0中,这些寄存器都不是双缓冲的,所以数据会覆盖
  • TR0会清除MUASR中的TE0位,并置MUBSR中的RF0(接收满)位
  • TR0寄存器的任何写操作都将更新所有状态信息。

MU_ReceiveMsg

uint32_t MU_ReceiveMsg(MU_Type *base, uint32_t regIndex)
{while (0U == (base->SR & (((uint32_t)kMU_Rx0FullFlag) >> regIndex))){}return base->RR[regIndex];
}

前面有提到,MUA发来数据后,会置MUBSR中的RF0(接收满)位。

在这里插入图片描述

所以我们等待RF0位被置位,然后获取消息即可。消息从RR寄存器获取,同样地,四个寄存器对应四个通道:

在这里插入图片描述

其中RR0寄存器的描述如下:

在这里插入图片描述

3.1.3 调试从核注意事项

  • 这篇文章就不说明如何调试双核了,后面我会写一篇文章来讲解。

这里主要是双核调试有一个问题:我们通常首先启动主核,初始化系统,然后启动次核运行。在同时调试双核的情况下,调试器会启动次核。然后,在主核初始化尚未完成的情况下,次核可能会提前开始运行。

这里,我们使用RT1170的SRC(System Reset Controller)中的GPR(General Purpose Register)指示从核是否可以运行。如下图所示,这个寄存器对双核都可见,除了第0,1,2,3,4,9个GPR被ROM BootLoader使用外,其它的我们可以用来设置标志位,这里我们使用GPR20

在这里插入图片描述

次核在启动时应检查并等待SRC->GPR中的标志,主核在其初始化工作完成时在SRC->GPR中设置该标志。

主核在启动从核后执行以下代码

#define BOARD_SECONDARY_CORE_GO_FLAG 0xa5a5a5a5u
#define BOARD_SECONDARY_CORE_SRC_GPR kSRC_GeneralPurposeRegister20SRC->GPR[BOARD_SECONDARY_CORE_SRC_GPR] = BOARD_SECONDARY_CORE_GO_FLAG;

从核在上电后执行以下代码

#define BOARD_SECONDARY_CORE_GO_FLAG 0xa5a5a5a5u
#define BOARD_SECONDARY_CORE_SRC_GPR kSRC_GeneralPurposeRegister20while (BOARD_SECONDARY_CORE_GO_FLAG != SRC->GPR[BOARD_SECONDARY_CORE_SRC_GPR]){}  // 等待主核置位
SRC->GPR[BOARD_SECONDARY_CORE_SRC_GPR] = 0x0; // 用完后恢复GPR20的初始值0,防止主从核软件复位后,从核又提前运行

3.2 中断实现多核通信

和刚刚轮询实现的功能一样,我们来学习一下如何使用中断来收发数据。
这里使用中断的方式实现与刚刚轮询代码一样的功能,整体代码类似,下面来梳理一下中断需要做的操作:

主核

1、使能中断

(1)NVIC使能

NVIC_EnableIRQ(MUA_IRQn);

(2)使能中断标志位:发送和接收中断

MU_EnableInterrupts(MUA, (kMU_Tx0EmptyInterruptEnable | kMU_Rx0FullInterruptEnable));

(3)发送和接收数据

我们打开发送空中断后,就调用MU_SendMsgNonBlockingMUB发送消息,等这次发送完毕后,再次进入发送空中断则调用MU_DisableInterrupts禁用发送空中断。

同样地,等从核MUB发来消息后,进入接收满中断,然后调用MU_ReceiveMsgNonBlocking接收数据,等下次接收满时调用MU_DisableInterrupts关闭接收满中断。

#define MSG_LENGTH 32U
void APP_MU_IRQHandler(void)
{uint32_t flag = 0;flag = MU_GetStatusFlags(MUA);if ((flag & kMU_Tx0EmptyFlag) == kMU_Tx0EmptyFlag){if (g_curSend < MSG_LENGTH){MU_SendMsgNonBlocking(MUA, kMU_MsgReg0, g_msgSend[g_curSend++]);}else{MU_DisableInterrupts(MUA, kMU_Tx0EmptyInterruptEnable);}}if ((flag & kMU_Rx0FullFlag) == kMU_Rx0FullFlag){if (g_curRecv < MSG_LENGTH){g_msgRecv[g_curRecv++] = MU_ReceiveMsgNonBlocking(MUA, kMU_MsgReg0);}else{MU_DisableInterrupts(MUA, kMU_Rx0FullInterruptEnable);}}SDK_ISR_EXIT_BARRIER;
}

从核

整体流程和轮询代码一致,另外和主核一样要打开对应的中断,现在来看看MUB的中断回调函数:

void APP_MU_IRQHandler(void)
{uint32_t flag = 0;flag = MU_GetStatusFlags(APP_MU);if ((flag & kMU_Rx0FullFlag) == kMU_Rx0FullFlag){if (g_curRecv < MSG_LENGTH){g_msgRecv[g_curRecv++] = MU_ReceiveMsgNonBlocking(MUB, kMU_MsgReg0);}else{MU_DisableInterrupts(MUB, kMU_Rx0FullInterruptEnable);}}if (((flag & kMU_Tx0EmptyFlag) == kMU_Tx0EmptyFlag) && (g_curRecv == MSG_LENGTH)){if (g_curSend < MSG_LENGTH){MU_SendMsgNonBlocking(MUB, kMU_MsgReg0, g_msgRecv[g_curSend++]);}else{MU_DisableInterrupts(MUB, kMU_Tx0EmptyInterruptEnable);}}SDK_ISR_EXIT_BARRIER;
}

同样地在使能发送空中断后,这里的中断就一直会被调用,但是这里的发送空分支中还判断了(g_curRecv == MSG_LENGTH),也就是MUB接收了MUA发送的完整的MSG_LENGTH(32)字节才允许进入这个分支,进入后将收到的数据回显给MUA,然后在下一次进入发送空中断时关闭中断。

对于接收满中断来说一样,收到MSG_LENGTH字节后,在下一次进入中断时关闭接收满中断。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/217483.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

路由基本原理

目录 一、路由器概述 二、路由器的工作原理 三、路由表的形成 四、路由配置 1.连接设备 2.进入系统模式 3.进入接口模式 4.配置网络 5.下一跳的设置 6.设置浮动路由 7.设置默认路由 一、路由器概述 路由器&#xff08;Router&#xff09;是一种用于连接不同网络或子…

django实现增删改查分页接口

django实现增删改查分页接口(小白必备) 在上篇文章中我使用nodejs实现了增删改查分页接口&#xff0c;这一篇我们则使用django实现。 1.创建一个django项目&#xff0c;命令如下 python manage.py startapp myapp 2.在你自己的myapp文件夹中的models.py中定义你们自己的模型 f…

看图识药,python开发实现基于VisionTransformer的119种中草药图像识别系统

中药药材图像识别相关的实践在前面的系列博文中已经有了相应的实践了&#xff0c;感兴趣的话可以自行移步阅读即可&#xff0c;每篇文章的侧重点不同&#xff1a; 《python基于轻量级GhostNet模型开发构建23种常见中草药图像识别系统》 《基于轻量级MnasNet模型开发构建40种常…

Kafka系列之:统计kafka集群Topic的分区数和副本数,批量增加topic副本数

Kafka系列之:统计kafka集群Topic的分区数和副本数,批量增加topic副本数 一、创建KafkaAdminClient二、获取kafka集群topic元信息三、获取每个topic的名称、分区数、副本数四、生成增加topic副本的json文件五、执行增加topic副本的命令六、确认topic增加副本是否成功一、创建K…

Linux——基本指令(二)

​ 个人主页&#xff1a;日刷百题 系列专栏&#xff1a;〖C语言小游戏〗〖Linux〗〖数据结构〗 〖C语言〗 &#x1f30e;欢迎各位→点赞&#x1f44d;收藏⭐️留言&#x1f4dd; ​ ​ 写在前面&#xff1a; 紧接上一章&#xff0c;我们在理解接下来的命令之前&#xff0c…

Baumer工业相机堡盟工业相机如何通过BGAPISDK获取相机的各种信息如SN/ID等等(C#)

Baumer工业相机堡盟工业相机如何通过BGAPISDK获取相机的各种信息如SN/ID等等&#xff08;C#&#xff09; Baumer工业相机Baumer工业相机通过SDK获取相关生产信息的技术背景通过SDK获取相机信息的代码分析获取Baumer工业相机相关信息Baumer工业相机相关参数信息获取的测试 Baume…

【EventBus】EventBus源码浅析

二、EventBus源码解析 目录 1、EventBus的构造方法2、订阅者注册 2.1 订阅者方法的查找过程2.2 订阅者的注册过程1. subscriptionsByEventType 映射&#xff1a;2. typesBySubscriber 映射&#xff1a;2.3 总结订阅者的注册过程 3、事件的发送 3.1 使用Post提交事件3.2 使用p…

Axure的使用

1.Axure是什么&#xff1f;&#xff1f;&#xff1f; Axure是一款功能强大的原型设计工具&#xff0c;它可以让用户快速地创建交互式原型&#xff0c;并针对原型进行测试和改进。Axure的主要特点包括可定制的界面元素库、交互动画效果、条件逻辑、团队协作等功能&#xff0c;适…

day02、数据库系统的结构抽象与演变

数据库系统的结构抽象与演变 1、数据库系统的标准结构1.1 分层抽象1.2 数据视图与模式1. 3 三级模式与两层映像是数据系统的标准结构1.4 逻辑独立性与物理独立性 2 数据模型、数据、模式三者区别3. 文件系统到数据库&#xff08;数据的不可再分特性&#xff0c;我们将他称为第一…

python:五种算法(SSA、WOA、GWO、PSO、GA)求解23个测试函数(python代码)

一、五种算法简介 1、麻雀搜索算法SSA 2、鲸鱼优化算法WOA 3、灰狼优化算法GWO 4、粒子群优化算法PSO 5、遗传算法GA 二、5种算法求解23个函数 &#xff08;1&#xff09;23个函数简介 参考文献&#xff1a; [1] Yao X, Liu Y, Lin G M. Evolutionary programming made…

在做题中学习(32):只出现一次的数字 III

260. 只出现一次的数字 III - 力扣&#xff08;LeetCode&#xff09; 根据题目可知&#xff1a;有两个元素只出现一次&#xff0c;其余出现两次。 而在只出现一次的数字 I 里&#xff0c;只有一个元素出现一次&#xff0c;可以用异或的方式直接得到最后的答案&#xff0c;而此…

(C++)长度最小的子数组--滑动窗口

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能&#xff0c;轻松拿下世界 IT 名企 Dream Offer。https://le…

智能优化算法应用:基于鸟群算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于鸟群算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于鸟群算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.鸟群算法4.实验参数设定5.算法结果6.参考文献7.MA…

时间序列预测 — CNN-LSTM实现多变量多步光伏预测(Tensorflow)

目录 1 数据处理 1.1 导入库文件 1.2 导入数据集 1.3 缺失值分析 2 构造训练数据 ​3 模型训练 3.1 CNN-LSTM网络 3.2 模型训练 4 模型预测 专栏链接&#xff1a;https://blog.csdn.net/qq_41921826/category_12495091.html 1 数据处理 1.1 导入库文件 import scip…

【华为数据之道学习笔记】4-1信息架构的四个组件

企业在运作过程中&#xff0c;首先需要管理好人和物等“资源”&#xff0c;然后管理好各类资源之间的联系&#xff0c;即各类业务交易“事件”&#xff0c;再对各类事件的执行效果进行“整体描述和评估”&#xff0c;最终实现组织目标和价值。以一个通用的工业企业运营为例&…

[NAND Flash 3.2] 3D NAND 工艺与发展前沿

依公知及经验整理&#xff0c;原创保护&#xff0c;禁止转载。 专栏 《深入理解NAND Flash》 全文 6200 字&#xff0c;​2023.12.12 更新 1. 导论 1.1 何为 3D NAND? 3D NAND, 也叫做 Sumsung V-NAND, 是一种高密度闪存。 以前&#xff0c;把NAND闪存颗粒&#xff0c;直接…

Java键值对Pair的使用方式和操作流程

Java键值对Pair的使用方式和操作流程 什么是键值对 键值对是一种常见的数据结构&#xff0c;它由一个唯一的键&#xff08;key&#xff09;和与之关联的值&#xff08;value&#xff09;组成。键和值之间存在一种映射关系&#xff0c;通过键可以查找或访问对应的值。 在键值对…

nodejs微信小程序+python+PHP健身服务应用APP-计算机毕业设计推荐 android

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

『App自动化测试之Appium基础篇』| Desired Capabilities详解与使用

App自动化测试之Appium基础篇』| Desired Capabilities详解与使用 1 关于appium driver2 安装appium driver3 安装Appium Python Client4 安装测试对象5 获取测试对象信息5.1 使用dumpsys5.2 使用AndroidKiller5.3 使用aapt 6 Capabilities详解6.1 Capabilities介绍6.2 automat…

复旦微在线调试DDR

模式介绍 Jtag模式 Jtag模式用于在线调试&#xff0c;烧写&#xff0c;红色箭头所示拨码开关&#xff0c;拨上为jtag模式 Qspi模式 Qspi模式用于独立运行&#xff0c;红色箭头所示拨码开关&#xff0c;拨下为Qspi模式 级联模式 当PL侧代码不用修改时可以用级联模式&#xff0c…