独立看门狗

看门狗简介

中科芯CKS32F4xx系列产品内部提供两个看门狗定时器单元,独立型看门狗IWDG(Independent Watchdog)和窗口型看门狗WWDG(Window Watchdog),它们在安全性、时间精确性和使用灵活性方面变现得非常优秀。两个看门狗定时器单元都可用来检测由软件错误引起的故障,具体表现为当计数器达到给定的超时值或未能在指定时间窗口内刷新计数器的值,会触发系统复位。

IWDG由MCU内部独立RC振荡器产生的低速时钟LSI(Low-speed Internal)驱动,因此即使主时钟发生故障它也仍然有效。而WWDG是由从APB1分频后得到的时钟驱动,通过可配置的时间窗口来检测应用程序非正常的过迟或过早的操作。IWDG最适合应用于那些需要看门狗作为一个在主程序之外,能够完全独立工作,并且对时间精度要求较低的场合,比如检测由程序跑飞或死机引起的故障。WWDG最适合那些需要看门狗在精确计时窗口时间内起作用的应用程序,比如检测由外部干扰或不可预见的逻辑条件造成的应用程序背离正常运行序列而产生的软件故障。

本文主要介绍IWDG的应用,关于窗口看门狗的详情,请参看我们的WWDG微课堂内容。

IWDG详细介绍

IWDG通俗的解释它是一个12位的递减计数器,当计数器的值从某个值一直减到0的时候,就会产生一个系统复位信号,即IWDG_RESET。如果在计数器没减到0之前,“刷新”计数器的值,就不会产生复位信号,“刷新”这个动作就是我们经常说的喂狗。IWDG直接由VDD电压域供电,即使在MCU停止模式和待机模式下仍然能照常工作。 

1.IWDG功能框图解析

下图是独立看门狗的功能框图,分6个部分进行说明:

1.png

① LSI时钟:IWDG的时钟由专门的32KHz低速时钟LSI驱动,即使主时钟发生故障它也仍然有效,非常独立。这里需要注意的是,由于RC振荡器的原理和特性(根据温度和环境会有一定的漂移),IWDG并不是严格准确的32KHz,只是我们在应用的时候,默认以32KHz的频率来估算。所以IWDG的定时时间并不一定非常精确,只适用于对时间精度要求比较低的场合。

② 计数器时钟和IWDG_PR寄存器:递减计数器的时钟由LSI经过一个8位的预分频器得到,预分频器寄存器IWDG_PR的值决定分频因子,分频因子可以是:4、8、16、32、64、128、256。分频因子(假设为W)和IWDG_PR值的关系是W = 4 * 2^IWDG_PR。

③ 状态寄存器IWDG_SR:顾名思义,IWDG_SR表示独立看门狗模块的当前状态,该寄存器只有位0:PVU(Prescaler Value Update)和位1:RVU(Reload Value Update)有效,且只能读不能写。PVU置1指示预分频值的更新正在进行中,更新完成后由硬件置0。RVU置1表示重装载值的更新正在进行中,更新完毕之后由硬件置0。只有当RVU或PVU等于0的时候才可以进行下一次更新操作。

④ 重载寄存器IWDG_RLR:重载寄存器是一个12位的寄存器,里面装着要刷新到计数器的值,这个值的大小决定着独立看门狗的溢出时间。溢出时间Tout(s) = (4 * 2^IWDG_PR) / 32KHz * IWDG_RLR,根据这个公式,可以计算出当LSI为32KHz时,IWDG的理论溢出时间最小值和最大值分别是125us和32.768s。

⑤ 递减计数器:IWDG的递减计数器是一个12位寄存器,设置范围是0~4095,一个计数器时钟计数器就减1,当计数器减到0时,IWDG会产生一个系统复位信号IWDG_RESET,让程序重新启动运行,如果在计数器减到0之前刷新计数器的值(重新写入新值),就不会产生复位信号,重新刷新计数器值的这个动作俗称喂狗。

⑥ 密钥寄存器IWDG_KR:密钥寄存器IWDG_KR是独立看门狗IWDG的一个核心控制寄存器,主要有三种寄存器值对应三种控制效果。

2.IWDG库函数配置步骤

我们接下来介绍如何驱动CKS32F4xx系列产品的IWDG工作。独立看门狗相关的库操作函数在文件cks32f4xx_iwdg.c和对应的头文件cks32f4xx_iwdg.h中。具体配置步骤如下:

(1)解除寄存器写保护(向IWDG_KR写入0x5555)

IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);  //使能写权限

(2)设置IWDG预分频因子和重装载值

void IWDG_SetPrescaler(uint8_t IWDG_Prescaler); //设置IWDG预分频值void IWDG_SetReload(uint16_t Reload); //设置IWDG重装载值

此时可以计算出看门狗溢出时间,比如我们最终设定IWDG_PR值为 4,IWDG_RLR值500,那么就可以得到 Tout = (4 * 2^IWDG_PR) / 32KHz * IWDG_RLR = 64 / 32 * 500 = 1000ms,看门狗的溢出时间是1s,只要在一秒钟之内,写入0xAAAA到IWDG_KR,就不会触发看门狗复位(一秒内写入多次也是可以的)。这里需要提醒大家的是,由于看门狗的时钟不是准确的32KHz,所以喂狗时间应适当提前。

(3)重载计数值喂狗(向IWDG_KR写入0xAAAA) 

IWDG_ReloadCounter();  //把重装载寄存器IWDG_RLR的值放到计数器中

(4)开启看门狗(向IWDG_KR写入0xCCCC)

IWDG_Enable();  //使能 IWDG

通过上面4个步骤,就可以启动CKS32F4的IWDG独立看门狗了,之后在程序里面就必须周期性的进行喂狗(一般会使用定时器定时的调用IWDG_ReloadCounter函数),否则将导致系统复位。注意IWDG在一旦开启,系统运行时就不能再被关闭,想要关闭,只能重启,并且重启之后要迅速关闭IWDG。

实验例程

为本期微课堂配套了一个例子,整体功能如下:

(1)系统上电后,LED1~LED4依次点亮后熄灭(流水动态效果),配置看门狗,进入主程序while循环,LED1~LED4周期性闪烁,主程序中设置周期性喂狗操作。

(2)按下USER按键,LED1~LED4保持点亮不熄灭,停止周期性喂狗操作,从而造成无法执行喂狗程序,IWDG触发系统复位,可重新看到LED1~LED4依次点亮后熄灭(流水动态效果)现象。

来源:中科芯MCU

免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 14

独立看门狗(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所示。

“MM32F0140学习笔记——独立看门狗(IWDG)"
图1

3、重装载寄存器

每次执行喂狗操作,就会将重装载寄存器(IWDG_RLR)的值重新加载到计数器中,从而避免产生复位或者中断信号,该操作通常叫做喂狗操作。复位时重装载寄存器(IWDG_RLR)的值为0xFFF,如图2。

“MM32F0140学习笔记——独立看门狗(IWDG)"
图2

4、看门狗超时时间

IWDG的超时周期可以通过重装载寄存器(IWDG_RLR)的值和预分频寄存器(IWDG_PR)计算得到,公式如下:

Tout(ms)=((4×2^PR)×RLR)/40

当IWDG_RLR寄存器为最大值时,可以获得最长的超时时间,参考时间如表1:

“MM32F0140学习笔记——独立看门狗(IWDG)"
表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”。

“MM32F0140学习笔记——独立看门狗(IWDG)"
图3

针对需要短时间低功耗STOP模式唤醒的应用场景,可以使用该方式唤醒,同时针对LSI精度不高的问题,可以通过HSI对LSI进行校准方式,从而获取高精度的LSI时钟源。

来源:灵动MM32MCU
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 199

在由单片机构成的微型计算机系统中,由于单片机的工作常常会受到来自外界干扰,造成程序的跑飞,而陷入死循环,程序的正常运行被打断,由单片机控制的系统无法继续工作,会造成整个系统的陷入停滞状态,发生不可预料的后果,因此产生了一种专门用于监测单片机程序运行状态的模块或者芯片,俗称“看门狗”(watchdog) 。MM32内置两个看门狗(独立看门狗和窗口看门狗),提供了更高的安全性、时间的精确性和使用的灵活性,可以用来检测和解决由软件错误引起的故障,其中可以使用独立看门狗在stop低功耗模式下进行MCU不复位唤醒功能。

独立看门狗与窗口看门狗的区别

同样是看门狗,独立看门狗(IWDG)和窗口看门狗(WWDG)十分相似,但还是有些不同之处需要注意:

独立看门狗(IWDG)由专门的低速时钟(LSI)驱动,即使主时钟发生故障它也仍然有效,可在停止(STOP)和待机(STANDBY)模式下工作。

窗口看门狗(WWDG)则由从APB1时钟分频后得到的时钟驱动,通过可配置的时间窗口来检测应用程序非正常的过迟或过早的操作。

图1 独立看门狗框图

IWDG介绍

IWDG 最适合应用于那些需要看门狗作为一个正在主程序外,能够完全独立工作,并且对时间精度要求低的场合,可以在低功耗的停机和待机模式下唤醒或复位MCU。当计数器达到给定的超时值时,触发一个产生系统复位。在SPIN2x系列中,加入了IWDG中断功能。

• 自由运行的递减计数器

• 时钟由独立的振荡器提供(可在停止和待机模式下工作)

• 看门狗被激活后,则在计数器计数至 0x0000 时产生复位或外部中断信号。

注:MM32不同型号IWDG中断功能和中断线的设置不同,本文仅介绍MM32SPIN2x系列。

MM32SPIN2x系列芯片的独立看门狗的时钟来源为LSI(40kHz),根据预分频寄存器的值,LSI可以最多256分频,最少4分频,配合重装载寄存器,超时时间可以设置为最少0.1ms,最多26.2s,如下图

图2 看门狗出超时时间

IWDG使用

使用IWDG的基本步骤如下:
1、(可选)配置看门狗外部中断线和中断函数;
2、配置独立看门狗的预分频系数和重装载值;
3、重载计数值喂狗;
4、启动看门狗。

在SPIN2x系列中,IWDG使用外部中断线24,与WWDG使用同一个中断处理函数,若使用IWDG中断,再退出中断之后需要重新配置IWDG。

下面我们简单的配置一下MM32SPIN27的IWDG中断模式:

1、(可选)配置看门狗外部中断线和中断函数

void Iwdg_Interrupt_Config()
{
NVIC_InitTypeDef NVIC_InitSturcture;
EXTI_InitTypeDef EXTI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); //使能外部中断
EXTI_InitStructure.EXTI_Line = EXTI_Line24;                      //IWDG中断线
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;                  //上升沿触发
EXTI_Init(&EXTI_InitStructure);

NVIC_InitSturcture.NVIC_IRQChannel = WWDG_IRQn; 
NVIC_InitSturcture.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitSturcture.NVIC_IRQChannelPriority = 0;
NVIC_Init(&NVIC_InitSturcture);
GPIO_LED_Config();//使用LED显示看门狗是否进入中断
}

void WWDG_IRQHandler()//IWDG与WWDG使用同一个中断函数
{
GPIOB->ODR ^= GPIO_Pin_4;
iwdg_flag = 1;
EXTI->PR |= 0x1 << 24;
IWDG_ClearIT();
UartSendGroup((u8 *)printBuf, sprintf(printBuf, "interrupt\r\n"));

}

2、配置独立看门狗

void PVU_CheckStatus(void)//查询看门狗预分频更新标志
{
while (1)
if (IWDG_GetFlagStatus(IWDG_FLAG_PVU) == RESET)
break;
}

void RVU_CheckStatus(void)//查询看门狗计数器重载值更新标志
{
while (1)
if (IWDG_GetFlagStatus(IWDG_FLAG_RVU) == RESET)
break;
}

void Interrput_Iwdg_ON(unsigned short int IWDG_Prescaler, unsigned short int Reload)
{
RCC_LSICmd(ENABLE);//启用LSI并等待时钟就绪
while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);
PVU_CheckStatus();//配置时钟分频
IWDG_WriteAccessCmd(0x5555);
IWDG_SetPrescaler(IWDG_Prescaler);
RVU_CheckStatus();//配置重装载值
IWDG_WriteAccessCmd(0x5555);
IWDG_SetReload(Reload & 0xfff);
IWDG_EnableIT(); //启用中断模式
IWDG_ReloadCounter();//使能IWDG前先喂狗
IWDG_Enable();
}

3、时钟配置函数

void HSI_SYSCLK(void)//设置为HIS 8分频
{
RCC_HSICmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY)==RESET);
RCC->CFGR &=~ 0xf;
while((RCC->CFGR&0xf) != 0x0);
}

4、main函数

int main(void)
{
HSI_SYSCLK();        //设置为HIS 8分频
Uart_ConfigInit(9600);
UartSendGroup((u8 *)printBuf, sprintf(printBuf, "sprintf ok\r\n"));

Iwdg_Interrupt_Config();//中断配置
Interrput_Iwdg_ON(IWDG_Prescaler_16, 0xFFF);     //配置并使能IWDG

PWR_EnterSTOPMode(0, PWR_STOPEntry_WFI);//进入STOP模式
while (1)
{
if (iwdg_flag)
{
iwdg_flag = 0;
Interrput_Iwdg_ON(IWDG_Prescaler_16, 0xFFF);           //退出中断函数后重新配置IWDG,建议在清除中断标志位之后有一个延迟在执行这一函数
PWR_EnterSTOPMode(0, PWR_STOPEntry_WFI);        //进入STOP模式
}
// IWDG_ReloadCounter(); //取消注释开启喂狗
}
}

运行结果

编译下载并运行程序,在GPIO的B4引脚上接上一个LED灯,我们可以看到LED灯在闪烁,在UART定时输出”interrupt”,如图3。使用设备记录MCU的供电电流,可以得到图4,在STOP模式下电流仅为3.8uA,持续1.36s唤醒,电流增加为1.65mA。我们可以改变Interrput_Iwdg_ON()函数中的分频值和重装载值来得到想要的唤醒间隔。

图3 UART输出

到这里,一个简单的IWDG中断程序就配置好了。

相比复位模式,在IWDG的中断模式中,我们可以根据需要,在超时的时候向外界发送一些信息,比如MCU的运行状态,更加方便的调试程序。

本文转自: 灵动MM32MCU(MindMotion-MMCU),转载此文目的在于传递更多信息,版权归原作者所有。

围观 202
订阅 RSS - 独立看门狗