Перейти к содержанию

Task Watchdog Timer (TWDT) в ESP-IDF

Сообщение «Task watchdog got triggered» в логе ESP32 — не аппаратный сброс, а сторожевой таймер FreeRTOS-уровня, который заметил, что какая-то задача не отдаёт процессор уже 5 секунд. Разбираемся, кого он сторожит и как его кормить.

Обновлено Редакция GAW

Task Watchdog Timer (TWDT, сторожевой таймер задач) — механизм ESP-IDF, который проверяет, что подписанные на него задачи FreeRTOS регулярно получают процессор и сбрасывают таймер. По умолчанию он следит за idle-задачами каждого ядра: если idle-задача не выполнялась дольше таймаута, значит, кто-то монополизировал процессор — спин-цикл по периферии или бесконечный цикл. В отличие от классического сторожевого таймера, TWDT по умолчанию не сбрасывает чип, а печатает предупреждение с backtrace. Разбор самого сообщения и типичных ошибок в коде — в вопросе «Почему ESP32 пишет Task watchdog got triggered».

Параметры по умолчанию

ПараметрЗначениеОпция
Таймаут5 с (диапазон 1–60 с)CONFIG_ESP_TASK_WDT_TIMEOUT_S
Кого сторожитidle-задачи CPU0 и CPU1CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0/1
Инициализацияавтоматически при стартеCONFIG_ESP_TASK_WDT_INIT
При срабатываниипредупреждение и backtrace, работа продолжаетсяCONFIG_ESP_TASK_WDT_PANIC выключена
Аппаратная основаMWDT группы таймеров 0, по истечении — прерывание—

Голодание idle-задачи ESP-IDF считает вредным само по себе: от неё зависят служебные задачи FreeRTOS. Поэтому TWDT — это не столько защита от зависания, сколько детектор плохо написанного кода, который не уступает процессор.

API

  • esp_task_wdt_init() — инициализирует TWDT и подписывает idle-задачи; вызывать только после запуска планировщика. Структура esp_task_wdt_config_t: timeout_ms, idle_core_mask, trigger_panic. Повторный вызов меняет таймаут на лету — ESP-IDF советует так делать перед стиранием большой области флеш.
  • esp_task_wdt_add(handle) — подписывает задачу; NULL — текущую. Подписанная задача обязана периодически звать esp_task_wdt_reset().
  • esp_task_wdt_delete(handle) — отписывает; esp_task_wdt_deinit() — отписывает idle-задачи и выключает TWDT.
  • esp_task_wdt_add_user(), esp_task_wdt_reset_user(), esp_task_wdt_delete_user() — «пользователи»: контроль не задачи, а конкретного участка кода или функции, которая должна вызываться периодически.
  • esp_task_wdt_isr_user_handler() — пользовательская функция, вызываемая из обработчика прерывания при таймауте (ограничения ISR, без ESP_LOGx).

Где именно сбрасывать сторожевой таймер в приложении и почему не стоит делать это из таймера, — в статье «Сторожевой таймер: где его сбрасывать». Если задача ждёт события, вместо спин-цикла используют блокирующие вызовы — например, уведомления задачи: заблокированная задача отдаёт процессор, и idle-задача успевает сбросить TWDT.

С чем не путать

  • Interrupt Watchdog (IWDT) — другой таймер (группа 1), следит за тем, что не заблокированы прерывания и тик FreeRTOS; его таймаут задаётся в миллисекундах, а при срабатывании по умолчанию вызывается обработчик паники.
  • RTC_WDT — аппаратный таймер загрузчика: сторожит время от старта ПЗУ до app_main() и перезагружает чип.
  • Четыре стадии у аппаратных MWDT и RTC_WDT: прерывание, сброс ядра, сброс системы, сброс системы вместе с RTC (только RTC_WDT) или отключено — ESP-IDF обычно ставит прерывание на ранние стадии и сброс на последние.

При отладке через OpenOCD оба таймера, TWDT и IWDT, отключаются на первой точке останова и обратно не включаются.

Частые вопросы

Что значит «Task watchdog got triggered: IDLE0 did not reset the watchdog in time»?

Idle-задача ядра 0 не получала процессор дольше таймаута TWDT (по умолчанию 5 с), а значит, какая-то задача с более высоким приоритетом всё это время не уступала — крутилась в цикле ожидания периферии или в бесконечном цикле. В той же строке ESP-IDF печатает, какие задачи выполнялись на каждом ядре в этот момент. Лечится так: добавить в долгий цикл vTaskDelay или ожидание события, вынести тяжёлую работу в задачу с меньшим приоритетом либо, если долгая работа ожидаема, поднять CONFIG_ESP_TASK_WDT_TIMEOUT_S.

Как подписать свою задачу на Task Watchdog и как его сбрасывать?

Вызвать esp_task_wdt_add(NULL) из самой задачи (или передать её handle), после чего задача обязана периодически вызывать esp_task_wdt_reset() — иначе наступит таймаут. Перед удалением задачи её отписывают через esp_task_wdt_delete(). Если нужно контролировать не задачу, а конкретный участок кода, ESP-IDF предлагает «пользователей»: esp_task_wdt_add_user() выдаёт handle, который сбрасывают через esp_task_wdt_reset_user().

Перезагружает ли Task Watchdog чип?

По умолчанию нет: ESP-IDF печатает предупреждение и backtrace, а приложение продолжает работать. Чтобы таймаут вызывал обработчик паники и сброс, включают CONFIG_ESP_TASK_WDT_PANIC (или trigger_panic в структуре esp_task_wdt_config_t при инициализации на лету). При отладке по JTAG таймер не сработает вовсе: OpenOCD отключает TWDT и IWDT на первой же точке останова и обратно не включает.

Источники

  1. Espressif. ESP-IDF Programming Guide v6.1, ESP32: Watchdogs — Overview: TWDT обнаруживает задачи, которые слишком долго работают без уступки процессора; аппаратно — MWDT_WDT группы таймеров 0, при истечении — прерывание; по умолчанию следит за idle-задачами каждого ядра, подписаться может любая задача; симптом — спин-цикл по периферии или бесконечный цикл; esp_task_wdt_isr_user_handler — пользовательская функция на событие; Usage: esp_task_wdt_init() инициализирует и подписывает idle-задачи, esp_task_wdt_add() подписывает задачу, esp_task_wdt_reset() сбрасывает таймер из задачи, esp_task_wdt_delete() отписывает, esp_task_wdt_deinit(); «пользователи» — esp_task_wdt_add_user(), esp_task_wdt_reset_user(), esp_task_wdt_delete_user(); Configuration: CONFIG_ESP_TASK_WDT_TIMEOUT_S — не меньше самого долгого ожидаемого монопольного участка, меняется на лету через esp_task_wdt_init(); стирание больших областей флеш может вызвать срабатывание; опции CONFIG_ESP_TASK_WDT_EN, _INIT, _CHECK_IDLE_TASK_CPU0, _CHECK_IDLE_TASK_CPU1 включены по умолчанию; по умолчанию при срабатывании печатается предупреждение и backtrace, выполнение продолжается, CONFIG_ESP_TASK_WDT_PANIC переводит в панику и сброс; Timeout Stages: четыре стадии — прерывание, сброс ядра, сброс системы, сброс системы и RTC (только RTC_WDT), отключено; JTAG & Watchdogs: OpenOCD отключает таймеры на точках останова и не включает обратно; текст ошибки «Task watchdog got triggered. The following tasks/users did not reset the watchdog in time: - IDLE0 (CPU 0), Tasks currently running: CPU 0: main, CPU 1: IDLE1»; API: esp_task_wdt_init() только после запуска планировщика; esp_task_wdt_config_t — timeout_ms, idle_core_mask, trigger_panic; esp_task_wdt_status(), esp_task_wdt_reconfigure(), esp_task_wdt_print_triggered_tasks()
  2. Espressif. ESP-IDF Programming Guide v6.1, ESP32: Configuration Options Reference; Fatal Errors — CONFIG_ESP_TASK_WDT_TIMEOUT_S — диапазон 1–60 с, по умолчанию 5; CONFIG_ESP_TASK_WDT_PANIC — по умолчанию выключено; CONFIG_ESP_TASK_WDT_EN, CONFIG_ESP_TASK_WDT_INIT, CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 — включены; описание: голодание idle-задачи вредно, потому что от неё зависят служебные задачи FreeRTOS; Fatal Errors: таймаут TWDT фатален только при CONFIG_ESP_TASK_WDT_PANIC
Страница помогла?

Нашли ошибку? ·