ESP32-C3 Watch Dog Timer (WDT)

Hello everyone.
I am still a relative low ability programmer.
Recently, I grabbed some ESP32-C3 Espressif boards, to use with ESP-NOW for a project.
After starting, I thought 'I should add a WDT in my code'.
There-in started the first of my problems.
As has been noted, recent upgrades of Arduino & Espressif changed the code around the Task WDT significantly.
This gave rise to the Compile error “invalid conversion from ‘int’ to ‘const esp_task_wdt_config_t*'
Managed to find the solution posted for that one.
So - No more compiler errors.
But... the code didn't actually work (!?!).

After many trials (thinking it was to do with the 'Reset WDT' statement), I finally realised that it Wasn't tying up the early #define CONFIG_FREERTOS_NUMBER_OF_CORES 1 statement with the .idle_core_mask = (1 << CONFIG_FREERTOS_NUMBER_OF_CORES) - 1, statement.
I just manually Set it to 1 core for the ESP32-C3

So to help anyone else out there in the same boat, I thought I'd post my functioning code here. I have Not broached the subject of Changing the WDT Timeout period.

// Watch Dog Timer example for ESP32-C3 (Single Core)
// Oct' 2024

// Based on code from "iotassistant.io/esp32/"

#include <esp_task_wdt.h>

#define WDT_TIMEOUT 1000 // 1000mS = 1 second... -> Change to your requirement.
#define CONFIG_FREERTOS_NUMBER_OF_CORES 1 

// Fixes complier error “invalid conversion from ‘int’ to ‘const esp_task_wdt_config_t*'”:
esp_task_wdt_config_t twdt_config = 
    {
        .timeout_ms = WDT_TIMEOUT,
        .idle_core_mask = 0,    // Bitmask of cores
        .trigger_panic = true,
    };

int i;
int last;

void setup() 
{
  Serial.begin(115200);
  Serial.println("");
  Serial.println("Configuring WDT...");
  Serial.println("");
  esp_task_wdt_deinit(); //wdt is enabled by default, so we need to 'deinit' it first
  esp_task_wdt_init(&twdt_config); //enable panic so ESP32 restarts
  esp_task_wdt_add(NULL); //add current thread to WDT watch
  i = 0;
  last = millis();
}

void loop() 
{
  // Reset the WDT every 0.5s, 20 times only
  if (millis() - last >= 500 && i < 20) 
  {
      Serial.print("MiliSeconds elapsed from last reset = "); Serial.println(millis() - last);
      last = millis();
      i++;
      Serial.print("WDT Reset # "); Serial.println(i);
      esp_task_wdt_reset(); // ***** This is the Only WDT Reset line required for your code *****
  }
  if (i == 20) 
  {
    Serial.println("");
    Serial.println("Stopping WDT reset. CPU should reboot in 1 second");
    Serial.println("");
    i=30; // (simply to Negate both 'if...' statements)
  }
}

Hopefully I haven't made any errors, but feel free to comment if I have.
Enjoy ! :upside_down_face:

Looks to me like you didn't select any cores! Try:
.idle_core_mask = (1 << configNUM_CORES) - 1,

I had taken that line: 'Core Mask', as meaning with Core 0, or Core 1.

Just plumbed your line in.
It compiled, but failed on the C3 - No WDT reset occurs.
Is it supposed to be a Bitwise Operand (ie: <<), or just a regular 'Less Than' (<) ?
I did try it with just '<' but that failed.
I returned it to '<<' & tried brackets around the (1 << (configNUM_CORES - 1)).
It compiled & uploaded, but also failed.
Hmmm...

That is correct, it's a bit mask that identifies which Cores will have their Task WDT facility enabled.

It's a bitwise operator, exactly as I posted.

I don't have a C3 to try it. But, this code works fine on several ESP32 flavors that I've tried. After it's running, type 's' into the Serial Monitor to (s)top the task from resetting the WDT on Core 1. The WDT reset will ensue after it times out (10 seconds after the last reset in this code). Using ESP32 Arduino Core 3.x.

#include "Arduino.h"
#include "esp_task_wdt.h"

void testTask(void * parms);

void setup() {
	Serial.begin(115200);
	vTaskDelay(200);
	Serial.println("Starting");

	esp_task_wdt_config_t twdt_config = {
			.timeout_ms = 10000,
			.idle_core_mask = (1 << configNUM_CORES) - 1,    // Bitmask of all cores,
			.trigger_panic = true,
	};
	ESP_ERROR_CHECK(esp_task_wdt_reconfigure(&twdt_config));
	xTaskCreatePinnedToCore(testTask, "Test Task", 2000, NULL, 5, NULL, ARDUINO_RUNNING_CORE);
}

void loop() {
	vTaskDelete(NULL);
}

void testTask(void * parms) {
	int64_t prevMicros = esp_timer_get_time();
	const int64_t watchDogResetTime = 2000000;
	bool resetWdt = true;

    ESP_ERROR_CHECK(esp_task_wdt_add(NULL));
    ESP_ERROR_CHECK(esp_task_wdt_status(NULL));

	for(;;) {
		int64_t currentMicros = esp_timer_get_time();
		if((resetWdt)&&(currentMicros-prevMicros > watchDogResetTime)) {
			prevMicros = currentMicros;
			Serial.println("Resetting Watchdog");
			esp_task_wdt_reset();
		}

		if(Serial.read() == 's') {
			Serial.println("Halting Watch Dog Resets");
			resetWdt = false;
		}

		vTaskDelay(100); // Allow Idle Task to run and reset its watch dog
	}
}

I just threw that into the ESP32-C3, and it works Perfectly.
Much appreciated.

Would it be easy enough to create (perhaps) a Function, that you could call to change the TimeOut period ?
My reasoning is that my original code I'm writing is for a Cruise control unit for my car.
It would be useful to have a Longer TimeOut period during startup initialisation sequences, then a Shorter TimeOut for normal code run.

Many thanks.

PS: I'm using Arduino IDE Version: 2.3.3 on a Mac.
Date: 2024-09-25 T09:37:41.856Z
CLI Version: 1.0.4

Probably best to check the Documentation to determine what's required to change the TWDT's configuration.

The relevant information is which version of the ESP32 Arduino Core are you using?

you can call esp_task_wdt_reconfigure - see Espressif WDT reference

have a look at

// ESP32 WDT test - tested on ESP32, ESP32S3, ESP32C3

//  for ESP32 core V3.x see https://iotassistant.io/esp32/fixing-error-hardware-wdt-arduino-esp32/
//   and  https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/wdts.html

// on powerup set WDT timeout to 10 seconds
// print count every second - enter new WDT timeout on keyboard

#include <esp_task_wdt.h>
#define WDT_TIMEOUT 10000  // WDT timeout

//if 1 core doesn't work, try with 2
#define CONFIG_FREERTOS_NUMBER_OF_CORES 1
esp_task_wdt_config_t twdt_config = {
  .timeout_ms = WDT_TIMEOUT,
  .idle_core_mask = (1 << CONFIG_FREERTOS_NUMBER_OF_CORES) - 1,  // Bitmask of all cores
  .trigger_panic = true,
};

void setup() {
  Serial.begin(115200);
  delay(1000);
  int watchDogTimerReset = 0, brownOutReset = 0;
  Serial.println("\n\nTesting WDT with ESP32 Arduino Core  3.x");
  Serial.println("Configuring WDTtimeout 10seconds");
  esp_task_wdt_deinit();            //wdt is enabled by default, so we need to deinit it first
  esp_task_wdt_init(&twdt_config);  //enable panic so ESP32 restarts
  esp_task_wdt_add(NULL);           //add current thread to WDT watch
  // get reason for powerup reset and save to NVM
  int reason = print_reset_reason();
  switch (reason) {
    case ESP_RST_POWERON:
      Serial.printf("POR reset\n");
      break;
    case ESP_RST_BROWNOUT:
      brownOutReset = 1;
      Serial.printf("Brown out reset\n");
      break;
    case ESP_RST_DEEPSLEEP:
      Serial.printf("Exit from Sleep detected\r\n");
      break;
    case ESP_RST_WDT:
    case ESP_RST_TASK_WDT:
      Serial.printf("Watchdog timer reset\n");
      watchDogTimerReset = 1;
      break;
  }
}

void loop() {
  static char ch = '0';
  if (Serial.available()) {  // read new WDT timeout
    int i;
    if ((i = Serial.parseInt()) > 0) set_WDT(i);
  }
  delay(1000);       // wait for a second
  Serial.print(ch);  // print second counter
  if (ch == '9') ch = '0';
  else ch++;
}

// setup WDT timeout
void set_WDT(int timeout) {
  twdt_config.timeout_ms = timeout;
  esp_task_wdt_reconfigure(&twdt_config);
  Serial.printf("\n new WDT timeout %d\n", timeout);
}

// print and return reason for system reset
// see https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/misc_system_api.html#_CPPv418esp_reset_reason_t
int print_reset_reason(void) {
  int reason = esp_reset_reason();
  Serial.printf("CPU reset reason: %d ", reason);
  switch (reason) {
    case ESP_RST_UNKNOWN: Serial.println("unknown_RESET"); break;
    case ESP_RST_POWERON: Serial.println("POWERON_RESET"); break;
    case ESP_RST_SW: Serial.println("SW_RESET"); break;
    case ESP_RST_PANIC: Serial.println("PANIC_RESET"); break;
    //case ESP_RST_INT_WD: Serial.println("INTERRUPT_WDT_RESET"); break;
    case ESP_RST_TASK_WDT: Serial.println("TASK_WDT_RESET"); break;
    case ESP_RST_WDT: Serial.println("OTHER_WDT_RESET"); break;
    case ESP_RST_DEEPSLEEP: Serial.println("EXIT_DEEP_SLEEP_RESET"); break;
    case ESP_RST_BROWNOUT: Serial.println("BROWNOUT_RESET"); break;
    case ESP_RST_SDIO:
      Serial.println("SDIO_RESET");
      break;
      //case ESP_RST_USB: Serial.println("USB_RESET"); break;
  }
  return reason;
}

test on ESP32 WDT timeout 10, 20 then 30seconds

Testing WDT with ESP32 Arduino Core  3.x
Configuring WDTtimeout 10seconds
CPU reset reason: 1 POWERON_RESET
POR reset
0123456789E (11006) task_wdt: Task watchdog got triggered. The following tasks/users did not reset the watchdog in time:
E (11006) task_wdt:  - loopTask (CPU 1)
E (11007) task_wdt: Tasks currently running:
E (11007) task_wdt: CPU 0: IDLE0
E (11007) task_wdt: CPU 1: IDLE1
E (11010) task_wdt: Aborting.
E (11021) task_wdt: Print CPU 1 (current core) backtrace




Backtrace: 0x400866bb:0x3ffbcb90 0x400d91e6:0x3ffbcbb0 0x40088da4:0x3ffbcbd0 0x4008a23d:0x3ffbcbf0




ELF file SHA256: 31cec5d1d2fd79da

Rebooting...
ets Jul 29 2019 12:21:46

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:4832
load:0x40078000,len:16460
load:0x40080400,len:4
load:0x40080404,len:3504
entry 0x400805cc


Testing WDT with ESP32 Arduino Core  3.x
Configuring WDTtimeout 10seconds
CPU reset reason: 6 TASK_WDT_RESET
Watchdog timer reset
01
 new WDT timeout 20000
2345678901234567890E (24557) task_wdt: Task watchdog got triggered. The following tasks/users did not reset the watchdog in time:
E (24557) task_wdt:  - loopTask (CPU 1)
E (24558) task_wdt: Tasks currently running:
E (24558) task_wdt: CPU 0: IDLE0
E (24558) task_wdt: CPU 1: IDLE1
E (24561) task_wdt: Aborting.
E (24571) task_wdt: Print CPU 1 (current core) backtrace




Backtrace: 0x400866bb:0x3ffbcb90 0x400d91e6:0x3ffbcbb0 0x40088da4:0x3ffbcbd0 0x4008a23d:0x3ffbcbf0




ELF file SHA256: 31cec5d1d2fd79da

Rebooting...
ets Jul 29 2019 12:21:46

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:4832
load:0x40078000,len:16460
load:0x40080400,len:4
load:0x40080404,len:3504
entry 0x400805cc


Testing WDT with ESP32 Arduino Core  3.x
Configuring WDTtimeout 10seconds
CPU reset reason: 6 TASK_WDT_RESET
Watchdog timer reset
01
 new WDT timeout 30000
23456789012345678901234567890E (34629) task_wdt: Task watchdog got triggered. The following tasks/users did not reset the watchdog in time:
E (34629) task_wdt:  - loopTask (CPU 1)
E (34630) task_wdt: Tasks currently running:
E (34630) task_wdt: CPU 0: IDLE0
E (34630) task_wdt: CPU 1: IDLE1
E (34633) task_wdt: Aborting.
E (34643) task_wdt: Print CPU 1 (current core) backtrace

also tested on ESP32-S3-DevKitC-1 and ESP32-C3-MINI-1 - similar results

Sorry - I've had little time over the past week to get back to any of this.
I found where the 'ESP Core' info was (didn't know it was simply under the Board manager) - Currently v3.0.5 is installed.
Also - I went & grabbed one of my full ESP32 (38pin) boards, and uploaded the Original sketch.
It worked Perfectly straight off, which tells me it's the ESP32-C3 Single Core Board that doesn't like the (well established) code, without some modifications.

When I get more time, I'll try to go through the Espressif documentation and see if I can get my feeble brain to understand enough to progress things further.
Believe me when I say your input has been Much appreciated !