说明:本文记录基于RT-Thread 的 stm32看门狗的多线程监控方法,这里介绍的方法让看门狗线程监控多个线程,任何被监控的线程的卡死都可以触发看门狗复位。
测试平台:STM32 ,RT-Thread 3.1.5
#ifndef __iwdg_H
#define __iwdg_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ---------------------------------*/
#include "stm32g4xx.h"
#include "stm32g4xx_hal.h"
#include "stm32g4xx_ll_pwr.h"
#include "rtthread.h"
extern IWDG_HandleTypeDef hiwdg;
void MX_IWDG_Init(void);
void iwdg_thread_entry(void* parameter);
void sys_iwdg_app(rt_thread_t thread);
int sys_iwdg_thread_init(void);
#ifdef __cplusplus
}
#endif
#endif /*__ iwdg_H */
/* 使用范例 */
#if 0
/* step:1 打开看门狗相关头文件宏 stm32g4xx_hal_conf.h 文件的 #define HAL_IWDG_MODULE_ENABLED */
#define HAL_IWDG_MODULE_ENABLED
/* step:2 打开看门狗初始化函数定义,定义看门狗的溢出时间 */
MX_IWDG_Init();
/* step:3 系统看门狗管理线程初始化 sys_iwdg_thread_init() */
sys_iwdg_thread_init();
/* step:4 在需要看护的线程中调用这个函数即可,在线程中循环调用完成线程喂狗 */
sys_iwdg_app(rt_thread_self());
#endif
/* Includes ------------------------------------------------------------------*/
#include "iwdg.h"
#include <stdlib.h>
#include "stdio.h"
#include <string.h>
/* 系统线程管理看门狗配置参数 --------------------------------------------------*/
#define SYS_IWDG_DATA_NUM (10) /* 系统看门狗管理线程数量 */
#define SYS_IWDG_TIMEOUT (2000) /* 系统看门狗超时时间 :单位 ms,注意必须小于 IWDG_TIMOUT */
#define SYS_IWDG_TIME (100) /* 系统看门狗超循环监测间隔时间 :单位 ms,注意必须小于 IWDG_TIMOUT */
#define IWDG_PRINTF (1) /* 系统看门狗超信息打印,1开启,0关闭 */
#define IWDG_TIMOUT (5000) /* 看门狗重启时间,单位 ms,范围(8 - 32760)ms */
#define IWDG_LSI_RC (32000) /* 看门狗时钟,根据芯片确定, 单位 Hz, */
#define IWDG_RELOAD (uint32_t)(IWDG_TIMOUT * IWDG_LSI_RC / (256 * 1000)) /* 看门狗重载值,自动计算 */
/* IWDG 看门狗管理线程配置*/
#ifndef IWDG_THREAD_THREAD_PRIORITY_LEVEL
#define IWDG_THREAD_THREAD_PRIORITY_LEVEL (1) /* 线程优先级 */
#endif
#ifndef IWDG_THREAD_THREAD_STACKSIZE
#define IWDG_THREAD_THREAD_STACKSIZE (512) /* 线程堆栈 */
#endif
#ifndef IWDG_THREAD_THREAD_SLOT_DURATION
#define IWDG_THREAD_THREAD_SLOT_DURATION (20) /* 线程时间片 */
#endif
typedef struct
{
uint32_t thread; /* 看门狗线程句柄指针 */
uint32_t tick_time; /* 线程喂狗时间 */
}sys_iwdg_data_t;
static sys_iwdg_data_t sys_iwdg_data[SYS_IWDG_DATA_NUM]; /* 系统看门狗管理变量 */
IWDG_HandleTypeDef hiwdg;
/* IWDG init function 看门狗初始化函数
* LSI_RC 看门狗独立时钟 32K
* .看门狗延时计算 (1/32000) * Prescaler * Reload
* */
void MX_IWDG_Init(void)
{
hiwdg.Instance = IWDG;
hiwdg.Init.Prescaler = IWDG_PRESCALER_256; /* IWDG计数器时钟预分频器 */
hiwdg.Init.Window = 4095; /* IWDG看门狗窗口值,0~4095 */
hiwdg.Init.Reload = IWDG_RELOAD; /* IWDG看门狗重置值,0~4095,重置后会自减,减到0时MCU会复位。 */
if (HAL_IWDG_Init(&hiwdg) != HAL_OK)
{
// Error_Handler();
}
}
/* 线程注册和喂狗函数,如果线程没注册过就自动注册并喂狗 */
void sys_iwdg_app(rt_thread_t thread)
{
/* 查找线程 指针存储位置 */
for (uint16_t var = 0; var < SYS_IWDG_DATA_NUM; ++var)
{
if (sys_iwdg_data[var].thread == 0)
{
sys_iwdg_data[var].thread = (uint32_t)thread;
sys_iwdg_data[var].tick_time = rt_tick_get(); /* 存储线程喂狗时间 */
break;
}
else if (sys_iwdg_data[var].thread == (uint32_t)thread)
{
sys_iwdg_data[var].tick_time = rt_tick_get(); /* 存储线程喂狗时间 */
break;
}
}
}
/* 获取时间差 (差值为ms级别 由RT_TICK_PER_SECOND决定的) */
uint32_t get_time_difference_ms(uint32_t now_tick, uint32_t last_tick)
{
if (now_tick >= last_tick)
{
return (now_tick - last_tick);
}
else
{
return (UINT32_MAX - last_tick + now_tick + 1);
}
}
/* 看门狗管理线程 */
void sys_iwdg_thread_entry(void* parameter)
{
uint8_t timeout = 0;
memset(sys_iwdg_data, 0, sizeof(sys_iwdg_data_t));
while (1)
{
for (uint16_t var = 0; var < SYS_IWDG_DATA_NUM; ++var)
{
if (sys_iwdg_data[var].thread != 0)
{
if (get_time_difference_ms(rt_tick_get(), sys_iwdg_data[var].tick_time) > SYS_IWDG_TIMEOUT)
{
#if IWDG_PRINTF
printf("iwdg_thread_entry():thread timeout : No:%d ,thread_add = 0x%08X ,name = %s\r\n",
var,sys_iwdg_data[var].thread, ((rt_thread_t) sys_iwdg_data[var].thread)->name);
#endif
timeout = 1;
}
}
}
if (timeout == 0)
{
HAL_IWDG_Refresh(&hiwdg);
}
rt_thread_mdelay(SYS_IWDG_TIME);
}
}
static rt_thread_t sys_iwdg_thread = RT_NULL;
/* 系统看门狗初始化线程 */
int sys_iwdg_thread_init(void)
{
MX_IWDG_Init();
sys_iwdg_thread = rt_thread_create("sys_iwdg_thread", sys_iwdg_thread_entry, RT_NULL, IWDG_THREAD_THREAD_STACKSIZE, IWDG_THREAD_THREAD_PRIORITY_LEVEL, IWDG_THREAD_THREAD_SLOT_DURATION);
if (sys_iwdg_thread != RT_NULL)
{
rt_thread_startup(sys_iwdg_thread);
}
else
{
#if IWDG_PRINTF
printf("sys_iwdg_thread_entry():create thread fail!\n\n");
#endif
return -1;
}
return 1;
}
/* USER CODE END 1 */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/