ESP32双核下FreeRTOS任务看门狗与IDLE任务饥饿的定位方法
一、问题背景与原理
ESP32 双核(PRO_CPU 与 APP_CPU)各自运行一个 FreeRTOS 调度器,IDLE 任务优先级最低(0),负责空闲钩子与内存清理。任务看门狗(TWDT)默认监控 IDLE 任务,若某核的 IDLE 任务长时间得不到调度,TWDT 会打印超时任务名并重启。
核心机制:
-
esp_task_wdt可订阅任意任务,默认订阅两个 IDLE 任务。 - 高优先级任务若死循环且不阻塞,会饿死同核 IDLE,触发 TWDT。
- 双核下,一个核饥饿不影响另一个核,但 TWDT 会分别监控。
典型现象: 串口输出 Task watchdog got triggered. The following tasks did not reset the watchdog in time: IDLE1,随后系统重启。
二、定位步骤
步骤1:确认超时任务与核
查看 TWDT 日志中的任务名(IDLE0 对应 PRO_CPU,IDLE1 对应 APP_CPU),确定哪个核发生饥饿。
步骤2:启用运行时统计
在 menuconfig 中开启 CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS,并调用 vTaskGetRunTimeStats() 打印各任务 CPU 占用率。若某任务占用接近 100%,即为饥饿源。
步骤3:检查任务优先级与阻塞点
排查高优先级任务中是否存在无 vTaskDelay 或阻塞调用的死循环。常见于 while(1){...} 中缺少延时或事件等待。
步骤4:使用 TWDT 订阅关键任务
将关键任务加入 TWDT 监控,并在循环中调用 esp_task_wdt_reset(),可提前发现任务卡死。
步骤5:双核绑定验证
用 xTaskCreatePinnedToCore 将可疑任务绑定到指定核,观察饥饿是否转移,辅助定位。
三、完整代码示例
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_task_wdt.h"
#include "esp_log.h"
static const char *TAG = "TWDT_DEMO";
// 模拟饥饿任务:高优先级死循环,无阻塞
void hungry_task(void *pvParameters) {
ESP_LOGI(TAG, "Hungry task started on core %d", xPortGetCoreID());
while (1) {
// 故意不调用 vTaskDelay 或阻塞,饿死同核 IDLE
volatile int i = 0;
i++;
}
}
// 正常任务:定期喂狗
void normal_task(void *pvParameters) {
esp_task_wdt_add(NULL); // 订阅当前任务
while (1) {
esp_task_wdt_reset();
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void app_main(void) {
// 初始化 TWDT,超时 5 秒
esp_task_wdt_init(5, true);
// 打印运行时统计(需 menuconfig 开启)
// vTaskGetRunTimeStats 输出到串口
// 创建饥饿任务,绑定到 APP_CPU(core 1)
xTaskCreatePinnedToCore(hungry_task, "hungry", 2048, NULL, 5, NULL, 1);
// 创建正常任务,绑定到 PRO_CPU(core 0)
xTaskCreatePinnedToCore(normal_task, "normal", 2048, NULL, 5, NULL, 0);
}
运行现象: 约 5 秒后串口打印 Task watchdog got triggered. The following tasks did not reset the watchdog in time: IDLE1,系统重启。
四、注意事项
- 不要随意关闭 TWDT:它是定位死循环的有效工具,可临时调整超时时间而非禁用。
- IDLE 饥饿不等于系统死机:另一核可能仍正常运行,需分别检查。
- 喂狗位置要合理:在任务主循环中喂狗,而非中断或高频率调用,避免掩盖问题。
- 双核任务分配:计算密集型任务建议绑定到单独核,并保留 IDLE 调度机会。
-
使用
vTaskDelay(1)让出 CPU:在长循环中插入至少 1 tick 延时,可避免饥饿。 - 运行时统计有开销:仅调试时开启,量产关闭。
通过以上方法,可快速定位 ESP32 双核下 TWDT 超时与 IDLE 饥饿的根因,提升系统稳定性。
暂无评论,来抢沙发~