1 前言
这一节来看看S32K3的PMC(Power Management Controller)和MC_RGM(Reset Generation Module)。其中PMC提供了电压检测机制,当电源输入电压高于或者低于正常工作电压,那么就会触发一个中断,如果电压再低,就触发复位。而MC_RGM是K3的复位管理器,控制着K3的复位时序,让S32K3进行破坏性复位和功能性复位,在复位前会记录复位的详细原因,在复位之后可被读出。
2 PMC的电压检测
2.1 简介
S32K3有三种电源检测机制,分别是LVR,LVD和HVD,其功能主要如下:
- LVR:低于一个域值后,复位
- LVD:低于一个域值后,产生中断
- HVD:高于一个域值后,产生中断
首先LVR触发复位是默认使能的,LVD和HVD触发中断则是可以配置使能或者使能。这里需要注意的是,LVR,LVD和HVD触发的复位不会记录在MC_RGM模块中,而是记录在PMC->LVSC寄存器中。
2.2 MCAL配置
PMC相关功能在MCAL中被集成到了Mcu模块中,首先需要配置相关的callback函数如下:
这里需要注意的是,图中得PMC错误callback函数不仅仅是在PMC的HVD和LVD事件发生后触发中断被调用,相关复位源触发中断MC_RGM的也会调用这个Callback函数,进入standy模式前发现正在有Flash操作也会调用,具体可由该函数的传参来判断,如下:
void McuErrorIsrNotification(uint8 u8ErrorCode)//McuErrorIsrNotification
{
if(u8ErrorCode == POWER_IP_E_ISR_VOLTAGE_ERROR)
{
//HVD,LVD事件
}
if((u8ErrorCode == POWER_IP_E_ISR_FUNC_RESET_ALT_FAILURE)||(u8ErrorCode == POWER_IP_E_ISR_FUNC_RESET_ALT_FAILURE) )
{
//MC_RGM Function复位源触发
}
if(u8ErrorCode == POWER_IP_E_FLASH_HV_OPERATION_ONGOING)
{
//进入Standy模式前发现Last-mile配置错误或者发现正在有flash操作
}
else
{
while(1);
}
return;
}
void McuPerformResetCallout(void)//McuPerformResetCallout
{
//调用Mcu_PerformReset()软件复位函数的callback
}
void McuPmcNotification(uint8 u8ErrorCode)//McuPmcNotification
{
if(u8ErrorCode == POWER_IP_LAST_MILE_REGULATOR_DISABLED)
{
//进入standy模式前发现Last-mile使能了
}
}
随后使能HVD,LVD中断,如下:
最后再去Platform模块中使能PMC的中断以及注册中断服务函数:
这样关于PMC的HVD,LVD就配置完了。
3 MC_RGM
3.1 简介
MC_RGM是S32K3的复位管理,它在S32K3的整个功能安全下有着至关重要的作用,因为大多数错误都是需要通过复位来消除的,在前面的文章已经很多次提到它,基本上大多数模块的触发复位信号都会被发送到MC_RGM模块,然后由MC_RGM执行整个MCU的复位操作。MC_RGM支持两种复位类型,功能性复位(Functional reset)和(Destructive sequence)。
可以触发Functional reset的复位源如下:
可以触发Destructive reset的复位源如下:
在表中有两个词可能不太容易理解,分别是Demotable to IRQ和Escalation,那这两个功能代表什么意思呢?
- Demotable to IRQ
有一些可以触发Functional reset的复位源,可以将其配置为不触发Functional reset,而是转而去触发一个中断。表中Yes的意思就代表着这个复位源可以被配置成触发成中断。 - Escalation
Escalation类似一个复位计数功能,可以对Functional reset和Destructive reset分别预先设置个阈值FRET和DRET,然后K3每执行一次Functional复位或者Destructive复位,Functional复位或Destructive复位所对应的计数器就会加1。
如果Functional reset复位的次数超过阈值FRET,则会直接会触发一次Destructive reset。如果Destructive reset复位的次数超过阈值DRET,则会让K3卡在DEST0状态(就是处于复位状态,CPU不会运行)中,直到下一次的Power-On事件发生,一切从来。
当然这两个复位次数计数器是可以手动清零的,在目前RTD的驱动代码中,只有Power-On才会清零Destructive复位次数计数器,而每发生一次破坏性复位,都会清零Functional复位次数计数器。
3.2 MCAL配置
MC_RGM的相关功能在MCAL中被集成到了Mcu模块中,如下:
其中如果FRET和DRET设置的值为0,则Escalation功能则不使能。如果你选择了一些复位源去触发中断的话,那么还需要使能下面选项:
除此之外,还需要去Platform模块中使能MC_RGM的中断,以及注册MC_RGM中断服务函数MC_RGM_ResetAlt_IRQHandler,这个功能相信用的人不多,在这里就不详细截图做介绍了。
另外还有一个函数需要提一下,那就是复位后可通过函数Mcu_GetResetReason来获取上次导致MCU的复位源:
typedef enum
{
/* 'Destructive' Event Status Register (MC_RGM_DES) */
MCU_POWER_ON_RESET = McuConf_McuResetReasonConf_MCU_POWER_ON_RESET, /**< @brief Power on reset event. RGM_DES[F_DR0]. */
MCU_FCCU_FTR_RESET = McuConf_McuResetReasonConf_MCU_FCCU_FTR_RESET, /**< @brief Non-critical supply presence detector fail. RGM_DES[F_DR1]. */
MCU_STCU_URF_RESET = McuConf_McuResetReasonConf_MCU_STCU_URF_RESET, /**< @brief FCCU failure to react. RGM_DES[F_DR3]. */
MCU_MC_RGM_FRE_RESET = McuConf_McuResetReasonConf_MCU_MC_RGM_FRE_RESET, /**< @brief STCU unrecoverable fault. RGM_DES[F_DR4]. */
MCU_FXOSC_FAIL_RESET = McuConf_McuResetReasonConf_MCU_FXOSC_FAIL_RESET, /**< @brief Functional reset escalation. RGM_DES[F_DR6]. */
MCU_PLL_LOL_RESET = McuConf_McuResetReasonConf_MCU_PLL_LOL_RESET, /**< @brief FXOSC failure. RGM_DES[F_DR8]. */
MCU_CORE_CLK_FAIL_RESET = McuConf_McuResetReasonConf_MCU_CORE_CLK_FAIL_RESET, /**< @brief CORE_PLL and related DFS loss of lock. RGM_DES[F_DR9]. */
MCU_AIPS_PLAT_CLK_FAIL_RESET = McuConf_McuResetReasonConf_MCU_AIPS_PLAT_CLK_FAIL_RESET, /**< @brief PERIPH_PLL and related DFS loss of lock. RGM_DES[F_DR10]. */
MCU_HSE_CLK_FAIL_RESET = McuConf_McuResetReasonConf_MCU_HSE_CLK_FAIL_RESET, /**< @brief DDR_PLL loss of lock. RGM_DES[F_DR11]. */
MCU_SYS_DIV_FAIL_RESET = McuConf_McuResetReasonConf_MCU_SYS_DIV_FAIL_RESET, /**< @brief ACCEL_PLL loss of lock. RGM_DES[F_DR12]. */
MCU_HSE_TMPR_RST_RESET = McuConf_McuResetReasonConf_MCU_HSE_TMPR_RST_RESET, /**< @brief XBAR_DIV3_CLK failure. RGM_DES[F_DR13]. */
MCU_HSE_SNVS_RST_RESET = McuConf_McuResetReasonConf_MCU_HSE_SNVS_RST_RESET, /**< @brief Life-cycle error. RGM_DES[F_DR16]. */
MCU_SW_DEST_RESET = McuConf_McuResetReasonConf_MCU_SW_DEST_RESET, /**< @brief HSE SNVS tamper detected. RGM_DES[F_DR17]. */
MCU_DEBUG_DEST_RESET = McuConf_McuResetReasonConf_MCU_DEBUG_DEST_RESET, /**< @brief HSE SWT timeout. RGM_DES[F_DR18]. */
/* 'Functional' Event Status Register (MC_RGM_FES) */
MCU_F_EXR_RESET = McuConf_McuResetReasonConf_MCU_F_EXR_RESET, /**< @brief Software destructive reset. RGM_DES[F_DR30]. */
MCU_FCCU_RST_RESET = McuConf_McuResetReasonConf_MCU_FCCU_RST_RESET, /**< @brief FCCU Reset Reaction. RGM_FES[F_FR3]. */
MCU_ST_DONE_RESET = McuConf_McuResetReasonConf_MCU_ST_DONE_RESET, /**< @brief Self-Test Done. RGM_FES[F_FR4]. */
MCU_SWT0_RST_RESET = McuConf_McuResetReasonConf_MCU_SWT0_RST_RESET, /**< @brief SWT0 Timeout. RGM_FES[F_FR6]. */
MCU_SWT1_RST_RESET = McuConf_McuResetReasonConf_MCU_SWT1_RST_RESET, /**< @brief SWT1 Timeout. RGM_FES[F_FR6]. */
MCU_JTAG_RST_RESET = McuConf_McuResetReasonConf_MCU_JTAG_RST_RESET, /**< @brief HSE Memory ECC Error. RGM_FES[F_FR18]. */
MCU_HSE_SWT_RST_RESET = McuConf_McuResetReasonConf_MCU_HSE_SWT_RST_RESET, /**< @brief HSE Boot Failure Error. RGM_FES[F_FR20]. */
MCU_HSE_BOOT_RST_RESET = McuConf_McuResetReasonConf_MCU_HSE_BOOT_RST_RESET, /**< @brief HSE M7 Core Lock. RGM_FES[F_FR21]. */
MCU_SW_FUNC_RESET = McuConf_McuResetReasonConf_MCU_SW_FUNC_RESET, /**< @brief Software functional reset. RGM_FES[F_FR30]. */
MCU_DEBUG_FUNC_RESET = McuConf_McuResetReasonConf_MCU_DEBUG_FUNC_RESET, /**< @brief Debug functional reset. RGM_FES[F_FR31]. */
MCU_WAKEUP_REASON = McuConf_McuResetReasonConf_MCU_WAKEUP_REASON, /**< @brief Wake-up event detected. */
MCU_NO_RESET_REASON = McuConf_McuResetReasonConf_MCU_NO_RESET_REASON, /**< @brief No reset reason found */
MCU_MULTIPLE_RESET_REASON = McuConf_McuResetReasonConf_MCU_MULTIPLE_RESET_REASON, /**< @brief More than one reset events are logged except "Power on event" */
MCU_RESET_UNDEFINED = McuConf_McuResetReasonConf_MCU_RESET_UNDEFINED /**< @brief Undefined reset source. */
} Power_Ip_ResetType;
Mcu_ResetType Mcu_GetResetReason(void);
//另外如果使用此函数不利于调试,也可直接去读取寄存器FES和DES的值