-
Notifications
You must be signed in to change notification settings - Fork 7.5k
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
PowerManagement support #9083
base: master
Are you sure you want to change the base?
PowerManagement support #9083
Changes from 26 commits
298b7a3
8e5c957
1511552
3277229
1518743
c2af5fd
82eb3d5
ffae7e9
9374554
5a7576f
eb86e50
25fd651
1575558
4375f4c
1b9474a
0b0698a
1ea4eea
d3c132b
ea7400f
096e5cb
45577bd
c58bc28
9166bc0
40702b2
80bcb52
205db45
9b93762
07046f8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
/* | ||
Cpu automatic LightSleep | ||
===================================== | ||
This code displays how to use automatic light sleep | ||
and demonstrates a difference between busywait and | ||
sleep-aware wait using delay(). | ||
Another examples of a 'sleep-friendly' blocking might be | ||
FreeRTOS mutexes/semaphores, queues. | ||
|
||
This code is under Public Domain License. | ||
|
||
Hardware Connections (optional) | ||
====================== | ||
Use an ammeter/scope connected in series with a CPU/DevKit board to measure power consumption | ||
|
||
Author: | ||
Taras Shcherban <[email protected]> | ||
*/ | ||
|
||
#include "Arduino.h" | ||
|
||
void setup() | ||
{ | ||
Serial.begin(115200); | ||
while (!Serial) | ||
; // wait for serial port to connect | ||
|
||
// CPU will automatically go into light sleep if no ongoing activity (active task, peripheral activity etc.) | ||
setAutomaticLightSleep(true); | ||
} | ||
|
||
void loop() | ||
{ | ||
Serial.printf("Time since boot: %ld ms; going to block for a 5 seconds...\n", millis()); | ||
|
||
// Serial output is being suspended during sleeping, so without a Flush call logs | ||
// will be printed to the terminal with a delay depending on how much CPU spends in a sleep state | ||
Serial.flush(); | ||
|
||
// This is a sleep-aware waiting using delay(). Blocking in this manner | ||
// allows CPU to go into light sleep mode until there is some task to do. | ||
// if you remove that delay completely - CPU will have to call loop() function constantly, | ||
// so no power saving will be available | ||
delay(5000); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
/* | ||
Gpio Interrupts with sleep mode | ||
===================================== | ||
This code displays how to use automatic light sleep with a GPIO interrupts. | ||
|
||
With a light sleep mode the only available interrupts are ONLOW_WE and ONHIGH_WE. | ||
RISING/FALLING/CHANGE/ONLOW/ONHIGH would be not fired. | ||
Keep in mind that the interrupt ONLOW_WE/ONLOW would be fired repetitively as long as | ||
the input is held in a LOW state, so a single button press by a fraction of second can | ||
easily trigger your interrupt handler a few hundreds times. | ||
The same is valid for ONHIGH_WE/ONHIGH and HIGH level. | ||
To catch every button press only once - we are going to change the interrupt level | ||
(from ONHIGH_WE to ONLOW_WE and vice versa). | ||
Since ONHIGH_WE interrupt handler is detached right on the first execution - it can be | ||
also treated as a RISING interrupt handler. | ||
The same way ONLOW_WE can be treated as a FALLING interrupt handler. | ||
If CHANGE interrupt is needed - just put your logic in both ONHIGH_WE and ONLOW_WE handlers. | ||
|
||
This code is under Public Domain License. | ||
|
||
Hardware Connections | ||
====================== | ||
A button from IO10 to ground (or a jumper wire to mimic that button). | ||
Optionally - an ammeter/scope connected in series with a CPU/DevKit board to measure power consumption. | ||
|
||
Author: | ||
Taras Shcherban <[email protected]> | ||
*/ | ||
|
||
#include "Arduino.h" | ||
#include <atomic> | ||
|
||
std::atomic_int interruptsCounter = 0; | ||
|
||
#define BTN_INPUT 10 | ||
|
||
void lowIsrHandler(); | ||
|
||
void IRAM_ATTR highIsrHandler() | ||
{ | ||
// button was released - attach button press interrupt back | ||
attachInterrupt(BTN_INPUT, lowIsrHandler, ONLOW_WE); | ||
} | ||
|
||
void IRAM_ATTR lowIsrHandler() | ||
{ | ||
// button is pressed - count it | ||
interruptsCounter++; | ||
|
||
// attach interrupt to catch an event of button releasing | ||
// implicitly detaches previous interrupt and stops this function from being called | ||
// while the input is held in a LOW state | ||
attachInterrupt(BTN_INPUT, highIsrHandler, ONHIGH_WE); | ||
} | ||
|
||
void setup() | ||
{ | ||
Serial.begin(115200); | ||
while (!Serial) | ||
; // wait for serial port to connect | ||
|
||
// CPU will automatically go into light sleep if no ongoing activity (active task, peripheral activity etc.) | ||
setAutomaticLightSleep(true); | ||
|
||
pinMode(BTN_INPUT, INPUT_PULLUP); | ||
attachInterrupt(BTN_INPUT, lowIsrHandler, ONLOW_WE); | ||
|
||
// this function is required for GPIO to be able to wakeup CPU from a lightSleep mode | ||
esp_sleep_enable_gpio_wakeup(); | ||
} | ||
|
||
void loop() | ||
{ | ||
Serial.printf("Button press count: %d\n", (int)interruptsCounter); | ||
|
||
// Serial output is being suspended during sleeping, so without a Flush call logs | ||
// will be printed to the terminal with a delay depending on how much CPU spends in a sleep state | ||
Serial.flush(); | ||
|
||
// This is a sleep-aware waiting using delay(). Blocking in this manner | ||
// allows CPU to go into light sleep mode until there is some task to do. | ||
// if you remove that delay completely - CPU will have to call loop() function constantly, | ||
// so no power saving will be available | ||
delay(5000); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
/* | ||
WiFi automatic LightSleep | ||
===================================== | ||
This code displays how to use automatic light sleep with an active WiFi connection | ||
and tune WiFi modem sleep modes | ||
|
||
This code is under Public Domain License. | ||
|
||
Hardware Connections (optional) | ||
====================== | ||
Use an ammeter/scope connected in series with a CPU/DevKit board to measure power consumption | ||
|
||
Author: | ||
Taras Shcherban <[email protected]> | ||
*/ | ||
|
||
#include "Arduino.h" | ||
|
||
#include <WiFi.h> | ||
#include <HTTPClient.h> | ||
|
||
const char *wifi_ssid = ""; | ||
const char *wifi_password = ""; | ||
|
||
void doHttpRequest(); | ||
|
||
void setup() | ||
{ | ||
Serial.begin(115200); | ||
while (!Serial) | ||
; // wait for serial port to connect | ||
|
||
// CPU will automatically go into light sleep if no ongoing activity (active task, peripheral activity etc.) | ||
setAutomaticLightSleep(true); | ||
|
||
WiFi.begin(wifi_ssid, wifi_password); | ||
|
||
// Additionally to automatic CPU sleep a modem can also be setup for a power saving. | ||
// If a WiFi is active - selected modem sleep mode will determine how much CPU will be sleeping. | ||
// There are two functions available:setSleep(mode) and setSleep(mode, listenInterval) | ||
// mode - supports one of three values: | ||
// * WIFI_PS_NONE - No power save | ||
// * WIFI_PS_MIN_MODEM - Minimum modem power saving. In this mode, station wakes up to receive beacon every DTIM period | ||
// * WIFI_PS_MAX_MODEM - Maximum modem power saving. In this mode, interval to receive beacons is determined by the listenInterval parameter | ||
// listenInterval - effective only with a WIFI_PS_MAX_MODEM mode. determines how often will modem (and consequently CPU) wakeup to catch WiFi beacon packets. | ||
// The larger the interval - the less power needed for WiFi connection support. However that comes at a cost of increased networking latency, i.e. | ||
// If your device responds to some external requests (web-server, ping etc.) - larger listenInterval means device takes more to respond. | ||
// Reasonable range is 2..9, going larger would not benefit too much in terms of power consumption. Too large value might result in WiFi connection drop. | ||
// listenInterval is measured in DTIM intervals, which is determined by your access point (typically ~100ms). | ||
WiFi.setSleep(WIFI_PS_MAX_MODEM, 4); | ||
} | ||
|
||
void loop() | ||
{ | ||
doHttpRequest(); | ||
|
||
// Serial output is being suspended during sleeping, so without a Flush call logs | ||
// will be printed to the terminal with a delay depending on how much CPU spends in a sleep state | ||
Serial.flush(); | ||
|
||
// This is a sleep-aware waiting using delay(). Blocking in this manner | ||
// allows CPU to go into light sleep mode until there is some task to do. | ||
// if you remove that delay completely - CPU will have to call loop() function constantly, | ||
// so no power saving will be available | ||
delay(5000); | ||
} | ||
|
||
// simulate some job - make an HTTP GET request | ||
void doHttpRequest() | ||
{ | ||
if (!WiFi.isConnected()) | ||
return; | ||
|
||
HTTPClient http; | ||
|
||
Serial.print("[HTTP] request...\n"); | ||
http.begin("http://example.com/index.html"); | ||
|
||
int httpCode = http.GET(); | ||
if (httpCode > 0) | ||
{ | ||
Serial.printf("[HTTP] GET... code: %d\n", httpCode); | ||
|
||
if (httpCode == HTTP_CODE_OK) | ||
{ | ||
Serial.printf("[HTTP] GET... payload size: %d\n", http.getSize()); | ||
} | ||
} | ||
else | ||
{ | ||
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str()); | ||
} | ||
|
||
http.end(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -621,6 +621,27 @@ bool WiFiGenericClass::setSleep(wifi_ps_type_t sleepType) { | |
return false; | ||
} | ||
|
||
bool WiFiGenericClass::setSleep(wifi_ps_type_t sleepType, uint16_t listenInterval) | ||
{ | ||
if (!setSleep(sleepType)) | ||
return false; | ||
|
||
wifi_config_t current_conf; | ||
if(esp_wifi_get_config((wifi_interface_t)ESP_IF_WIFI_STA, ¤t_conf) != ESP_OK){ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. from |
||
log_e("setSleep(wifi_ps_type_t sleepType, uint16_t listenInterval) failed: get current config failed!"); | ||
return false; | ||
} | ||
|
||
current_conf.sta.listen_interval = listenInterval; | ||
|
||
if(esp_wifi_set_config((wifi_interface_t)ESP_IF_WIFI_STA, ¤t_conf) != ESP_OK){ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. from |
||
log_e("setSleep(wifi_ps_type_t sleepType, uint16_t listenInterval) failed: set wifi config failed!"); | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* get modem sleep enabled | ||
* @return true if modem sleep is enabled | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -103,6 +103,16 @@ class WiFiGenericClass { | |
bool setSleep(wifi_ps_type_t sleepType); | ||
wifi_ps_type_t getSleep(); | ||
|
||
/** | ||
* @brief Set modem sleep state | ||
* @param sleepType Modem sleep type, one of WIFI_PS_NONE, WIFI_PS_MIN_MODEM, WIFI_PS_MAX_MODEM | ||
* @param listenInterval Listen interval for ESP32 station to receive beacon when WIFI_PS_MAX_MODEM is set. Units: AP beacon intervals. Defaults to 3 if set to 0. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it would be good to indicate the units of this parameter. As written it could be interpreted as milliseconds, seconds, minutes, etc. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unit is specified here (AP beacon intervals). It is determined by the access point parameters, I've often seen a 102400us value during testing with different routers, however it can differ. |
||
* @return | ||
* - true on success | ||
* - false on internal error when parameters combination is not valid | ||
*/ | ||
bool setSleep(wifi_ps_type_t sleepType, uint16_t listenInterval); | ||
|
||
bool setTxPower(wifi_power_t power); | ||
wifi_power_t getTxPower(); | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
from
to
?