STM32F7xx —— 看門狗
看門狗:指定時間内不喂狗,就重新開機系統。
最簡單的看門狗設計(喂狗就是指定時間内給寄存器寫一個固定值)
// 初始化獨立看門狗
// prer:分頻數:0~7(隻有低 3 位有效!)
// rlr:自動重裝載值,0~0XFFF.
// 分頻因子=4*2^prer.但最大值隻能是 256!
// rlr:重裝載寄存器值:低 11 位有效.
// 時間計算(大概):Tout=((4*2^prer)*rlr)/32 (ms).
static IWDG_HandleTypeDef iwdg_handle;
void WatchdogInit(void)
{
iwdg_handle.Instance = IWDG;
iwdg_handle.Init.Prescaler = 5;
iwdg_handle.Init.Reload = 250;
iwdg_handle.Init.Window = IWDG_WINDOW_DISABLE; // 關閉視窗功能
HAL_IWDG_Init(&iwdg_handle);
os_watchdog_lock = xSemaphoreCreateMutex();
}
void WatchdogFeed(void)
{
HAL_IWDG_Refresh(&iwdg_handle);
}
FreeRTOS看門狗設計(系統看門狗+任務看門狗)(其他作業系統也可以用這種思路)
任務看門狗:監控每個任務的活動狀态,如果任務卡死,會導緻系統重新開機。核心思想是使用計數,計數減為0後說明任務卡死。
TaskHandle_t os_watchdog_handle;
// 互斥信号量
static SemaphoreHandle_t os_watchdog_lock;
#define WATCHDOG_LOCK() xSemaphoreTake(os_watchdog_lock, 100);
#define WATCHDOG_UNLOCK() xSemaphoreGive(os_watchdog_lock)
#define WATCHDOG_CHECK_INTERVAL 100 // 100ms喂一次狗
#define WATCHDOG_POOL_SIZE (OS_PRIO_MAX + OS_PRIO_MAX - 1) // 任務池 2倍的任務-1
typedef struct
{
TaskHandle_t handle; // 任務句柄
const char *name; // 任務看門狗名稱
uint16_t timeout; // 任務看門狗逾時
uint16_t time; // 任務看門狗計數
uint8_t suspended; // 任務看門狗暫停
} watchdog_t;
static watchdog_t watchdogs[WATCHDOG_POOL_SIZE];
static void task_watchdog(void *params)
{
int i;
while(1)
{
WatchdogFeed();
for(i = 0; i < WATCHDOG_POOL_SIZE; ++i)
{
if(0 == watchdogs[i].handle)
{
continue;
}
if(!watchdogs[i].suspended && watchdogs[i].time)
{
--(watchdogs[i].time);
}
if(!watchdogs[i].suspended && (0 == watchdogs[i].time))
{
printf("!!!!!!!!!!!!!!!! Watchdog %s timeout !!!!!!!!!!!!!!!!\n", watchdogs[i].name);
while(1); // reset
}
}
vTaskDelay(WATCHDOG_CHECK_INTERVAL);
}
}
// 初始化獨立看門狗
// prer:分頻數:0~7(隻有低 3 位有效!)
// rlr:自動重裝載值,0~0XFFF.
// 分頻因子=4*2^prer.但最大值隻能是 256!
// rlr:重裝載寄存器值:低 11 位有效.
// 時間計算(大概):Tout=((4*2^prer)*rlr)/32 (ms).
static IWDG_HandleTypeDef iwdg_handle;
void WatchdogInit(void)
{
iwdg_handle.Instance = IWDG;
iwdg_handle.Init.Prescaler = 5;
iwdg_handle.Init.Reload = 250;
iwdg_handle.Init.Window = IWDG_WINDOW_DISABLE; // 關閉視窗功能
HAL_IWDG_Init(&iwdg_handle);
os_watchdog_lock = xSemaphoreCreateMutex();
xTaskCreate((TaskFunction_t)task_watchdog,
(const char* )"task_watchdog",
(uint16_t )OS_WATCHDOG_STK_SIZE,
(void* )NULL,
(UBaseType_t )OS_PRIO_WATCHDOG,
(TaskHandle_t* )&os_watchdog_handle);
}
void WatchdogFeed(void)
{
HAL_IWDG_Refresh(&iwdg_handle);
}
//===============================================================================================================
// 任務看門狗注冊
void WatchdogRegister(const char *name, uint16_t timeout)
{
int i;
TaskHandle_t handle = xTaskGetCurrentTaskHandle();
WATCHDOG_LOCK();
for(i = 0; i < WATCHDOG_POOL_SIZE; ++i)
{
if (handle == watchdogs[i].handle)
{
WATCHDOG_UNLOCK();
return;
}
}
for(i = 0; i < WATCHDOG_POOL_SIZE; ++i)
{
if (0 == watchdogs[i].handle)
{
watchdogs[i].handle = handle;
watchdogs[i].name = name;
watchdogs[i].timeout = (timeout + WATCHDOG_CHECK_INTERVAL - 1) / WATCHDOG_CHECK_INTERVAL;
watchdogs[i].time = watchdogs[i].timeout;
watchdogs[i].suspended = 0;
break;
}
}
WATCHDOG_UNLOCK();
}
// 任務看門狗喂狗
void WatchdogKick(void)
{
int i;
TaskHandle_t handle = xTaskGetCurrentTaskHandle();
for(i = 0; i < WATCHDOG_POOL_SIZE; ++i)
{
if (handle == watchdogs[i].handle)
{
WATCHDOG_LOCK();
watchdogs[i].time = watchdogs[i].timeout;
WATCHDOG_UNLOCK();
break;
}
}
}
// 任務看門狗暫停
void WatchdogSuspend(void)
{
int i;
TaskHandle_t handle = xTaskGetCurrentTaskHandle();
for(i = 0; i < WATCHDOG_POOL_SIZE; ++i)
{
if (handle == watchdogs[i].handle)
{
WATCHDOG_LOCK();
watchdogs[i].suspended = 1;
WATCHDOG_UNLOCK();
break;
}
}
}
// 任務看門狗恢複
void WatchdogResume(void)
{
int i;
TaskHandle_t handle = xTaskGetCurrentTaskHandle();
for(i = 0; i < WATCHDOG_POOL_SIZE; ++i)
{
if (handle == watchdogs[i].handle)
{
WATCHDOG_LOCK();
watchdogs[i].time = watchdogs[i].timeout;
watchdogs[i].suspended = 0;
WATCHDOG_UNLOCK();
break;
}
}
}