feat: Dynamic light sleep support for ESP32 platform#7121
feat: Dynamic light sleep support for ESP32 platform#7121m1nl wants to merge 30 commits intomeshtastic:developfrom
Conversation
9526383 to
d8f2fcd
Compare
|
This is a ton of work, thank you very much |
|
If you have time .... I "maintain" the GPS code - just wondering what the impact might be there or whether we might need further extensions? |
|
AFAIK dynamic light-sleep in ESP32 platform makes the chip light-sleep when FreeRTOS waits for an event or there is an explicit vTaskDelay call (=~ sleep in Arduino). So most of the functionality shouldn't be impacted as Arduino runs all the code in one loop, which waits different intervals depending on the type of thread (using vTaskDelay under the hood). However, for critical modules or core functionality I added an explicit call to PowerFSM.trigger to exit LS state and allow for at least 300ms of uninterrupted processing time; another approach is to use "preflightSleepObserver" which prevents entering LS state if there is some work pending (like TX queue is not empty). I took a look at GPS code and I think we should exit LS state when we change state to GPS_ACTIVE and prevent entering LS as long as the state doesn't change. I'll take a look at the code and propose some changes soon. |
|
If there is a chance to have this feature merged, I'd appreciate getting some feedback on the additional repos to be hosted under |
|
@fifieldt changes committed; device should not go into light-sleep when GPS position is requested (=module is in GPS_ACTIVE state). I'm unable to test as I'm on vacation right now. |
151def2 to
a42c8f6
Compare
a42c8f6 to
892f77b
Compare
892f77b to
4223701
Compare
4223701 to
f58f5e5
Compare
|
hi,
|
058e904 to
50151fc
Compare
src/sleep.cpp
Outdated
| #if defined(ARCH_ESP32) && HAS_WIFI && !HAS_TFT | ||
|
|
||
| #if defined(ARCH_ESP32) && !HAS_TFT | ||
| #ifdef HAS_WIFI |
There was a problem hiding this comment.
Would it also make sense to have the HAS_ESP32_DYNAMIC_LIGHT_SLEEP (and HAS_ESP32_PM_SUPPORT, HAS_32768HZ) as a bool as well, instead of just checking #ifdef ?
It's more broad discussion about convention. This has to be decided on project level I guess.
There was a problem hiding this comment.
sure, I'll check these definitions and I can update them to bool. I see there is inconsistency about how we use HAS_XYZ flags in the project. I will create a separate PR for this.
|
General critique about having a lot of While I've already make a boot loop with those asserts because of a wrong setting, the more concerning part is that Surely some of the calls can fail in runtime or due to a wrong setting. Should we then crash the device? There is a known issue here that some ESP32 devices corrupt their device configuration when running on solar power. This not only increases the risk, but also cause the device to become irrecoverable, because of a wrong setting. Example: I'd recommend an approach that would fail in a recoverable way. |
The linker fails on ESP32 (not S3). |
| [env:heltec-v3] | ||
| extends = esp32s3_base | ||
| platform_packages = | ||
| platformio/framework-arduinoespressif32 @ https://github.com/m1nl/arduino-esp32/archive/refs/tags/2.0.17+5ae9873e.tar.gz ; disable WiFi IRAM optimizations in ESP-IDF |
There was a problem hiding this comment.
2.0.17 seems to be a downgrade from the current framework-arduinoespressif32 @ 3.20017.241212+sha.dcc1105b
There was a problem hiding this comment.
To be honest, I think Espressif’s versioning scheme is pretty misleading :) I spent several hours digging into it, so let me shed some light:
- If you check the release page you will see that current framework is based on Arduino v2.0.17, not v3.2.0; so this is a first red flag saying that the semantic version doesn't align with Arduino version in use - additionally, you'll see that release page mentions that Arduino framework is based on IDF v4.4.7 (which is already out of support).
- If you go to the PlatformIO Registry page for framework-arduinoespressif32, you'll see that release tag
v3.20017.241212+sha.dcc1105bdoesn't exist in GitHub. However if you trace hashdcc1105b, it points to this commit on branch release/v2.x.
What I did to create my custom repo:
- I created a fork of lib-builder repo
- Made release/v4.4 a default branch (to follow ESP-IDF version in use)
- Fixed scripts to ensure build uses compatible versions of esp-dl, esp_littlefs, esp-rainmaker, esp-dsp and tinyusb (it looks they're not really doing automated builds - without these modifications build fails as it tries to pull latest commit from branches which are no longer compatible with ESP-IDF v4.4.x)
- Changed sdkconfigs for esp32 platforms (to enable PM support)
- Built the framework (
./build.sh -i tags/v4.4.8 -A tags/2.0.17) - Created a fork of arduino-esp32 using branch release/v2.x as a main branch
- Copied binary artifacts from esp32-arduino-lib-builder to arduino-esp32 repository and commited them (this is wrong IMO, but this was the way Espressif was releasing the framework)
- Released arduino-esp32
For consistency, I stuck with the Arduino version number for naming. As for Espressif’s tag style (v3.20017.241212+sha.dcc1105b), I honestly have no idea what logic they’re following :)
I think the build process can be improved by creating a GitHub action which would combine binary output from esp32-arduino-lib-builder upon release of arduino-esp32; binary artifacts should be removed from arduino-esp32 repository.
This fails because the ESP32 platform has very limited IRAM available, and enabling PM capabilities pushes it beyond the limit. I’ll explore making the ESP-IDF components lighter to reduce memory usage without affecting Meshtastic functionality, but that may not be feasible. In the end, we may have to accept that dynamic light-sleep isn’t compatible with the ESP32. In newer ESP-IDF versions (5.x compatible with Arduino 3.2.x), there’s a new sdkconfig option CONFIG_ESP_SYSTEM_ESP32_SRAM1_REGION_AS_IRAM, which makes more RAM available as IRAM, allowing the build to succeed. However, adopting this would be a breaking change for the project, since it requires moving from Arduino 2.x to 3.x. I’ve already created and tested such a build with the current Meshtastic version, but this shift is too significant to include in this PR. |
Understood, I'll check if there is any assertion, which relies on user settings and make them fail safe. However I'd recommend to keep assertions for all calls, which use predefined values (board configuration, etc.). IMO this is the only way to validate the changes with all devices during alpha testing phase. Let me know what you think. |
2815ae5 to
89b296d
Compare
89b296d to
4b22d1d
Compare
4b22d1d to
2e860a8
Compare
|
I'm testing this on ESP32C3 and so far the testing is looking very good. My only nitpick is that I think that there should be a comment in e.g. |
fix logging make log entry more consistent
current value of 256 bytes is very dangerous and may negatively impact the overall performance; we need to keep in mind that spiram is very slow comparing to regular RAM and many things may just fail; in my case, dynamic light-sleep made the device unoperational; spiram can be used to offload some costly allocations but this is not the right way to handle that
d2f8cfb to
1cdb65d
Compare
|
@thebentern I spent several days debugging why this PR made SPIRAM-capable devices extremely unstable when using latest develop branch. I was able to narrow the issue down to commit 5910cc2, which changes the SPIRAM allocation threshold to a very aggressive value of 256 bytes. We need to keep in mind that SPIRAM is significantly slower than internal RAM, and moving small allocations there can easily cause subtle and hard-to-debug failures. In my case, enabling dynamic light sleep made the device completely unresponsive. With a 256-byte threshold, even very small buffers are pushed to SPIRAM, and this was causing Bluetooth to hang after sleep. SPIRAM can absolutely be used to offload larger, memory-heavy allocations - but lowering the threshold this much is not the right approach. Based on my experience with ESP32 development, keeping it at 256 bytes will likely introduce instability in components like LittleFS and other subsystems that are already difficult to debug. For reference:
Given this, I strongly recommend against keeping the 256-byte threshold. One comment regarding my changes conflicting with af518fb - I have also noticed that before and I added holds for these pins in my PR some time ago. However I don't understand, why we skip these pins when holds are disabled. We need to keep in mind that GPIO holds should be active only during sleep, so all of them have to be disabled after sleeping to avoid issues with normal GPIO usage. The PR itself is now complete, and I’ve moved it to "ready" state. I’d really appreciate getting it merged. Two things to consider:
I'm happy to discuss all the changes, I'm available for a longer conversation on discord, just let me now. |
fixes #6660
I've finally implemented the Feature Request I created a few months ago. Since then, I've been testing the dynamic light-sleep functionality and haven't encountered any issues.
In the initial version, legacy light-sleep support with the default Arduino framework could lead to problems after my changes. To address this, I had to rewrite and refactor parts of the code to ensure compatibility with builds compiled using the default PlatformIO Arduino framework.
I tested the updated implementation on a Heltec V3 board in the following scenarios:
There are a few topics that need discussion:
meshtasticorganization.platformio.inifiles for the hardware variants I was able to test. I shared customized builds with others, who confirmed they were working as expected.variant.hfiles for the hardware variants which do have 32kHz oscillator, according to Espressif docs, it helps with Bluetooth stability when dynamic light-sleep is enabledLinks to repositiories mentioned in 1) :
🤝 Attestations