概述
本篇主要记录看门狗的使用。复位原因查看
《S32K1xx MCU Family Reference Manual》
S32K144使用记录(一)
S32K144使用记录(二)
二、看门狗
看门狗使用比较简单,相关的寄存器只有四个。
下面就结合驱动函数,对涉及的寄存器内容进行说明。每个寄存器的具体描述可以在手册中查看。
2.1 初始化
看门狗的初始化主要是解锁看门狗、设置时钟、设置超时值、使能看门狗。当前的初始化函数如下:
void WatchDogInitialize(void)
{
#if(WATCH_DOG_EANBLE)
RTOS_HalDisableScheduler();//disable interrupt
WDOG->CNT = 0xD928C520;//unlock watchdog
while((WDOG->CS&WDOG_CS_ULK_MASK)==0);//wait until register unlocked
WDOG->TOVAL = (500*1);//set timeout value is 1s
/****
clock 128K LPO
256 prescaler
*************/
WDOG->CS = WDOG_CS_EN(1)|WDOG_CS_PRES(1)|WDOG_CS_CLK(1);//WDOG_CS_UPDATE(1)|
while((WDOG->CS&WDOG_CS_RCS_MASK)==0);//wait until new configuration take effect
RTOS_HalEnableScheduler();//enable interrupt
#endif
}
- 控制寄存器涉及五处:
WDOG_CS_ULK_MASK bit11 读取解锁状态
WDOG_CS_EN(1) bit7 使能看门狗
WDOG_CS_PRES(1) bit12 256分频
WDOG_CS_CLK(1) bit8 LPO clock 低功率振荡器时钟
WDOG_CS_RCS_MASK bit10 读取重新配置是否成功
- 解锁时序
write-once bit必须要先进行unlock操作
解锁的要求如下:
- 计算超时时间
看门狗时钟源选择 LPO clock(Internal low power oscillator,内部低功率振荡器),也就是128K。根据256分频,计数+1所需时间就是1/128K * 256 = 2ms
。设置500,也就是看门狗超时500 * 0.2 = 1S。
2.2 喂狗
看门狗的喂狗,主要是刷新计数值。喂狗函数如下:
void PeripheralDriverHal_FeedWatchDog(void)
{
#if(WATCH_DOG_EANBLE)
RTOS_HalDisableScheduler();//disable interrupt
//WDOG->CNT = 0xB480A602;//refresh watchdog
WDOG->CNT = 0xA602;//refresh watchdog
WDOG->CNT = 0xB480;//refresh watchdog
RTOS_HalEnableScheduler();//enable interrupt
#endif
}
对应MCU手册内的:
注意:
1. 复位后CS寄存器的默认值CMD32EN = 1,是32 bit操作。初始化函数中置为0,后续操作都以16 bit或8 bit操作。
2. 没有初始化的情况下,喂狗会导致复位。
3. 在章节末,有示例代码。
2.3 关闭 - 重开 看门狗
在休眠前关闭看门狗,唤醒后再使能看门狗。
- 调整看门狗初始化
WatchDogInitialize
函数中,增加WDOG_CS_UPDATE
,即
WDOG->CS = WDOG_CS_UPDATE(1)|WDOG_CS_EN(1)|WDOG_CS_PRES(1)|WDOG_CS_CLK(1);
这一点,在章节示例代码中也有提到:
2. 增加两个函数
void WatchDogClose(void)
{
#if(WATCH_DOG_EANBLE)
RTOS_HalDisableScheduler();//disable interrupt
WDOG->CNT = 0xC520;//unlock watchdog
WDOG->CNT = 0xD928;//unlock watchdog
while((WDOG->CS&WDOG_CS_ULK_MASK)==0);//wait until register unlocked
WDOG->CS &= ~WDOG_CS_EN_MASK; //disable watchdog
while((WDOG->CS&WDOG_CS_RCS_MASK)==0);//wait until new configuration take effect
RTOS_HalEnableScheduler();//enable interrupt
#endif
}
void WatchDogReInit(void)
{
#if(WATCH_DOG_EANBLE)
RTOS_HalDisableScheduler();//disable interrupt
WDOG->CNT = 0xC520;//unlock watchdog
WDOG->CNT = 0xD928;//unlock watchdog
while((WDOG->CS&WDOG_CS_ULK_MASK)==0);//wait until register unlocked
WDOG->CS |= WDOG_CS_EN(1);
while((WDOG->CS&WDOG_CS_RCS_MASK)==0);//wait until new configuration take effect
RTOS_HalEnableScheduler();//enable interrupt
#endif
}
注意:解锁序列区别于初始化,以16 bit写入。
2.4 中断
希望在看门狗复位前,拉低一个管脚。需要开启看门狗中断。
- 看门狗初始化
在这里插入代码片
- 中断函数实现
void WDOG_EWM_IRQHandler(void)
{
PeripheralDriverHal_GsmModulePowerEnable(0);
}
但是没有调试成功,没有使用示波器查看,复位后读取IO,仍然为高电平。
先保留这一小节,有时间继续调试
添加链接描述:如何验证进入看门狗中断???
中断相关寄存器的描述在《Cortex-M4 Devices Generic User Guide》中:
2.5 窗口看门狗和独立看门狗区别
前面所述使用的是独立看门狗
启用窗口模式时,必须在计数器达到最小预期时间值后刷新看门狗;否则,看门狗将重置MCU。最小期望时间值在WIN寄存器中指定。设置CS[WIN]启用窗口模式。
独立看门狗只要在时间到达之前,都可以喂狗。而窗口看门狗必须在设置的窗口范围内喂狗。
窗口看门狗计时更为精准,使用系统时钟源。(点击进入)
复位
1. 软件复位
void SystemSoftwareReset(void)
{
uint32_t regValue;
/* Read Application Interrupt and Reset Control Register */
regValue = S32_SCB->AIRCR;
/* Clear register key */
regValue &= ~( S32_SCB_AIRCR_VECTKEY_MASK);
/* Configure System reset request bit and Register Key */
regValue |= S32_SCB_AIRCR_VECTKEY(FEATURE_SCB_VECTKEY);
regValue |= S32_SCB_AIRCR_SYSRESETREQ(0x1u);
/* Write computed register value */
S32_SCB->AIRCR = regValue;
}
2. 查看复位原因
程序复位以后,可以通过POWER_SYS_GetResetSrcStatusCmd查看指定复位源的状态(点击进入),从而确定复位原因。
实际上也就是读取复位状态寄存器RCM_SRS
:
在上电后增加以下代码,查看原因:
uint32_t regValue = (uint32_t)RCM->SRS;
TBOX_PRINT("reset_status = 0x%04x\n", regValue);
if(((regValue & RCM_SRS_WDOG_MASK) >> RCM_SRS_WDOG_SHIFT) == 1)
{
TBOX_PRINT("RCM_WATCH_DOG has occurred\n");
}
if(((regValue & RCM_SRS_SW_MASK) >> RCM_SRS_SW_SHIFT) == 1)
{
TBOX_PRINT("RCM_SOFTWARE has occurred\n");
}
休眠
void RUN_to_VLPS (void)
{
/* Adjust SCG settings to meet maximum
frequencies value */
//scg_disable_pll_and_firc();
/* Enable SLEEPDEEP bit in the Core
* (Allow deep sleep modes) */
S32_SCB->SCR |= S32_SCB_SCR_SLEEPDEEP_MASK;
/* Allow very low power run mode */
SMC->PMPROT |= SMC_PMPROT_AVLP_MASK;
/* Select VLPS Mode */
SMC->PMCTRL=SMC_PMCTRL_STOPM(2);
PMC->REGSC |= PMC_REGSC_BIASEN_MASK;
/* Check if current mode is RUN mode */
if(SMC->PMSTAT == 0x01)
{
/* Go to deep sleep mode */
__asm("WFI");
}
}