小猫爪:S32K3学习笔记15-S32K3之SEMA42和INTM
1 前言
这一节来看看S32K3上面的两个小东西,有之锦上添花,那就是SEMA42(Semaphores2)和INTM(Interrupt Monitor)。这两者之间并没有什么关联,只是这两个小东西内容比较少,所以我给放到了一起。
2 SEMA42
2.1 简介
SEMA42是建立在XRDC基础上的一个硬件信号量模块,如果要使用SEMA42,那么就一定需要使能XRDC。SEMA42是为了解决避免在多核系统中,多核同一时间访问共享资源混乱的问题而设计的硬件信号量机制,其机制也是及其的简单,其功能框图如下所示:
SEMA42一个有16个信号量通道,每一个通道都有一个叫做Gate的玩意,那这个Gate是可以被任何一个Domian的核通过软件来锁定的(这里的锁定指的是这个Gate只对当前Domain开放),一旦被锁住,那么其他Domian里面的核访问都会被这个Gate给截住,从而访问失败(Domain的含义可参考XRDC文章)。在这里一定要搞清楚的一点就是,SEMA42并不是针对不同的核设置的信号量,而是针对不同的Domian设置的信号量。所以如果将S32K324的M7_0和M7_1放在了同一个Domain,那么这个时候SEMA42是没有用的,该混乱还是会混乱。所以在配置XRDC的Domain的时候千万不要把两个核放在同一个Domian里面,傻子才会这么配。
注意:SEMA42只有在写访问申请的时候才会起作用,也就是说,就算共享资源被Domain0锁住,那么这个时候Domain1的Master是可以正常读的。但是为了数据同步,在进行软件设计时,一般都是只有获取到信号量后,才会进行接下来的读写操作。
2.2 MCAL配置
要使用SEMA42也是非常的简单,只需要在Rm模块中使能SEMA42,如下:
然后就可以在XRDC的Memory Config和Peripheral Config中为相关的共享资源(这里的共享资源指的可被不同Domain访问的外设和Memory)分配SEMA42通道,如下:
这样配置后,SEMA42的通道就和相应的外设和Memory区域绑定在了一起,当一个Master对共享资源发起写访问申请后,在DdACP评估阶段之前就会先查看这个时候共享资源的SEMA42通道的Gate是否其他Domain锁着,如果没有被其他Domain被锁着的话,就可以继续进行DdACP评估流程。
另外如果在这里没有配置SEMA42的话,有些特殊的外设也可以在其对应的模块来使能SEMA42,比如在Fls模块中,面对双核同时访问Flash的情况,就可以通过使能Fls Multi Core Syncronization Enable选项来使能SEMA42,如下:
这里需要注意的是,SEMA42通道的Gate的锁定和解锁都是通过软件来手动实现的,当然MCAL的驱动函数给你写好了,不用管。所以在规划多核软件时,访问共享资源时,都是先上锁,再访问,再解锁的形式来进行相关操作,另外也可以使用SEMA42来实现对一个虚拟资源的信号量控制。
MCAL为SEMA42提供了非常方便的CDD API接口,分别如下:
//获取信号量状态
Rm_Sema42_CoreType Rm_SemaphoreGetStatus(Rm_Sema42_ChannelType ChannelNumber);
//上锁,即获取信号量
Std_ReturnType Rm_SemaphoreLockGate(Rm_Sema42_ChannelType ChannelNumber);
//解锁,即释放信号量
Std_ReturnType Rm_SemaphoreUnlockGate(Rm_Sema42_ChannelType ChannelNumber);
//复位SEMA42的单个通道
void Rm_SemaphoreResetGate(Rm_Sema42_ChannelType ChannelNumber);
//复位SEMA42的所有通道
void Rm_SemaphoreResetAllGates(void);
3 INTM
3.1 简介
INTM其实就是一个专门监控中断响应的看门狗,主要监测的是一个中断从request到acknowledged的时间有没有超时,如果超时则会报告错误给FCCU模块。INTM总共有四个通道,即INTM最大可同时监测四个中断。INTM的功能框图如下:
工作机制也是非常简单,其流程如下:
- 配置 INTM_IRQSEL来选择触发INTM_TIMER开始计时的中断号
- 配置INTM_LATENCYa来规定超时时间
- 配置INTM_MM来使能INTM模块开始监控
- INTM检测到第1步配置的中断号对应的中断申请,INTM_TIMER开始计时
- 如果在第2步规定的时间内通过写INTM_IACK停止INTM_TIMER计时,则正常
- 如果没有在第2步规定的时间内停止INTM_TIMER,而导致超时,INTM_STATUS置位,INTM发送一个错误信号至FCCU模块
3.2 MCAL配置和代码处理
首先需要需要在Mcu模块中打开INTM的外设时钟:
INTM的配置在MCAL被集成到了Platform中, 如下:
然后对INTM通道进行配置,如下:
这里我选择让INTM0监控PIT0,所以需要在PIT0中断的callback函数里面调用函数Platform_AckIrq来停止INTM的Timer,如下:
void Gpt_Pit0_CH0_Notification(void)
{
volatile uint32_t cnt;
/* if INTM fault injection is enabled. */
if(INTMFaultInjectFlag > 0){
INTMFaultInjectFlag = 0;
/* delay some time to let INTM timeout occur. */
TestDelay(16000000);
}
/* writing INTM ACK register to clear the timeout timer. */
Platform_AckIrq(IntmChannel_0);
if ((Dio_LevelType)STD_LOW == LED0_RED_level)
{
LED0_RED_level = (Dio_LevelType)STD_HIGH;
}
else
{
LED0_RED_level = (Dio_LevelType)STD_LOW;
}
/* toggle LED D28 on White Board */
Dio_WriteChannel(DioConf_DioChannel_LED0_RED, LED0_RED_level);
return;
}
接下来就是代码里面的处理了,INTM检测到中断响应超时后会将错误发送给FCCU,所以我们需要在FCCU中进行处理,INTM占据的是FCCU通道是NCF6,如果使能了NCF6通道的Alarm中断,就可以在Alarm中添加相关处理代码如下:
eMcem_ErrRecoveryType eMcemUserAlarmHandler( eMcem_FaultType nFaultId )
{
uint32_t u32FccuFaults = 0;
uint32_t u32FaultAddr = 0;
/* read fault information */
eMcem_GetErrors( &faultContainer );
eMcem_Fccu_GetErrors( &u32FccuFaults, &u32FccuFaults );
/* Must clear faults in time (within 10ms after fault detected),
otherwise FCCU enters fault state and reset occurred. */
eMcem_ClearFaults( nFaultId );
/* print message showing execution of FCCU Alarm Handler. */
printf("FCCU alarm handler. FCCU_NCF=0x%X, Fault_ID=%d.\r\n", (unsigned int)u32FccuFaults, (unsigned int)nFaultId);
printf("faultContainer = 0x%08X, 0x%08X, 0x%08X. \r\n", (unsigned int)faultContainer.au32Faults[0], (unsigned int)faultContainer.au32Faults[1], (unsigned int)faultContainer.au32Faults[2]);
//...........
//...........
/* if it's NCF6 fault - INTM interrupt monitor error */
if(u32FccuFaults & FCCU_NCF_S_NCFS6_MASK)
{
eMcemUserIntmFaultHandler();//用户可根据自己进行相关处理
eMcem_ClearFaults( nFaultId );
return EMCEM_ERR_RECOVERED;
}
//...........
//...........
}