Gracefully halt execution - ESP32 - FreeRTOS

Hi all!

I have an ESP32 connected to sensors, a lcd touchscreen, and a communication device. Using FreeRTOS, I've assigned sensor and communication device code to core 0, and core 1 handles the lcd touchscreen/user input. It works great so far.

My problem is, when the code encounters an error, and should halt execution, I'd use a while(true) loop for that. When I do that with my code, since I'm using FreeRTOS, that trigger's a WatchDogTimer in FreeRTOS and the ESP32 reboots.

Anyone know how to disable the WDT in FreeRTOS?

Thanks, Randy

  disableCore0WDT();
  disableCore1WDT();

You could also

while (true)
     delay(1);

This will feed the watchdog timer without disabling it. That way an un-intended lockup will be recoverable.

That may not prevent the other FreeRTOS tasks form executing.

Getting Guru or core debug errors? I'd work to fix them before trying to go around them.

One way is to install and load the Exception Decoder for the Arduino IDE, which can... Well you can use the search things and figure that out.

Not running freeRTOS code in a for( ; ; ) or while(1) loop will cause a crash; see 1. Whiles a stack size is specified in the task creation, freeRTOS puts the next task stack space in the very next stack location. The loops are to keep your task within the stack space. With no loop the task continues executing code and jumps the stack space barrier. Thus the code for the next task begins execution, not as new assigned task but as the currently executing task. SMASH!

1) There is freeRTOS code that I add to the task so that if the loop is jumped the task is killed. If the task is not to be run in a loop then there is freeRTOS code that should be added to properly kill the task and stop the code from a stack smash.

MHotchin: You could also

while (true)
     delay(1);

This will feed the watchdog timer without disabling it. That way an un-intended lockup will be recoverable.

Using delay on a ESP32 whiles using freeRTOS is a waste of CPU time. vTaskDelay is a non-blocking delay. Which means the freeRTOS task switcher will swap to another task during the delay, non-blocking.

Idahowalker: Using delay on a ESP32 whiles using freeRTOS is a waste of CPU time. vTaskDelay is a non-blocking delay. Which means the freeRTOS task switcher will swap to another task during the delay, non-blocking.

The orginal poster was using while(1); to deliberately block everything because there was an error, but the WDT was firing.

There's no need to swap to another task in this case, the whole point is to lock-up without re-booting.

MHotchin: The orginal poster was using while(1); to deliberately block everything because there was an error, but the WDT was firing.

There's no need to swap to another task in this case, the whole point is to lock-up without re-booting.

My interest is towards solving the issue and not trying to do a work around but really, without the code, the error messages, and the like providing any real help would be all speculation. When the issue could be as simple as setting a GPIO pin to output on portB causing a core debug or Guru Meditation error.

Thanks for all the replies!

You have all given me some things to think about, which leads to another question - How do I kill a task in FreeRTOS? ( I will be googling for that, but sometimes a simple answer is best)

To clarify a few things - I'm reading a sensor once every 5 seconds, after 6 consective falied readings from the sensor, I consider the sensor has failed and I want to halt execution. Thanks to the discussion here, I see I have more to handle than just entering an endless loop. For example, after the sensor fails and a bluetooth device connects to the ESP32, an error message should be sent to the device.

So, at the end of the day, I guess I won't have an empty while(1) loop, which will keep feeding the wdt. But I will still have 1 task running that I need to kill off.

Thanks again, Randy

Idahowalker: Using delay on a ESP32 whiles using freeRTOS is a waste of CPU time.

No it's not. delay() in ESP32 core is actually a yield(). So if you have other threads ready to run they will be executed while current one is waiting.

revolt_randy: Thanks for all the replies!

So, at the end of the day, I guess I won't have an empty while(1) loop, which will keep feeding the wdt. But I will still have 1 task running that I need to kill off.

Thanks again, Randy

The usual way is to have the task do its own cleanup, then delete itself. It's the only safe way to endure that the task you want to delete is NOT in a problematic state.

So, just drop off the end of the working loop, and at the end of the task function, just do your cleanup, then:

vTaskDelete(NULL);

Locking the processor in an infinite loop means the user needs to reboot the device to get going again. That's not the most user friendly thing to do

I'm reading a sensor once every 5 seconds, after 6 consective falied readings from the sensor, I consider the sensor has failed and I want to halt execution.

may be you could just make a note that the sensor is no longer working and keep the program running without touching the sensor, but offering some sort of red blinking led or message or may be some way for the user to test stuff / calibrate ....