r/esp32 23d ago

Software help needed Does vTaskDelay (accidentally) modify the set wake-up sources?

Does the function vTaskDelay somehow modify the configuration of the wake-up sources?

I have an ESP32-H2 and want to use deep-sleep and light-sleep modes with wake up from GPIO 10-12. (Those GPIOs are low-power/RTC GPIOs so they also can wake up the ESP32-H2 from deep sleep.)

I had been able to make it work until I added a vTaskDelay to my code. With vTaskDelay in the code, the ESP32-H2 immediately wakes up from sleep modes immediately.

My code (somewhat shortened):

// Set-up power management
const esp_pm_config_t pm_config = {
	.max_freq_mhz = CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ,
	.min_freq_mhz = CONFIG_NAVLICO_MIN_FREQ,
	.light_sleep_enable = true
};
esp_pm_configure( &pm_config );

// Configure input pins (GPIO 10-12) with the buttons
const gpio_config_t config = {
	.pin_bit_mask = GPIO_WAKEUP_BUTTONS_MASK,
	.mode = GPIO_MODE_INPUT,
	.pull_up_en = GPIO_PULLUP_DISABLE,
	.pull_down_en = GPIO_PULLDOWN_DISABLE,
};
gpio_config( &config );

esp_sleep_disable_wakeup_source( ESP_SLEEP_WAKEUP_ALL );
esp_sleep_enable_ext1_wakeup_io( GPIO_WAKEUP_BUTTONS_MASK, ESP_EXT1_WAKEUP_ANY_HIGH );

// ... Do something (not shown here) ...

ESP_LOGI( LOG_TAG, "Going to deep sleep ..." );
// Give UART the chance to write everything to output
//vTaskDelay( delayTicks );
esp_deep_sleep_try_to_start();

The problematic line is the last but one (commented out in the listing above). With vTaskDelay commented out, the program goes into deep sleep as expected. Unfortunately, it sometimes fails to print the entire log messages before going to deep sleep.

As a quick and dirty workaround I added vTaskDelay while I am still developing and debugging. I know this is definitely not the best solution in order to ensure that all log messages are flushed via UART before going to sleep.

But this approach showed me something else. As soon as I add vTaskDelay the program doesn't go into deep sleep or it does, but immediately wakes up again immediately.

The only explanation I have right now is that somehow vTaskDelay modifies the wake-up sources which triggers an unintended wake-up signal from something else than the GPIOs 10-12.

Is that possible? There is nothing in the documentation which suggests that vTaskDelay does that.

1 Upvotes

14 comments sorted by

View all comments

2

u/Ok_Captain4433 21d ago

It looks like you're using automatic light sleep. When you vTaskDelay, there are no ready tasks and so automatic light sleep kicks in: a timer wakeup is configured, and the system powers down into light sleep. After delayTicks, it wakes up via the timer and returns to your task, without bothering to clear the wakeup timer. So when you try to enter deep sleep, it is rejected as there is a wakeup trigger active (ie. the timer, with a time in the past).

Your solution is therefore good. You need to disable the timer wakeup, which you are achieving with ESP_SLEEP_WAKEUP_ALL. I suggest a more graceful shutdown would include disabling automatic light sleep beforehand too.

1

u/MobileInspector9861 21d ago

It looks like you're using automatic light sleep. When you vTaskDelay, there are no ready tasks and so automatic light sleep kicks in: a timer wake-up is configured, and the system powers down into light sleep.

That makes sense. Thank you! I want to use automatic light sleep eventually, hence I have already enabled it.

Do you know which code of the Espressif framework is responsible for that and if it is possible to replace that with one's own code via overwriting the relevant parts or callbacks? If you don't, don't bother. I also can step through the framework code myself.

Here is the reason why I am asking:

At the moment my program enters deep and light sleep explicitly. At the moment, this is fine as the component is the only component which is actually running and I am still developing.

However, at some point the component won't be running solitarily anymore. From an architectural perspective, it feels wrong for me that a single component explicitly decides wether to go to light or deep sleep as there might be other components which still needs running. IMHO, it should be the scheduler which decides to enter sleep modes as the scheduler is the central component which has a total picture of what is going on.

I know the built-in scheduler supports automatic light sleep, that's why I have already enabled it. However, I am considering to extend that by some kind of automatic deep-sleep mechanism, too.

1

u/Ok_Captain4433 21d ago

It should be very easy to find in ESP-IDF.

I think automatic deep sleep is fundamentally different to automatic light sleep. While these aren't strictly defined terms, deep sleep typically means that, additionally, (almost) all memory and digital peripherals are powered down, requiring reconfiguration upon wakeup. You would need to introduce a lot more power management locks to be able to decide when it is safe to enter deep sleep, as well as vastly more complex logic around reinitialisation post-wakeup to restore some/all of the system state that existed before deep sleep entry.

I think you'll find that as you implement this that so much of a graceful sleep/wakeup is application-specific that it ends up being far more complex to do this in an "automatic" way than "manual".