看门狗(IWDG_WWDG)详解

更多精彩文章,已关注如下微信公众号:

1、看门狗简介

STM32H5系列内部自带了两个看门狗:独立看门狗(IWDG)与窗口看门狗(WWDG)。

独立看门狗内部含有一个12位的递减计数器,当计数器值减到0时,会产生一个复位信号。所以必须在计数器值减到0之前,重置计数器的值。该机制可检测出MCU由软件或硬件故障导致的故障。

窗口看门狗内部也有一个递减计数器,窗口看门狗产生复位信号有两种情况:

1、当计数器的值减到0x40时不喂狗,下一个计数就会产生复位,该下限值不可更改。

2、当窗口看门狗的计数器的值减到某一个数之前喂狗也会产生复位,该值叫窗口的上限值,可由用户设置。

1.1、IWDG介绍

IWDG内部框图如下所示:

由上图可知IWDCNT计数器的时钟由iwdg_ker_ck经过一个分频器输入。iwdg_ker_ck时钟来自于LSI(即内部低速振荡器,32KHz)。LSI时钟是一个内部RC时钟,并不是准确的32KHz而是在29.4~33.6KHz之间的一个变化的时钟。即使主时钟发生故障,LSI仍然有效。IWDG中断与寄存器的请求接口控制时钟来自APB时钟。

独立看门狗模式允许用户配置软件模式或硬件模式。默认工作模式为软件模式

软件模式:向IWDG_KR寄存器写入值0x0000CCCC来启动,IWDCNT会从0xFFF开始递减。

硬件模式:该功能通过设备选项位启用。

1.2、WWDG介绍

wwdg内部框图如下所示:

窗口看门狗的输入时钟为pclk经过一个除4096的分频器,在经过一个可编程预分频器后提供给7位递减计数器。输出复位信号wwdg_out_rst及中断信号wwdg_it。pclk时钟由PCLK1提供,一般把PCLK1时钟频率设置为250MHz。窗口看门狗的工作示意图如下:

由上图可观察到当T[6:0]>W[6:0]是不允许刷新T[6:0]的值,即不允许喂狗,否则会复位。喂狗时间只能在W[6:0] < T[6:0] < 0x3F这个时间区间,当T[6:0]=0x3F时,也会产生复位。窗口看门狗的超时公式如下图:

Tpclk :APB时钟周期以ms为单位。

WDGTB[2:0]:WWDG的预分频系数,0~7

T[5:0]:窗口看门狗的计数器低6位

以APB时钟为48MHz为例,计数结果如下:

2、IWDG/WWDG寄存器介绍

2.1、独立看门狗(IWDG)寄存器

1、密钥寄存器(IWDG_KR)

KEY[15:0]:向其中写入0xCCCC,开启独立看门狗。向其中写入0xAAAA,IWDG_RLR值会被重新加载到计数器中避免复位。向其中写入0x5555,可修改IWDG_PR与IWDGRLR寄存器值

2、预分频寄存器(IWDG_PR)

PR[3:0]:设置看门狗时钟(LSI)的分频系数,最低为4分频,最高为1024分频。

3、重载寄存器(IWDG_RLR)

RL[11:0]:计数器重载值,有效位12位。

4、状态寄存器

2.2、窗户看门狗(WWDG)寄存器

1、控制寄存器(WWDG_CR)

T[6:0]:看门狗计数器的值,每隔(4096*2^WDGTB[2:0])PCLK个周期减1。

WDGA:看门狗激活位,由软件置1。

2、配置寄存器(WWDG_CFR)

3、状态寄存器(WWDG_SR)


3、代码实战

IWDG看门狗的初始化即喂狗代码如下:

/**
 * @brief iwdg初始化函数
 * @note 设置分频系数64 即LSI/64 = 32000/64=500Hz,寄存器值为500,即喂狗超时时间T = 500/500 =1s
 * 
 */
void iwdg_init(void)
{
            
    iwdg_handle.Instance = IWDG;                        //初始IWDG实例
    iwdg_handle.Init.Prescaler = IWDG_PRESCALER_64;     //IWDG时钟分频系数
    iwdg_handle.Init.Reload = 500;                      //IWDG寄存器重载值
    iwdg_handle.Init.Window = IWDG_WINDOW_DISABLE;      //关闭窗口功能
    HAL_IWDG_Init(&iwdg_handle);
}

/**
 * @brief iwdg喂狗函数
 * 
 */
void iwdg_feed(void)
{
            
    HAL_IWDG_Refresh(&iwdg_handle);                     //重载计数器
}

WWDG看门狗初始化即相关函数如下:

/**
 * @brief wwdg_init wwdg初始化函数
 * @note WWDG分频系数为32,即Fwwdg = PCLK/(4096 *32)
 * 溢出时间 = 4096 *32 *(COUNTER - 0x3F)/pclk,如下counter = 0x7F
 * 则溢出时间 = 4096*32*64/25Mhz = 33.55ms
 */
void wwdg_init(void)
{
            
    wwdg_handle.Instance = WWDG;                        //初始化WWDG实例
    wwdg_handle.Init.Prescaler = WWDG_PRESCALER_32;     //WWDG时钟分频系数 PCLK1/4096/32
    wwdg_handle.Init.Counter = 0x7F;                    //计数器值
    wwdg_handle.Init.Window = 0x5F;                     //寄存器窗口值,窗口寄存器近能在计数器值在0x3F~0x5F之间喂狗
    wwdg_handle.Init.EWIMode = WWDG_EWI_ENABLE;         //使能窗口看门狗提前唤醒中段
    HAL_WWDG_Init(&wwdg_handle);                        //初始化wwdg
}

void HAL_WWDG_MspInit(WWDG_HandleTypeDef *hwdg)
{
            
    __HAL_RCC_WWDG_CLK_ENABLE();                        //使能窗口看门狗时钟

    HAL_NVIC_SetPriority(WWDG_IRQn, 0, 3);
    HAL_NVIC_EnableIRQ(WWDG_IRQn);                      //使能窗口看门狗中断
}

/**
 * @brief wwdg_feed
 * @note 窗口看门狗喂狗
 */
void wwdg_feed(void)
{
            
    HAL_WWDG_Refresh(&wwdg_handle);
}

void WWDG_IRQHandler(void)
{
            
    HAL_WWDG_IRQHandler(&wwdg_handle);
}

void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef* hwwdg)
{
            
    wwdg_feed();
}

main.c测试函数代码如下:

#include "stm32h5xx_hal.h"
#include "sys_freq.h"
#include "wdg.h"


uint8_t count = 0;

int main(void)
{
            
    HAL_Init();
    sys_clock_init();
    iwdg_init();
    wwdg_init();
    while(1)
    {
            
        if(count < 10)
        {
            
            iwdg_feed();
            count++;
        }   
        HAL_Delay(800);
    }
}
© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容