一、介绍
在 STM32系列中,是内置有两种看门狗的,分别是 IWDG和 WWDG,本次要分析的是 IWDG独立看门狗;从层面上来讲,IWDG和 WWDG都属于硬件看门狗,如果程序上跑了多线程,需要在每个线程上进行检测而另外设计看门狗保护程序,那么这种就属于软件看门狗,软件看门狗更值得注意设计的理念。
独立看门狗 (IWDG) 由专用的低速时钟 (LSI) 驱动,即使主时钟发生故障它也仍然有效。窗口看门狗由从 APB1时钟分频后得到的时钟驱动,通过可配置的时间窗口来检测应用程序非正常的过迟或过早的操作。
IWDG最适合应用于那些需要看门狗作为一个在主程序之外,能够完全独立工作,并且对时间精度要求较低的场合。
二、配置参数
在了解如何配置 IWDG之前,我们先分析以下它的功能框图:

从图中可以看到,IWDG启用的必要条件有两个,那就是必须为它提供 VDD电压以及 LSI时钟(一般是 40kHz);然后就是我们的常规操作 --- 寄存器配置。
在配置参数中,我们主要注意的预分频操作,因为它决定了独立看门狗的触发时间,因此,需要通过表格来找到分频值对应的时间:

而在这里,可以从上图知道,实际的周期时间是不太稳定的,那么当我们实际应用的时候,喂狗时间应该留有足够的余量。
三、配置代码
bsp_idwg.c 源文件
#include “bsp_iwdg.h”
/*
* 设置 IWDG 的超时时间
* Tout = prv/40 * rlv (s)
* prv可以是[4,8,16,32,64,128,256]
* Prv:预分频器值,取值如下:
* @arg IWDG_Prescaler_4: IWDG prescaler set to 4
* @arg IWDG_Prescaler_8: IWDG prescaler set to 8
* @arg IWDG_Prescaler_16: IWDG prescaler set to 16
* @arg IWDG_Prescaler_32: IWDG prescaler set to 32
* @arg IWDG_Prescaler_64: IWDG prescaler set to 64
* @arg IWDG_Prescaler_128: IWDG prescaler set to 128
* @arg IWDG_Prescaler_256: IWDG prescaler set to 256
*
* 独立看门狗使用LSI作为时钟。
* LSI 的频率一般在 30~60KHZ 之间,根据温度和工作场合会有一定的漂移,我
* 们一般取 40KHZ,所以独立看门狗的定时时间并一定非常精确,只适用于对时间精度
* 要求比较低的场合。
*
* Rlv:重装载寄存器的值,取值范围为:0-0XFFF
* 函数调用举例:
* IWDG_Config(IWDG_Prescaler_64 ,625); // IWDG 1s 超时溢出
* (64/40)*625 = 1s
*/ void IWDG_Config(uint8_t Prv ,uint16_t Rlv)
{
// 使能 预分频寄存器PR和重装载寄存器RLR可写
IWDG_WriteAccessCmd( IWDG_WriteAccess_Enable );
// 设置预分频器值
IWDG_SetPrescaler( Prv );
// 设置重装载寄存器值
IWDG_SetReload( Rlv );
// 把重装载寄存器的值放到计数器中
IWDG_ReloadCounter();
// 使能 IWDG
IWDG_Enable();
}
// 喂狗
void IWDG_Feed(void)
{
// 把重装载寄存器的值放到计数器中,喂狗,防止IWDG复位
// 当计数器的值减到0的时候会产生系统复位
IWDG_ReloadCounter();
}
/*---------------------------- END OF FILE ----------------------------*/
bsp_adc.h 头文件
#ifndef __BSP_IWDG_H
#define __BSP_IWDG_H
#include “stm32f10x.h”
void IWDG_Config(uint8_t Prv ,uint16_t Rlv);
void IWDG_Feed(void);
#endif /* __BSP_IWDG_H */
/*---------------------------- END OF FILE ----------------------------*/
四、设计思维
1、单一主循环、非多线程
这个是我们最常见的,往往出现在裸机程序上面,只需要在 main函数的 while主循环里及时进行喂狗就可以了:
#include “bsp_iwdg.h”
/************************************************
函数名称 : main
功 能 : 主函数入口
参 数 : 无
返 回 值 : 无
*************************************************/
int main(void)
{
/* Initial Configuration */
System_Starts();
/* -------- End -------- */
IWDG_Config(IWDG_Prescaler_128 ,625); // 4S
if (RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET){ /* 是否为 iwdg复位*/
RCC_ClearFlag();
printf(“%sn”, “iwdg resetn”);
}
/* Infinite loop */
while (1)
{
/* User handling code */
。。.
。。.
IWDG_Feed(); // 喂狗
}
}
在上面的代码中,加入 IWDG复位判断处理,这样可以根据是否触发了独立看门狗复位而在下次重新运行用户代码前做一系列恢复工作或提示等等。
2、多线程监测保护
在多线程中,并不能像上面那样去喂狗,因为万一其中一个高优先级的线程抢占的 cpu,那么就会来不及及时喂狗,从而很容易触发 IWDG复位;因此我们需要一个健壮的监测程序就要处理好各个线程之间的干扰项。
这里我们常用的技巧就是创建一个最高优先级的监测线程,以避免确保其他线程打断,而自身线程监测以及会遇到那些内存溢出进入硬件中断的,就靠 IWDG监测,其余的各个线程就把自己的状态反馈给我们所创建的最高优先级的监测线程,如果某一线程反馈的状态不对,那么就自动软件复位。
大致的主监控代码:
xTaskCreate( vSysGuard_Task, “vSysGuard_Task”, configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL );
void vSysGuard_Task(void *pvParameters)
{
#if USER_IWDG_ENABLE
IWDG_Config(IWDG_Prescaler_128 ,625); // 4S
#endif /* USER_IWDG_ENABLE */
while(1)
{
vTaskDelay(1000 / portTICK_RATE_MS);
#if USER_IWDG_ENABLE
IWDG_Feed();
#endif /* USER_IWDG_ENABLE */
SysGuard_Scan(); // 扫描各个线程返回的状态是否正确
}
}
五、调试模式下的使用
在打开独立看门狗模式后,如果进入 DEBUG调试,你会发现,当我们建立一个断点进行单步调试等操作时,系统会因为没有及时喂狗而进行复位操作;照理来说,在程序执行到断点停止的时候,我们会默认程序并不工作,但是实际情况并不是这样,还是有部分功能在没有修改特定配置之前,这些功能依然在起作用,独立看门狗的执行就是其中一个。
在调试 MCU配置寄存器(DBGMCU_CR)中,决定着某些功能在 DEBUG调试中是否仍然继续工作:

默认情况下是打开的,因此,我们把它使能:调用 stm32f1xx_dbgmcu.c文件里面的 DBGMCU_APB1PeriphConfig();函数应用。
一、介绍
在 STM32系列中,是内置有两种看门狗的,分别是 IWDG和 WWDG,本次要分析的是 IWDG独立看门狗;从层面上来讲,IWDG和 WWDG都属于硬件看门狗,如果程序上跑了多线程,需要在每个线程上进行检测而另外设计看门狗保护程序,那么这种就属于软件看门狗,软件看门狗更值得注意设计的理念。
独立看门狗 (IWDG) 由专用的低速时钟 (LSI) 驱动,即使主时钟发生故障它也仍然有效。窗口看门狗由从 APB1时钟分频后得到的时钟驱动,通过可配置的时间窗口来检测应用程序非正常的过迟或过早的操作。
IWDG最适合应用于那些需要看门狗作为一个在主程序之外,能够完全独立工作,并且对时间精度要求较低的场合。
二、配置参数
在了解如何配置 IWDG之前,我们先分析以下它的功能框图:

从图中可以看到,IWDG启用的必要条件有两个,那就是必须为它提供 VDD电压以及 LSI时钟(一般是 40kHz);然后就是我们的常规操作 --- 寄存器配置。
在配置参数中,我们主要注意的预分频操作,因为它决定了独立看门狗的触发时间,因此,需要通过表格来找到分频值对应的时间:

而在这里,可以从上图知道,实际的周期时间是不太稳定的,那么当我们实际应用的时候,喂狗时间应该留有足够的余量。
三、配置代码
bsp_idwg.c 源文件
#include “bsp_iwdg.h”
/*
* 设置 IWDG 的超时时间
* Tout = prv/40 * rlv (s)
* prv可以是[4,8,16,32,64,128,256]
* Prv:预分频器值,取值如下:
* @arg IWDG_Prescaler_4: IWDG prescaler set to 4
* @arg IWDG_Prescaler_8: IWDG prescaler set to 8
* @arg IWDG_Prescaler_16: IWDG prescaler set to 16
* @arg IWDG_Prescaler_32: IWDG prescaler set to 32
* @arg IWDG_Prescaler_64: IWDG prescaler set to 64
* @arg IWDG_Prescaler_128: IWDG prescaler set to 128
* @arg IWDG_Prescaler_256: IWDG prescaler set to 256
*
* 独立看门狗使用LSI作为时钟。
* LSI 的频率一般在 30~60KHZ 之间,根据温度和工作场合会有一定的漂移,我
* 们一般取 40KHZ,所以独立看门狗的定时时间并一定非常精确,只适用于对时间精度
* 要求比较低的场合。
*
* Rlv:重装载寄存器的值,取值范围为:0-0XFFF
* 函数调用举例:
* IWDG_Config(IWDG_Prescaler_64 ,625); // IWDG 1s 超时溢出
* (64/40)*625 = 1s
*/ void IWDG_Config(uint8_t Prv ,uint16_t Rlv)
{
// 使能 预分频寄存器PR和重装载寄存器RLR可写
IWDG_WriteAccessCmd( IWDG_WriteAccess_Enable );
// 设置预分频器值
IWDG_SetPrescaler( Prv );
// 设置重装载寄存器值
IWDG_SetReload( Rlv );
// 把重装载寄存器的值放到计数器中
IWDG_ReloadCounter();
// 使能 IWDG
IWDG_Enable();
}
// 喂狗
void IWDG_Feed(void)
{
// 把重装载寄存器的值放到计数器中,喂狗,防止IWDG复位
// 当计数器的值减到0的时候会产生系统复位
IWDG_ReloadCounter();
}
/*---------------------------- END OF FILE ----------------------------*/
bsp_adc.h 头文件
#ifndef __BSP_IWDG_H
#define __BSP_IWDG_H
#include “stm32f10x.h”
void IWDG_Config(uint8_t Prv ,uint16_t Rlv);
void IWDG_Feed(void);
#endif /* __BSP_IWDG_H */
/*---------------------------- END OF FILE ----------------------------*/
四、设计思维
1、单一主循环、非多线程
这个是我们最常见的,往往出现在裸机程序上面,只需要在 main函数的 while主循环里及时进行喂狗就可以了:
#include “bsp_iwdg.h”
/************************************************
函数名称 : main
功 能 : 主函数入口
参 数 : 无
返 回 值 : 无
*************************************************/
int main(void)
{
/* Initial Configuration */
System_Starts();
/* -------- End -------- */
IWDG_Config(IWDG_Prescaler_128 ,625); // 4S
if (RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET){ /* 是否为 iwdg复位*/
RCC_ClearFlag();
printf(“%sn”, “iwdg resetn”);
}
/* Infinite loop */
while (1)
{
/* User handling code */
。。.
。。.
IWDG_Feed(); // 喂狗
}
}
在上面的代码中,加入 IWDG复位判断处理,这样可以根据是否触发了独立看门狗复位而在下次重新运行用户代码前做一系列恢复工作或提示等等。
2、多线程监测保护
在多线程中,并不能像上面那样去喂狗,因为万一其中一个高优先级的线程抢占的 cpu,那么就会来不及及时喂狗,从而很容易触发 IWDG复位;因此我们需要一个健壮的监测程序就要处理好各个线程之间的干扰项。
这里我们常用的技巧就是创建一个最高优先级的监测线程,以避免确保其他线程打断,而自身线程监测以及会遇到那些内存溢出进入硬件中断的,就靠 IWDG监测,其余的各个线程就把自己的状态反馈给我们所创建的最高优先级的监测线程,如果某一线程反馈的状态不对,那么就自动软件复位。
大致的主监控代码:
xTaskCreate( vSysGuard_Task, “vSysGuard_Task”, configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL );
void vSysGuard_Task(void *pvParameters)
{
#if USER_IWDG_ENABLE
IWDG_Config(IWDG_Prescaler_128 ,625); // 4S
#endif /* USER_IWDG_ENABLE */
while(1)
{
vTaskDelay(1000 / portTICK_RATE_MS);
#if USER_IWDG_ENABLE
IWDG_Feed();
#endif /* USER_IWDG_ENABLE */
SysGuard_Scan(); // 扫描各个线程返回的状态是否正确
}
}
五、调试模式下的使用
在打开独立看门狗模式后,如果进入 DEBUG调试,你会发现,当我们建立一个断点进行单步调试等操作时,系统会因为没有及时喂狗而进行复位操作;照理来说,在程序执行到断点停止的时候,我们会默认程序并不工作,但是实际情况并不是这样,还是有部分功能在没有修改特定配置之前,这些功能依然在起作用,独立看门狗的执行就是其中一个。
在调试 MCU配置寄存器(DBGMCU_CR)中,决定着某些功能在 DEBUG调试中是否仍然继续工作:

默认情况下是打开的,因此,我们把它使能:调用 stm32f1xx_dbgmcu.c文件里面的 DBGMCU_APB1PeriphConfig();函数应用。
举报