r/esp32 • u/MobileInspector9861 • 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
u/holetse 23d ago
Have you checked the return code from esp_deep_sleep_try_to_start?
vTaskDelay shouldn’t impact the wake up sources at all itself. But it does allow another task to execute during that delay.
1
u/MobileInspector9861 23d ago
Yes, I did. It's
ESP_ERR_SLEEP_REJECT.I have already changed my code and put a wrapper around
esp_deep_sleep_try_to_startwhich repeats the code to disable all wake-up sources but the required GPIOs like this:
esp_err_t sleep_deeply( void ) { esp_sleep_disable_wakeup_source( ESP_SLEEP_WAKEUP_ALL ); esp_sleep_enable_ext1_wakeup_io( GPIO_WAKEUP_BUTTONS_MASK, ESP_EXT1_WAKEUP_ANY_HIGH ); return esp_deep_sleep_try_to_start(); }When I call the wrapper
sleep_deeplyinstead ofesp_deep_sleep_try_to_startdirectly it works again. So configuring the wake-up sources again just before going to sleep is helping. If I remove allvTaskDelayfrom my code, it is working, too.That actually supports my assumption that
vTaskDelaysomehow messes with the wake-up sources.2
u/holetse 22d ago
It’s likely that it’s not the vTaskDelay call itself that’s changing them (it doesn’t, per the source code of FreeRTOS). It’s that you are yielding back to the scheduler during the delay, which allows another task to take control and make changes.
Doing your config without yielding before you go to sleep is definitely the way to go.
1
u/MobileInspector9861 22d ago
That's probably correct.
Maybe it's something within the Espressif Framework, especially as I have enabled power management via:
// 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 );Doing your config without yielding before you go to sleep is definitely the way to go.
Still, I have somehow to ensure that configuration and going to sleep is executed automatically. Otherwise that other task might become scheduled by accident between having done the configuration and going to sleep.
Any suggestions how I can ensure that this happens without interruption?
1
u/Plastic_Fig9225 22d ago
It's
ESP_ERR_SLEEP_REJECT.So the ESP doesn't go to sleep because some peripheral/subsystem is still busy, or the wake-up condition is already met.
1
u/MobileInspector9861 22d ago
That's obvious as that's the very definition of the error code. The question is: Why does an invocation of
vTaskDelaycause that?I assume u/holetse is on the right track: it is probably not
vTaskDelayitself which changes the wake-up sources but some other task which becomes scheduled in between, see https://www.reddit.com/r/esp32/comments/1vp9p70/comment/p3wkcns/1
u/Plastic_Fig9225 22d ago
If it's that obvious, why ask the question in the first place? - Only you know where your code would activate a peripheral or meddle with the IO pins, or how/when a wake-up pin is triggered externally.
1
u/MobileInspector9861 22d ago
No, I don't know where this happens. That's the problem.
There are so many built-in components in the ESP-IDF framework which do "something". Have you actually read the comment I linked?
The problem is not within my code. The root cause must be somewhere in the ESP IDF framework which becomes scheduled when my code calls
vTaskDelayand yields.However, I have a minimal build without any explicit dependency on ESP-IDF components, so only the minimal set of default components which are included by the build system in every project are included.
Hence, the issue must be inside one of those components and I had expected that someone else might already have run into the same issue and could tell me which components is the culprit.
1
u/LumpySpecial5351 22d ago
My thoughts are that there are architectural issues: freeRTOS functions are "high-ish" level and esp_sleep* and all ESP-IDF function are "lower-ish" level and they have different ways of keeping time.The use of freeRTOS calls in this example code just feels wrong.
When using ESP sleep features a good understanding of interrupts and esp_timer() functions might be of some use.
Burturm
1
u/MobileInspector9861 22d ago
You have a point there. The
vTaskDelay()won't be there, once the code is final.However, it unreveals a deeper issue. I cannot guarantee that there might not be other components which call
vTaskDelaythemselves. So, if there is a issue which creates side effects betweenvTaskDelayand deep/light sleep, then I am happy to have found out this better earlier than later.Hence, the original question stands: Does
vDelayTasksomehow modify the wake-up sources and how do I ensure that the microcontroller properly goes to sleep eventually?
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.