ESP32 ESP-WROOM-32 and WDT()

Hi all,

I am trying to implement the use of the WatchDogTimer as seen in several of the available examples.

I have this put in the definitions part of my code:

#include <esp_task_wdt.h>
#define WDT_TIMEOUT 3     // define a 3 seconds WDT (Watch Dog Timer)

And this in setup():

esp_task_wdt_init(WDT_TIMEOUT, true);  // enable panic so ESP32 restarts
esp_task_wdt_add(NULL);                           // add current thread to WDT watch

And this in the loop() part:

esp_task_wdt_reset();            // Added to repeatedly reset the Watch Dog Timer

According to the example(s)s this should work, and since I had a 'hang' only ever 3-4 days, it did not happen so far, I think...

And that is where my question comes from:

Is there a way for the ESP32 to differentiate between a "Power-On' reboot, and a 'Forced by the WDT' ?
Maybe a stored register that can be read somehow, or an Interrupt Service Routine that can run as son as the WDT() is triggered?

If not by means of software, I am thinking of reading an analog input connected to a big, slowly charged capacitor, or an external, One-Shot delay timer like a NE555.

This way, if the ESP32 is booted from Power-On, that input is still seeing a low voltage, but when it reboots WDT initiated that input would already be high, so the program could decide based on that condition.

Anyway, my first interest would be a software solution.

Thanks for reading,

Leo

Most modern MCUs have a status register for reset causes.

You could consult the data sheet, but first check the Espressif docs for a routine that retrieves the reset status flags.

The ESP32 is not an Arduino, so the Espressif forums would be a better place to post such questions.

Edit:


Reset Reason

ESP-IDF applications can be started or restarted due to a variety of reasons. To get the last reset reason, call esp_reset_reason() function. See description of esp_reset_reason_t for the list of possible reset reasons.

1 Like

Hi @jremington , Thank you!! Your response was exactly what was needed.

It is possible to check for the reboot reason eg. in setup(), and use that information later in the program if needed.

I now did this in the definition part:

#include <esp_task_wdt.h>                                         // https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/misc_system_api.html
#define WDT_TIMEOUT   3                                           // define a 3 seconds WDT (Watch Dog Timer)
int BootReason        = 99;

and this in setup():

    Serial.println("Configuring WatchDogTimeout WDT...");
    esp_task_wdt_init(WDT_TIMEOUT, true);             // enable panic so ESP32 restarts
    esp_task_wdt_add(NULL);                           // add current thread to WDT watch

etc.
etc.

    BootReason = esp_reset_reason();
    if ( BootReason == 1 ) {                          // Reset due to power-on event.
          Serial.println("Reboot was because of Power-On!!");
          }
          
    if ( BootReason == 6 ) {                          // Reset due to task watchdog.
          Serial.println("Reboot was because of WDT!!");
          }

    Serial.print("Reset/Boot Reason was: "); Serial.println( BootReason );

And to force a WDT time out after 3 minutes, just to test and see the difference in reset reason, this in loop():

void loop() {
    if ( millis() < 180000 ){
        esp_task_wdt_reset();   // Added to repeatedly reset the Watch Dog Timer      
        }
etc. 
etc.
}

The if ( millis() < 180000) is there only for this test, in the real program that loop is removed, just the esp_task_wdt_reset(); will be there.

I use the BootReason variable later to display the reboot status on a info-screen.

Al the info I needed was in the link you pointed me to: ESP32 Watch Dog Timer information

Thanks again!!

Leo

Don't use Magic Numbers! Use the defined type. From esp_system.h:

typedef enum {
    ESP_RST_UNKNOWN,    //!< Reset reason can not be determined
    ESP_RST_POWERON,    //!< Reset due to power-on event
    ESP_RST_EXT,        //!< Reset by external pin (not applicable for ESP32)
    ESP_RST_SW,         //!< Software reset via esp_restart
    ESP_RST_PANIC,      //!< Software reset due to exception/panic
    ESP_RST_INT_WDT,    //!< Reset (software or hardware) due to interrupt watchdog
    ESP_RST_TASK_WDT,   //!< Reset due to task watchdog
    ESP_RST_WDT,        //!< Reset due to other watchdogs
    ESP_RST_DEEPSLEEP,  //!< Reset after exiting deep sleep mode
    ESP_RST_BROWNOUT,   //!< Brownout reset (software or hardware)
    ESP_RST_SDIO,       //!< Reset over SDIO
} esp_reset_reason_t;


esp_reset_reason_t esp_reset_reason(void);
1 Like

Hi @gfvalvo , thanks for your response, I never got a proper training in programming, I get most of my stuff using Google, and examples from other Arduino users, but I always want to learn stuff.

Is this better and what you mean by not using Magic Numbers?
At least I used a variable with a -more or less- descriptive name.

I changed this part of the code in:

    if ( ESP_RST_POWERON == true ) {                  // Reset due to power-on event.
          Serial.println("Reboot was because of Power-On!!");
          }
          
    if ( ESP_RST_TASK_WDT == true ) {                 // Reset due to task watchdog.
          Serial.println("Reboot was because of WDT!!");
          }

    BootReason = esp_reset_reason();               // but I still can use and find the ummerical value
    Serial.print("Reset/Boot Reason was: "); Serial.println( BootReason );

Thanks,

Leo

No. A "magic number" is, for example, an integer like "6" which has no obvious meaning.

The corrected if statement below has an obvious meaning.

    BootReason = esp_reset_reason();
    if ( BootReason == ESP_RST_TASK_WDT  ) {                 // Reset due to task watchdog.
          Serial.println("Reboot was because of WDT!!");
          }

No, more like this inside of setup():

  esp_reset_reason_t reason = esp_reset_reason();
  switch (reason) {
    case ESP_RST_UNKNOWN:
      Serial.println("Reset for unknown reason");
      break;

    case ESP_RST_POWERON:
      Serial.println("Power on reset");
      break;

    case ESP_RST_EXT:
      Serial.println("Reset from external pin");
      break;

    // .
    // .
    // other reset reasons
    // .
    // .

    default:
      break;
  }

Hi @gfvalvo , thanks for the suggestions.

I did change my code into the (full) case construction as you suggested, and (of course) it works. :slightly_smiling_face:

Like this:

BootReason = esp_reset_reason();
    Serial.print("Reset/Boot Reason was: "); Serial.println( BootReason );
    
    esp_reset_reason_t reason = esp_reset_reason();
 
    switch (reason) {
        case ESP_RST_UNKNOWN:
          Serial.println("Reset reason can not be determined");
        break;

        case ESP_RST_POWERON:
          Serial.println("Reset due to power-on event");
        break;

        case ESP_RST_EXT:
          Serial.println("Reset by external pin (not applicable for ESP32)");
        break;

        case ESP_RST_SW:
          Serial.println("Software reset via esp_restart");
        break;

        case ESP_RST_PANIC:
          Serial.println("Software reset due to exception/panic");
        break;

        case ESP_RST_INT_WDT:
          Serial.println("Reset (software or hardware) due to interrupt watchdog");
        break;

        case ESP_RST_TASK_WDT:
          Serial.println("Reset due to task watchdog");
        break;

        case ESP_RST_WDT:
          Serial.println("Reset due to other watchdogs");
        break;                                

        case ESP_RST_DEEPSLEEP:
          Serial.println("Reset after exiting deep sleep mode");
        break;

        case ESP_RST_BROWNOUT:
          Serial.println("Brownout reset (software or hardware)");
        break;
        
        case ESP_RST_SDIO:
          Serial.println("Reset over SDIO");
        break;
        
        default:
        break;
    }

The reason I used a variable to store the reset reason was that I am/was not sure if that reason would be available later when the program had been running for some time, where my variable would be. For the same reason I did it in setup(), meaning: as soon as possible.

And the main purpose I have is -when I find my program running- to know if it is still running, or if it is running again, so if the WDT kicked in.

And because I am learning every day, the way I see it there is not much difference,
you use basically another way of showing the boot-reason, but still derived from the esp_reset_reason() function?

Where I was putting the numerical result of that function in an integer, you would re-use the function and its enumerator output.

In terms of readability the enumerator is descriptive in its own, but when properly commented (I use a lot of comments) use of a variable should provide the same level of readability.

Or, is there another reason one way compared to the other is preferred?
Memory usage? Speed? ...?

Thanks again,

Leo

There's no reason to call esp_reset_reason() twice. Just call it once, save the result to a variable of type esp_reset_reason_t and be done with it.

Using the enum helps the compiler help you by doing proper type checking and prevents you from trying to do comparisons against impossible values. Sort of shows you know what you're doing.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.