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

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);
}
}





















暂无评论内容