Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extending on the new WiFi-less startup and new power saving APIs in ESP class #7979

Open
wants to merge 44 commits into
base: master
Choose a base branch
from

Conversation

dok-net
Copy link
Contributor

@dok-net dok-net commented Apr 13, 2021

Implementing in ESP class the sleep modes that are pertinent with and without WiFi:

  • forced light sleep, with/without timeout, with/without GPIO wakeup.
  • automatic light sleep when idling, like during delay()
  • automatic modem sleep when idling, like during delay()
  • never sleeping (NONE_SLEEP_T)

For sketches without WiFi, additional RF powersaving mode support on power up and deep-sleep resume. Could avoid power use spikes and delays during startup.

WiFi default is "off" now, don't force sleep in setup() of examples that do use WiFi.

Examples for the new modes.

Fixes #7055 - thanks to @Tech-TX for pointing this out.

@dok-net dok-net changed the title WiFi default is off now, don't force sleep in setup() of examples Extending on the new WiFi-less startup and new power saving APIs in ESP class Apr 15, 2021
@dok-net dok-net force-pushed the wifioff branch 8 times, most recently from 5732573 to ab8a20e Compare April 18, 2021 09:58
cores/esp8266/Esp.cpp Show resolved Hide resolved
cores/esp8266/core_esp8266_phy.cpp Outdated Show resolved Hide resolved
cores/esp8266/Esp.cpp Outdated Show resolved Hide resolved
cores/esp8266/Esp.h Outdated Show resolved Hide resolved
@dok-net dok-net force-pushed the wifioff branch 6 times, most recently from 1f08089 to 68875bf Compare April 25, 2021 11:05
@Tech-TX
Copy link
Contributor

Tech-TX commented Apr 25, 2021

I've been doing some testing for Dirk for a week or two, and have re-verified the correct operation of this last commit 637f5d6. The timers are properly re-attached after Forced Light Sleep, which I never could get to. Thanks, Dirk! The three examples function as expected, and all power saving modes hit the right current levels. No surprises, no warts that I've seen. For people using servos I'd stop them before Forced Light Sleep, else they may slam the stops when PWM halts. You can restart them afterwards.

In order to maintain WiFi across Forced Light Sleep you must sleep the modem cleanly before ESP.forcedLightSleepBegin(). I tried it the dirty way and WiFi wouldn't recover after Sleep.
I tested WiFi.forceSleepBegin(0xFFFFFFF) (sleep forever) before putting it to sleep, and WiFi.forceSleepWake() after it had recovered from ESP.forcedLightSleepEnd(). No problems restoring the connection that way.

I need to revisit #6989 and clean that demo program up with the new API calls. When merged this closes #7055

I didn't review all of the code, merely tested the functionality very thoroughly.

@Tech-TX
Copy link
Contributor

Tech-TX commented Apr 27, 2021

Utterly side comment, not required for this PR: I think I just figured out how the NodeMCU folks implemented something like 'wake from Forced Light Sleep with a CHANGE level interrupt', not just the HI LEVEL and LO LEVEL specified in the API Reference.

If you read the pin level of the interrupt pin just before going to Forced Light Sleep and set the interrupt to the opposite level, it accomplishes the same thing. Going in with a HIGH on the pin, set the interrupt to LOW and vice versa. Then any change during Forced Light Sleep wakes it, and the user doesn't care what state the pin had been in immediately prior to Sleep; any change wakes it up.

Since the interrupt attachment is done outside of this API wrapper, the end user would have to do this in their code.

Due to the delay() needed to put it to Sleep, there's a small but nonzero chance that the pin might change after you read it, and it wouldn't come out of Sleep at all without a Reset as the Sleep logic is all mangled.

cores/esp8266/Esp.cpp Outdated Show resolved Hide resolved
cores/esp8266/Esp.cpp Show resolved Hide resolved
doc/libraries.rst Outdated Show resolved Hide resolved
cores/esp8266/core_esp8266_main.cpp Show resolved Hide resolved
cores/esp8266/core_esp8266_phy.cpp Show resolved Hide resolved
@dok-net dok-net force-pushed the wifioff branch 3 times, most recently from e8cab42 to 5a73c73 Compare May 1, 2021 14:04
@dok-net dok-net force-pushed the wifioff branch 3 times, most recently from 2a34cbd to 336c1c9 Compare May 17, 2021 11:07
@dok-net
Copy link
Contributor Author

dok-net commented Mar 12, 2023

Reinstated #define RF_PRE_INIT() due to its use in #8783

Comment on lines +178 to +187
void EspClass::forcedModemSleepOff()
{
const sleep_type_t sleepType = wifi_fpm_get_sleep_type();
if (sleepType != NONE_SLEEP_T) {
if (sleepType == MODEM_SLEEP_T) wifi_fpm_do_wakeup();
wifi_fpm_close();
}
wifi_fpm_set_sleep_type(saved_sleep_type);
saved_sleep_type = NONE_SLEEP_T;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Combine with begin() as a single operation?
If begin() called once and then off(), sort-of works (if fpm was not enabled externally)
If begin() called once and then again, sleep mode gets overwritten

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any calls to the SDK or modifying sleep modes by sidelining this API is undefined behavior. Simple as that.
The saved_sleep_type, if that is what you are focused on, is rather a convenience than a full-blown requirement for this to be useful. I don't see any real malfunction if its used the way you described.

#ifdef HAVE_ESP_SUSPEND
esp_delay(10);
#else
delay(10);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we waiting for certain condition to happen? Should it check something instead of assuming 10ms delay does something?
also not necessary ifdef

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your opinion may differ, even for a reason, but I implement to the public specification and as my comment // SDK turns on forced modem sleep in idle task explains, there shall be a delay for the idle task to take over.
Thanks for picking up the quite dated HAVE_ESP_SUSPEND, it's been so long, I don't even recall where and when it was ever defined.

wifi_fpm_set_sleep_type(MODEM_SLEEP_T);
wifi_fpm_open();
saved_wakeupCb = nullptr;
if (wakeupCb) wifi_fpm_set_wakeup_cb(wakeupCb);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fpm_wakeup_cb_func will be called after system wakes up only if the force sleep
time out (wifi_fpm_do_sleep and the parameter is not 0xFFFFFFF).
fpm_wakeup_cb_func will not be called if wake-up is caused by
wifi_fpm_do_wakeup from MODEM_SLEEP_T type force sleep.

Also, perhaps, not necessary to expose to user? Isn't return signal enough of a result?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there's no hurt in exposing it as an option, let's keep it this way, please.

cores/esp8266/Esp.cpp Show resolved Hide resolved
#endif
{
esp8266::InterruptLock lock;
saved_timer_list = timer_list;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-//- as modem - if we hide timer list, it should not be possible for user to overwrite this accidentally. Single operation instead of separate begin() -> end()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This way, it worked/works, other ways, it didn't work/does work, i.e. doesn't enter the power saving modes properly. It was all carefully measured by the other guy at the time. Whatever happened to him :-(

Single operation instead of separate begin() -> end()?

I don't understand that sentence, I am sorry.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This way, it worked/works, other ways, it didn't work/does work, i.e. doesn't enter the power saving modes properly. It was all carefully measured by the other guy at the time. Whatever happened to him :-(

Sadly, yeah, might be difficult to test at this point from our baseline of knowledge :/
As I understand it, we have issue where SDK processes timer list. So, that is what we try to avoid in code. If there is an ets_post to a task, does it still work? Are timers waking up early, or SDK never sleeps / idles to begin with?

I don't understand that sentence, I am sorry.

Something like InterruptLock. Imagine FpmThingy class that enables sleep on begin or construction, and disables on destruction. It may or may not be applicable to our internal usage, but seems like a better API for user side of things. Plus, it would not be necessary to expose too much methods to control it

Copy link
Contributor Author

@dok-net dok-net Jun 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mcspr I have added an RAII class and modified libraries\esp8266\examples\ForcedLightSleep\ForcedLightSleep.ino. Please review that and let me know if that matches to what you had in mind. Thanks for the suggestion!

#endif
{
esp8266::InterruptLock lock;
saved_timer_list = timer_list;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Repeating the q from above - what is the difference between GPIO-activated sleep and timed one here? Is CPU really sleeping or we just simulate that it does?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OMG, you are asking questions that I cannot remember the answer to, except that I am 100% certain that we literally did hours of repetitive tests to show that power consumption dropped to the expected levels, and it didn't or the MCU became unreliable or the tables got corrupted if it wasn't done in exactly this - documented by Espressif - way. We really should not change a single line.

Copy link
Collaborator

@mcspr mcspr Jun 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, but now we have a half-understood feature that maybe works?
Reading our issues simply repeats the above - we copy nodemcu and test how it did. I'd have to read that yet again if you don't have link or an explanation :/
(nodemcu/nodemcu-firmware#1231 (comment) and below)
edit: link oops

Copy link
Contributor Author

@dok-net dok-net Jun 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure we are not talking past each other. The sleep isn't actived by the GPIO, but cancelled. Same for the timer. I'm sure that's what you meant. As far as it got measure two years ago, yes we were sure it did as advertised - sleeping to save power, resuming either by GPIO trigger - push of a button - or timeout.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mcspr Is this now stalled again due to to unrelated workload, or have my changes and explanations been unconvincing so far? I would be totally relieved if this finally got merged, I am sure it will help people a lot, at least it might allow more specific reports about power-saving mode issues?

cores/esp8266/Esp.cpp Outdated Show resolved Hide resolved
cores/esp8266/Esp.cpp Outdated Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement low power mode api
4 participants