独立看门狗(IWDG)的设计初衷是为了检测和解决由软件错误所引起的故障,与窗口看门狗的主要区别在于独立看门狗可以作为一个处于主程序之外,由内部低速时钟(LSI)驱动,能够完全独立工作的模块,当主时钟发生故障或芯片处在低功耗模式的时候,独立看门狗依旧可以继续工作。
它的原理可以简述为:当独立看门狗计数器不断递减达到给定数值时,将产生一个系统复位信号使系统复位或产生中断信号。
MM32F0140的独立看门狗有一个特色功能,用户可以通过配置选择IWDG产生复位还是产生中断功能,比如在stop模式下,用户可以选择中断方式唤醒从而不用复位MCU,SRAM数据不用因为看门狗唤醒而被清除。
1 产生复位或者中断
MM32F014x的独立看门狗内部是自由运行的12位递减计数器,当设置IWDG复位方式时,当计数达到0x0000时,会产生一个系统复位;当设置IWDG中断方式时,当设置看门狗中断生成值IGEN,每当计数器值递减等于该值时,会产生一个中断信号。
2 计数器时钟
IWDG是由低速时钟源(LSI)驱动,经过IWDG_PR预分频器分频得到,预分频因子可以被设置为4,8,16,32,64,128,256,在开启IWDG前需要先开启LSI,如图1所示。
图1
3 重装载寄存器
每次执行喂狗操作,就会将重装载寄存器(IWDG\_RLR)的值重新加载到计数器中,从而避免产生复位或者中断信号,该操作通常叫做喂狗操作。复位时重装载寄存器(IWDG\_RLR)的值为0xFFF,如图2。
图2
4 看门狗超时时间
IWDG的超时周期可以通过重装载寄存器(IWDG_RLR)的值和预分频寄存器(IWDG_PR)计算得到,公式如下:
Tout(ms)=((4×2^PR)×RLR)/40
当IWDG_RLR寄存器为最大值时,可以获得最长的超时时间,参考时间如表1:
表1
5 寄存器保护
独立看门狗中的IWDG_PR,IWDG_RLR,IWDG_IGEN寄存器具有访问保护功能,只能在向键值寄存器(IWDG_KR)写入0x5555,才能修改以上被保护的寄存器的值。向键值寄存器写入其他值或者重载操作时,寄存器依旧出在保护状态。
6 看门狗中断
当开启独立看门狗后,计数器开始从其复位值0xFFF开始递减,当IWDG_CR控制寄存器中的IRQ_SEL位置1时,计数器递减到IWDG_IGEN设定的值后会产生一个中断。独立看门狗中断被连接到EXTI24上,所以看门狗中断可以使MCU从低功耗模式下唤醒,结合IWDG_IGEN寄存器的设定,可以模拟低功耗定时器来使用。
7 部分库函数参考
PVU_CheckStatus();
IWDG_WriteAccessCmd(0x5555);
IWDG_SetPrescaler(IWDG_Prescaler);
修改预分频寄存器(IWDG_PR),修改前需要先向键值寄存器(IWDG_KR)写入0x5555。
RVU_CheckStatus();
IWDG_WriteAccessCmd(0x5555);
IWDG_SetReload(Reload & 0xfff);
修改重装载寄存器(IWDG_RLR),修改前需要先向键值寄存器(IWDG_KR)写入0x5555。
IVU_CheckStatus();
IWDG_WriteAccessCmd(0x5555);
IWDG_SetIGen(0x7ff);
修改中断生成寄存器(IWDG_IGEN),修改前需要先向键值寄存器(IWDG_KR)写入0x5555。
IWDG_EnableIT();
开启看门狗中断,如果需要看门狗复位方式需要设置:IWDG_Reset();
IWDG_ReloadCounter();
IWDG_Enable();
重载计数器、开启IWDG计数器。
IWDG_ClearITPendingBit();
清除看门狗中断标志位。
8 程序配置
8.1 开启独立看门狗
开启看门狗前需要先打开LSI,配置预分频寄存器,配置重装载寄存器,然后开启IWDG计数器,以下示例代码对IWDG进行初始化,配置预分频因子为16,重装载寄存器从最大值(0xFFF)开始计数,最大看门狗超时时间大概为1.6秒,代码如下:
void IWDG_Init(void)
{
//开启低速时钟,等待时钟稳定
RCC_LSICmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);
//设置预分频寄存器
PVU_CheckStatus();
IWDG_WriteAccessCmd(0x5555);
IWDG_SetPrescaler(0x02); //选择对LSI进行16分频
//设置重装载寄存器
RVU_CheckStatus();
IWDG_WriteAccessCmd(0x5555);
IWDG_SetReload(0xfff); //重装载寄存器设置为0xFFF
//将重装载寄存器的值加载到计数器,并开启计数器
IWDG_ReloadCounter();
IWDG_Enable();
}
8.2 重装载计数器(喂狗)
在任何时候向IWDG_KR寄存器写入0xAAAA,就会将重装载寄存器(IWDG_RLR)中的值加载到计数器中,避免产生复位或者中断,可以使用如下库函数:
IWDG_ReloadCounter();
或者直接操作寄存器,但要特别注意,在喂狗后最多需要5个LSI的振荡周期。
IWDG->KR = 0xAAAA;
8.3 开启看门狗中断
如需要开启看门狗中断,在配置IWDG时需要配置IWDG_CR中的IRQ_SEL和IWDG_IGEN寄存器,在开启看门狗之前加入如下代码:
1)配置中断生成寄存器(IWDG_IGEN),并开启看门狗中断
IVU_CheckStatus();
IWDG_WriteAccessCmd(0x5555);
IWDG_SetIGen(0x7FF); //将IWDG_IGEN配置为0x7FF,当计数器到该值时会产生中断
IWDG_EnableIT();
2)使能NVIC和外部中断源
{
EXTI_InitTypeDef EXTI_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1ENR_PWR, ENABLE);
// Enable the IWDG Interrupt
NVIC_InitStruct.NVIC_IRQChannel = WWDG_IWDG_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
RCC_APB2PeriphClockCmd(RCC_APB2RSTR_SYSCFG, ENABLE);
EXTI_StructInit(&EXTI_InitStruct);
EXTI_ClearITPendingBit(EXTI_Line24);
// IWDG map to EXTI_Line24
EXTI_InitStruct.EXTI_Line = EXTI_Line24;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStruct);
}
3)编写看门狗中断服务函数,由于和窗口看门狗共用一个中断源,所以库中函数名和窗口看门狗一致。
void WWDG_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line24) != RESET)
{
EXTI_ClearITPendingBit(EXTI_Line24);
IWDG_ClearIT();
IWDG_ReloadCounter(); //可以在中断中喂狗或者置标志位
}
}
9 功能验证
在测试验证程序中在看门狗中断服务函数添加printf("IWDG IRQ Mode\r\n");下载程序可以看到MCU上电完成后会一直循环打印“IWDG IRQ Mode”。
针对需要短时间低功耗STOP模式唤醒的应用场景,可以使用该方式唤醒,同时针对LSI精度不高的问题,可以通过HSI对LSI进行校准方式,从而获取高精度的LSI时钟源。
作者:灵动MM32
文章来源:灵动MM32MCU
推荐阅读
更多MM32F5系列资料请关注灵动MM32 MCU专栏。如想进行MM32相关芯片技术交流,请添加极术小姐姐微信(id:aijishu20)加入微信群。