春娇霹雳娃 发表于 2023-7-28 17:58

喂狗?为什么IWDG和WWDG里起这么奇怪的名字?开发过程在这里

本帖最后由 春娇霹雳娃 于 2023-8-16 17:35 编辑

#申请原创# @21小跑堂
本实验基于MM32F0040实现IWDG和WWDG工程开发工作。

1.开发板简介
MM32F0040使用高性能的 Arm® Cortex-M0 为内核的 32 位微控制器,最高工作频率可达 72MHz,内置高速存储器,其硬件外观如下图所示:

电路图如下:


2.功能描述
2.1 IWDG

IWDG(Independent Watch Dog),为检测和解决由软件错误所引起的故障而设计。独立看门狗(IWDG)适用于需要看门狗作为一个处于主程序之外,能够完全独立工作,适用于对时间精度要求低的需求场景中。IWDG分为两种工作模式:

[*]硬件独立看门狗
[*]软件独立看门狗(默认为软件独立看门狗模式)

功能框图如下:


本质:可理解为一个12位递减计数器,当计数器的值从装载的值一直递减到零时,向系统触发复位信号,即IWDG_RESET。在计数器递减到零之前,重新装置计数器内的值,则不会产生复位信号,重置计数器值的操作即为“喂狗”。
“喂狗” 分为两种方式:

[*]直接重载初始化设定值
[*]重新设定重载值

2.2 WWDG
WWDG(Window Watchdog Timer)窗口看门狗,一种七位向下计数的timer,计数范围0x7F~0x3F(计数到0x3F将发出复位请求)。喂狗操作:通过更新计数器WWDG_CR计数值,避免计数器向下计数到0x3F,实现“喂狗”操作。
有上下限的喂狗(IWDG只有下限)

[*]上限:寄存器WWDG_CFGR配置值,如果计数值大于此配置值时“喂狗”,则WWDG向CPU发出复位请求(提前“喂狗”)
[*]下限:0x3F(不可修改),如果计数值计数到0x3F,则WWDG向CPU发出复位请求(没有“喂狗”)

作用:

[*]当程序运行偏离了正常的程序路径,能够及时发出复位请求
[*]程序运行偏离了正常的程序路径,提前执行了“喂狗”操作,也能及时发出复位请求

WWDG功能框图如下:

WWDG使用范围:
1.用于程序执行时间精度要求较高的场景

[*]通过APB时钟分频作为计数器时钟来源,计数时钟可精确计算
[*]具有上下限的喂狗窗口范围,避免过早喂狗使喂狗失效
2.喂狗时间范围极小

[*]当APB1时钟频率为60MHz时,最晚30毫秒内就需要喂狗一次
3.能否在低功耗状态下使用

[*]WWDG的计数时钟来源于APB时钟的分频
[*]如果APB时钟关闭,WWDG则无法继续计数,因此WWDG无法在低功耗状态下使用。


3.寄存器配置
3.1 IWDG
iwdg 受访问保护的寄存器有:

[*]IWDG_PR
[*]IWDG_CR
[*]IWDG_IGEN
[*]IWDG_RLR

上述四个寄存器受访问保护。若要修改其中任一寄存器,须先对 IWDG_KR寄存器写入解锁值( 0x5555),写入后四个寄存器将同时被解除访问保护。当IWDG_KR被写入除0x5555外的值时,上述四个寄存器将同时都被锁定。如重装载操作(即“喂狗”)也会对上述四个寄存器启动访问保护功能。

预分频系数设置:


IWDG 实现思路:

[*]初始化IWDG

[*]开启LSI时钟
[*]设置IWDG预分频系数
[*]设置IWDG重载值
[*]IWDG溢出配置
[*]更新IWDG重载值
[*]使能IWDG
2. 更新重载值

[*]方法一:通过IWDG_KG直接重载初定值
[*]方法二: 重新设定重载值
3. 中断配置

[*]使能IWDG中断
[*]失能IWDG中断(仅能在初始化阶段使用)
[*]配置IWDG中断触发值
[*]获取IWDG中断状态
[*]清除IWDG中断


3.2 WWDG
WWDG实现思路:
1.启动WWDG

[*]开启WWDG的RCC时钟
[*]初始化WWDG,包括配置时基和重装载窗口值
[*]使能WWDG,计数器开始计数
[*]使能WWDG_INT_EW中断(可选)
2.喂狗

[*]在规定时间内重装载计数值“喂狗”,提前或超时重装载计数值将产生复位请求
3.中断

[*]使能WWDG_INT_EW中断后,计数器计数到0x40产生中断
4.复位

[*]WWDG产生复位请求后,CPU响应复位请求产生复位,复位后RCC_CSR置位
[*]MCU复位后,可通过查看RCC_CSR标志位确定是否为窗口看门狗复位

4.软件实现
4.1 IWDG
启动检测,若为独立看门口复位,则通过UART输出本次启动为独立看门口复位,若非独立看门狗复位,则通过UART输出本次启动为正常启动或其他复位。开启时钟LSI , 配置IWDG的预分频系数为 32,重载值为 0x1F,初始化独立看门狗功能。在主函数中循环喂狗10次后停止喂狗。停止喂狗,则等待计数器溢出,独立看门狗触发复位信号。
主函数:int main(void){
    uint32_t i = 0;

    BOARD_Init();
    printf("iwdg_basic example.\r\n");

    app_iwdg_init();

    for(i = 0; i < 10; i++){
      /* Reload the IWDG counter. */
      IWDG_DoReload(BOARD_IWDG_PORT);
      printf("Feed dog count: %u\r\n", (unsigned)(i+1) );
      app_soft_delay(200);}

    /* Waiting for MCU reset. */
    while(1){}}配置IWDG
/* IWDG. */
#define BOARD_IWDG_PORT            IWDG
#define BOARD_IWDG_RELOAD            0x7ff //0x3ff
#define BOARD_IWDG_PRESCALER         IWDG_Prescaler_32初始化:
void IWDG_Init(IWDG_Type * IWDGx, IWDG_Init_Type * init)
{   
    if ( NULL != init )
    {
      IWDGx->KR = IWDG_KEY_UNLOCK;   
      IWDGx->PR = init->Prescaler;
      
      IWDGx->KR = IWDG_KEY_UNLOCK;
      IWDGx->RLR = init->Relaod;

      IWDG_DoReload(IWDGx);
    }
}使能IWDG
void IWDG_Start(IWDG_Type * IWDGx)
{
    IWDGx->KR = IWDG_KEY_ENABLE;
}重载IWDG
void IWDG_DoReload(IWDG_Type * IWDGx)
{
    IWDGx->KR = IWDG_KEY_RELOAD;
}开启中断
void IWDG_EnableInterrupts(IWDG_Type * IWDGx, uint32_t interrupts, bool enable)
{
    if( (true == enable ) && (IWDG_INT_ALMOST_TIMEOUT == interrupts) )
    {
      IWDGx->CR |= IWDG_CR_IRQSEL_MASK;
    }
    else
    {
      /* if IWDG_EnableInterrupts interrupt was enabled, only MCU reset can close it. */
    }
}
4.2 WWDG
1.初始化WWDG_Init():

[*]配置计数器的计数时基(分频系数)TimeBase
[*]配置“喂狗”重装载窗口值(喂狗上限)ReloadWindow
2.使能WWDG_Enable():

[*]使能WWDG,使计数器开始计数
[*]使能WWDG后,只有复位才能关闭WWDG。
3.重装载计数值WWDG_Reload():

[*]重装载计数值,实现“喂狗”操作
[*]重装载计数值后,计数器从新的计数值开始向下计数
4.中断

[*]提前唤醒中断WWDG_INT_EW,当计数器计数到0x40时发出,通知CPU即将发出复位请求。
[*]同使能WWDG一样,使能提前唤醒中断WWDG_INT_EW后只有复位才能关闭此中断。
初始化:void WWDG_Init(WWDG_Type * WWDGx, WWDG_Init_Type * init)
{
    if (NULL != init)
    {
      WWDGx->CFGR = WWDG_CFGR_WDGTB(init->Prescaler)
                  | WWDG_CFGR_W(init->UpperLimit);
    }
}使能WWDG
void WWDG_Start(WWDG_Type * WWDGx)
{
    WWDGx->CR |=WWDG_CR_WDGA_MASK;
}重载WWDG
void WWDG_Reload(WWDG_Type * WWDGx, uint32_t value)
{
    if (value > WWDG_LOWER_LIMIT)
    {
      WWDGx->CR = (WWDGx->CR & ~WWDG_CR_T_MASK) | WWDG_CR_T(value);
    }
}中断唤醒
void WWDG_EnableInterrupts(WWDG_Type * WWDGx, uint32_t interrupts, bool enable)
{
    if ( (true == enable) && (WWDG_INT_ALMOST_TIMEOUT == interrupts) )
    {
      WWDGx->CFGR |= WWDG_CFGR_EWI_MASK;
    }
    else
    {
      /* if WWDG_INT_ALMOST_TIMEOUT interrupt is enabled, only MCU reset can close it. */
    }
}配置中断/* WWDG */
#define BOARD_WWDG_PORT            WWDG
#define BOARD_WWDG_IRQn            WWDG_IWDG_IRQn
#define BOARD_WWDG_IRQHandler      WWDG_IWDG_IRQHandler
#define BOARD_WWDG_UPPER_LIMIT       0x7fu
#define BOARD_WWDG_RELOAD_TIMES      100u
#define BOARD_WWDG_RELOAD_VALUE      0x7fu
#define BOARD_WWDG_PRESCALER         WWDG_Prescaler_8开启时钟
/* WWDG. */
    RCC_EnableAPB1Periphs(RCC_APB1_PERIPH_WWDG, true);
    RCC_ResetAPB1Periphs(RCC_APB1_PERIPH_WWDG);主函数:
int main(void)
{
    BOARD_Init();
    printf("\r\nwwdg_basic example.\r\n");

    /* Setup WWDG. */
    app_wwdg_init();

    while (1)
    {
      putchar('.');
      app_soft_delay(100);
    }
}
5.实验现象
iwdg_basic
https://www.bilibili.com/video/BV11V411V78E/

wwdg_basic
https://www.bilibili.com/video/BV1Ac411c7Sp/

6.附件
原理图:
工程文件:



春娇霹雳娃 发表于 2023-7-31 17:43

春娇霹雳娃 发表于 2023-8-10 11:13

zwll 发表于 2023-8-10 20:56

密码帖?

春娇霹雳娃 发表于 2023-8-15 09:32

zwll 发表于 2023-8-10 20:56
密码帖?

单片小菜 发表于 2023-8-16 16:45

密码贴是啥意思?

春娇霹雳娃 发表于 2023-8-16 17:31

单片小菜 发表于 2023-8-16 16:45
密码贴是啥意思?

页: [1]
查看完整版本: 喂狗?为什么IWDG和WWDG里起这么奇怪的名字?开发过程在这里