ESP 32 kernel hang

I use platformio to work with esp 32.
I also use a custom framework - https://github.com/pioarduino/platform-espressif32/releases/download/53.03.13/platform-espressif32.zip.

My platform.ini file :

[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200
upload_port = COM12
monitor_port = COM12
board_build.partitions = partitions.csv
monitor_filters = esp32_exception_decoder
lib_deps = 
	arduino-libraries/Arduino_JSON @ 0.1.0
	esp32async/ESPAsyncWebServer@^3.7.0

The problem is the following - after some time, about a day. My controller freezes and simply stops working at all. Even a simple task that blinks the LED does not work. In the log that is visible through the download port there is absolutely nothing, the controller has stopped working.

Theoretically, the WDT should have been triggered when one of the FreeRTOS tasks stopped working, but this does not happen.

I thought about using this - https://docs.espressif.com/projects/esp-idf/en/v5.3.3/esp32/api-reference/system/wdts.html ,
but as I understand it, this API will simply create another FreeRTOS task and will monitor that I reset the flag inside my task. But if the entire kernel hangs, then this is useless.
Therefore, only the hardware WDT should do this, but I did not find a description of how to configure it and work with it in the documentation.
Although initially I thought that the esp 32 framework system itself launches such a timer, well, as my MC hangs showed, this is not so.

I decided to reboot the MС once every 24 hours by timer. But after three days, it froze again.

I ask for help to understand this. Theoretically, it is enough to configure the WDT, but there is no documentation on how to do this.

I think there is just a difference between Espressif Arduino 2.x and 3.x
It seems that in 3.x the watchdog is not enabled by default.

You can easily activate the watchdog for the current task by calling esp_task_wdt_add(NULL);

#include <Arduino.h>
#include <esp_task_wdt.h>

void setup() {
    Serial.begin(115200);
    esp_task_wdt_add(NULL); // Add the current task to the watchdog
}

void loop() {
    static unsigned long lastMillis;
    unsigned long        currentMillis = millis();
    if (currentMillis - lastMillis >= 1000) {
        lastMillis = currentMillis;
        Serial.println("Main loop running...");
    }
}

With the watchdog enabled, the sketch above crashes after around 5 seconds. Commenting out the call to esp_task_wdt_add() or calling yield() or delay() or esp_task_wdt_reset() periodically and the sketch will continue.

But this won’t fix your issue (hang after few hours). Can you provide a minimal example to reproduce?

You just need to call esp_task_wdt_reset(); inside the loop.
But I’m almost sure that this code simply creates a FreeRTOS task that checks the counter for the task that we signed with WDT.
And when this counter overflows, then inside it is called - esp_reset(); -reset MC.
But if the whole kernel hangs, then such a task will hang itself and nothing will help.

In any other MC there is a hardware WDT, which works independently of the core and will reset the MC if the WDT counter is not reset inside the program.

I am sure that ESP32 also has such a timer, the only question is how to set it up.

According to Watchdogs - ESP32 - — ESP-IDF Programming Guide v5.5 documentation, a hardware timer is used for this. So there is no such a task that could hang.

By the way: You can also determine what should happen when the WDT is triggered (restart the ESP or not) - see esp_task_wdt_reconfigure().

As i am experimenting with the task wdt: To avoid unwanted triggers by the Arduino Core itself you should set the flag loopTaskWDTEnabled to true when enabling the WDT:

#include <Arduino.h>
#include <esp_task_wdt.h>

extern bool loopTaskWDTEnabled;

void setup() {
    loopTaskWDTEnabled = true;
    esp_task_wdt_add(NULL);  // Add the current task to the watchdog
}

void loop() {
    static unsigned long lastMillis;
    unsigned long        currentMillis = millis();
    if (currentMillis - lastMillis >= 1000) {
        lastMillis = currentMillis;
        Serial.printf("Main loop running...%d\r\n", currentMillis);
    }
}

This makes the Ardino core call esp_wdt_task_reset() periodically: See

Ok, I will still test it in practice. And I will see whether it will work or not. Thank you very much for responding to my posts.

1 Like

:+1:

Otherwise please provide a minimal example to reproduce.

This library is especially for Arduino boards.
You should consider to switch over to ArduinoJson by bblanchon

1 Like