当前位置: 首页 > news >正文

做网站设计抬头溧水区住房和城乡建设厅网站

做网站设计抬头,溧水区住房和城乡建设厅网站,网站建设那种语言好,网站建设调查本文通过SDK中最简单的hello_world例程来说明一下双核程序如何运行。在CM7和CM4的工程中都有一个MCMGR(Multicore Manager)文件夹#xff0c;它是用来管理多核之间的操作的#xff0c;当然也包括我们前面提到的那些寄存器的设置。 文章目录 1 MCMGR_EarlyInit1.1 MCMGR_Trigg…本文通过SDK中最简单的hello_world例程来说明一下双核程序如何运行。在CM7和CM4的工程中都有一个MCMGR(Multicore Manager)文件夹它是用来管理多核之间的操作的当然也包括我们前面提到的那些寄存器的设置。 文章目录 1 MCMGR_EarlyInit1.1 MCMGR_TriggerEvent 2 MCMGR_Init函数2.1 MCMGR_RegisterEvent函数2.2 事件回调函数2.3 mcmgr_late_init_internal 3 MCMGR_StartCore函数4 MCMGR_GetStartupData函数5 MU中断接收函数6 双核状态机交互过程详解7 总结 我们现在就以CM7核激活CM4核为例先分析一下CM7核的代码。实际上在CM7的例程中就调用了 MCMGR_EarlyInit、 MCMGR_Init和 MCMGR_StartCore三个函数就能启动M4核了。下面就来分析一下这三个函数 1 MCMGR_EarlyInit 无论是CM7还是CM4都需要调用这个函数它是用来初始化底层的多核管理库(MCMGR)的这个函数应该尽可能在reset_handler附近调用表示某个核已经启动并准备好执行任务。在这里这个函数在ResetISR-SystemInit中就调用了。这个函数最终调用的是mcmgr_early_init_internal mcmgr_status_t mcmgr_early_init_internal(mcmgr_core_t coreNum) {MU_Init(MUA); //实际上就是使能MU的时钟(M7核初始化MUA,M4核这里的参数为MUB)return MCMGR_TriggerEvent(kMCMGR_RemoteCoreUpEvent, 0); }1.1 MCMGR_TriggerEvent MCMGR_TriggerEvent函数实际上调用的是MCMGR_TriggerEventCommon mcmgr_status_t MCMGR_TriggerEvent(mcmgr_event_type_t type, uint16_t eventData) {return MCMGR_TriggerEventCommon(type, eventData, false); }所以来看一下MCMGR_TriggerEventCommon函数 /*! brief Type definition of event types. */ typedef enum _mcmgr_event_type_t {kMCMGR_RemoteCoreUpEvent 1,kMCMGR_RemoteCoreDownEvent,kMCMGR_RemoteExceptionEvent,kMCMGR_StartupDataEvent,kMCMGR_FeedStartupDataEvent,kMCMGR_RemoteRPMsgEvent,kMCMGR_RemoteApplicationEvent,kMCMGR_FreeRtosMessageBuffersEvent,kMCMGR_EventTableLength } mcmgr_event_type_t;static mcmgr_status_t MCMGR_TriggerEventCommon(mcmgr_event_type_t type, uint16_t eventData, bool forcedWrite) {uint32_t remoteData;remoteData (((uint32_t)type) 16) | eventData;return mcmgr_trigger_event_internal(remoteData, forcedWrite); }接着看一下mcmgr_trigger_event_internal函数 /* MCMGR MU channel index - used for passing startupData */ #define MCMGR_MU_CHANNEL 3mcmgr_status_t mcmgr_trigger_event_internal(uint32_t remoteData, bool forcedWrite) {/* When forcedWrite is false, execute the blocking call, i.e. wait until previouslysent data is processed. Otherwise, run the non-blocking version of the MU send function. */if (false forcedWrite){MU_SendMsg(MUA, MCMGR_MU_CHANNEL, remoteData);// M7执行这条,M4的第一个参数MUA换为MUB}else{MU_SendMsgNonBlocking(MUA, MCMGR_MU_CHANNEL, remoteData);// M7执行这条,M4的第一个参数MUA换为MUB}return kStatus_MCMGR_Success; }这里的forcedWrite参数为false的时候执行阻塞写函数等待上一次发送的数据处理完了才发送forcedWrite参数为true时直接往寄存器中写数据这个函数最好搭配中断使用。 从上面我们知道mcmgr_early_init_internal实际上就是通过自己核对应的MU的通道3发送一个组合的32位数(高16位为type低16位为eventData这里type为kMCMGR_RemoteCoreUpEventeventData为0)给对方核对应的MU的通道3。 如果不知道MU的建议看一下我之前介绍MU的文章双核通信之MU消息单元详解 2 MCMGR_Init函数 接着就是调用MCMGR_Init函数 mcmgr_status_t MCMGR_Init(void) {// 通过OCOTP熔丝相应位可以判断当前是CM4(返回0)还是CM7核(返回1)mcmgr_core_t coreNum MCMGR_GetCurrentCore();// 两个回调函数MCMGR_RegisterEvent(kMCMGR_StartupDataEvent, MCMGR_StartupDataEventHandler, (void *)s_mcmgrCoresContext[coreNum]);MCMGR_RegisterEvent(kMCMGR_FeedStartupDataEvent, MCMGR_FeedStartupDataEventHandler, (void *)s_mcmgrCoresContext[(coreNum 0) ? 1 : 0]);return mcmgr_late_init_internal(coreNum); }MCMGR_RegisterEvent用来注册某个事件(参数一)的回调函数(参数二)其中参数三s_mcmgrCoresContext会传给回调函数作为其参数供其使用它的定义如下 typedef struct _mcmgr_core_context {/*! brief Current state of the core. */mcmgr_core_state_t state;/*! brief Startup data, if state kMCMGR_RunningCoreState */uint32_t startupData; } mcmgr_core_context_t;/*! brief Type definition of possible core states. */ typedef enum _mcmgr_core_state {kMCMGR_ResetCoreState 0,kMCMGR_StartupGettingLowCoreState,kMCMGR_StartupGettingHighCoreState,kMCMGR_RunningCoreState, } mcmgr_core_state_t;volatile mcmgr_core_context_t s_mcmgrCoresContext[2] {{.state kMCMGR_ResetCoreState, .startupData 0}, {.state kMCMGR_ResetCoreState, .startupData 0}};看样子似乎是一个状态机其中 s_mcmgrCoresContext[0]用于kMCMGR_StartupDataEvent事件的MCMGR_StartupDataEventHandler回调 s_mcmgrCoresContext[1]用于kMCMGR_FeedStartupDataEvent事件的MCMGR_FeedStartupDataEventHandler回调 具体完成了什么我们后面用到了再分析。 2.1 MCMGR_RegisterEvent函数 顾名思义就是用来注册回调函数的实现也非常简单就是定义了一个结构体数组然后填充即可 /*! brief Type definition of structure with event handler and data. */ typedef struct _mcmgr_event {/*! brief Pointer to callback function. */mcmgr_event_callback_t callback;/*! brief Context data for callback. */void *callbackData; } mcmgr_event_t;mcmgr_event_t MCMGR_eventTable[kMCMGR_EventTableLength] {0};mcmgr_status_t MCMGR_RegisterEvent(mcmgr_event_type_t type, mcmgr_event_callback_t callback, void *callbackData) {if (type kMCMGR_EventTableLength){return kStatus_MCMGR_Error;}MCMGR_eventTable[type].callback ((void *)0);MCMGR_eventTable[type].callbackData callbackData;MCMGR_eventTable[type].callback callback;return kStatus_MCMGR_Success; }在mcmgr_event_type_t有8种事件每个事件占据MCMGR_eventTable数组的一个索引。 接下来看一下两个回调函数完成了什么 2.2 事件回调函数 下面来看一下MCMGR_StartupDataEventHandler和MCMGR_FeedStartupDataEventHandler static void MCMGR_StartupDataEventHandler(uint16_t startupDataChunk, void *context) {mcmgr_core_context_t *coreContext (mcmgr_core_context_t *)context;switch (coreContext-state){case kMCMGR_StartupGettingLowCoreState:coreContext-startupData startupDataChunk; /* Receive the low part */coreContext-state kMCMGR_StartupGettingHighCoreState;(void)MCMGR_TriggerEvent(kMCMGR_FeedStartupDataEvent, (uint16_t)kMCMGR_StartupGettingHighCoreState);break;case kMCMGR_StartupGettingHighCoreState:coreContext-startupData | ((uint32_t)startupDataChunk) 16;coreContext-state kMCMGR_RunningCoreState;(void)MCMGR_TriggerEvent(kMCMGR_FeedStartupDataEvent, (uint16_t)kMCMGR_RunningCoreState);break;default:break;} }static void MCMGR_FeedStartupDataEventHandler(uint16_t startupDataChunk, void *context) {mcmgr_core_context_t *coreContext (mcmgr_core_context_t *)context;switch ((mcmgr_core_state_t)startupDataChunk){case kMCMGR_StartupGettingLowCoreState:(void)MCMGR_TriggerEvent(kMCMGR_StartupDataEvent, (uint16_t)(coreContext-startupData 0xFFFFU));coreContext-state (mcmgr_core_state_t)startupDataChunk;break;case kMCMGR_StartupGettingHighCoreState:(void)MCMGR_TriggerEvent(kMCMGR_StartupDataEvent, (uint16_t)((coreContext-startupData) 16));coreContext-state (mcmgr_core_state_t)startupDataChunk;break;case kMCMGR_RunningCoreState:coreContext-state (mcmgr_core_state_t)startupDataChunk;break;default:break;} }这里的context就是前面注册回调函数时的第三个参数s_mcmgrCoresContext[0/1]前面我们看到默认的state为kMCMGR_ResetCoreState所以不会进入任何分支中具体初始状态在何时改变的我们后续分析。 我们看到这里两个Handler最后都是调用MCMGR_TriggerEvent函数即通过MU发送一个32位数给对方核。 2.3 mcmgr_late_init_internal MCMGR_Init最后调用mcmgr_late_init_internal打开MU的通道3的接收中断 (下面代码为CM7核的CM4核打开的是MUB) mcmgr_status_t mcmgr_late_init_internal(mcmgr_core_t coreNum) {MU_EnableInterrupts(MUA, (uint32_t)kMU_Rx3FullInterruptEnable);NVIC_SetPriority(MUA_IRQn, 2);NVIC_EnableIRQ(MUA_IRQn);return kStatus_MCMGR_Success; }在前面的MCMGR_TriggerEvent中最后也是使用通道3发送的消息所以在SDK中使用MU的通道3来完成双核执行的同步。 3 MCMGR_StartCore函数 对于CM7来说注册完回调函数之后还需要调用MCMGR_StartCore来启动CM4核。 MCMGR_StartCore(kMCMGR_Core1, (void *)(char *)CORE1_BOOT_ADDRESS, 2, kMCMGR_Start_Synchronous);具体实现如下 #define CORE1_BOOT_ADDRESS (void *)0x20200000 MCMGR_StartCore(kMCMGR_Core1, (void *)(char *)CORE1_BOOT_ADDRESS, 2, kMCMGR_Start_Synchronous); //kMCMGR_Core11mcmgr_status_t MCMGR_StartCore(mcmgr_core_t coreNum, void *bootAddress, uint32_t startupData, mcmgr_start_mode_t mode) {mcmgr_status_t ret;/* 填充startupData */s_mcmgrCoresContext[coreNum].startupData startupData;/* 设置相关寄存器 */ret mcmgr_start_core_internal(coreNum, bootAddress);if (mode kMCMGR_Start_Synchronous){/* 等待M4核读取和确认我们刚刚填充的startupData */while (s_mcmgrCoresContext[coreNum].state ! kMCMGR_RunningCoreState){}}return kStatus_MCMGR_Success; }这里假设我们将CM4的程序通过CM7的映射地址0x20200000拷贝到CM4的TCM中了如果CM4的程序在NOR Flash中填写对应的地址即可。 mcmgr_start_core_internal就是我们上一篇文章双核相互激活和启动流程提到的CM7激活CM4相关寄存器的修改 mcmgr_status_t mcmgr_start_core_internal(mcmgr_core_t coreNum, void *bootAddress) {IOMUXC_LPSR_GPR-GPR0 IOMUXC_LPSR_GPR_GPR0_CM4_INIT_VTOR_LOW(((uint32_t)(char *)bootAddress) 3u);IOMUXC_LPSR_GPR-GPR1 IOMUXC_LPSR_GPR_GPR1_CM4_INIT_VTOR_HIGH(((uint32_t)(char *)bootAddress) 16u);SRC-CTRL_M4CORE SRC_CTRL_M4CORE_SW_RESET_MASK;SRC-SCR | SRC_SCR_BT_RELEASE_M4_MASK;return kStatus_MCMGR_Success; }4 MCMGR_GetStartupData函数 在CM4核启动后会调用MCMGR_GetStartupData函数直到这个函数返回kStatus_MCMGR_Success do{status MCMGR_GetStartupData(startupData);} while (status ! kStatus_MCMGR_Success);现在来看一下这个函数 mcmgr_status_t MCMGR_GetStartupData(uint32_t *startupData) {if (s_mcmgrCoresContext[1].state kMCMGR_ResetCoreState){s_mcmgrCoresContext[1].state kMCMGR_StartupGettingLowCoreState;if (kStatus_MCMGR_Success !MCMGR_TriggerEvent(kMCMGR_FeedStartupDataEvent, (uint16_t)kMCMGR_StartupGettingLowCoreState)){return kStatus_MCMGR_Error;}}return mcmgr_get_startup_data_internal(1, startupData); }mcmgr_status_t mcmgr_get_startup_data_internal(mcmgr_core_t coreNum, uint32_t *startupData) {if (s_mcmgrCoresContext[1].state kMCMGR_RunningCoreState){*startupData s_mcmgrCoresContext[1].startupData;return kStatus_MCMGR_Success;}return kStatus_MCMGR_NotReady; }实际上也是和刚刚的状态机相关。 5 MU中断接收函数 现在我们对CM7和CM4的交互过程还是一头雾水前面注册的回调函数什么时刻被调用CM7启动CM4后等待s_mcmgrCoresContext[coreNum].state变为kMCMGR_RunningCoreState还有CM4启动后CM4也要等待状态变化再往下执行程序那么这些状态是在哪里被修改的呢下面就来分析一下这个过程。 前面我们打开了中断所以我们首先看一下中断处理回调函数在通道三收到数据后将调用此回调函数(下面为CM7核MUA的回调MUB的类似) void MU_Rx3FullFlagISR(void) {uint32_t data;uint16_t eventType;uint16_t eventData;#if defined(FSL_FEATURE_MU_SIDE_A)data MU_ReceiveMsgNonBlocking(MUA, 3); #elif defined(FSL_FEATURE_MU_SIDE_B)data MU_ReceiveMsgNonBlocking(MUB, 3); #endif/* To be MISRA compliant, return value needs to be checked even it could not never be 0 */if (0U ! data){eventType (uint16_t)(data 16u);eventData (uint16_t)(data 0x0000FFFFu);if (((mcmgr_event_type_t)eventType kMCMGR_RemoteCoreUpEvent) ((mcmgr_event_type_t)eventType kMCMGR_EventTableLength)){if (MCMGR_eventTable[(mcmgr_event_type_t)eventType].callback ! ((void *)0)){MCMGR_eventTable[(mcmgr_event_type_t)eventType].callback(eventData, MCMGR_eventTable[(mcmgr_event_type_t)eventType].callbackData);}}} }在理论上我们的程序中没有发送数据内容为0的代码但是为了符合MISRA规范这里还是检查了0U ! data。 前面在MCMGR_TriggerEvent中我们将type和event组合成一个32位的数发送给对方这里同样的我们收到数据后取出高16位的type和低16位的event。然后调用我们使用MCMGR_RegisterEvent注册的回调函数第一个参数为eventData第二个参数为我们注册的时候提供的callbackData(这里为s_mcmgrCoresContext)。 6 双核状态机交互过程详解 看完了中断函数后感觉两个核有一些联系了我们先来看一下两个核的执行流程 这些函数前面都分析过了但是里面状态机的状态改变似乎有些复杂而状态的改变是通过双核之间的通道3进行交互的这里我们就来捋清里面的流程 这里通道间发送数据为32位高16位为type低16位为eventData下面都表示为(type, eventData) 1、MCMGR_EarlyInit 发送32位数据(kMCMGR_RemoteCoreUpEvent,0)。由于后面我们在MCMGR_Init函数中并没有注册kMCMGR_RemoteCoreUpEvent的回调函数实际上这个消息会被忽略。 2、MCMGR_Init 这里没有发送任何数据但是注册了两个回调函数在回调函数中会发送数据 3、启动CM4MCMGR_StartCore s_mcmgrCoresContext[1].startupData 2; while (s_mcmgrCoresContext[1].state ! kMCMGR_RunningCoreState);这里CM7将s_mcmgrCoresContext[1]的startupData设置为了2然后等待s_mcmgrCoresContext[1]的state变为kMCMGR_RunningCoreState。 4、CM4和CM7消息同步 (1)CM4在MCMGR_GetStartupData中将s_mcmgrCoresContext[1]的state设置为了kMCMGR_StartupGettingLowCoreState然后向CM7发送(kMCMGR_FeedStartupDataEvent, kMCMGR_StartupGettingLowCoreState)。 (2)在CM7接收到这个32位消息后将进入MCMGR_FeedStartupDataEventHandler中向CM4发送(kMCMGR_StartupDataEvent, 2)然后将state设置为kMCMGR_StartupGettingLowCoreState。 case kMCMGR_StartupGettingLowCoreState:(void)MCMGR_TriggerEvent(kMCMGR_StartupDataEvent, (uint16_t)(coreContext-startupData 0xFFFFU));coreContext-state (mcmgr_core_state_t)startupDataChunk;break;此时双核的状态如下 (3)CM4收到(kMCMGR_StartupDataEvent, 0)进入MCMGR_StartupDataEventHandler的下面分支 case kMCMGR_StartupGettingLowCoreState:coreContext-startupData startupDataChunk; /* Receive the low part */coreContext-state kMCMGR_StartupGettingHighCoreState;(void)MCMGR_TriggerEvent(kMCMGR_FeedStartupDataEvent, (uint16_t)kMCMGR_StartupGettingHighCoreState);break;将startupData设置为2state设置为kMCMGR_StartupGettingHighCoreState然后发送(kMCMGR_FeedStartupDataEvent, kMCMGR_StartupGettingHighCoreState)给CM7。 (4)CM7收到(kMCMGR_FeedStartupDataEvent, kMCMGR_StartupGettingHighCoreState)进入MCMGR_FeedStartupDataEventHandler的下面分支 case kMCMGR_StartupGettingHighCoreState:(void)MCMGR_TriggerEvent(kMCMGR_StartupDataEvent, (uint16_t)((coreContext-startupData) 16));coreContext-state (mcmgr_core_state_t)startupDataChunk;break;这里发送(kMCMGR_StartupDataEvent, (uint16_t)(2 16))给CM4然后设置自身的state为kMCMGR_StartupGettingHighCoreState。 此时双核的状态如下 (5)CM4收到(kMCMGR_StartupDataEvent, 0)后进入MCMGR_StartupDataEventHandler的下面分支 case kMCMGR_StartupGettingHighCoreState:coreContext-startupData | ((uint32_t)startupDataChunk) 16;coreContext-state kMCMGR_RunningCoreState;(void)MCMGR_TriggerEvent(kMCMGR_FeedStartupDataEvent, (uint16_t)kMCMGR_RunningCoreState);break;将startupData与之前收到的低16位进行组合然后赋到startupData中即CM7在MCMGR_StartCore函数中的第三个参数传给了CM4。然后将state设置为kMCMGR_RunningCoreState并向CM7发送(kMCMGR_FeedStartupDataEvent, kMCMGR_RunningCoreState)。 (6)CM7收到(kMCMGR_FeedStartupDataEvent, kMCMGR_RunningCoreState)后进入MCMGR_FeedStartupDataEventHandler中的kMCMGR_RunningCoreState分支 case kMCMGR_RunningCoreState:coreContext-state (mcmgr_core_state_t)startupDataChunk;break;最终就将state设置为了kMCMGR_RunningCoreState。此时在MCMGR_StartCore中等待s_mcmgrCoresContext[1]的state变为kMCMGR_RunningCoreState则成立此时CM7知道CM4已经成功启动。 最终的状态如下 7 总结 从上面状态机分析可知CM7仅用了kMCMGR_FeedStartupDataEvent而CM4仅用了kMCMGR_StartupDataEvent。在CM4启动后先发送一个消息给CM7然后CM7开始传startupData给CM4最终CM7的状态都变为kMCMGR_RunningCoreState表示CM7知道CM4已经启动了就可以执行其它操作了。
http://www.zqtcl.cn/news/466183/

相关文章:

  • 天津深圳网站开发定制网络工程考研方向
  • 做app网站的公司哪家好济南网站建设市场
  • 自己做网站页面网站国内空间和国外空间
  • 桂城网站制作公司asp.net jsp 网站
  • 太原免费静态网页制作网站如何搭建钓鱼网站
  • 英语门户网站织梦源码修改wordpress登录页面
  • 网络建设和网站建设网站快速收录提交
  • 免费的建设网站软件北京电力交易中心谢开
  • 建设一个网站需要提供什么手续好看的美食网站设计
  • 西宁网站seo公司网站建设和维护释义
  • 建站平台有哪些免费一键搭建网站wordpress ent 主题
  • 国内比较大的源码网站营销型网站与普通网站的区别
  • 眼镜企业网站建设方案广州最新新闻
  • 茶业网站设计方案绍兴网站建设方案托管
  • 怎样免费建设网站网站建设规划书txt微盘
  • 邯郸网站设计培训做网站建设公司crm在线的培训服务
  • 网站建设文化案例萧山网页设计
  • 融安有那几个网站做的比较好的林州网站建设熊掌号
  • 织梦个人博客网站源码深圳华强北鬼市
  • 成都公司建站模板营销策略有哪些方面
  • 南京哪里做网站河北建设工程交易信息网
  • 广州开发网站设计拍摄宣传片
  • 小型企业网站设计教程深圳seo网站推广方案
  • 做视频网站怎么备案最新网站架构
  • 黄金网站app软件下载安装免费淘宝网页版登录
  • 幸运28网站建设网站返回指定位置怎么做
  • 建设个直播网站要多少钱兴业大街网站建设
  • 网站设计培训班创业上海今天新闻发布会直播
  • 电商网站制作设计wordpress jquery 无法
  • 关键词优化易下拉效率北京和隆优化科技