默认情况下,TWDT(任务看门狗) 将监视每个 CPU 的空闲任务,但任何任务都可以选择由 TWDT 监视。每个观察任务必须定期“重置” TWDT 以指示它们已被分配 CPU 时间。如果任务未在 TWDT 超时期限内重置,则将打印一条警告,其中包含有关哪些任务未能及时重置 TWDT 以及哪些任务当前正在 ESP32 CPU 上运行的信息。并且还有可能在用户代码中重新定义函数 esp_task_wdt_isr_user_handler() 以接收此事件。
TWDT 围绕定时器组 0 中的硬件看门狗定时器构建。可以通过调用 esp_task_wdt_init() 来初始化 TWDT,这将配置硬件定时器。然后,任务可以使用 esp_task_wdt_add() 订阅 TWDT 监视。每个订阅的任务必须定期调用 esp_task_wdt_reset() 来重置 TWDT。任何订阅任务无法定期调用 esp_task_wdt_reset() 表示一个或多个任务已经缺乏 CPU 资源或者陷入某个循环。
可以使用 esp_task_wdt_delete() 从 TWDT 取消订阅监视的任务。已取消订阅的任务不应再调用 esp_task_wdt_reset()。一旦所有任务都从 TWDT 取消订阅,可以通过调用esp_task_wdt_deinit() 来取消初始化 TWDT。
默认情况下,make menuconfig 中的 CONFIG_TASK_WDT 将被启用,导致 TWDT 在启动期间自动初始化。同样,CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0 和 CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1 也会默认启用,导致两个空闲任务在启动期间订阅 TWDT。
默认情况下,任务看门狗中断task_wdt_isr()会打印类似如下的信息:
E (10299) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (10299) task_wdt: - reset task (CPU 0/1)
E (10299) task_wdt: Tasks currently running:
E (10299) task_wdt: CPU 0: IDLE0
E (10299) task_wdt: CPU 1: IDLE1
E (10299) task_wdt: Aborting.
如果你希望任务看门狗触发之后进行重启,有以下两种方法:
调用panic handler :在 make menuconfig --> Component config --> ESP32-specific选中 Invoke panic handler on Task Watchdog timeout
在main()中重新定义esp_task_wdt_isr_user_handler()函数,我在里面仅仅加了一个打印语句就会达到看门狗触发重启的效果,也不知道这是不是正确姿势。
Note:
- main()中CHECK_ERROR_CODE(esp_task_wdt_add(NULL), ESP_OK);也可以将主函数加入监视列表。当然因为它不是在任务中,所以无法从监视列表中移除,因为移除之前必须先删除任务。
- 移除顺序是: 先删除任务
1. vTaskDelete(task_handles); 然后移除任务看门狗监视
CHECK_ERROR_CODE(esp_task_wdt_delete(task_handles), ESP_OK); CHECK_ERROR_CODE(esp_task_wdt_status(task_handles), ESP_ERR_NOT_FOUND);
- 默认情况下TWDT是开启的,间隔时间默认是5s。可以通过menuconfig修改,也可以在代码中重新初始化修改间隔。 以下是一个基于官方例程修改的main loop 使用TWDT的代码,完整项目源码github传送门(基于idf3.3,更高版本应该也能用))。
/* Task_Watchdog Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_task_wdt.h"
#define TWDT_TIMEOUT_S 2
/*
* Macro to check the outputs of TWDT functions and trigger an abort if an
* incorrect code is returned.
*/
#define CHECK_ERROR_CODE(returned, expected) ({ \
if(returned != expected){ \
printf("TWDT ERROR\n"); \
abort(); \
} \
})
static TaskHandle_t reset_wdt_task_handles;
void app_main()
{
printf("Initialize TWDT\n");
// //Initialize or reinitialize TWDT
CHECK_ERROR_CODE(esp_task_wdt_init(TWDT_TIMEOUT_S, false), ESP_OK);
CHECK_ERROR_CODE(esp_task_wdt_add(NULL), ESP_OK);
CHECK_ERROR_CODE(esp_task_wdt_status(NULL), ESP_OK);
printf("Delay for 11 seconds, you will see TWDT being triggered every 2 seconds\n");
vTaskDelay(pdMS_TO_TICKS(11000)); //Delay for 10 seconds
printf("Start to reset TWDT every second, TWDT should not be triggered\n");
for (int i=0;i<20;i++)
{
//reset the watchdog every second for 20 times
printf("reset TWDT, count(%d)\n", i);
CHECK_ERROR_CODE(esp_task_wdt_reset(), ESP_OK); //Comment this line to trigger a TWDT timeout
vTaskDelay(pdMS_TO_TICKS(1000));
}
printf("reset TWDT complete, you will see TWDT being triggered every 2 seconds again.\n");
}
参考文献:
- 看门狗 — ESP-IDF Programming Guide 文档
- task_watchdog idf官方例程