From 0c870ae1013d91263c72390b5e0d5f033042a700 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Sun, 5 Jan 2020 21:05:58 -0600 Subject: [PATCH 01/51] add Low-Power demo --- .../examples/LowPowerDemo/LowPowerDemo.ino | 365 ++++++++++++++++++ .../esp8266/examples/LowPowerDemo/README.md | 106 +++++ 2 files changed, 471 insertions(+) create mode 100644 libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino create mode 100644 libraries/esp8266/examples/LowPowerDemo/README.md diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino new file mode 100644 index 0000000000..f7181a3b37 --- /dev/null +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -0,0 +1,365 @@ +/* This example demonstrates the different low-power modes of the ESP8266 + + My initial setup was a WeMos D1 Mini with 3.3V connected to the 3V3 pin through a meter + so that it bypassed the on-board voltage regulator and USB chip. There's still about + 0.3 mA worth of leakage current due to the unpowered chips, so an ESP-01 will show lower + current readings than what I could achieve. These tests should work with any module. + While the modem is on the current is 67 mA or jumping around with a listed minimum. + To verify the 20 uA Deep Sleep current I removed the voltage regulator and USB chip. + + Since I'm now missing the USB chip, I've included OTA upload. You'll need to upload + from USB or a USB-to-TTL converter the first time, then you can disconnect and use OTA + afterwards during any test if the WiFi is connected. Some tests disconnect or sleep WiFi + so OTA won't go through. If you want OTA upload, hit RESET & press the test button once. + + This test assumes you have a pushbutton switch connected between D3 and GND to advance + the tests. You'll also need to connect D0/GPIO16 to RST for the Deep Sleep tests. + If you forget to connect D0 to RST it will hang after the first Deep Sleep test. + Connect an LED from any free pin through a 330 ohm resistor to the 3.3V supply, NOT the 3V3 + pin on the module or it adds to the measured current. When it blinks you can proceed. + When the LED is lit continuously it's connecting WiFi, when it's off the CPU is asleep. + The LED blinks slowly when the tests are complete. + + WiFi connections will be made over twice as fast if you can use a static IP address. + + This example code is in the public domain, and was inspired by code from numerous sources */ + +#include +#include +#include +#include +#include + +//#define DEBUG // prints WiFi connection info to serial, uncomment if you want WiFi messages +#ifdef DEBUG +#define DEBUG_PRINTLN(x) Serial.println(x) +#define DEBUG_PRINT(x) Serial.print(x) +#else +#define DEBUG_PRINTLN(x) +#define DEBUG_PRINT(x) +#endif + +#define WAKE_UP_PIN D3 // GPIO0, can also force a serial flash upload with RESET + +// un-comment one of the two lines below for your LED connection +#define LED D1 // external LED for modules with built-in LEDs so it doesn't add to the current +//#define LED D4 // GPIO2 LED for ESP-01,07 modules; D4 is LED_BUILTIN on most other modules + +ADC_MODE(ADC_VCC); // allows us to monitor the internal VCC level; it varies with WiFi load +// don't connect anything to the analog input pin(s)! + +// enter your WiFi configuration below +const char* AP_SSID = "SSID"; // your router's SSID here +const char* AP_PASS = "password"; // your router's password here +IPAddress staticIP(0, 0, 0, 0); // parameters below are for your static IP address, if used +IPAddress gateway(0, 0, 0, 0); +IPAddress subnet(0, 0, 0, 0); +IPAddress dns1(0, 0, 0, 0); +IPAddress dns2(0, 0, 0, 0); + + +// CRC function used to ensure data validity of RTC User Memory +uint32_t calculateCRC32(const uint8_t *data, size_t length); + +// This structure will be stored in RTC memory to remember the reset loop count. +// First field is CRC32, which is calculated based on the rest of the structure contents. +// Any fields can go after the CRC32. The structure must be 4-byte aligned. +struct { + uint32_t crc32; + byte data[4]; // the last byte stores the reset count +} rtcData; + +byte resetLoop = 0; // keeps track of the number of Deep Sleep tests / resets +String resetCause = ""; + +const unsigned int blinkDelay = 100; // fast blink rate for the LED when waiting for the user +const unsigned int longDelay = 350; // longer delay() for the two AUTOMATIC modes +esp8266::polledTimeout::periodicFastMs blinkLED(blinkDelay); +// use fully qualified type and avoid importing all ::esp8266 namespace to the global namespace + +void wakeupCallback() { // unlike ISRs, you can do a print() from a callback function + Serial.println(F("Woke from Forced Light Sleep - this is the callback")); +} + +void setup() { + pinMode(LED, OUTPUT); // Activity and Status indicator + digitalWrite(LED, LOW); // turn on the LED + pinMode(WAKE_UP_PIN, INPUT_PULLUP); // polled to advance tests, INTR for Forced Light Sleep + Serial.begin(115200); + Serial.print(F("\nReset reason = ")); + String resetCause = ESP.getResetReason(); + Serial.println(resetCause); + if (resetCause == "External System") { + Serial.println(F("I'm awake and starting the low power tests")); + resetLoop = 5; + updateRTC(); // if external reset, wipe the RTC memory and start all over + } + + // Read struct from RTC memory + if (ESP.rtcUserMemoryRead(64, (uint32_t*) &rtcData, sizeof(rtcData))) { + uint32_t crcOfData = calculateCRC32((uint8_t*) &rtcData.data[0], sizeof(rtcData.data)); + if (crcOfData != rtcData.crc32) { // if the CRC is invalid + resetLoop = 0; // set first test loop since power on or external reset + } else { + resetLoop = rtcData.data[3]; // read the previous reset count + } + } +} // end of Setup() + +void loop() { + if (resetLoop == 0) { + // 1st test - running with WiFi unconfigured, reads ~67 mA minimum + Serial.println(F("\n1st test - running with WiFi unconfigured")); + float volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.println(F("press the button to continue")); + waitPushbutton(false, blinkDelay); + + // 2nd test - Automatic Modem Sleep 7 seconds after WiFi is connected (LED flashes) + Serial.println(F("\n2nd test - Automatic Modem Sleep")); + Serial.println(F("connecting WiFi, please wait until the LED blinks")); + init_WiFi(); + init_OTA(); + Serial.println(F("The current will drop in 7 seconds.")); + volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.println(F("press the button to continue")); + waitPushbutton(true, longDelay); + + // 3rd test - Forced Modem Sleep + Serial.println(F("\n3rd test - Forced Modem Sleep")); + WiFi.forceSleepBegin(); + delay(10); // it doesn't always go to sleep unless you delay(10) + volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.println(F("press the button to continue")); + waitPushbutton(false, blinkDelay); + + // 4th test - Automatic Light Sleep + Serial.println(F("\n4th test - Automatic Light Sleep")); + Serial.println(F("reconnecting WiFi")); + Serial.println(F("it will be in Automatic Light Sleep once WiFi connects (LED blinks)")); + digitalWrite(LED, LOW); // visual cue that we're reconnecting + WiFi.setSleepMode(WIFI_LIGHT_SLEEP, 5); // Automatic Light Sleep + WiFi.forceSleepWake(); // reconnect with previous STA mode and connection settings + while (!WiFi.localIP()) + delay(50); + volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.println(F("press the button to continue")); + waitPushbutton(true, longDelay); + + // 5th test - Forced Light Sleep using Non-OS SDK calls + Serial.println(F("\n5th test - Forced Light Sleep using Non-OS SDK calls")); + WiFi.mode(WIFI_OFF); // you must turn the modem off; using disconnect won't work + yield(); + digitalWrite(LED, HIGH); // turn the LED off so they know the CPU isn't running + volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.println(F("CPU going to sleep, pull WAKE_UP_PIN low to wake it (press the button)")); + delay(100); // needs a brief delay after the print or it may print the whole message + wifi_fpm_set_sleep_type(LIGHT_SLEEP_T); + gpio_pin_wakeup_enable(GPIO_ID_PIN(WAKE_UP_PIN), GPIO_PIN_INTR_LOLEVEL); + // only LOLEVEL or HILEVEL interrupts work, no edge, that's an SDK or CPU limitation + wifi_fpm_set_wakeup_cb(wakeupCallback); // Set wakeup callback (optional) + wifi_fpm_open(); + wifi_fpm_do_sleep(0xFFFFFFF); // only 0xFFFFFFF allowed; any other value and it won't sleep + delay(10); // it goes to sleep some time during this delay() and waits for an interrupt + Serial.println(F("Woke up!")); // the interrupt callback hits before this is executed + + // 6th test - Deep Sleep for 10 seconds, wake with RF_DEFAULT + Serial.println(F("\n6th test - Deep Sleep for 10 seconds, wake with RF_DEFAULT")); + init_WiFi(); // initialize WiFi since we turned it off in the last test + init_OTA(); + resetLoop = 1; // advance to the next Deep Sleep test after the reset + updateRTC(); // save the current test state in RTC memory + volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.println(F("press the button to continue")); + while (!digitalRead(WAKE_UP_PIN)) // wait for them to release the button from the last test + delay(10); + delay(50); // debounce time for the switch, button released + waitPushbutton(false, blinkDelay); + digitalWrite(LED, LOW); // turn the LED on, at least briefly + Serial.println(F("going into Deep Sleep now...")); + delay(10); // sometimes the \n isn't printed without a short delay + ESP.deepSleep(10E6, WAKE_RF_DEFAULT); // good night! D0 fires a reset in 10 seconds... + delay(10); + // if you do ESP.deepSleep(0, mode); it needs a RESET to come out of sleep (RTC is off) + // maximum timed Deep Sleep interval = 71.58 minutes with 0xFFFFFFFF + // the 2 uA GPIO current during Deep Sleep can't drive the LED so it's off now + Serial.println(F("What... I'm not asleep?!?")); // it will never get here + } + + // 7th test - Deep Sleep for 10 seconds, wake with RFCAL + if (resetLoop < 4) { + init_WiFi(); // need to reinitialize WiFi & OTA due to Deep Sleep resets + init_OTA(); // since we didn't do it in setup() because of the first test + } + if (resetLoop == 1) { // second reset loop since power on + resetLoop = 2; // advance to the next Deep Sleep test after the reset + updateRTC(); // save the current test state in RTC memory + Serial.println(F("\n7th test - in RF_DEFAULT, Deep Sleep for 10 seconds, wake with RFCAL")); + float volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.println(F("press the button to continue")); + waitPushbutton(false, blinkDelay); + Serial.println(F("going into Deep Sleep now...")); + delay(10); // sometimes the \n isn't printed without a short delay + ESP.deepSleep(10E6, WAKE_RFCAL); // good night! D0 fires a reset in 10 seconds... + delay(10); + Serial.println(F("What... I'm not asleep?!?")); // it will never get here + } + + // 8th test - Deep Sleep Instant for 10 seconds, wake with NO_RFCAL + if (resetLoop == 2) { // third reset loop since power on + resetLoop = 3; // advance to the next Deep Sleep test after the reset + updateRTC(); // save the current test state in RTC memory + Serial.println(F("\n8th test - in RFCAL, Deep Sleep Instant for 10 seconds, wake with NO_RFCAL")); + float volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.println(F("press the button to continue")); + waitPushbutton(false, blinkDelay); + Serial.println(F("going into Deep Sleep now...")); + delay(10); // sometimes the \n isn't printed without a short delay + ESP.deepSleepInstant(10E6, WAKE_NO_RFCAL); // good night! D0 fires a reset in 10 seconds... + delay(10); + Serial.println(F("What... I'm not asleep?!?")); // it will never get here + } + + // 9th test - Deep Sleep Instant for 10 seconds, wake with RF_DISABLED + if (resetLoop == 3) { // fourth reset loop since power on + resetLoop = 4; // advance to the next Deep Sleep test after the reset + updateRTC(); // save the current test state in RTC memory + Serial.println(F("\n9th test - in NO_RFCAL, Deep Sleep Instant for 10 seconds, wake with RF_DISABLED")); + float volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.println(F("press the button to continue")); + waitPushbutton(false, blinkDelay); + Serial.println(F("going into Deep Sleep now...")); + delay(10); // sometimes the \n isn't printed without a short delay + ESP.deepSleepInstant(10E6, WAKE_RF_DISABLED); // good night! D0 fires a reset in 10 seconds... + delay(10); + Serial.println(F("What... I'm not asleep?!?")); // it will never get here + } + + if (resetLoop == 4) { + resetLoop = 5; // start all over + updateRTC(); // save the current test state in RTC memory + float volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.println(F("\nTests completed, in RF_DISABLED, press the button to do an ESP.restart()")); + waitPushbutton(false, 1000); + ESP.restart(); + } +} + +void waitPushbutton(bool usesDelay, unsigned int delayTime) { // loop until they press the button + // note: 2 different modes, as both of the AUTOMATIC power saving modes need a long delay() + if (!usesDelay) { // quick interception of button press, no delay() + blinkLED.reset(delayTime); + while (digitalRead(WAKE_UP_PIN)) { // wait for a button press + if (blinkLED) { + digitalWrite(LED, !digitalRead(LED)); // toggle the activity LED + if (WiFi.localIP()) // don't check OTA if WiFi isn't connected + ArduinoOTA.handle(); //see if we need to reflash + } + yield(); + } + } else { // long delay() for the 2 AUTOMATIC modes, but it misses quick button presses + while (digitalRead(WAKE_UP_PIN)) { // wait for a button press + digitalWrite(LED, !digitalRead(LED)); // toggle the activity LED + if (WiFi.localIP()) // don't check OTA if WiFi isn't connected + ArduinoOTA.handle(); //see if we need to reflash + delay(delayTime); + } + } + delay(50); // debounce time for the switch, button pressed + while (!digitalRead(WAKE_UP_PIN)) // now wait for them to release the button + delay(10); + delay(50); // debounce time for the switch, button released +} + +uint32_t calculateCRC32(const uint8_t *data, size_t length) { + uint32_t crc = 0xffffffff; + while (length--) { + uint8_t c = *data++; + for (uint32_t i = 0x80; i > 0; i >>= 1) { + bool bit = crc & 0x80000000; + if (c & i) { + bit = !bit; + } + crc <<= 1; + if (bit) { + crc ^= 0x04c11db7; + } + } + } + return crc; +} + +void updateRTC() { + rtcData.data[3] = resetLoop; // save the loop count for the next reset + // Update CRC32 of data + rtcData.crc32 = calculateCRC32((uint8_t*) &rtcData.data[0], sizeof(rtcData.data)); + if (resetLoop == 5) // wipe the CRC in RTC memory when we're done with all tests + rtcData.crc32 = 0; + // Write struct to RTC memory + ESP.rtcUserMemoryWrite(64, (uint32_t*) &rtcData, sizeof(rtcData)); +} + +void init_WiFi() { + /* Explicitly set the ESP8266 as a WiFi-client (STAtion mode), otherwise by default it + would try to act as both a client and an access-point and could cause network issues + with other WiFi devices on your network. */ + digitalWrite(LED, LOW); // give a visual indication that we're alive but busy + WiFi.persistent(false); // don't store the connection each time to save wear on the flash + WiFi.mode(WIFI_STA); + WiFi.config(staticIP, gateway, subnet); // if using static IP, enter parameters at the top + WiFi.begin(AP_SSID, AP_PASS); + Serial.print(F("connecting to WiFi ")); + Serial.println(AP_SSID); + DEBUG_PRINT(F("my MAC: ")); + DEBUG_PRINTLN(WiFi.macAddress()); + while (WiFi.status() != WL_CONNECTED) + delay(50); + DEBUG_PRINTLN(F("WiFi connected")); + while (!WiFi.localIP()) + delay(50); + WiFi.setAutoReconnect(true); + DEBUG_PRINT(F("WiFi Gateway IP: ")); + DEBUG_PRINTLN(WiFi.gatewayIP()); + DEBUG_PRINT(F("my IP address: ")); + DEBUG_PRINTLN(WiFi.localIP()); +} + +void init_OTA() { + // Port defaults to 8266 + // ArduinoOTA.setPort(8266); + + // Hostname defaults to esp8266-[ChipID] + // ArduinoOTA.setHostname("myesp8266")); + + // No authentication by default + // ArduinoOTA.setPassword((const char *)"123")); + + ArduinoOTA.onStart([]() { + Serial.println(F("Start")); + }); + ArduinoOTA.onEnd([]() { + Serial.println(F("\nEnd")); + }); + ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { + Serial.printf("Progress: %u%%\r", (progress / (total / 100))); + }); + ArduinoOTA.onError([](ota_error_t error) { + Serial.printf("Error[%u]: ", error); + if (error == OTA_AUTH_ERROR) Serial.println(F("Auth Failed")); + else if (error == OTA_BEGIN_ERROR) Serial.println(F("Begin Failed")); + else if (error == OTA_CONNECT_ERROR) Serial.println(F("Connect Failed")); + else if (error == OTA_RECEIVE_ERROR) Serial.println(F("Receive Failed")); + else if (error == OTA_END_ERROR) Serial.println(F("End Failed")); + }); + ArduinoOTA.begin(); + yield(); +} diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md new file mode 100644 index 0000000000..aec7b589e5 --- /dev/null +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -0,0 +1,106 @@ +#
Low-Power Demo
+ +There is a lot of confusion, out-of-date information, and bad examples of how to use the 5 basic low-power modes of the ESP8266. This demo code shows you how to use them reliably. If you're here for very low power, then the 2 Light Sleep modes and Deep Sleep are what you want. + +The two relevant reference manuals from Espressif are the [Low-Power Solutions](https://www.espressif.com/sites/default/files/documentation/9b-esp8266-low_power_solutions__en.pdf) and the [Non-OS SDK API Reference](https://www.espressif.com/sites/default/files/documentation/2c-esp8266_non_os_sdk_api_reference_en.pdf). There is more information in the two PDFs than I have presented here, so you'll want both of them for your reference. + + +The table below is a corrected version of Table 1.1 from the Low-Power Solutions PDF. The currents listed are absolute minimums, and most people will not get that low with typical hardware and program. + +| item | Automatic Modem Sleep | Forced Modem Sleep | Automatic Light Sleep | Forced Light Sleep | Forced Deep Sleep | +|:---------------------:|:---------------------:|:------------------:|:---------------------:|:------------------:|:------------------:| +| WiFi connectivity | Connected | Disconnected | Connected | Disconnected | Disconnected | +| GPIO state | Unchanged | Unchanged | Unchanged | Unchanged | Low current (2 uA) | +| WiFi | ON | OFF | ON | OFF | OFF | +| System Clock | ON | ON | CYCLING | OFF | OFF | +| RTC | ON | ON | ON | ON | ON (1) | +| CPU | ON | ON | ON | ON | OFF | +| Substrate Current | 15 mA | 15 mA | 2-15 mA (2) | 0.4 mA | 20 uA | +| Avg Current DTIM = 1 | 16.2 mA | | (1.8 mA) | | | +| Avg Current DTIM = 3 | 15.4 mA | | (0.9 mA) | | | +| Avg Current DTIM = 10 | 15.2 mA | | (0.55 mA) | | | + +Notes: +(1) setting a sleep time of 0 for Deep Sleep turns off the RTC, requiring an external RESET to wake it +(2) due to a bug in SDK 2, the minimum current will never be less than 2 mA and is frequently 15 mA between DTIM beacons + +I haven't verified the Average Current with different DTIM settings. I expect the numbers above aren't realistic. All of the currents listed in this README are for the ESP8266 chip. Modules that have voltage regulators, USB chips or other hardware will draw more. + +--- + +## Basic Tests in the Demo + +1. Unconfigured modem +2. Automatic Modem Sleep +3. Forced Modem Sleep +4. Automatic Light Sleep +5. Forced Light Sleep (stop the clock, and wait for an interrupt) +6. Deep Sleep for 10 seconds, wake with default modem power settings +7. Deep Sleep for 10 seconds, wake with RFCAL +8. Deep Sleep Instant for 10 seconds, wake with NO_RFCAL +9. Deep Sleep Instant for 10 seconds, wake with RF_DISABLED + +--- + +### Test 1 - Unconfigured modem + +This is typical for programs that don't use WiFi, and is a high current drain of at least 67 mA continuous. Even if you don't plan to use WiFi, it's wise to use the SDK 2 functions below in **Lower Power without the WiFi library** to reduce the power. + +### Test 2 - Automatic Modem Sleep + +This is the default power saving mode when you have an active WiFi connection. You don't need to add anything to your code to get it. However, it's not as wonderful as it may seem, as the only time the modem sleeps is when you spend a long time in delay(), with delay times over 50mS. The LED blinks more slowly during this test as I'm doing delay(350) to get the modem to sleep. While in delay() your sketch isn't doing anything interesting. Average current during long delay()s is 15 mA minimum. Without the delay() the average current is 67 mA with short spikes above 250 mA as transmissions occur. When the WiFi has traffic (even couple of pings), the modem can turn on for over 2 seconds continuous at 67 mA, and it may stay on for a second after the traffic. In a high traffic environment you won't get any power savings with either of the 2 Automatic modes. Automatic Modem Sleep turns on 7-8 seconds after an active connection is established. + +### Test 3 - Forced Modem Sleep + +Turns off the modem (losing the connection), and dropping the current by 50 mA. This uses the WiFi library function. It's good if there is a long interval with no expected traffic, as you can do other things while only drawing 15 mA. + +### Test 4 - Automatic Light Sleep + +Like Automatic Modem Sleep, with the same restrictions. Once configured it's immediately active when a connection is established. During periods of long delay() the average current can drop to ~2 mA. In a network with sparse traffic you might get something near 2-5 mA average current. The LED blinks more slowly during this test as I'm doing delay(350) to get the modem to sleep. + +### Test 5 - Forced Light Sleep + +Similar to Deep Sleep, but without the timer. The chip sleeps at 0.4 mA current until it is woken by an external interrupt. The only allowed interrupts are high level and low level; edge interrupts won't work. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using Forced Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more efficient. The chip wakes after an interrupt in about 5.1mS. + +### Test 6 - Deep Sleep, wake with RF_DEFAULT + +In Deep Sleep almost everything is turned off, and the chip draws ~20 uA. If you have D0/GPIO16 connected to RST, you can use the RTC timer to wake the chip up at a timed interval. You can also wake it with an external RESET. Waking with RF_DEFAULT means it will do an RFCAL if it needs to. These first two Deep Sleep tests use the standard Deep Sleep function, so the WiFi connection is closed and the modem turned off, which takes about 270mS before Deep Sleep begins. Deep Sleep ends with a RESET, and the boot time after that is around 120mS. Any Deep Sleep less than 2 seconds is wasting power due to the boot time and modem shut-off, and Forced Light Sleep will be a better choice. + +### Test 7 - Deep Sleep, wake with RFCAL + +Identical to the test above, but the modem does a power calibration when booting. In normal use, I'd likely do WAKE_RF_DEFAULT instead to save the extra RFCAL power burst if it's not needed. + +### Test 8 - Deep Sleep Instant, wake with NO_RFCAL + +This variation doesn't do an automatic RF calibration, so power requirements will be slightly less. Additionally, *most* of the time it immediately goes into Deep Sleep without turning off the modem (that's the INSTANT part). There's another bug in SDK 2, and I see both SDK functions and WiFi-class functions occasionally do a modem shut-down before Deep Sleep; it's not always Instant. When it doesn't do the modem shut-down it saves an extra 270mS of power. + +### Test 9 - Deep Sleep Instant, wake with RF_DISABLED + +This last variation also uses Deep Sleep Instant, but it wakes up with the modem disabled so current after Deep Sleep is only 15 mA. You'll have to turn the modem back on in your program when you want to use WiFi again. Each of the 4 WAKE styles has their own use, depending on what you need. + +--- + +All of the Deep Sleep modes end with a RESET, so you must re-initialize everything. You can store *some* information in the RTC memory to survive a Deep Sleep reset, which I've done in this demo to illustrate it. See the **RTCUserMemory** example for more on this feature. + +The maximum Deep Sleep interval is 71.58 minutes (2^32 -1 microseconds). + +If you need a longer sleep period than that, you can pass zero as the time variable to Deep Sleep and it turns off the RTC. The only way to wake it at that point is an external RESET; D0 can't do it. Both Forced Light Sleep and Deep Sleep(0) are woken by an external signal, so short delays under 2 seconds are more efficient with Forced Light Sleep, and longer delays are more power efficient with Deep Sleep. + + +--- + +### Lower Power without the WiFi library: + +If all you want to do is reduce power for a sketch that doesn't need WiFi, add these SDK 2 functions to your code: +```c + wifi_station_disconnect(); + wifi_set_opmode(NULL_MODE); + wifi_fpm_set_sleep_type(MODEM_SLEEP_T); + wifi_fpm_open(); + wifi_fpm_do_sleep(0xFFFFFFF); + delay(1); +``` +That allows you to shut down the modem *without* loading the WiFi library, dropping your average current by 50 mA, or around 1/5th of the initial power. You have to add it as shown, although the delay() can be longer. It doesn't time out at 71 minutes, as you might think from the (0xFFFFFFF). + +You can also use the Deep Sleep modes without loading the WiFi library, as they use ESP API functions. + From fd1c36617cabf17f992af36313704ff38d6e2224 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Sun, 5 Jan 2020 22:42:24 -0600 Subject: [PATCH 02/51] add Low-Power demo --- .../examples/LowPowerDemo/LowPowerDemo.ino | 40 +++++++++---------- .../esp8266/examples/LowPowerDemo/README.md | 6 +-- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index f7181a3b37..ea6f017f20 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -39,11 +39,11 @@ #define DEBUG_PRINT(x) #endif -#define WAKE_UP_PIN D3 // GPIO0, can also force a serial flash upload with RESET +#define WAKE_UP_PIN 0 // D3/GPIO0, can also force a serial flash upload with RESET // un-comment one of the two lines below for your LED connection -#define LED D1 // external LED for modules with built-in LEDs so it doesn't add to the current -//#define LED D4 // GPIO2 LED for ESP-01,07 modules; D4 is LED_BUILTIN on most other modules +#define LED 5 // D1/GPIO5 external LED for modules with built-in LEDs so it doesn't add to the current +//#define LED 2 // D4/GPIO2 LED for ESP-01,07 modules; D4 is LED_BUILTIN on most other modules ADC_MODE(ADC_VCC); // allows us to monitor the internal VCC level; it varies with WiFi load // don't connect anything to the analog input pin(s)! @@ -69,7 +69,7 @@ struct { byte data[4]; // the last byte stores the reset count } rtcData; -byte resetLoop = 0; // keeps track of the number of Deep Sleep tests / resets +byte resetCount = 0; // keeps track of the number of Deep Sleep tests / resets String resetCause = ""; const unsigned int blinkDelay = 100; // fast blink rate for the LED when waiting for the user @@ -91,7 +91,7 @@ void setup() { Serial.println(resetCause); if (resetCause == "External System") { Serial.println(F("I'm awake and starting the low power tests")); - resetLoop = 5; + resetCount = 5; updateRTC(); // if external reset, wipe the RTC memory and start all over } @@ -99,15 +99,15 @@ void setup() { if (ESP.rtcUserMemoryRead(64, (uint32_t*) &rtcData, sizeof(rtcData))) { uint32_t crcOfData = calculateCRC32((uint8_t*) &rtcData.data[0], sizeof(rtcData.data)); if (crcOfData != rtcData.crc32) { // if the CRC is invalid - resetLoop = 0; // set first test loop since power on or external reset + resetCount = 0; // set first test loop since power on or external reset } else { - resetLoop = rtcData.data[3]; // read the previous reset count + resetCount = rtcData.data[3]; // read the previous reset count } } } // end of Setup() void loop() { - if (resetLoop == 0) { + if (resetCount == 0) { // 1st test - running with WiFi unconfigured, reads ~67 mA minimum Serial.println(F("\n1st test - running with WiFi unconfigured")); float volts = ESP.getVcc(); @@ -171,7 +171,7 @@ void loop() { Serial.println(F("\n6th test - Deep Sleep for 10 seconds, wake with RF_DEFAULT")); init_WiFi(); // initialize WiFi since we turned it off in the last test init_OTA(); - resetLoop = 1; // advance to the next Deep Sleep test after the reset + resetCount = 1; // advance to the next Deep Sleep test after the reset updateRTC(); // save the current test state in RTC memory volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); @@ -192,12 +192,12 @@ void loop() { } // 7th test - Deep Sleep for 10 seconds, wake with RFCAL - if (resetLoop < 4) { + if (resetCount < 4) { init_WiFi(); // need to reinitialize WiFi & OTA due to Deep Sleep resets init_OTA(); // since we didn't do it in setup() because of the first test } - if (resetLoop == 1) { // second reset loop since power on - resetLoop = 2; // advance to the next Deep Sleep test after the reset + if (resetCount == 1) { // second reset loop since power on + resetCount = 2; // advance to the next Deep Sleep test after the reset updateRTC(); // save the current test state in RTC memory Serial.println(F("\n7th test - in RF_DEFAULT, Deep Sleep for 10 seconds, wake with RFCAL")); float volts = ESP.getVcc(); @@ -212,8 +212,8 @@ void loop() { } // 8th test - Deep Sleep Instant for 10 seconds, wake with NO_RFCAL - if (resetLoop == 2) { // third reset loop since power on - resetLoop = 3; // advance to the next Deep Sleep test after the reset + if (resetCount == 2) { // third reset loop since power on + resetCount = 3; // advance to the next Deep Sleep test after the reset updateRTC(); // save the current test state in RTC memory Serial.println(F("\n8th test - in RFCAL, Deep Sleep Instant for 10 seconds, wake with NO_RFCAL")); float volts = ESP.getVcc(); @@ -228,8 +228,8 @@ void loop() { } // 9th test - Deep Sleep Instant for 10 seconds, wake with RF_DISABLED - if (resetLoop == 3) { // fourth reset loop since power on - resetLoop = 4; // advance to the next Deep Sleep test after the reset + if (resetCount == 3) { // fourth reset loop since power on + resetCount = 4; // advance to the next Deep Sleep test after the reset updateRTC(); // save the current test state in RTC memory Serial.println(F("\n9th test - in NO_RFCAL, Deep Sleep Instant for 10 seconds, wake with RF_DISABLED")); float volts = ESP.getVcc(); @@ -243,8 +243,8 @@ void loop() { Serial.println(F("What... I'm not asleep?!?")); // it will never get here } - if (resetLoop == 4) { - resetLoop = 5; // start all over + if (resetCount == 4) { + resetCount = 5; // start all over updateRTC(); // save the current test state in RTC memory float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); @@ -299,10 +299,10 @@ uint32_t calculateCRC32(const uint8_t *data, size_t length) { } void updateRTC() { - rtcData.data[3] = resetLoop; // save the loop count for the next reset + rtcData.data[3] = resetCount; // save the loop count for the next reset // Update CRC32 of data rtcData.crc32 = calculateCRC32((uint8_t*) &rtcData.data[0], sizeof(rtcData.data)); - if (resetLoop == 5) // wipe the CRC in RTC memory when we're done with all tests + if (resetCount == 5) // wipe the CRC in RTC memory when we're done with all tests rtcData.crc32 = 0; // Write struct to RTC memory ESP.rtcUserMemoryWrite(64, (uint32_t*) &rtcData, sizeof(rtcData)); diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md index aec7b589e5..f9b36d1d57 100644 --- a/libraries/esp8266/examples/LowPowerDemo/README.md +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -48,11 +48,11 @@ This is typical for programs that don't use WiFi, and is a high current drain of ### Test 2 - Automatic Modem Sleep -This is the default power saving mode when you have an active WiFi connection. You don't need to add anything to your code to get it. However, it's not as wonderful as it may seem, as the only time the modem sleeps is when you spend a long time in delay(), with delay times over 50mS. The LED blinks more slowly during this test as I'm doing delay(350) to get the modem to sleep. While in delay() your sketch isn't doing anything interesting. Average current during long delay()s is 15 mA minimum. Without the delay() the average current is 67 mA with short spikes above 250 mA as transmissions occur. When the WiFi has traffic (even couple of pings), the modem can turn on for over 2 seconds continuous at 67 mA, and it may stay on for a second after the traffic. In a high traffic environment you won't get any power savings with either of the 2 Automatic modes. Automatic Modem Sleep turns on 7-8 seconds after an active connection is established. +This is the default power saving mode when you have an active WiFi connection. You don't need to add anything to your code to get it. However, it's not as wonderful as it may seem, as the only time the modem sleeps is when you spend a long time in delay(), with delay times over 50mS. The LED blinks more slowly during this test as I'm doing delay(350) to get the modem to sleep. While in delay() your sketch isn't doing anything interesting. Average current during long delay()s is 15 mA minimum. Without the delay() the average current is 67 mA with short spikes above 250 mA as transmissions occur. When the WiFi has traffic (even a couple of pings), the modem can turn on for over 2 seconds continuous at 67 mA, and it may stay on for a second after the traffic. In a high traffic environment you won't get any power savings with either of the 2 Automatic modes. Automatic Modem Sleep turns on 7-8 seconds after an active connection is established. ### Test 3 - Forced Modem Sleep -Turns off the modem (losing the connection), and dropping the current by 50 mA. This uses the WiFi library function. It's good if there is a long interval with no expected traffic, as you can do other things while only drawing 15 mA. +Turns off the modem (losing the connection), and dropping the current by 50 mA. This uses the WiFi library function. It's good if there is a long interval with no expected WiFi traffic, as you can do other things while only drawing 15 mA. ### Test 4 - Automatic Light Sleep @@ -68,7 +68,7 @@ In Deep Sleep almost everything is turned off, and the chip draws ~20 uA. If yo ### Test 7 - Deep Sleep, wake with RFCAL -Identical to the test above, but the modem does a power calibration when booting. In normal use, I'd likely do WAKE_RF_DEFAULT instead to save the extra RFCAL power burst if it's not needed. +Identical to the test above, but the modem does a power calibration when booting. In normal use, I'd likely do WAKE_RF_DEFAULT instead to minimize the extra RFCAL power burst if it's not needed. ### Test 8 - Deep Sleep Instant, wake with NO_RFCAL From b9126647ac6311e099a46c019fa43d0bd7f6e061 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Wed, 8 Jan 2020 19:45:59 -0600 Subject: [PATCH 03/51] add Low-Power demo, remove OTA and add WiFi timeout --- .../examples/LowPowerDemo/LowPowerDemo.ino | 138 ++++++++---------- .../esp8266/examples/LowPowerDemo/README.md | 21 +-- 2 files changed, 68 insertions(+), 91 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index ea6f017f20..0645bf30cd 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -1,33 +1,29 @@ /* This example demonstrates the different low-power modes of the ESP8266 - My initial setup was a WeMos D1 Mini with 3.3V connected to the 3V3 pin through a meter + The initial setup was a WeMos D1 Mini with 3.3V connected to the 3V3 pin through a meter so that it bypassed the on-board voltage regulator and USB chip. There's still about - 0.3 mA worth of leakage current due to the unpowered chips, so an ESP-01 will show lower - current readings than what I could achieve. These tests should work with any module. - While the modem is on the current is 67 mA or jumping around with a listed minimum. - To verify the 20 uA Deep Sleep current I removed the voltage regulator and USB chip. - - Since I'm now missing the USB chip, I've included OTA upload. You'll need to upload - from USB or a USB-to-TTL converter the first time, then you can disconnect and use OTA - afterwards during any test if the WiFi is connected. Some tests disconnect or sleep WiFi - so OTA won't go through. If you want OTA upload, hit RESET & press the test button once. - - This test assumes you have a pushbutton switch connected between D3 and GND to advance - the tests. You'll also need to connect D0/GPIO16 to RST for the Deep Sleep tests. - If you forget to connect D0 to RST it will hang after the first Deep Sleep test. - Connect an LED from any free pin through a 330 ohm resistor to the 3.3V supply, NOT the 3V3 - pin on the module or it adds to the measured current. When it blinks you can proceed. - When the LED is lit continuously it's connecting WiFi, when it's off the CPU is asleep. - The LED blinks slowly when the tests are complete. + 0.3 mA worth of leakage current due to the unpowered chips. These tests should work with + any module, although on-board components will affect the actual current measurement. + While the modem is turned on the current is > 67 mA or jumping around with a minimum value. + To verify the 20 uA Deep Sleep current the voltage regulator and USB chip were removed. + + This test series requires an active WiFi connection to illustrate two tests. If you + have problems with WiFi, uncomment the #ifdef DEBUG for additional WiFi error messages. + The test requires a pushbutton switch connected between D3 and GND to advance the tests. + You'll also need to connect D0/GPIO16 to RST for the Deep Sleep tests. If you forget to + connect D0 to RST it will hang after the first Deep Sleep test. Additionally, you can + connect an LED from any free pin through a 330 ohm resistor to the 3.3V supply, though + preferably not the 3V3 pin on the module or it adds to the measured current. When the + LED blinks you can proceed to the next test. When the LED is lit continuously it's + connecting WiFi, and when it's off the CPU is asleep. The LED blinks slowly when the + tests are complete. Test progress is also shown on the serial monitor. WiFi connections will be made over twice as fast if you can use a static IP address. This example code is in the public domain, and was inspired by code from numerous sources */ #include -#include -#include -#include +#include // crc32() #include //#define DEBUG // prints WiFi connection info to serial, uncomment if you want WiFi messages @@ -41,11 +37,12 @@ #define WAKE_UP_PIN 0 // D3/GPIO0, can also force a serial flash upload with RESET -// un-comment one of the two lines below for your LED connection +// uncomment one of the two lines below for your LED connection, if used #define LED 5 // D1/GPIO5 external LED for modules with built-in LEDs so it doesn't add to the current //#define LED 2 // D4/GPIO2 LED for ESP-01,07 modules; D4 is LED_BUILTIN on most other modules +// you can use LED_BUILTIN, but it adds to the measured current by 0.3mA to 6mA. -ADC_MODE(ADC_VCC); // allows us to monitor the internal VCC level; it varies with WiFi load +ADC_MODE(ADC_VCC); // allows you to monitor the internal VCC level; it varies with WiFi load // don't connect anything to the analog input pin(s)! // enter your WiFi configuration below @@ -56,12 +53,13 @@ IPAddress gateway(0, 0, 0, 0); IPAddress subnet(0, 0, 0, 0); IPAddress dns1(0, 0, 0, 0); IPAddress dns2(0, 0, 0, 0); - +uint32_t wifiTimeout = 30E3; // 30 second timeout on the WiFi connection +bool wifiOK; // used to skip tests if WiFi never connected // CRC function used to ensure data validity of RTC User Memory uint32_t calculateCRC32(const uint8_t *data, size_t length); -// This structure will be stored in RTC memory to remember the reset loop count. +// This structure will be stored in RTC memory to remember the reset count (number of Deep Sleeps). // First field is CRC32, which is calculated based on the rest of the structure contents. // Any fields can go after the CRC32. The structure must be 4-byte aligned. struct { @@ -72,8 +70,8 @@ struct { byte resetCount = 0; // keeps track of the number of Deep Sleep tests / resets String resetCause = ""; -const unsigned int blinkDelay = 100; // fast blink rate for the LED when waiting for the user -const unsigned int longDelay = 350; // longer delay() for the two AUTOMATIC modes +const uint32_t blinkDelay = 100; // fast blink rate for the LED when waiting for the user +const uint32_t longDelay = 350; // longer delay() for the two AUTOMATIC modes esp8266::polledTimeout::periodicFastMs blinkLED(blinkDelay); // use fully qualified type and avoid importing all ::esp8266 namespace to the global namespace @@ -119,12 +117,15 @@ void loop() { Serial.println(F("\n2nd test - Automatic Modem Sleep")); Serial.println(F("connecting WiFi, please wait until the LED blinks")); init_WiFi(); - init_OTA(); - Serial.println(F("The current will drop in 7 seconds.")); - volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); - Serial.println(F("press the button to continue")); - waitPushbutton(true, longDelay); + if (WiFi.localIP()) { + Serial.println(F("The current will drop in 7 seconds.")); + volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.println(F("press the button to continue")); + waitPushbutton(true, longDelay); + } else { + Serial.println(F("test skipped")); + } // 3rd test - Forced Modem Sleep Serial.println(F("\n3rd test - Forced Modem Sleep")); @@ -137,17 +138,21 @@ void loop() { // 4th test - Automatic Light Sleep Serial.println(F("\n4th test - Automatic Light Sleep")); +if (WiFi.localIP()) { Serial.println(F("reconnecting WiFi")); Serial.println(F("it will be in Automatic Light Sleep once WiFi connects (LED blinks)")); digitalWrite(LED, LOW); // visual cue that we're reconnecting WiFi.setSleepMode(WIFI_LIGHT_SLEEP, 5); // Automatic Light Sleep WiFi.forceSleepWake(); // reconnect with previous STA mode and connection settings while (!WiFi.localIP()) - delay(50); + delay(50); volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); Serial.println(F("press the button to continue")); waitPushbutton(true, longDelay); + } else { + Serial.println(F("test skipped")); + } // 5th test - Forced Light Sleep using Non-OS SDK calls Serial.println(F("\n5th test - Forced Light Sleep using Non-OS SDK calls")); @@ -168,9 +173,8 @@ void loop() { Serial.println(F("Woke up!")); // the interrupt callback hits before this is executed // 6th test - Deep Sleep for 10 seconds, wake with RF_DEFAULT - Serial.println(F("\n6th test - Deep Sleep for 10 seconds, wake with RF_DEFAULT")); + Serial.println(F("\n6th test - Deep Sleep for 10 seconds, reset and wake with RF_DEFAULT")); init_WiFi(); // initialize WiFi since we turned it off in the last test - init_OTA(); resetCount = 1; // advance to the next Deep Sleep test after the reset updateRTC(); // save the current test state in RTC memory volts = ESP.getVcc(); @@ -187,19 +191,19 @@ void loop() { delay(10); // if you do ESP.deepSleep(0, mode); it needs a RESET to come out of sleep (RTC is off) // maximum timed Deep Sleep interval = 71.58 minutes with 0xFFFFFFFF - // the 2 uA GPIO current during Deep Sleep can't drive the LED so it's off now + // the 2 uA GPIO current during Deep Sleep can't drive the LED so it's not lit now, although + // depending on the LED used, you might see it very dimly lit in a dark room during this test Serial.println(F("What... I'm not asleep?!?")); // it will never get here } // 7th test - Deep Sleep for 10 seconds, wake with RFCAL if (resetCount < 4) { - init_WiFi(); // need to reinitialize WiFi & OTA due to Deep Sleep resets - init_OTA(); // since we didn't do it in setup() because of the first test + init_WiFi(); // need to reinitialize WiFi due to Deep Sleep resets } if (resetCount == 1) { // second reset loop since power on resetCount = 2; // advance to the next Deep Sleep test after the reset updateRTC(); // save the current test state in RTC memory - Serial.println(F("\n7th test - in RF_DEFAULT, Deep Sleep for 10 seconds, wake with RFCAL")); + Serial.println(F("\n7th test - in RF_DEFAULT, Deep Sleep for 10 seconds, reset and wake with RFCAL")); float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); Serial.println(F("press the button to continue")); @@ -215,7 +219,7 @@ void loop() { if (resetCount == 2) { // third reset loop since power on resetCount = 3; // advance to the next Deep Sleep test after the reset updateRTC(); // save the current test state in RTC memory - Serial.println(F("\n8th test - in RFCAL, Deep Sleep Instant for 10 seconds, wake with NO_RFCAL")); + Serial.println(F("\n8th test - in RFCAL, Deep Sleep Instant for 10 seconds, reset and wake with NO_RFCAL")); float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); Serial.println(F("press the button to continue")); @@ -231,7 +235,7 @@ void loop() { if (resetCount == 3) { // fourth reset loop since power on resetCount = 4; // advance to the next Deep Sleep test after the reset updateRTC(); // save the current test state in RTC memory - Serial.println(F("\n9th test - in NO_RFCAL, Deep Sleep Instant for 10 seconds, wake with RF_DISABLED")); + Serial.println(F("\n9th test - in NO_RFCAL, Deep Sleep Instant for 10 seconds, reset and wake with RF_DISABLED")); float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); Serial.println(F("press the button to continue")); @@ -261,16 +265,12 @@ void waitPushbutton(bool usesDelay, unsigned int delayTime) { // loop until the while (digitalRead(WAKE_UP_PIN)) { // wait for a button press if (blinkLED) { digitalWrite(LED, !digitalRead(LED)); // toggle the activity LED - if (WiFi.localIP()) // don't check OTA if WiFi isn't connected - ArduinoOTA.handle(); //see if we need to reflash } yield(); } } else { // long delay() for the 2 AUTOMATIC modes, but it misses quick button presses while (digitalRead(WAKE_UP_PIN)) { // wait for a button press digitalWrite(LED, !digitalRead(LED)); // toggle the activity LED - if (WiFi.localIP()) // don't check OTA if WiFi isn't connected - ArduinoOTA.handle(); //see if we need to reflash delay(delayTime); } } @@ -312,7 +312,7 @@ void init_WiFi() { /* Explicitly set the ESP8266 as a WiFi-client (STAtion mode), otherwise by default it would try to act as both a client and an access-point and could cause network issues with other WiFi devices on your network. */ - digitalWrite(LED, LOW); // give a visual indication that we're alive but busy + digitalWrite(LED, LOW); // give a visual indication that we're alive but busy with WiFi WiFi.persistent(false); // don't store the connection each time to save wear on the flash WiFi.mode(WIFI_STA); WiFi.config(staticIP, gateway, subnet); // if using static IP, enter parameters at the top @@ -321,45 +321,21 @@ void init_WiFi() { Serial.println(AP_SSID); DEBUG_PRINT(F("my MAC: ")); DEBUG_PRINTLN(WiFi.macAddress()); - while (WiFi.status() != WL_CONNECTED) + uint32_t wifiStart = millis(); + while (( WiFi.status() != WL_CONNECTED ) && ( millis() - wifiStart < wifiTimeout )) { delay(50); - DEBUG_PRINTLN(F("WiFi connected")); - while (!WiFi.localIP()) + } + if (WiFi.status() == WL_CONNECTED) { + DEBUG_PRINTLN(F("WiFi connected")); + } else { + Serial.println(F("WiFi timed out and didn't connect")); + } + while (!WiFi.localIP() && (WiFi.status() == WL_CONNECTED)) { delay(50); + } WiFi.setAutoReconnect(true); DEBUG_PRINT(F("WiFi Gateway IP: ")); DEBUG_PRINTLN(WiFi.gatewayIP()); DEBUG_PRINT(F("my IP address: ")); DEBUG_PRINTLN(WiFi.localIP()); } - -void init_OTA() { - // Port defaults to 8266 - // ArduinoOTA.setPort(8266); - - // Hostname defaults to esp8266-[ChipID] - // ArduinoOTA.setHostname("myesp8266")); - - // No authentication by default - // ArduinoOTA.setPassword((const char *)"123")); - - ArduinoOTA.onStart([]() { - Serial.println(F("Start")); - }); - ArduinoOTA.onEnd([]() { - Serial.println(F("\nEnd")); - }); - ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { - Serial.printf("Progress: %u%%\r", (progress / (total / 100))); - }); - ArduinoOTA.onError([](ota_error_t error) { - Serial.printf("Error[%u]: ", error); - if (error == OTA_AUTH_ERROR) Serial.println(F("Auth Failed")); - else if (error == OTA_BEGIN_ERROR) Serial.println(F("Begin Failed")); - else if (error == OTA_CONNECT_ERROR) Serial.println(F("Connect Failed")); - else if (error == OTA_RECEIVE_ERROR) Serial.println(F("Receive Failed")); - else if (error == OTA_END_ERROR) Serial.println(F("End Failed")); - }); - ArduinoOTA.begin(); - yield(); -} diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md index f9b36d1d57..dc16400a97 100644 --- a/libraries/esp8266/examples/LowPowerDemo/README.md +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -1,11 +1,11 @@ #
Low-Power Demo
-There is a lot of confusion, out-of-date information, and bad examples of how to use the 5 basic low-power modes of the ESP8266. This demo code shows you how to use them reliably. If you're here for very low power, then the 2 Light Sleep modes and Deep Sleep are what you want. +There is a lot of confusion, out-of-date information, and poor or non-working examples of how to use the 5 basic low-power modes of the ESP8266. This demo code shows you how to use them reliably. If you're here for very low power, then the 2 Light Sleep modes and Deep Sleep are what you want. -The two relevant reference manuals from Espressif are the [Low-Power Solutions](https://www.espressif.com/sites/default/files/documentation/9b-esp8266-low_power_solutions__en.pdf) and the [Non-OS SDK API Reference](https://www.espressif.com/sites/default/files/documentation/2c-esp8266_non_os_sdk_api_reference_en.pdf). There is more information in the two PDFs than I have presented here, so you'll want both of them for your reference. +The two relevant reference manuals from Espressif are the [Low-Power Solutions](https://www.espressif.com/sites/default/files/documentation/9b-esp8266-low_power_solutions__en.pdf) and the [Non-OS SDK API Reference](https://www.espressif.com/sites/default/files/documentation/2c-esp8266_non_os_sdk_api_reference_en.pdf). There is more information in the two PDFs than is presented here, so you'll want both of them for your reference. -The table below is a corrected version of Table 1.1 from the Low-Power Solutions PDF. The currents listed are absolute minimums, and most people will not get that low with typical hardware and program. +The table below is an expanded version of Table 1.1 from the Low-Power Solutions PDF. The currents listed are absolute minimums, and most people will not get that low with typical hardware and programs. | item | Automatic Modem Sleep | Forced Modem Sleep | Automatic Light Sleep | Forced Light Sleep | Forced Deep Sleep | |:---------------------:|:---------------------:|:------------------:|:---------------------:|:------------------:|:------------------:| @@ -22,9 +22,10 @@ The table below is a corrected version of Table 1.1 from the Low-Power Solutions Notes: (1) setting a sleep time of 0 for Deep Sleep turns off the RTC, requiring an external RESET to wake it + (2) due to a bug in SDK 2, the minimum current will never be less than 2 mA and is frequently 15 mA between DTIM beacons -I haven't verified the Average Current with different DTIM settings. I expect the numbers above aren't realistic. All of the currents listed in this README are for the ESP8266 chip. Modules that have voltage regulators, USB chips or other hardware will draw more. +The Average Current with different DTIM settings is unverified, and will likely be higher in a real-world environment. All of the currents listed in this README are for the ESP8266 chip only. Modules that have voltage regulators, USB chips, LEDs or other hardware will draw additional current. --- @@ -44,11 +45,11 @@ I haven't verified the Average Current with different DTIM settings. I expect t ### Test 1 - Unconfigured modem -This is typical for programs that don't use WiFi, and is a high current drain of at least 67 mA continuous. Even if you don't plan to use WiFi, it's wise to use the SDK 2 functions below in **Lower Power without the WiFi library** to reduce the power. +This is typical for programs that don't use WiFi, and is a high current drain of at least 67 mA continuous. ### Test 2 - Automatic Modem Sleep -This is the default power saving mode when you have an active WiFi connection. You don't need to add anything to your code to get it. However, it's not as wonderful as it may seem, as the only time the modem sleeps is when you spend a long time in delay(), with delay times over 50mS. The LED blinks more slowly during this test as I'm doing delay(350) to get the modem to sleep. While in delay() your sketch isn't doing anything interesting. Average current during long delay()s is 15 mA minimum. Without the delay() the average current is 67 mA with short spikes above 250 mA as transmissions occur. When the WiFi has traffic (even a couple of pings), the modem can turn on for over 2 seconds continuous at 67 mA, and it may stay on for a second after the traffic. In a high traffic environment you won't get any power savings with either of the 2 Automatic modes. Automatic Modem Sleep turns on 7-8 seconds after an active connection is established. +This is the default power saving mode when you have an active WiFi connection. You don't need to add anything to your code to get it. The only time the modem sleeps is when you spend a long time in delay(), with delay times over 50mS. The LED blinks more slowly during this test as I'm doing delay(350) to get the modem to sleep. While in delay() your sketch isn't doing anything worthwhile. Average current during long delay()s is 15 mA minimum. Without the delay() the average current is 67 mA with short spikes above 250 mA as transmissions occur. When the WiFi has traffic (even a couple of pings), the modem can turn on for over 2 seconds continuous at 67 mA, and it may stay on for a second after the traffic. In a high traffic environment you won't get any power savings with either of the 2 Automatic modes. Automatic Modem Sleep turns on 7-8 seconds after an active connection is established. ### Test 3 - Forced Modem Sleep @@ -80,11 +81,11 @@ This last variation also uses Deep Sleep Instant, but it wakes up with the modem --- -All of the Deep Sleep modes end with a RESET, so you must re-initialize everything. You can store *some* information in the RTC memory to survive a Deep Sleep reset, which I've done in this demo to illustrate it. See the **RTCUserMemory** example for more on this feature. +All of the Deep Sleep modes end with a RESET, so you must re-initialize everything. You can store *some* information in the RTC memory to survive a Deep Sleep reset, which was done in this demo to illustrate it. See the **RTCUserMemory** example for more on this feature. The maximum Deep Sleep interval is 71.58 minutes (2^32 -1 microseconds). -If you need a longer sleep period than that, you can pass zero as the time variable to Deep Sleep and it turns off the RTC. The only way to wake it at that point is an external RESET; D0 can't do it. Both Forced Light Sleep and Deep Sleep(0) are woken by an external signal, so short delays under 2 seconds are more efficient with Forced Light Sleep, and longer delays are more power efficient with Deep Sleep. +If you need a longer sleep period than 72 minutes, you can pass zero as the time variable to Deep Sleep and it turns off the RTC. The only way to wake it at that point is an external RESET; D0 can't do it. Both Forced Light Sleep and Deep Sleep(0) are woken by an external signal, so short delays under 2 seconds are more efficient with Forced Light Sleep, and longer delays are more power efficient with Deep Sleep. --- @@ -100,7 +101,7 @@ If all you want to do is reduce power for a sketch that doesn't need WiFi, add t wifi_fpm_do_sleep(0xFFFFFFF); delay(1); ``` -That allows you to shut down the modem *without* loading the WiFi library, dropping your average current by 50 mA, or around 1/5th of the initial power. You have to add it as shown, although the delay() can be longer. It doesn't time out at 71 minutes, as you might think from the (0xFFFFFFF). +That allows you to shut down the modem *without* loading the WiFi library, dropping your average current by 50 mA, or around 1/5th of the initial power. You have to add it as shown preferably in setup(), although the delay() can be longer. It doesn't time out at 71 minutes, as you might think from the (0xFFFFFFF). The Forced Modem Sleep test does the same thing with a WiFi library call that essentially encapsulates the code above. -You can also use the Deep Sleep modes without loading the WiFi library, as they use ESP API functions. +You can also use the Deep Sleep modes without loading the WiFi library, as they use ESP API functions. The tests above try to bring the WiFi up to show you the differences after the 4 reset modes. From 287bc2d1029475a4b28bd817459f0872a07c4b9f Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Sun, 5 Jan 2020 21:05:58 -0600 Subject: [PATCH 04/51] add Low-Power demo --- .../examples/LowPowerDemo/LowPowerDemo.ino | 365 ++++++++++++++++++ .../esp8266/examples/LowPowerDemo/README.md | 106 +++++ 2 files changed, 471 insertions(+) create mode 100644 libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino create mode 100644 libraries/esp8266/examples/LowPowerDemo/README.md diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino new file mode 100644 index 0000000000..f7181a3b37 --- /dev/null +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -0,0 +1,365 @@ +/* This example demonstrates the different low-power modes of the ESP8266 + + My initial setup was a WeMos D1 Mini with 3.3V connected to the 3V3 pin through a meter + so that it bypassed the on-board voltage regulator and USB chip. There's still about + 0.3 mA worth of leakage current due to the unpowered chips, so an ESP-01 will show lower + current readings than what I could achieve. These tests should work with any module. + While the modem is on the current is 67 mA or jumping around with a listed minimum. + To verify the 20 uA Deep Sleep current I removed the voltage regulator and USB chip. + + Since I'm now missing the USB chip, I've included OTA upload. You'll need to upload + from USB or a USB-to-TTL converter the first time, then you can disconnect and use OTA + afterwards during any test if the WiFi is connected. Some tests disconnect or sleep WiFi + so OTA won't go through. If you want OTA upload, hit RESET & press the test button once. + + This test assumes you have a pushbutton switch connected between D3 and GND to advance + the tests. You'll also need to connect D0/GPIO16 to RST for the Deep Sleep tests. + If you forget to connect D0 to RST it will hang after the first Deep Sleep test. + Connect an LED from any free pin through a 330 ohm resistor to the 3.3V supply, NOT the 3V3 + pin on the module or it adds to the measured current. When it blinks you can proceed. + When the LED is lit continuously it's connecting WiFi, when it's off the CPU is asleep. + The LED blinks slowly when the tests are complete. + + WiFi connections will be made over twice as fast if you can use a static IP address. + + This example code is in the public domain, and was inspired by code from numerous sources */ + +#include +#include +#include +#include +#include + +//#define DEBUG // prints WiFi connection info to serial, uncomment if you want WiFi messages +#ifdef DEBUG +#define DEBUG_PRINTLN(x) Serial.println(x) +#define DEBUG_PRINT(x) Serial.print(x) +#else +#define DEBUG_PRINTLN(x) +#define DEBUG_PRINT(x) +#endif + +#define WAKE_UP_PIN D3 // GPIO0, can also force a serial flash upload with RESET + +// un-comment one of the two lines below for your LED connection +#define LED D1 // external LED for modules with built-in LEDs so it doesn't add to the current +//#define LED D4 // GPIO2 LED for ESP-01,07 modules; D4 is LED_BUILTIN on most other modules + +ADC_MODE(ADC_VCC); // allows us to monitor the internal VCC level; it varies with WiFi load +// don't connect anything to the analog input pin(s)! + +// enter your WiFi configuration below +const char* AP_SSID = "SSID"; // your router's SSID here +const char* AP_PASS = "password"; // your router's password here +IPAddress staticIP(0, 0, 0, 0); // parameters below are for your static IP address, if used +IPAddress gateway(0, 0, 0, 0); +IPAddress subnet(0, 0, 0, 0); +IPAddress dns1(0, 0, 0, 0); +IPAddress dns2(0, 0, 0, 0); + + +// CRC function used to ensure data validity of RTC User Memory +uint32_t calculateCRC32(const uint8_t *data, size_t length); + +// This structure will be stored in RTC memory to remember the reset loop count. +// First field is CRC32, which is calculated based on the rest of the structure contents. +// Any fields can go after the CRC32. The structure must be 4-byte aligned. +struct { + uint32_t crc32; + byte data[4]; // the last byte stores the reset count +} rtcData; + +byte resetLoop = 0; // keeps track of the number of Deep Sleep tests / resets +String resetCause = ""; + +const unsigned int blinkDelay = 100; // fast blink rate for the LED when waiting for the user +const unsigned int longDelay = 350; // longer delay() for the two AUTOMATIC modes +esp8266::polledTimeout::periodicFastMs blinkLED(blinkDelay); +// use fully qualified type and avoid importing all ::esp8266 namespace to the global namespace + +void wakeupCallback() { // unlike ISRs, you can do a print() from a callback function + Serial.println(F("Woke from Forced Light Sleep - this is the callback")); +} + +void setup() { + pinMode(LED, OUTPUT); // Activity and Status indicator + digitalWrite(LED, LOW); // turn on the LED + pinMode(WAKE_UP_PIN, INPUT_PULLUP); // polled to advance tests, INTR for Forced Light Sleep + Serial.begin(115200); + Serial.print(F("\nReset reason = ")); + String resetCause = ESP.getResetReason(); + Serial.println(resetCause); + if (resetCause == "External System") { + Serial.println(F("I'm awake and starting the low power tests")); + resetLoop = 5; + updateRTC(); // if external reset, wipe the RTC memory and start all over + } + + // Read struct from RTC memory + if (ESP.rtcUserMemoryRead(64, (uint32_t*) &rtcData, sizeof(rtcData))) { + uint32_t crcOfData = calculateCRC32((uint8_t*) &rtcData.data[0], sizeof(rtcData.data)); + if (crcOfData != rtcData.crc32) { // if the CRC is invalid + resetLoop = 0; // set first test loop since power on or external reset + } else { + resetLoop = rtcData.data[3]; // read the previous reset count + } + } +} // end of Setup() + +void loop() { + if (resetLoop == 0) { + // 1st test - running with WiFi unconfigured, reads ~67 mA minimum + Serial.println(F("\n1st test - running with WiFi unconfigured")); + float volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.println(F("press the button to continue")); + waitPushbutton(false, blinkDelay); + + // 2nd test - Automatic Modem Sleep 7 seconds after WiFi is connected (LED flashes) + Serial.println(F("\n2nd test - Automatic Modem Sleep")); + Serial.println(F("connecting WiFi, please wait until the LED blinks")); + init_WiFi(); + init_OTA(); + Serial.println(F("The current will drop in 7 seconds.")); + volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.println(F("press the button to continue")); + waitPushbutton(true, longDelay); + + // 3rd test - Forced Modem Sleep + Serial.println(F("\n3rd test - Forced Modem Sleep")); + WiFi.forceSleepBegin(); + delay(10); // it doesn't always go to sleep unless you delay(10) + volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.println(F("press the button to continue")); + waitPushbutton(false, blinkDelay); + + // 4th test - Automatic Light Sleep + Serial.println(F("\n4th test - Automatic Light Sleep")); + Serial.println(F("reconnecting WiFi")); + Serial.println(F("it will be in Automatic Light Sleep once WiFi connects (LED blinks)")); + digitalWrite(LED, LOW); // visual cue that we're reconnecting + WiFi.setSleepMode(WIFI_LIGHT_SLEEP, 5); // Automatic Light Sleep + WiFi.forceSleepWake(); // reconnect with previous STA mode and connection settings + while (!WiFi.localIP()) + delay(50); + volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.println(F("press the button to continue")); + waitPushbutton(true, longDelay); + + // 5th test - Forced Light Sleep using Non-OS SDK calls + Serial.println(F("\n5th test - Forced Light Sleep using Non-OS SDK calls")); + WiFi.mode(WIFI_OFF); // you must turn the modem off; using disconnect won't work + yield(); + digitalWrite(LED, HIGH); // turn the LED off so they know the CPU isn't running + volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.println(F("CPU going to sleep, pull WAKE_UP_PIN low to wake it (press the button)")); + delay(100); // needs a brief delay after the print or it may print the whole message + wifi_fpm_set_sleep_type(LIGHT_SLEEP_T); + gpio_pin_wakeup_enable(GPIO_ID_PIN(WAKE_UP_PIN), GPIO_PIN_INTR_LOLEVEL); + // only LOLEVEL or HILEVEL interrupts work, no edge, that's an SDK or CPU limitation + wifi_fpm_set_wakeup_cb(wakeupCallback); // Set wakeup callback (optional) + wifi_fpm_open(); + wifi_fpm_do_sleep(0xFFFFFFF); // only 0xFFFFFFF allowed; any other value and it won't sleep + delay(10); // it goes to sleep some time during this delay() and waits for an interrupt + Serial.println(F("Woke up!")); // the interrupt callback hits before this is executed + + // 6th test - Deep Sleep for 10 seconds, wake with RF_DEFAULT + Serial.println(F("\n6th test - Deep Sleep for 10 seconds, wake with RF_DEFAULT")); + init_WiFi(); // initialize WiFi since we turned it off in the last test + init_OTA(); + resetLoop = 1; // advance to the next Deep Sleep test after the reset + updateRTC(); // save the current test state in RTC memory + volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.println(F("press the button to continue")); + while (!digitalRead(WAKE_UP_PIN)) // wait for them to release the button from the last test + delay(10); + delay(50); // debounce time for the switch, button released + waitPushbutton(false, blinkDelay); + digitalWrite(LED, LOW); // turn the LED on, at least briefly + Serial.println(F("going into Deep Sleep now...")); + delay(10); // sometimes the \n isn't printed without a short delay + ESP.deepSleep(10E6, WAKE_RF_DEFAULT); // good night! D0 fires a reset in 10 seconds... + delay(10); + // if you do ESP.deepSleep(0, mode); it needs a RESET to come out of sleep (RTC is off) + // maximum timed Deep Sleep interval = 71.58 minutes with 0xFFFFFFFF + // the 2 uA GPIO current during Deep Sleep can't drive the LED so it's off now + Serial.println(F("What... I'm not asleep?!?")); // it will never get here + } + + // 7th test - Deep Sleep for 10 seconds, wake with RFCAL + if (resetLoop < 4) { + init_WiFi(); // need to reinitialize WiFi & OTA due to Deep Sleep resets + init_OTA(); // since we didn't do it in setup() because of the first test + } + if (resetLoop == 1) { // second reset loop since power on + resetLoop = 2; // advance to the next Deep Sleep test after the reset + updateRTC(); // save the current test state in RTC memory + Serial.println(F("\n7th test - in RF_DEFAULT, Deep Sleep for 10 seconds, wake with RFCAL")); + float volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.println(F("press the button to continue")); + waitPushbutton(false, blinkDelay); + Serial.println(F("going into Deep Sleep now...")); + delay(10); // sometimes the \n isn't printed without a short delay + ESP.deepSleep(10E6, WAKE_RFCAL); // good night! D0 fires a reset in 10 seconds... + delay(10); + Serial.println(F("What... I'm not asleep?!?")); // it will never get here + } + + // 8th test - Deep Sleep Instant for 10 seconds, wake with NO_RFCAL + if (resetLoop == 2) { // third reset loop since power on + resetLoop = 3; // advance to the next Deep Sleep test after the reset + updateRTC(); // save the current test state in RTC memory + Serial.println(F("\n8th test - in RFCAL, Deep Sleep Instant for 10 seconds, wake with NO_RFCAL")); + float volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.println(F("press the button to continue")); + waitPushbutton(false, blinkDelay); + Serial.println(F("going into Deep Sleep now...")); + delay(10); // sometimes the \n isn't printed without a short delay + ESP.deepSleepInstant(10E6, WAKE_NO_RFCAL); // good night! D0 fires a reset in 10 seconds... + delay(10); + Serial.println(F("What... I'm not asleep?!?")); // it will never get here + } + + // 9th test - Deep Sleep Instant for 10 seconds, wake with RF_DISABLED + if (resetLoop == 3) { // fourth reset loop since power on + resetLoop = 4; // advance to the next Deep Sleep test after the reset + updateRTC(); // save the current test state in RTC memory + Serial.println(F("\n9th test - in NO_RFCAL, Deep Sleep Instant for 10 seconds, wake with RF_DISABLED")); + float volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.println(F("press the button to continue")); + waitPushbutton(false, blinkDelay); + Serial.println(F("going into Deep Sleep now...")); + delay(10); // sometimes the \n isn't printed without a short delay + ESP.deepSleepInstant(10E6, WAKE_RF_DISABLED); // good night! D0 fires a reset in 10 seconds... + delay(10); + Serial.println(F("What... I'm not asleep?!?")); // it will never get here + } + + if (resetLoop == 4) { + resetLoop = 5; // start all over + updateRTC(); // save the current test state in RTC memory + float volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.println(F("\nTests completed, in RF_DISABLED, press the button to do an ESP.restart()")); + waitPushbutton(false, 1000); + ESP.restart(); + } +} + +void waitPushbutton(bool usesDelay, unsigned int delayTime) { // loop until they press the button + // note: 2 different modes, as both of the AUTOMATIC power saving modes need a long delay() + if (!usesDelay) { // quick interception of button press, no delay() + blinkLED.reset(delayTime); + while (digitalRead(WAKE_UP_PIN)) { // wait for a button press + if (blinkLED) { + digitalWrite(LED, !digitalRead(LED)); // toggle the activity LED + if (WiFi.localIP()) // don't check OTA if WiFi isn't connected + ArduinoOTA.handle(); //see if we need to reflash + } + yield(); + } + } else { // long delay() for the 2 AUTOMATIC modes, but it misses quick button presses + while (digitalRead(WAKE_UP_PIN)) { // wait for a button press + digitalWrite(LED, !digitalRead(LED)); // toggle the activity LED + if (WiFi.localIP()) // don't check OTA if WiFi isn't connected + ArduinoOTA.handle(); //see if we need to reflash + delay(delayTime); + } + } + delay(50); // debounce time for the switch, button pressed + while (!digitalRead(WAKE_UP_PIN)) // now wait for them to release the button + delay(10); + delay(50); // debounce time for the switch, button released +} + +uint32_t calculateCRC32(const uint8_t *data, size_t length) { + uint32_t crc = 0xffffffff; + while (length--) { + uint8_t c = *data++; + for (uint32_t i = 0x80; i > 0; i >>= 1) { + bool bit = crc & 0x80000000; + if (c & i) { + bit = !bit; + } + crc <<= 1; + if (bit) { + crc ^= 0x04c11db7; + } + } + } + return crc; +} + +void updateRTC() { + rtcData.data[3] = resetLoop; // save the loop count for the next reset + // Update CRC32 of data + rtcData.crc32 = calculateCRC32((uint8_t*) &rtcData.data[0], sizeof(rtcData.data)); + if (resetLoop == 5) // wipe the CRC in RTC memory when we're done with all tests + rtcData.crc32 = 0; + // Write struct to RTC memory + ESP.rtcUserMemoryWrite(64, (uint32_t*) &rtcData, sizeof(rtcData)); +} + +void init_WiFi() { + /* Explicitly set the ESP8266 as a WiFi-client (STAtion mode), otherwise by default it + would try to act as both a client and an access-point and could cause network issues + with other WiFi devices on your network. */ + digitalWrite(LED, LOW); // give a visual indication that we're alive but busy + WiFi.persistent(false); // don't store the connection each time to save wear on the flash + WiFi.mode(WIFI_STA); + WiFi.config(staticIP, gateway, subnet); // if using static IP, enter parameters at the top + WiFi.begin(AP_SSID, AP_PASS); + Serial.print(F("connecting to WiFi ")); + Serial.println(AP_SSID); + DEBUG_PRINT(F("my MAC: ")); + DEBUG_PRINTLN(WiFi.macAddress()); + while (WiFi.status() != WL_CONNECTED) + delay(50); + DEBUG_PRINTLN(F("WiFi connected")); + while (!WiFi.localIP()) + delay(50); + WiFi.setAutoReconnect(true); + DEBUG_PRINT(F("WiFi Gateway IP: ")); + DEBUG_PRINTLN(WiFi.gatewayIP()); + DEBUG_PRINT(F("my IP address: ")); + DEBUG_PRINTLN(WiFi.localIP()); +} + +void init_OTA() { + // Port defaults to 8266 + // ArduinoOTA.setPort(8266); + + // Hostname defaults to esp8266-[ChipID] + // ArduinoOTA.setHostname("myesp8266")); + + // No authentication by default + // ArduinoOTA.setPassword((const char *)"123")); + + ArduinoOTA.onStart([]() { + Serial.println(F("Start")); + }); + ArduinoOTA.onEnd([]() { + Serial.println(F("\nEnd")); + }); + ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { + Serial.printf("Progress: %u%%\r", (progress / (total / 100))); + }); + ArduinoOTA.onError([](ota_error_t error) { + Serial.printf("Error[%u]: ", error); + if (error == OTA_AUTH_ERROR) Serial.println(F("Auth Failed")); + else if (error == OTA_BEGIN_ERROR) Serial.println(F("Begin Failed")); + else if (error == OTA_CONNECT_ERROR) Serial.println(F("Connect Failed")); + else if (error == OTA_RECEIVE_ERROR) Serial.println(F("Receive Failed")); + else if (error == OTA_END_ERROR) Serial.println(F("End Failed")); + }); + ArduinoOTA.begin(); + yield(); +} diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md new file mode 100644 index 0000000000..aec7b589e5 --- /dev/null +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -0,0 +1,106 @@ +#
Low-Power Demo
+ +There is a lot of confusion, out-of-date information, and bad examples of how to use the 5 basic low-power modes of the ESP8266. This demo code shows you how to use them reliably. If you're here for very low power, then the 2 Light Sleep modes and Deep Sleep are what you want. + +The two relevant reference manuals from Espressif are the [Low-Power Solutions](https://www.espressif.com/sites/default/files/documentation/9b-esp8266-low_power_solutions__en.pdf) and the [Non-OS SDK API Reference](https://www.espressif.com/sites/default/files/documentation/2c-esp8266_non_os_sdk_api_reference_en.pdf). There is more information in the two PDFs than I have presented here, so you'll want both of them for your reference. + + +The table below is a corrected version of Table 1.1 from the Low-Power Solutions PDF. The currents listed are absolute minimums, and most people will not get that low with typical hardware and program. + +| item | Automatic Modem Sleep | Forced Modem Sleep | Automatic Light Sleep | Forced Light Sleep | Forced Deep Sleep | +|:---------------------:|:---------------------:|:------------------:|:---------------------:|:------------------:|:------------------:| +| WiFi connectivity | Connected | Disconnected | Connected | Disconnected | Disconnected | +| GPIO state | Unchanged | Unchanged | Unchanged | Unchanged | Low current (2 uA) | +| WiFi | ON | OFF | ON | OFF | OFF | +| System Clock | ON | ON | CYCLING | OFF | OFF | +| RTC | ON | ON | ON | ON | ON (1) | +| CPU | ON | ON | ON | ON | OFF | +| Substrate Current | 15 mA | 15 mA | 2-15 mA (2) | 0.4 mA | 20 uA | +| Avg Current DTIM = 1 | 16.2 mA | | (1.8 mA) | | | +| Avg Current DTIM = 3 | 15.4 mA | | (0.9 mA) | | | +| Avg Current DTIM = 10 | 15.2 mA | | (0.55 mA) | | | + +Notes: +(1) setting a sleep time of 0 for Deep Sleep turns off the RTC, requiring an external RESET to wake it +(2) due to a bug in SDK 2, the minimum current will never be less than 2 mA and is frequently 15 mA between DTIM beacons + +I haven't verified the Average Current with different DTIM settings. I expect the numbers above aren't realistic. All of the currents listed in this README are for the ESP8266 chip. Modules that have voltage regulators, USB chips or other hardware will draw more. + +--- + +## Basic Tests in the Demo + +1. Unconfigured modem +2. Automatic Modem Sleep +3. Forced Modem Sleep +4. Automatic Light Sleep +5. Forced Light Sleep (stop the clock, and wait for an interrupt) +6. Deep Sleep for 10 seconds, wake with default modem power settings +7. Deep Sleep for 10 seconds, wake with RFCAL +8. Deep Sleep Instant for 10 seconds, wake with NO_RFCAL +9. Deep Sleep Instant for 10 seconds, wake with RF_DISABLED + +--- + +### Test 1 - Unconfigured modem + +This is typical for programs that don't use WiFi, and is a high current drain of at least 67 mA continuous. Even if you don't plan to use WiFi, it's wise to use the SDK 2 functions below in **Lower Power without the WiFi library** to reduce the power. + +### Test 2 - Automatic Modem Sleep + +This is the default power saving mode when you have an active WiFi connection. You don't need to add anything to your code to get it. However, it's not as wonderful as it may seem, as the only time the modem sleeps is when you spend a long time in delay(), with delay times over 50mS. The LED blinks more slowly during this test as I'm doing delay(350) to get the modem to sleep. While in delay() your sketch isn't doing anything interesting. Average current during long delay()s is 15 mA minimum. Without the delay() the average current is 67 mA with short spikes above 250 mA as transmissions occur. When the WiFi has traffic (even couple of pings), the modem can turn on for over 2 seconds continuous at 67 mA, and it may stay on for a second after the traffic. In a high traffic environment you won't get any power savings with either of the 2 Automatic modes. Automatic Modem Sleep turns on 7-8 seconds after an active connection is established. + +### Test 3 - Forced Modem Sleep + +Turns off the modem (losing the connection), and dropping the current by 50 mA. This uses the WiFi library function. It's good if there is a long interval with no expected traffic, as you can do other things while only drawing 15 mA. + +### Test 4 - Automatic Light Sleep + +Like Automatic Modem Sleep, with the same restrictions. Once configured it's immediately active when a connection is established. During periods of long delay() the average current can drop to ~2 mA. In a network with sparse traffic you might get something near 2-5 mA average current. The LED blinks more slowly during this test as I'm doing delay(350) to get the modem to sleep. + +### Test 5 - Forced Light Sleep + +Similar to Deep Sleep, but without the timer. The chip sleeps at 0.4 mA current until it is woken by an external interrupt. The only allowed interrupts are high level and low level; edge interrupts won't work. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using Forced Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more efficient. The chip wakes after an interrupt in about 5.1mS. + +### Test 6 - Deep Sleep, wake with RF_DEFAULT + +In Deep Sleep almost everything is turned off, and the chip draws ~20 uA. If you have D0/GPIO16 connected to RST, you can use the RTC timer to wake the chip up at a timed interval. You can also wake it with an external RESET. Waking with RF_DEFAULT means it will do an RFCAL if it needs to. These first two Deep Sleep tests use the standard Deep Sleep function, so the WiFi connection is closed and the modem turned off, which takes about 270mS before Deep Sleep begins. Deep Sleep ends with a RESET, and the boot time after that is around 120mS. Any Deep Sleep less than 2 seconds is wasting power due to the boot time and modem shut-off, and Forced Light Sleep will be a better choice. + +### Test 7 - Deep Sleep, wake with RFCAL + +Identical to the test above, but the modem does a power calibration when booting. In normal use, I'd likely do WAKE_RF_DEFAULT instead to save the extra RFCAL power burst if it's not needed. + +### Test 8 - Deep Sleep Instant, wake with NO_RFCAL + +This variation doesn't do an automatic RF calibration, so power requirements will be slightly less. Additionally, *most* of the time it immediately goes into Deep Sleep without turning off the modem (that's the INSTANT part). There's another bug in SDK 2, and I see both SDK functions and WiFi-class functions occasionally do a modem shut-down before Deep Sleep; it's not always Instant. When it doesn't do the modem shut-down it saves an extra 270mS of power. + +### Test 9 - Deep Sleep Instant, wake with RF_DISABLED + +This last variation also uses Deep Sleep Instant, but it wakes up with the modem disabled so current after Deep Sleep is only 15 mA. You'll have to turn the modem back on in your program when you want to use WiFi again. Each of the 4 WAKE styles has their own use, depending on what you need. + +--- + +All of the Deep Sleep modes end with a RESET, so you must re-initialize everything. You can store *some* information in the RTC memory to survive a Deep Sleep reset, which I've done in this demo to illustrate it. See the **RTCUserMemory** example for more on this feature. + +The maximum Deep Sleep interval is 71.58 minutes (2^32 -1 microseconds). + +If you need a longer sleep period than that, you can pass zero as the time variable to Deep Sleep and it turns off the RTC. The only way to wake it at that point is an external RESET; D0 can't do it. Both Forced Light Sleep and Deep Sleep(0) are woken by an external signal, so short delays under 2 seconds are more efficient with Forced Light Sleep, and longer delays are more power efficient with Deep Sleep. + + +--- + +### Lower Power without the WiFi library: + +If all you want to do is reduce power for a sketch that doesn't need WiFi, add these SDK 2 functions to your code: +```c + wifi_station_disconnect(); + wifi_set_opmode(NULL_MODE); + wifi_fpm_set_sleep_type(MODEM_SLEEP_T); + wifi_fpm_open(); + wifi_fpm_do_sleep(0xFFFFFFF); + delay(1); +``` +That allows you to shut down the modem *without* loading the WiFi library, dropping your average current by 50 mA, or around 1/5th of the initial power. You have to add it as shown, although the delay() can be longer. It doesn't time out at 71 minutes, as you might think from the (0xFFFFFFF). + +You can also use the Deep Sleep modes without loading the WiFi library, as they use ESP API functions. + From 7ea68d82d4bb8f1836dd86355349df8d4f1330b0 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Sun, 5 Jan 2020 22:42:24 -0600 Subject: [PATCH 05/51] add Low-Power demo --- .../examples/LowPowerDemo/LowPowerDemo.ino | 40 +++++++++---------- .../esp8266/examples/LowPowerDemo/README.md | 6 +-- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index f7181a3b37..ea6f017f20 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -39,11 +39,11 @@ #define DEBUG_PRINT(x) #endif -#define WAKE_UP_PIN D3 // GPIO0, can also force a serial flash upload with RESET +#define WAKE_UP_PIN 0 // D3/GPIO0, can also force a serial flash upload with RESET // un-comment one of the two lines below for your LED connection -#define LED D1 // external LED for modules with built-in LEDs so it doesn't add to the current -//#define LED D4 // GPIO2 LED for ESP-01,07 modules; D4 is LED_BUILTIN on most other modules +#define LED 5 // D1/GPIO5 external LED for modules with built-in LEDs so it doesn't add to the current +//#define LED 2 // D4/GPIO2 LED for ESP-01,07 modules; D4 is LED_BUILTIN on most other modules ADC_MODE(ADC_VCC); // allows us to monitor the internal VCC level; it varies with WiFi load // don't connect anything to the analog input pin(s)! @@ -69,7 +69,7 @@ struct { byte data[4]; // the last byte stores the reset count } rtcData; -byte resetLoop = 0; // keeps track of the number of Deep Sleep tests / resets +byte resetCount = 0; // keeps track of the number of Deep Sleep tests / resets String resetCause = ""; const unsigned int blinkDelay = 100; // fast blink rate for the LED when waiting for the user @@ -91,7 +91,7 @@ void setup() { Serial.println(resetCause); if (resetCause == "External System") { Serial.println(F("I'm awake and starting the low power tests")); - resetLoop = 5; + resetCount = 5; updateRTC(); // if external reset, wipe the RTC memory and start all over } @@ -99,15 +99,15 @@ void setup() { if (ESP.rtcUserMemoryRead(64, (uint32_t*) &rtcData, sizeof(rtcData))) { uint32_t crcOfData = calculateCRC32((uint8_t*) &rtcData.data[0], sizeof(rtcData.data)); if (crcOfData != rtcData.crc32) { // if the CRC is invalid - resetLoop = 0; // set first test loop since power on or external reset + resetCount = 0; // set first test loop since power on or external reset } else { - resetLoop = rtcData.data[3]; // read the previous reset count + resetCount = rtcData.data[3]; // read the previous reset count } } } // end of Setup() void loop() { - if (resetLoop == 0) { + if (resetCount == 0) { // 1st test - running with WiFi unconfigured, reads ~67 mA minimum Serial.println(F("\n1st test - running with WiFi unconfigured")); float volts = ESP.getVcc(); @@ -171,7 +171,7 @@ void loop() { Serial.println(F("\n6th test - Deep Sleep for 10 seconds, wake with RF_DEFAULT")); init_WiFi(); // initialize WiFi since we turned it off in the last test init_OTA(); - resetLoop = 1; // advance to the next Deep Sleep test after the reset + resetCount = 1; // advance to the next Deep Sleep test after the reset updateRTC(); // save the current test state in RTC memory volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); @@ -192,12 +192,12 @@ void loop() { } // 7th test - Deep Sleep for 10 seconds, wake with RFCAL - if (resetLoop < 4) { + if (resetCount < 4) { init_WiFi(); // need to reinitialize WiFi & OTA due to Deep Sleep resets init_OTA(); // since we didn't do it in setup() because of the first test } - if (resetLoop == 1) { // second reset loop since power on - resetLoop = 2; // advance to the next Deep Sleep test after the reset + if (resetCount == 1) { // second reset loop since power on + resetCount = 2; // advance to the next Deep Sleep test after the reset updateRTC(); // save the current test state in RTC memory Serial.println(F("\n7th test - in RF_DEFAULT, Deep Sleep for 10 seconds, wake with RFCAL")); float volts = ESP.getVcc(); @@ -212,8 +212,8 @@ void loop() { } // 8th test - Deep Sleep Instant for 10 seconds, wake with NO_RFCAL - if (resetLoop == 2) { // third reset loop since power on - resetLoop = 3; // advance to the next Deep Sleep test after the reset + if (resetCount == 2) { // third reset loop since power on + resetCount = 3; // advance to the next Deep Sleep test after the reset updateRTC(); // save the current test state in RTC memory Serial.println(F("\n8th test - in RFCAL, Deep Sleep Instant for 10 seconds, wake with NO_RFCAL")); float volts = ESP.getVcc(); @@ -228,8 +228,8 @@ void loop() { } // 9th test - Deep Sleep Instant for 10 seconds, wake with RF_DISABLED - if (resetLoop == 3) { // fourth reset loop since power on - resetLoop = 4; // advance to the next Deep Sleep test after the reset + if (resetCount == 3) { // fourth reset loop since power on + resetCount = 4; // advance to the next Deep Sleep test after the reset updateRTC(); // save the current test state in RTC memory Serial.println(F("\n9th test - in NO_RFCAL, Deep Sleep Instant for 10 seconds, wake with RF_DISABLED")); float volts = ESP.getVcc(); @@ -243,8 +243,8 @@ void loop() { Serial.println(F("What... I'm not asleep?!?")); // it will never get here } - if (resetLoop == 4) { - resetLoop = 5; // start all over + if (resetCount == 4) { + resetCount = 5; // start all over updateRTC(); // save the current test state in RTC memory float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); @@ -299,10 +299,10 @@ uint32_t calculateCRC32(const uint8_t *data, size_t length) { } void updateRTC() { - rtcData.data[3] = resetLoop; // save the loop count for the next reset + rtcData.data[3] = resetCount; // save the loop count for the next reset // Update CRC32 of data rtcData.crc32 = calculateCRC32((uint8_t*) &rtcData.data[0], sizeof(rtcData.data)); - if (resetLoop == 5) // wipe the CRC in RTC memory when we're done with all tests + if (resetCount == 5) // wipe the CRC in RTC memory when we're done with all tests rtcData.crc32 = 0; // Write struct to RTC memory ESP.rtcUserMemoryWrite(64, (uint32_t*) &rtcData, sizeof(rtcData)); diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md index aec7b589e5..f9b36d1d57 100644 --- a/libraries/esp8266/examples/LowPowerDemo/README.md +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -48,11 +48,11 @@ This is typical for programs that don't use WiFi, and is a high current drain of ### Test 2 - Automatic Modem Sleep -This is the default power saving mode when you have an active WiFi connection. You don't need to add anything to your code to get it. However, it's not as wonderful as it may seem, as the only time the modem sleeps is when you spend a long time in delay(), with delay times over 50mS. The LED blinks more slowly during this test as I'm doing delay(350) to get the modem to sleep. While in delay() your sketch isn't doing anything interesting. Average current during long delay()s is 15 mA minimum. Without the delay() the average current is 67 mA with short spikes above 250 mA as transmissions occur. When the WiFi has traffic (even couple of pings), the modem can turn on for over 2 seconds continuous at 67 mA, and it may stay on for a second after the traffic. In a high traffic environment you won't get any power savings with either of the 2 Automatic modes. Automatic Modem Sleep turns on 7-8 seconds after an active connection is established. +This is the default power saving mode when you have an active WiFi connection. You don't need to add anything to your code to get it. However, it's not as wonderful as it may seem, as the only time the modem sleeps is when you spend a long time in delay(), with delay times over 50mS. The LED blinks more slowly during this test as I'm doing delay(350) to get the modem to sleep. While in delay() your sketch isn't doing anything interesting. Average current during long delay()s is 15 mA minimum. Without the delay() the average current is 67 mA with short spikes above 250 mA as transmissions occur. When the WiFi has traffic (even a couple of pings), the modem can turn on for over 2 seconds continuous at 67 mA, and it may stay on for a second after the traffic. In a high traffic environment you won't get any power savings with either of the 2 Automatic modes. Automatic Modem Sleep turns on 7-8 seconds after an active connection is established. ### Test 3 - Forced Modem Sleep -Turns off the modem (losing the connection), and dropping the current by 50 mA. This uses the WiFi library function. It's good if there is a long interval with no expected traffic, as you can do other things while only drawing 15 mA. +Turns off the modem (losing the connection), and dropping the current by 50 mA. This uses the WiFi library function. It's good if there is a long interval with no expected WiFi traffic, as you can do other things while only drawing 15 mA. ### Test 4 - Automatic Light Sleep @@ -68,7 +68,7 @@ In Deep Sleep almost everything is turned off, and the chip draws ~20 uA. If yo ### Test 7 - Deep Sleep, wake with RFCAL -Identical to the test above, but the modem does a power calibration when booting. In normal use, I'd likely do WAKE_RF_DEFAULT instead to save the extra RFCAL power burst if it's not needed. +Identical to the test above, but the modem does a power calibration when booting. In normal use, I'd likely do WAKE_RF_DEFAULT instead to minimize the extra RFCAL power burst if it's not needed. ### Test 8 - Deep Sleep Instant, wake with NO_RFCAL From f77a2c556d732b4c5ed55e8a4fa0c1876e6e9938 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Wed, 8 Jan 2020 19:45:59 -0600 Subject: [PATCH 06/51] add Low-Power demo, remove OTA and add WiFi timeout --- .../examples/LowPowerDemo/LowPowerDemo.ino | 138 ++++++++---------- .../esp8266/examples/LowPowerDemo/README.md | 21 +-- 2 files changed, 68 insertions(+), 91 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index ea6f017f20..0645bf30cd 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -1,33 +1,29 @@ /* This example demonstrates the different low-power modes of the ESP8266 - My initial setup was a WeMos D1 Mini with 3.3V connected to the 3V3 pin through a meter + The initial setup was a WeMos D1 Mini with 3.3V connected to the 3V3 pin through a meter so that it bypassed the on-board voltage regulator and USB chip. There's still about - 0.3 mA worth of leakage current due to the unpowered chips, so an ESP-01 will show lower - current readings than what I could achieve. These tests should work with any module. - While the modem is on the current is 67 mA or jumping around with a listed minimum. - To verify the 20 uA Deep Sleep current I removed the voltage regulator and USB chip. - - Since I'm now missing the USB chip, I've included OTA upload. You'll need to upload - from USB or a USB-to-TTL converter the first time, then you can disconnect and use OTA - afterwards during any test if the WiFi is connected. Some tests disconnect or sleep WiFi - so OTA won't go through. If you want OTA upload, hit RESET & press the test button once. - - This test assumes you have a pushbutton switch connected between D3 and GND to advance - the tests. You'll also need to connect D0/GPIO16 to RST for the Deep Sleep tests. - If you forget to connect D0 to RST it will hang after the first Deep Sleep test. - Connect an LED from any free pin through a 330 ohm resistor to the 3.3V supply, NOT the 3V3 - pin on the module or it adds to the measured current. When it blinks you can proceed. - When the LED is lit continuously it's connecting WiFi, when it's off the CPU is asleep. - The LED blinks slowly when the tests are complete. + 0.3 mA worth of leakage current due to the unpowered chips. These tests should work with + any module, although on-board components will affect the actual current measurement. + While the modem is turned on the current is > 67 mA or jumping around with a minimum value. + To verify the 20 uA Deep Sleep current the voltage regulator and USB chip were removed. + + This test series requires an active WiFi connection to illustrate two tests. If you + have problems with WiFi, uncomment the #ifdef DEBUG for additional WiFi error messages. + The test requires a pushbutton switch connected between D3 and GND to advance the tests. + You'll also need to connect D0/GPIO16 to RST for the Deep Sleep tests. If you forget to + connect D0 to RST it will hang after the first Deep Sleep test. Additionally, you can + connect an LED from any free pin through a 330 ohm resistor to the 3.3V supply, though + preferably not the 3V3 pin on the module or it adds to the measured current. When the + LED blinks you can proceed to the next test. When the LED is lit continuously it's + connecting WiFi, and when it's off the CPU is asleep. The LED blinks slowly when the + tests are complete. Test progress is also shown on the serial monitor. WiFi connections will be made over twice as fast if you can use a static IP address. This example code is in the public domain, and was inspired by code from numerous sources */ #include -#include -#include -#include +#include // crc32() #include //#define DEBUG // prints WiFi connection info to serial, uncomment if you want WiFi messages @@ -41,11 +37,12 @@ #define WAKE_UP_PIN 0 // D3/GPIO0, can also force a serial flash upload with RESET -// un-comment one of the two lines below for your LED connection +// uncomment one of the two lines below for your LED connection, if used #define LED 5 // D1/GPIO5 external LED for modules with built-in LEDs so it doesn't add to the current //#define LED 2 // D4/GPIO2 LED for ESP-01,07 modules; D4 is LED_BUILTIN on most other modules +// you can use LED_BUILTIN, but it adds to the measured current by 0.3mA to 6mA. -ADC_MODE(ADC_VCC); // allows us to monitor the internal VCC level; it varies with WiFi load +ADC_MODE(ADC_VCC); // allows you to monitor the internal VCC level; it varies with WiFi load // don't connect anything to the analog input pin(s)! // enter your WiFi configuration below @@ -56,12 +53,13 @@ IPAddress gateway(0, 0, 0, 0); IPAddress subnet(0, 0, 0, 0); IPAddress dns1(0, 0, 0, 0); IPAddress dns2(0, 0, 0, 0); - +uint32_t wifiTimeout = 30E3; // 30 second timeout on the WiFi connection +bool wifiOK; // used to skip tests if WiFi never connected // CRC function used to ensure data validity of RTC User Memory uint32_t calculateCRC32(const uint8_t *data, size_t length); -// This structure will be stored in RTC memory to remember the reset loop count. +// This structure will be stored in RTC memory to remember the reset count (number of Deep Sleeps). // First field is CRC32, which is calculated based on the rest of the structure contents. // Any fields can go after the CRC32. The structure must be 4-byte aligned. struct { @@ -72,8 +70,8 @@ struct { byte resetCount = 0; // keeps track of the number of Deep Sleep tests / resets String resetCause = ""; -const unsigned int blinkDelay = 100; // fast blink rate for the LED when waiting for the user -const unsigned int longDelay = 350; // longer delay() for the two AUTOMATIC modes +const uint32_t blinkDelay = 100; // fast blink rate for the LED when waiting for the user +const uint32_t longDelay = 350; // longer delay() for the two AUTOMATIC modes esp8266::polledTimeout::periodicFastMs blinkLED(blinkDelay); // use fully qualified type and avoid importing all ::esp8266 namespace to the global namespace @@ -119,12 +117,15 @@ void loop() { Serial.println(F("\n2nd test - Automatic Modem Sleep")); Serial.println(F("connecting WiFi, please wait until the LED blinks")); init_WiFi(); - init_OTA(); - Serial.println(F("The current will drop in 7 seconds.")); - volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); - Serial.println(F("press the button to continue")); - waitPushbutton(true, longDelay); + if (WiFi.localIP()) { + Serial.println(F("The current will drop in 7 seconds.")); + volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.println(F("press the button to continue")); + waitPushbutton(true, longDelay); + } else { + Serial.println(F("test skipped")); + } // 3rd test - Forced Modem Sleep Serial.println(F("\n3rd test - Forced Modem Sleep")); @@ -137,17 +138,21 @@ void loop() { // 4th test - Automatic Light Sleep Serial.println(F("\n4th test - Automatic Light Sleep")); +if (WiFi.localIP()) { Serial.println(F("reconnecting WiFi")); Serial.println(F("it will be in Automatic Light Sleep once WiFi connects (LED blinks)")); digitalWrite(LED, LOW); // visual cue that we're reconnecting WiFi.setSleepMode(WIFI_LIGHT_SLEEP, 5); // Automatic Light Sleep WiFi.forceSleepWake(); // reconnect with previous STA mode and connection settings while (!WiFi.localIP()) - delay(50); + delay(50); volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); Serial.println(F("press the button to continue")); waitPushbutton(true, longDelay); + } else { + Serial.println(F("test skipped")); + } // 5th test - Forced Light Sleep using Non-OS SDK calls Serial.println(F("\n5th test - Forced Light Sleep using Non-OS SDK calls")); @@ -168,9 +173,8 @@ void loop() { Serial.println(F("Woke up!")); // the interrupt callback hits before this is executed // 6th test - Deep Sleep for 10 seconds, wake with RF_DEFAULT - Serial.println(F("\n6th test - Deep Sleep for 10 seconds, wake with RF_DEFAULT")); + Serial.println(F("\n6th test - Deep Sleep for 10 seconds, reset and wake with RF_DEFAULT")); init_WiFi(); // initialize WiFi since we turned it off in the last test - init_OTA(); resetCount = 1; // advance to the next Deep Sleep test after the reset updateRTC(); // save the current test state in RTC memory volts = ESP.getVcc(); @@ -187,19 +191,19 @@ void loop() { delay(10); // if you do ESP.deepSleep(0, mode); it needs a RESET to come out of sleep (RTC is off) // maximum timed Deep Sleep interval = 71.58 minutes with 0xFFFFFFFF - // the 2 uA GPIO current during Deep Sleep can't drive the LED so it's off now + // the 2 uA GPIO current during Deep Sleep can't drive the LED so it's not lit now, although + // depending on the LED used, you might see it very dimly lit in a dark room during this test Serial.println(F("What... I'm not asleep?!?")); // it will never get here } // 7th test - Deep Sleep for 10 seconds, wake with RFCAL if (resetCount < 4) { - init_WiFi(); // need to reinitialize WiFi & OTA due to Deep Sleep resets - init_OTA(); // since we didn't do it in setup() because of the first test + init_WiFi(); // need to reinitialize WiFi due to Deep Sleep resets } if (resetCount == 1) { // second reset loop since power on resetCount = 2; // advance to the next Deep Sleep test after the reset updateRTC(); // save the current test state in RTC memory - Serial.println(F("\n7th test - in RF_DEFAULT, Deep Sleep for 10 seconds, wake with RFCAL")); + Serial.println(F("\n7th test - in RF_DEFAULT, Deep Sleep for 10 seconds, reset and wake with RFCAL")); float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); Serial.println(F("press the button to continue")); @@ -215,7 +219,7 @@ void loop() { if (resetCount == 2) { // third reset loop since power on resetCount = 3; // advance to the next Deep Sleep test after the reset updateRTC(); // save the current test state in RTC memory - Serial.println(F("\n8th test - in RFCAL, Deep Sleep Instant for 10 seconds, wake with NO_RFCAL")); + Serial.println(F("\n8th test - in RFCAL, Deep Sleep Instant for 10 seconds, reset and wake with NO_RFCAL")); float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); Serial.println(F("press the button to continue")); @@ -231,7 +235,7 @@ void loop() { if (resetCount == 3) { // fourth reset loop since power on resetCount = 4; // advance to the next Deep Sleep test after the reset updateRTC(); // save the current test state in RTC memory - Serial.println(F("\n9th test - in NO_RFCAL, Deep Sleep Instant for 10 seconds, wake with RF_DISABLED")); + Serial.println(F("\n9th test - in NO_RFCAL, Deep Sleep Instant for 10 seconds, reset and wake with RF_DISABLED")); float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); Serial.println(F("press the button to continue")); @@ -261,16 +265,12 @@ void waitPushbutton(bool usesDelay, unsigned int delayTime) { // loop until the while (digitalRead(WAKE_UP_PIN)) { // wait for a button press if (blinkLED) { digitalWrite(LED, !digitalRead(LED)); // toggle the activity LED - if (WiFi.localIP()) // don't check OTA if WiFi isn't connected - ArduinoOTA.handle(); //see if we need to reflash } yield(); } } else { // long delay() for the 2 AUTOMATIC modes, but it misses quick button presses while (digitalRead(WAKE_UP_PIN)) { // wait for a button press digitalWrite(LED, !digitalRead(LED)); // toggle the activity LED - if (WiFi.localIP()) // don't check OTA if WiFi isn't connected - ArduinoOTA.handle(); //see if we need to reflash delay(delayTime); } } @@ -312,7 +312,7 @@ void init_WiFi() { /* Explicitly set the ESP8266 as a WiFi-client (STAtion mode), otherwise by default it would try to act as both a client and an access-point and could cause network issues with other WiFi devices on your network. */ - digitalWrite(LED, LOW); // give a visual indication that we're alive but busy + digitalWrite(LED, LOW); // give a visual indication that we're alive but busy with WiFi WiFi.persistent(false); // don't store the connection each time to save wear on the flash WiFi.mode(WIFI_STA); WiFi.config(staticIP, gateway, subnet); // if using static IP, enter parameters at the top @@ -321,45 +321,21 @@ void init_WiFi() { Serial.println(AP_SSID); DEBUG_PRINT(F("my MAC: ")); DEBUG_PRINTLN(WiFi.macAddress()); - while (WiFi.status() != WL_CONNECTED) + uint32_t wifiStart = millis(); + while (( WiFi.status() != WL_CONNECTED ) && ( millis() - wifiStart < wifiTimeout )) { delay(50); - DEBUG_PRINTLN(F("WiFi connected")); - while (!WiFi.localIP()) + } + if (WiFi.status() == WL_CONNECTED) { + DEBUG_PRINTLN(F("WiFi connected")); + } else { + Serial.println(F("WiFi timed out and didn't connect")); + } + while (!WiFi.localIP() && (WiFi.status() == WL_CONNECTED)) { delay(50); + } WiFi.setAutoReconnect(true); DEBUG_PRINT(F("WiFi Gateway IP: ")); DEBUG_PRINTLN(WiFi.gatewayIP()); DEBUG_PRINT(F("my IP address: ")); DEBUG_PRINTLN(WiFi.localIP()); } - -void init_OTA() { - // Port defaults to 8266 - // ArduinoOTA.setPort(8266); - - // Hostname defaults to esp8266-[ChipID] - // ArduinoOTA.setHostname("myesp8266")); - - // No authentication by default - // ArduinoOTA.setPassword((const char *)"123")); - - ArduinoOTA.onStart([]() { - Serial.println(F("Start")); - }); - ArduinoOTA.onEnd([]() { - Serial.println(F("\nEnd")); - }); - ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { - Serial.printf("Progress: %u%%\r", (progress / (total / 100))); - }); - ArduinoOTA.onError([](ota_error_t error) { - Serial.printf("Error[%u]: ", error); - if (error == OTA_AUTH_ERROR) Serial.println(F("Auth Failed")); - else if (error == OTA_BEGIN_ERROR) Serial.println(F("Begin Failed")); - else if (error == OTA_CONNECT_ERROR) Serial.println(F("Connect Failed")); - else if (error == OTA_RECEIVE_ERROR) Serial.println(F("Receive Failed")); - else if (error == OTA_END_ERROR) Serial.println(F("End Failed")); - }); - ArduinoOTA.begin(); - yield(); -} diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md index f9b36d1d57..dc16400a97 100644 --- a/libraries/esp8266/examples/LowPowerDemo/README.md +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -1,11 +1,11 @@ #
Low-Power Demo
-There is a lot of confusion, out-of-date information, and bad examples of how to use the 5 basic low-power modes of the ESP8266. This demo code shows you how to use them reliably. If you're here for very low power, then the 2 Light Sleep modes and Deep Sleep are what you want. +There is a lot of confusion, out-of-date information, and poor or non-working examples of how to use the 5 basic low-power modes of the ESP8266. This demo code shows you how to use them reliably. If you're here for very low power, then the 2 Light Sleep modes and Deep Sleep are what you want. -The two relevant reference manuals from Espressif are the [Low-Power Solutions](https://www.espressif.com/sites/default/files/documentation/9b-esp8266-low_power_solutions__en.pdf) and the [Non-OS SDK API Reference](https://www.espressif.com/sites/default/files/documentation/2c-esp8266_non_os_sdk_api_reference_en.pdf). There is more information in the two PDFs than I have presented here, so you'll want both of them for your reference. +The two relevant reference manuals from Espressif are the [Low-Power Solutions](https://www.espressif.com/sites/default/files/documentation/9b-esp8266-low_power_solutions__en.pdf) and the [Non-OS SDK API Reference](https://www.espressif.com/sites/default/files/documentation/2c-esp8266_non_os_sdk_api_reference_en.pdf). There is more information in the two PDFs than is presented here, so you'll want both of them for your reference. -The table below is a corrected version of Table 1.1 from the Low-Power Solutions PDF. The currents listed are absolute minimums, and most people will not get that low with typical hardware and program. +The table below is an expanded version of Table 1.1 from the Low-Power Solutions PDF. The currents listed are absolute minimums, and most people will not get that low with typical hardware and programs. | item | Automatic Modem Sleep | Forced Modem Sleep | Automatic Light Sleep | Forced Light Sleep | Forced Deep Sleep | |:---------------------:|:---------------------:|:------------------:|:---------------------:|:------------------:|:------------------:| @@ -22,9 +22,10 @@ The table below is a corrected version of Table 1.1 from the Low-Power Solutions Notes: (1) setting a sleep time of 0 for Deep Sleep turns off the RTC, requiring an external RESET to wake it + (2) due to a bug in SDK 2, the minimum current will never be less than 2 mA and is frequently 15 mA between DTIM beacons -I haven't verified the Average Current with different DTIM settings. I expect the numbers above aren't realistic. All of the currents listed in this README are for the ESP8266 chip. Modules that have voltage regulators, USB chips or other hardware will draw more. +The Average Current with different DTIM settings is unverified, and will likely be higher in a real-world environment. All of the currents listed in this README are for the ESP8266 chip only. Modules that have voltage regulators, USB chips, LEDs or other hardware will draw additional current. --- @@ -44,11 +45,11 @@ I haven't verified the Average Current with different DTIM settings. I expect t ### Test 1 - Unconfigured modem -This is typical for programs that don't use WiFi, and is a high current drain of at least 67 mA continuous. Even if you don't plan to use WiFi, it's wise to use the SDK 2 functions below in **Lower Power without the WiFi library** to reduce the power. +This is typical for programs that don't use WiFi, and is a high current drain of at least 67 mA continuous. ### Test 2 - Automatic Modem Sleep -This is the default power saving mode when you have an active WiFi connection. You don't need to add anything to your code to get it. However, it's not as wonderful as it may seem, as the only time the modem sleeps is when you spend a long time in delay(), with delay times over 50mS. The LED blinks more slowly during this test as I'm doing delay(350) to get the modem to sleep. While in delay() your sketch isn't doing anything interesting. Average current during long delay()s is 15 mA minimum. Without the delay() the average current is 67 mA with short spikes above 250 mA as transmissions occur. When the WiFi has traffic (even a couple of pings), the modem can turn on for over 2 seconds continuous at 67 mA, and it may stay on for a second after the traffic. In a high traffic environment you won't get any power savings with either of the 2 Automatic modes. Automatic Modem Sleep turns on 7-8 seconds after an active connection is established. +This is the default power saving mode when you have an active WiFi connection. You don't need to add anything to your code to get it. The only time the modem sleeps is when you spend a long time in delay(), with delay times over 50mS. The LED blinks more slowly during this test as I'm doing delay(350) to get the modem to sleep. While in delay() your sketch isn't doing anything worthwhile. Average current during long delay()s is 15 mA minimum. Without the delay() the average current is 67 mA with short spikes above 250 mA as transmissions occur. When the WiFi has traffic (even a couple of pings), the modem can turn on for over 2 seconds continuous at 67 mA, and it may stay on for a second after the traffic. In a high traffic environment you won't get any power savings with either of the 2 Automatic modes. Automatic Modem Sleep turns on 7-8 seconds after an active connection is established. ### Test 3 - Forced Modem Sleep @@ -80,11 +81,11 @@ This last variation also uses Deep Sleep Instant, but it wakes up with the modem --- -All of the Deep Sleep modes end with a RESET, so you must re-initialize everything. You can store *some* information in the RTC memory to survive a Deep Sleep reset, which I've done in this demo to illustrate it. See the **RTCUserMemory** example for more on this feature. +All of the Deep Sleep modes end with a RESET, so you must re-initialize everything. You can store *some* information in the RTC memory to survive a Deep Sleep reset, which was done in this demo to illustrate it. See the **RTCUserMemory** example for more on this feature. The maximum Deep Sleep interval is 71.58 minutes (2^32 -1 microseconds). -If you need a longer sleep period than that, you can pass zero as the time variable to Deep Sleep and it turns off the RTC. The only way to wake it at that point is an external RESET; D0 can't do it. Both Forced Light Sleep and Deep Sleep(0) are woken by an external signal, so short delays under 2 seconds are more efficient with Forced Light Sleep, and longer delays are more power efficient with Deep Sleep. +If you need a longer sleep period than 72 minutes, you can pass zero as the time variable to Deep Sleep and it turns off the RTC. The only way to wake it at that point is an external RESET; D0 can't do it. Both Forced Light Sleep and Deep Sleep(0) are woken by an external signal, so short delays under 2 seconds are more efficient with Forced Light Sleep, and longer delays are more power efficient with Deep Sleep. --- @@ -100,7 +101,7 @@ If all you want to do is reduce power for a sketch that doesn't need WiFi, add t wifi_fpm_do_sleep(0xFFFFFFF); delay(1); ``` -That allows you to shut down the modem *without* loading the WiFi library, dropping your average current by 50 mA, or around 1/5th of the initial power. You have to add it as shown, although the delay() can be longer. It doesn't time out at 71 minutes, as you might think from the (0xFFFFFFF). +That allows you to shut down the modem *without* loading the WiFi library, dropping your average current by 50 mA, or around 1/5th of the initial power. You have to add it as shown preferably in setup(), although the delay() can be longer. It doesn't time out at 71 minutes, as you might think from the (0xFFFFFFF). The Forced Modem Sleep test does the same thing with a WiFi library call that essentially encapsulates the code above. -You can also use the Deep Sleep modes without loading the WiFi library, as they use ESP API functions. +You can also use the Deep Sleep modes without loading the WiFi library, as they use ESP API functions. The tests above try to bring the WiFi up to show you the differences after the 4 reset modes. From 387e30d37e60924da80968d8faa00d4ff51e20b7 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Wed, 8 Jan 2020 21:13:11 -0600 Subject: [PATCH 07/51] add Low-Power demo, remove OTA and add WiFi timeout --- libraries/esp8266/examples/LowPowerDemo/README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md index dc16400a97..0949fe31d9 100644 --- a/libraries/esp8266/examples/LowPowerDemo/README.md +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -49,7 +49,7 @@ This is typical for programs that don't use WiFi, and is a high current drain of ### Test 2 - Automatic Modem Sleep -This is the default power saving mode when you have an active WiFi connection. You don't need to add anything to your code to get it. The only time the modem sleeps is when you spend a long time in delay(), with delay times over 50mS. The LED blinks more slowly during this test as I'm doing delay(350) to get the modem to sleep. While in delay() your sketch isn't doing anything worthwhile. Average current during long delay()s is 15 mA minimum. Without the delay() the average current is 67 mA with short spikes above 250 mA as transmissions occur. When the WiFi has traffic (even a couple of pings), the modem can turn on for over 2 seconds continuous at 67 mA, and it may stay on for a second after the traffic. In a high traffic environment you won't get any power savings with either of the 2 Automatic modes. Automatic Modem Sleep turns on 7-8 seconds after an active connection is established. +This is the default power saving mode when you have an active WiFi connection. You don't need to add anything to your code to get it. The only time the modem sleeps is when you spend a long time in delay(), with delay times over 50mS. The LED blinks more slowly during this test as it's doing delay(350) to get the modem to sleep. While in delay() your sketch isn't doing anything worthwhile. Average current during long delay()s is 15 mA minimum. Without the delay() the average current is 67 mA with short spikes above 250 mA as transmissions occur. When the WiFi has traffic (even a couple of pings), the modem can turn on for over 2 seconds continuous at 67 mA, and it may stay on for a second after the traffic. In a high traffic environment you won't get any power savings with either of the 2 Automatic modes. Automatic Modem Sleep turns on 7-8 seconds after an active connection is established. ### Test 3 - Forced Modem Sleep @@ -57,7 +57,7 @@ Turns off the modem (losing the connection), and dropping the current by 50 mA. ### Test 4 - Automatic Light Sleep -Like Automatic Modem Sleep, with the same restrictions. Once configured it's immediately active when a connection is established. During periods of long delay() the average current can drop to ~2 mA. In a network with sparse traffic you might get something near 2-5 mA average current. The LED blinks more slowly during this test as I'm doing delay(350) to get the modem to sleep. +Like Automatic Modem Sleep, with the same restrictions. Once configured it's immediately active when a connection is established. During periods of long delay() the average current can drop to ~2 mA. In a network with sparse traffic you might get something near 2-5 mA average current. The LED blinks more slowly during this test as it's doing delay(350) to get the modem to sleep. ### Test 5 - Forced Light Sleep @@ -65,25 +65,25 @@ Similar to Deep Sleep, but without the timer. The chip sleeps at 0.4 mA current ### Test 6 - Deep Sleep, wake with RF_DEFAULT -In Deep Sleep almost everything is turned off, and the chip draws ~20 uA. If you have D0/GPIO16 connected to RST, you can use the RTC timer to wake the chip up at a timed interval. You can also wake it with an external RESET. Waking with RF_DEFAULT means it will do an RFCAL if it needs to. These first two Deep Sleep tests use the standard Deep Sleep function, so the WiFi connection is closed and the modem turned off, which takes about 270mS before Deep Sleep begins. Deep Sleep ends with a RESET, and the boot time after that is around 120mS. Any Deep Sleep less than 2 seconds is wasting power due to the boot time and modem shut-off, and Forced Light Sleep will be a better choice. +In Deep Sleep almost everything is turned off, and the chip draws ~20 uA. If you have D0/GPIO16 connected to RST, you can use the RTC timer to wake the chip up at a timed interval. You can also wake it with an external RESET. Waking with RF_DEFAULT means it will do an RFCAL if it needs to. These first two Deep Sleep tests use the standard Deep Sleep function, so the WiFi connection is closed and the modem turned off, which takes about 270mS before Deep Sleep begins. Deep Sleep ends with a RESET, and the boot time after that is around 120mS. Any Deep Sleep less than ~2 seconds is wasting power due to the modem shut-off and boot time, and Forced Light Sleep will be a better choice as it recovers in 5.1mS from the previous state. ### Test 7 - Deep Sleep, wake with RFCAL -Identical to the test above, but the modem does a power calibration when booting. In normal use, I'd likely do WAKE_RF_DEFAULT instead to minimize the extra RFCAL power burst if it's not needed. +Identical to the test above, but the modem does a power calibration when booting. In normal use, most people would do WAKE_RF_DEFAULT instead to minimize the extra RFCAL power burst if it's not needed. ### Test 8 - Deep Sleep Instant, wake with NO_RFCAL -This variation doesn't do an automatic RF calibration, so power requirements will be slightly less. Additionally, *most* of the time it immediately goes into Deep Sleep without turning off the modem (that's the INSTANT part). There's another bug in SDK 2, and I see both SDK functions and WiFi-class functions occasionally do a modem shut-down before Deep Sleep; it's not always Instant. When it doesn't do the modem shut-down it saves an extra 270mS of power. +This variation doesn't do an automatic RF calibration, so power requirements will be slightly less. Additionally, *most* of the time it immediately goes into Deep Sleep without turning off the modem (that's the INSTANT part). There's another bug in SDK 2, and the SDK functions the WiFi-class calls occasionally do a modem shut-down before Deep Sleep; it's not always Instant. When it doesn't do the modem shut-down it saves an extra 270mS of power. ### Test 9 - Deep Sleep Instant, wake with RF_DISABLED -This last variation also uses Deep Sleep Instant, but it wakes up with the modem disabled so current after Deep Sleep is only 15 mA. You'll have to turn the modem back on in your program when you want to use WiFi again. Each of the 4 WAKE styles has their own use, depending on what you need. +This last variation also uses Deep Sleep Instant, but it wakes up with the modem disabled so current after Deep Sleep is only 15 mA. Each of the 4 WAKE styles has their own use, depending on what you need. --- All of the Deep Sleep modes end with a RESET, so you must re-initialize everything. You can store *some* information in the RTC memory to survive a Deep Sleep reset, which was done in this demo to illustrate it. See the **RTCUserMemory** example for more on this feature. -The maximum Deep Sleep interval is 71.58 minutes (2^32 -1 microseconds). +The maximum Deep Sleep interval is 71.58 minutes (2^32 -1 microseconds), although the actual interval may be something less than that. If you need a longer sleep period than 72 minutes, you can pass zero as the time variable to Deep Sleep and it turns off the RTC. The only way to wake it at that point is an external RESET; D0 can't do it. Both Forced Light Sleep and Deep Sleep(0) are woken by an external signal, so short delays under 2 seconds are more efficient with Forced Light Sleep, and longer delays are more power efficient with Deep Sleep. From df7520039956c3d8fd995f5d28b18c4041b2f9a5 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Thu, 9 Jan 2020 18:15:12 -0600 Subject: [PATCH 08/51] add Low-Power demo --- .../esp8266/examples/LowPowerDemo/README.md | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 libraries/esp8266/examples/LowPowerDemo/README.md diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md new file mode 100644 index 0000000000..0949fe31d9 --- /dev/null +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -0,0 +1,107 @@ +#
Low-Power Demo
+ +There is a lot of confusion, out-of-date information, and poor or non-working examples of how to use the 5 basic low-power modes of the ESP8266. This demo code shows you how to use them reliably. If you're here for very low power, then the 2 Light Sleep modes and Deep Sleep are what you want. + +The two relevant reference manuals from Espressif are the [Low-Power Solutions](https://www.espressif.com/sites/default/files/documentation/9b-esp8266-low_power_solutions__en.pdf) and the [Non-OS SDK API Reference](https://www.espressif.com/sites/default/files/documentation/2c-esp8266_non_os_sdk_api_reference_en.pdf). There is more information in the two PDFs than is presented here, so you'll want both of them for your reference. + + +The table below is an expanded version of Table 1.1 from the Low-Power Solutions PDF. The currents listed are absolute minimums, and most people will not get that low with typical hardware and programs. + +| item | Automatic Modem Sleep | Forced Modem Sleep | Automatic Light Sleep | Forced Light Sleep | Forced Deep Sleep | +|:---------------------:|:---------------------:|:------------------:|:---------------------:|:------------------:|:------------------:| +| WiFi connectivity | Connected | Disconnected | Connected | Disconnected | Disconnected | +| GPIO state | Unchanged | Unchanged | Unchanged | Unchanged | Low current (2 uA) | +| WiFi | ON | OFF | ON | OFF | OFF | +| System Clock | ON | ON | CYCLING | OFF | OFF | +| RTC | ON | ON | ON | ON | ON (1) | +| CPU | ON | ON | ON | ON | OFF | +| Substrate Current | 15 mA | 15 mA | 2-15 mA (2) | 0.4 mA | 20 uA | +| Avg Current DTIM = 1 | 16.2 mA | | (1.8 mA) | | | +| Avg Current DTIM = 3 | 15.4 mA | | (0.9 mA) | | | +| Avg Current DTIM = 10 | 15.2 mA | | (0.55 mA) | | | + +Notes: +(1) setting a sleep time of 0 for Deep Sleep turns off the RTC, requiring an external RESET to wake it + +(2) due to a bug in SDK 2, the minimum current will never be less than 2 mA and is frequently 15 mA between DTIM beacons + +The Average Current with different DTIM settings is unverified, and will likely be higher in a real-world environment. All of the currents listed in this README are for the ESP8266 chip only. Modules that have voltage regulators, USB chips, LEDs or other hardware will draw additional current. + +--- + +## Basic Tests in the Demo + +1. Unconfigured modem +2. Automatic Modem Sleep +3. Forced Modem Sleep +4. Automatic Light Sleep +5. Forced Light Sleep (stop the clock, and wait for an interrupt) +6. Deep Sleep for 10 seconds, wake with default modem power settings +7. Deep Sleep for 10 seconds, wake with RFCAL +8. Deep Sleep Instant for 10 seconds, wake with NO_RFCAL +9. Deep Sleep Instant for 10 seconds, wake with RF_DISABLED + +--- + +### Test 1 - Unconfigured modem + +This is typical for programs that don't use WiFi, and is a high current drain of at least 67 mA continuous. + +### Test 2 - Automatic Modem Sleep + +This is the default power saving mode when you have an active WiFi connection. You don't need to add anything to your code to get it. The only time the modem sleeps is when you spend a long time in delay(), with delay times over 50mS. The LED blinks more slowly during this test as it's doing delay(350) to get the modem to sleep. While in delay() your sketch isn't doing anything worthwhile. Average current during long delay()s is 15 mA minimum. Without the delay() the average current is 67 mA with short spikes above 250 mA as transmissions occur. When the WiFi has traffic (even a couple of pings), the modem can turn on for over 2 seconds continuous at 67 mA, and it may stay on for a second after the traffic. In a high traffic environment you won't get any power savings with either of the 2 Automatic modes. Automatic Modem Sleep turns on 7-8 seconds after an active connection is established. + +### Test 3 - Forced Modem Sleep + +Turns off the modem (losing the connection), and dropping the current by 50 mA. This uses the WiFi library function. It's good if there is a long interval with no expected WiFi traffic, as you can do other things while only drawing 15 mA. + +### Test 4 - Automatic Light Sleep + +Like Automatic Modem Sleep, with the same restrictions. Once configured it's immediately active when a connection is established. During periods of long delay() the average current can drop to ~2 mA. In a network with sparse traffic you might get something near 2-5 mA average current. The LED blinks more slowly during this test as it's doing delay(350) to get the modem to sleep. + +### Test 5 - Forced Light Sleep + +Similar to Deep Sleep, but without the timer. The chip sleeps at 0.4 mA current until it is woken by an external interrupt. The only allowed interrupts are high level and low level; edge interrupts won't work. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using Forced Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more efficient. The chip wakes after an interrupt in about 5.1mS. + +### Test 6 - Deep Sleep, wake with RF_DEFAULT + +In Deep Sleep almost everything is turned off, and the chip draws ~20 uA. If you have D0/GPIO16 connected to RST, you can use the RTC timer to wake the chip up at a timed interval. You can also wake it with an external RESET. Waking with RF_DEFAULT means it will do an RFCAL if it needs to. These first two Deep Sleep tests use the standard Deep Sleep function, so the WiFi connection is closed and the modem turned off, which takes about 270mS before Deep Sleep begins. Deep Sleep ends with a RESET, and the boot time after that is around 120mS. Any Deep Sleep less than ~2 seconds is wasting power due to the modem shut-off and boot time, and Forced Light Sleep will be a better choice as it recovers in 5.1mS from the previous state. + +### Test 7 - Deep Sleep, wake with RFCAL + +Identical to the test above, but the modem does a power calibration when booting. In normal use, most people would do WAKE_RF_DEFAULT instead to minimize the extra RFCAL power burst if it's not needed. + +### Test 8 - Deep Sleep Instant, wake with NO_RFCAL + +This variation doesn't do an automatic RF calibration, so power requirements will be slightly less. Additionally, *most* of the time it immediately goes into Deep Sleep without turning off the modem (that's the INSTANT part). There's another bug in SDK 2, and the SDK functions the WiFi-class calls occasionally do a modem shut-down before Deep Sleep; it's not always Instant. When it doesn't do the modem shut-down it saves an extra 270mS of power. + +### Test 9 - Deep Sleep Instant, wake with RF_DISABLED + +This last variation also uses Deep Sleep Instant, but it wakes up with the modem disabled so current after Deep Sleep is only 15 mA. Each of the 4 WAKE styles has their own use, depending on what you need. + +--- + +All of the Deep Sleep modes end with a RESET, so you must re-initialize everything. You can store *some* information in the RTC memory to survive a Deep Sleep reset, which was done in this demo to illustrate it. See the **RTCUserMemory** example for more on this feature. + +The maximum Deep Sleep interval is 71.58 minutes (2^32 -1 microseconds), although the actual interval may be something less than that. + +If you need a longer sleep period than 72 minutes, you can pass zero as the time variable to Deep Sleep and it turns off the RTC. The only way to wake it at that point is an external RESET; D0 can't do it. Both Forced Light Sleep and Deep Sleep(0) are woken by an external signal, so short delays under 2 seconds are more efficient with Forced Light Sleep, and longer delays are more power efficient with Deep Sleep. + + +--- + +### Lower Power without the WiFi library: + +If all you want to do is reduce power for a sketch that doesn't need WiFi, add these SDK 2 functions to your code: +```c + wifi_station_disconnect(); + wifi_set_opmode(NULL_MODE); + wifi_fpm_set_sleep_type(MODEM_SLEEP_T); + wifi_fpm_open(); + wifi_fpm_do_sleep(0xFFFFFFF); + delay(1); +``` +That allows you to shut down the modem *without* loading the WiFi library, dropping your average current by 50 mA, or around 1/5th of the initial power. You have to add it as shown preferably in setup(), although the delay() can be longer. It doesn't time out at 71 minutes, as you might think from the (0xFFFFFFF). The Forced Modem Sleep test does the same thing with a WiFi library call that essentially encapsulates the code above. + +You can also use the Deep Sleep modes without loading the WiFi library, as they use ESP API functions. The tests above try to bring the WiFi up to show you the differences after the 4 reset modes. + From 11f193143fc40e1bf4ee013db88fa7f7f5ede8d3 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Thu, 9 Jan 2020 19:39:10 -0600 Subject: [PATCH 09/51] add Low-Power demo --- .../examples/LowPowerDemo/LowPowerDemo.ino | 95 +++++++++---------- 1 file changed, 45 insertions(+), 50 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index 0645bf30cd..572f7a4286 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -20,7 +20,19 @@ WiFi connections will be made over twice as fast if you can use a static IP address. - This example code is in the public domain, and was inspired by code from numerous sources */ + This example is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This example is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this example; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include // crc32() @@ -54,10 +66,6 @@ IPAddress subnet(0, 0, 0, 0); IPAddress dns1(0, 0, 0, 0); IPAddress dns2(0, 0, 0, 0); uint32_t wifiTimeout = 30E3; // 30 second timeout on the WiFi connection -bool wifiOK; // used to skip tests if WiFi never connected - -// CRC function used to ensure data validity of RTC User Memory -uint32_t calculateCRC32(const uint8_t *data, size_t length); // This structure will be stored in RTC memory to remember the reset count (number of Deep Sleeps). // First field is CRC32, which is calculated based on the rest of the structure contents. @@ -95,7 +103,7 @@ void setup() { // Read struct from RTC memory if (ESP.rtcUserMemoryRead(64, (uint32_t*) &rtcData, sizeof(rtcData))) { - uint32_t crcOfData = calculateCRC32((uint8_t*) &rtcData.data[0], sizeof(rtcData.data)); + uint32_t crcOfData = crc32((uint8_t*) &rtcData.data[0], sizeof(rtcData.data)); if (crcOfData != rtcData.crc32) { // if the CRC is invalid resetCount = 0; // set first test loop since power on or external reset } else { @@ -109,7 +117,7 @@ void loop() { // 1st test - running with WiFi unconfigured, reads ~67 mA minimum Serial.println(F("\n1st test - running with WiFi unconfigured")); float volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("press the button to continue")); waitPushbutton(false, blinkDelay); @@ -117,14 +125,14 @@ void loop() { Serial.println(F("\n2nd test - Automatic Modem Sleep")); Serial.println(F("connecting WiFi, please wait until the LED blinks")); init_WiFi(); - if (WiFi.localIP()) { + if (WiFi.localIP()) { // won't go into Automatic Sleep without an active WiFi connection Serial.println(F("The current will drop in 7 seconds.")); volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("press the button to continue")); waitPushbutton(true, longDelay); } else { - Serial.println(F("test skipped")); + Serial.println(F("no WiFi connection, test skipped")); } // 3rd test - Forced Modem Sleep @@ -132,26 +140,28 @@ void loop() { WiFi.forceSleepBegin(); delay(10); // it doesn't always go to sleep unless you delay(10) volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("press the button to continue")); waitPushbutton(false, blinkDelay); // 4th test - Automatic Light Sleep Serial.println(F("\n4th test - Automatic Light Sleep")); -if (WiFi.localIP()) { Serial.println(F("reconnecting WiFi")); Serial.println(F("it will be in Automatic Light Sleep once WiFi connects (LED blinks)")); digitalWrite(LED, LOW); // visual cue that we're reconnecting WiFi.setSleepMode(WIFI_LIGHT_SLEEP, 5); // Automatic Light Sleep WiFi.forceSleepWake(); // reconnect with previous STA mode and connection settings - while (!WiFi.localIP()) - delay(50); - volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); - Serial.println(F("press the button to continue")); - waitPushbutton(true, longDelay); + uint32_t wifiStart = millis(); + while ((!WiFi.localIP() ) && ( millis() - wifiStart < wifiTimeout )) { + delay(50); + } + if (WiFi.localIP()) { // won't go into Automatic Sleep without an active WiFi connection + volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); + Serial.println(F("press the button to continue")); + waitPushbutton(true, longDelay); } else { - Serial.println(F("test skipped")); + Serial.println(F("no WiFi connection, test skipped")); } // 5th test - Forced Light Sleep using Non-OS SDK calls @@ -160,7 +170,7 @@ if (WiFi.localIP()) { yield(); digitalWrite(LED, HIGH); // turn the LED off so they know the CPU isn't running volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("CPU going to sleep, pull WAKE_UP_PIN low to wake it (press the button)")); delay(100); // needs a brief delay after the print or it may print the whole message wifi_fpm_set_sleep_type(LIGHT_SLEEP_T); @@ -178,10 +188,11 @@ if (WiFi.localIP()) { resetCount = 1; // advance to the next Deep Sleep test after the reset updateRTC(); // save the current test state in RTC memory volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("press the button to continue")); - while (!digitalRead(WAKE_UP_PIN)) // wait for them to release the button from the last test + while (!digitalRead(WAKE_UP_PIN)) { // wait for them to release the button from the last test delay(10); + } delay(50); // debounce time for the switch, button released waitPushbutton(false, blinkDelay); digitalWrite(LED, LOW); // turn the LED on, at least briefly @@ -205,7 +216,7 @@ if (WiFi.localIP()) { updateRTC(); // save the current test state in RTC memory Serial.println(F("\n7th test - in RF_DEFAULT, Deep Sleep for 10 seconds, reset and wake with RFCAL")); float volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("press the button to continue")); waitPushbutton(false, blinkDelay); Serial.println(F("going into Deep Sleep now...")); @@ -221,7 +232,7 @@ if (WiFi.localIP()) { updateRTC(); // save the current test state in RTC memory Serial.println(F("\n8th test - in RFCAL, Deep Sleep Instant for 10 seconds, reset and wake with NO_RFCAL")); float volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("press the button to continue")); waitPushbutton(false, blinkDelay); Serial.println(F("going into Deep Sleep now...")); @@ -237,7 +248,7 @@ if (WiFi.localIP()) { updateRTC(); // save the current test state in RTC memory Serial.println(F("\n9th test - in NO_RFCAL, Deep Sleep Instant for 10 seconds, reset and wake with RF_DISABLED")); float volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("press the button to continue")); waitPushbutton(false, blinkDelay); Serial.println(F("going into Deep Sleep now...")); @@ -248,10 +259,10 @@ if (WiFi.localIP()) { } if (resetCount == 4) { - resetCount = 5; // start all over + resetCount = 5; // start all over, do an ESP.restart to insure it's a clean state updateRTC(); // save the current test state in RTC memory float volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000 ); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("\nTests completed, in RF_DISABLED, press the button to do an ESP.restart()")); waitPushbutton(false, 1000); ESP.restart(); @@ -260,7 +271,7 @@ if (WiFi.localIP()) { void waitPushbutton(bool usesDelay, unsigned int delayTime) { // loop until they press the button // note: 2 different modes, as both of the AUTOMATIC power saving modes need a long delay() - if (!usesDelay) { // quick interception of button press, no delay() + if (!usesDelay) { // quick interception of button press, no delay() used blinkLED.reset(delayTime); while (digitalRead(WAKE_UP_PIN)) { // wait for a button press if (blinkLED) { @@ -275,35 +286,19 @@ void waitPushbutton(bool usesDelay, unsigned int delayTime) { // loop until the } } delay(50); // debounce time for the switch, button pressed - while (!digitalRead(WAKE_UP_PIN)) // now wait for them to release the button + while (!digitalRead(WAKE_UP_PIN)) { // now wait for them to release the button delay(10); - delay(50); // debounce time for the switch, button released -} - -uint32_t calculateCRC32(const uint8_t *data, size_t length) { - uint32_t crc = 0xffffffff; - while (length--) { - uint8_t c = *data++; - for (uint32_t i = 0x80; i > 0; i >>= 1) { - bool bit = crc & 0x80000000; - if (c & i) { - bit = !bit; - } - crc <<= 1; - if (bit) { - crc ^= 0x04c11db7; - } - } } - return crc; + delay(50); // debounce time for the switch, button released } void updateRTC() { rtcData.data[3] = resetCount; // save the loop count for the next reset // Update CRC32 of data - rtcData.crc32 = calculateCRC32((uint8_t*) &rtcData.data[0], sizeof(rtcData.data)); - if (resetCount == 5) // wipe the CRC in RTC memory when we're done with all tests + rtcData.crc32 = crc32((uint8_t*) &rtcData.data[0], sizeof(rtcData.data)); + if (resetCount == 5) { // wipe the CRC in RTC memory when we're done with all tests rtcData.crc32 = 0; + } // Write struct to RTC memory ESP.rtcUserMemoryWrite(64, (uint32_t*) &rtcData, sizeof(rtcData)); } @@ -322,7 +317,7 @@ void init_WiFi() { DEBUG_PRINT(F("my MAC: ")); DEBUG_PRINTLN(WiFi.macAddress()); uint32_t wifiStart = millis(); - while (( WiFi.status() != WL_CONNECTED ) && ( millis() - wifiStart < wifiTimeout )) { + while ((WiFi.status() != WL_CONNECTED) && (millis() - wifiStart < wifiTimeout)) { delay(50); } if (WiFi.status() == WL_CONNECTED) { From 2003ef44a33888a151007d8d0c8b51cb4cafa443 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Thu, 9 Jan 2020 20:47:07 -0600 Subject: [PATCH 10/51] add Low-Power demo --- libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index 572f7a4286..67b2b98619 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -152,7 +152,7 @@ void loop() { WiFi.setSleepMode(WIFI_LIGHT_SLEEP, 5); // Automatic Light Sleep WiFi.forceSleepWake(); // reconnect with previous STA mode and connection settings uint32_t wifiStart = millis(); - while ((!WiFi.localIP() ) && ( millis() - wifiStart < wifiTimeout )) { + while ((!WiFi.localIP()) && (millis() - wifiStart < wifiTimeout)) { delay(50); } if (WiFi.localIP()) { // won't go into Automatic Sleep without an active WiFi connection From acf3cecabdbb0db8912504dc3805ee7a32b8fdc3 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Thu, 9 Jan 2020 21:31:10 -0600 Subject: [PATCH 11/51] add Low-Power demo --- libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index 67b2b98619..4eee9f84a0 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -12,7 +12,7 @@ The test requires a pushbutton switch connected between D3 and GND to advance the tests. You'll also need to connect D0/GPIO16 to RST for the Deep Sleep tests. If you forget to connect D0 to RST it will hang after the first Deep Sleep test. Additionally, you can - connect an LED from any free pin through a 330 ohm resistor to the 3.3V supply, though + connect an LED from any free pin through a 1K ohm resistor to the 3.3V supply, though preferably not the 3V3 pin on the module or it adds to the measured current. When the LED blinks you can proceed to the next test. When the LED is lit continuously it's connecting WiFi, and when it's off the CPU is asleep. The LED blinks slowly when the @@ -48,6 +48,7 @@ #endif #define WAKE_UP_PIN 0 // D3/GPIO0, can also force a serial flash upload with RESET +// you can use any pin for WAKE_UP_PIN except for D0/GPIO16 as it doesn't support interrupts // uncomment one of the two lines below for your LED connection, if used #define LED 5 // D1/GPIO5 external LED for modules with built-in LEDs so it doesn't add to the current From 2f2c5086f2e03349c0b555e9df62a7accba2c66c Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Fri, 10 Jan 2020 19:35:18 -0600 Subject: [PATCH 12/51] add Low-Power demo --- .../examples/LowPowerDemo/LowPowerDemo.ino | 14 +++++------ .../esp8266/examples/LowPowerDemo/README.md | 23 ++++++++++--------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index 4eee9f84a0..10b563fce1 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -139,7 +139,7 @@ void loop() { // 3rd test - Forced Modem Sleep Serial.println(F("\n3rd test - Forced Modem Sleep")); WiFi.forceSleepBegin(); - delay(10); // it doesn't always go to sleep unless you delay(10) + delay(10); // it doesn't always go to sleep unless you delay(10), yield() may also work volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("press the button to continue")); @@ -173,13 +173,13 @@ void loop() { volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("CPU going to sleep, pull WAKE_UP_PIN low to wake it (press the button)")); - delay(100); // needs a brief delay after the print or it may print the whole message + delay(100); // needs a delay() after the print or it may not print the whole message wifi_fpm_set_sleep_type(LIGHT_SLEEP_T); gpio_pin_wakeup_enable(GPIO_ID_PIN(WAKE_UP_PIN), GPIO_PIN_INTR_LOLEVEL); // only LOLEVEL or HILEVEL interrupts work, no edge, that's an SDK or CPU limitation wifi_fpm_set_wakeup_cb(wakeupCallback); // Set wakeup callback (optional) wifi_fpm_open(); - wifi_fpm_do_sleep(0xFFFFFFF); // only 0xFFFFFFF allowed; any other value and it won't sleep + wifi_fpm_do_sleep(0xFFFFFFF); // only 0xFFFFFFF works; any other value and it won't sleep delay(10); // it goes to sleep some time during this delay() and waits for an interrupt Serial.println(F("Woke up!")); // the interrupt callback hits before this is executed @@ -210,7 +210,7 @@ void loop() { // 7th test - Deep Sleep for 10 seconds, wake with RFCAL if (resetCount < 4) { - init_WiFi(); // need to reinitialize WiFi due to Deep Sleep resets + init_WiFi(); // need to reinitialize WiFi due to Deep Sleep reset } if (resetCount == 1) { // second reset loop since power on resetCount = 2; // advance to the next Deep Sleep test after the reset @@ -278,12 +278,12 @@ void waitPushbutton(bool usesDelay, unsigned int delayTime) { // loop until the if (blinkLED) { digitalWrite(LED, !digitalRead(LED)); // toggle the activity LED } - yield(); + yield(); // this would be a good spot for ArduinoOTA.handle(); } } else { // long delay() for the 2 AUTOMATIC modes, but it misses quick button presses while (digitalRead(WAKE_UP_PIN)) { // wait for a button press digitalWrite(LED, !digitalRead(LED)); // toggle the activity LED - delay(delayTime); + delay(delayTime); // another good spot for ArduinoOTA.handle(); } } delay(50); // debounce time for the switch, button pressed @@ -294,7 +294,7 @@ void waitPushbutton(bool usesDelay, unsigned int delayTime) { // loop until the } void updateRTC() { - rtcData.data[3] = resetCount; // save the loop count for the next reset + rtcData.data[3] = resetCount; // save the reset count for the next test run // Update CRC32 of data rtcData.crc32 = crc32((uint8_t*) &rtcData.data[0], sizeof(rtcData.data)); if (resetCount == 5) { // wipe the CRC in RTC memory when we're done with all tests diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md index 0949fe31d9..c7e011b768 100644 --- a/libraries/esp8266/examples/LowPowerDemo/README.md +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -21,6 +21,7 @@ The table below is an expanded version of Table 1.1 from the Low-Power Solutions | Avg Current DTIM = 10 | 15.2 mA | | (0.55 mA) | | | Notes: + (1) setting a sleep time of 0 for Deep Sleep turns off the RTC, requiring an external RESET to wake it (2) due to a bug in SDK 2, the minimum current will never be less than 2 mA and is frequently 15 mA between DTIM beacons @@ -45,15 +46,15 @@ The Average Current with different DTIM settings is unverified, and will likely ### Test 1 - Unconfigured modem -This is typical for programs that don't use WiFi, and is a high current drain of at least 67 mA continuous. +This is typical for programs that don't use WiFi, and is a high current drain of at least 67 mA continuous. This isn't a test as much as it sets a baseline or reference point for comparing the power savings. You can stop any time the CPU is halted or the LED is blinking to measure the current. ### Test 2 - Automatic Modem Sleep -This is the default power saving mode when you have an active WiFi connection. You don't need to add anything to your code to get it. The only time the modem sleeps is when you spend a long time in delay(), with delay times over 50mS. The LED blinks more slowly during this test as it's doing delay(350) to get the modem to sleep. While in delay() your sketch isn't doing anything worthwhile. Average current during long delay()s is 15 mA minimum. Without the delay() the average current is 67 mA with short spikes above 250 mA as transmissions occur. When the WiFi has traffic (even a couple of pings), the modem can turn on for over 2 seconds continuous at 67 mA, and it may stay on for a second after the traffic. In a high traffic environment you won't get any power savings with either of the 2 Automatic modes. Automatic Modem Sleep turns on 7-8 seconds after an active connection is established. +This is the default power saving mode when you have an active WiFi connection. You don't need to add anything to your code to get it. The only time the modem sleeps is when you spend a long time in delay(), with delay times over 50mS. The LED blinks more slowly during this test as it's doing delay(350) to get the modem to sleep. While in delay() your sketch isn't doing anything worthwhile. Average current during a long delay() is 15 mA minimum. Without the delay() the average current is 67 mA with short spikes above 250 mA as transmissions occur. When the WiFi has traffic (even a couple of pings), the modem can turn on for over 2 seconds continuous at 67 mA, and it may stay on for a second after the traffic. In a high traffic environment you won't get any power savings with either of the 2 Automatic modes. Automatic Modem Sleep turns on 7-8 seconds after an active connection is established. ### Test 3 - Forced Modem Sleep -Turns off the modem (losing the connection), and dropping the current by 50 mA. This uses the WiFi library function. It's good if there is a long interval with no expected WiFi traffic, as you can do other things while only drawing 15 mA. +Turns off the modem (losing the connection), and reducing the current by 50 mA. This test uses the WiFi library function. It's good if there is a long interval with no expected WiFi traffic, as you can do other things while only drawing 15 mA. ### Test 4 - Automatic Light Sleep @@ -61,19 +62,19 @@ Like Automatic Modem Sleep, with the same restrictions. Once configured it's im ### Test 5 - Forced Light Sleep -Similar to Deep Sleep, but without the timer. The chip sleeps at 0.4 mA current until it is woken by an external interrupt. The only allowed interrupts are high level and low level; edge interrupts won't work. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using Forced Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more efficient. The chip wakes after an interrupt in about 5.1mS. +Similar to Deep Sleep, but without the timer. The chip sleeps at 0.4 mA current until it is woken by an external interrupt. The only allowed interrupts are high level and low level; edge interrupts won't work. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using Forced Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more efficient. The chip wakes after an interrupt in about 5.1 mS, but WiFi was turned off to enter Forced Light Sleep so you may need to re-initialize it. ### Test 6 - Deep Sleep, wake with RF_DEFAULT -In Deep Sleep almost everything is turned off, and the chip draws ~20 uA. If you have D0/GPIO16 connected to RST, you can use the RTC timer to wake the chip up at a timed interval. You can also wake it with an external RESET. Waking with RF_DEFAULT means it will do an RFCAL if it needs to. These first two Deep Sleep tests use the standard Deep Sleep function, so the WiFi connection is closed and the modem turned off, which takes about 270mS before Deep Sleep begins. Deep Sleep ends with a RESET, and the boot time after that is around 120mS. Any Deep Sleep less than ~2 seconds is wasting power due to the modem shut-off and boot time, and Forced Light Sleep will be a better choice as it recovers in 5.1mS from the previous state. +In Deep Sleep almost everything is turned off, and the chip draws ~ 20 uA. If you have D0/GPIO16 connected to RST, you can use the RTC timer to wake the chip up at a timed interval. You can also wake it with an external RESET. Waking with RF_DEFAULT means it will do an RFCAL if it needs to. Doing ESP.deepSleep(time) without the mode variable uses this wake mode. These first two Deep Sleep tests use the standard Deep Sleep function, so the WiFi connection is closed and the modem turned off, which takes about 270 mS before the Deep Sleep will begin. Deep Sleep ends with a RESET, and the boot time after that is ~ 120 mS. Any Deep Sleep less than ~ 2 seconds is wasting power due to the modem shut-off and boot time, and Forced Light Sleep will be a better choice as it recovers in 5.1 mS from the previous state. ### Test 7 - Deep Sleep, wake with RFCAL -Identical to the test above, but the modem does a power calibration when booting. In normal use, most people would do WAKE_RF_DEFAULT instead to minimize the extra RFCAL power burst if it's not needed. +Identical to the test above, but the modem does an RF power calibration when booting. In normal use, most people would do WAKE_RF_DEFAULT instead to minimize the extra RFCAL power burst if it's not needed. ### Test 8 - Deep Sleep Instant, wake with NO_RFCAL -This variation doesn't do an automatic RF calibration, so power requirements will be slightly less. Additionally, *most* of the time it immediately goes into Deep Sleep without turning off the modem (that's the INSTANT part). There's another bug in SDK 2, and the SDK functions the WiFi-class calls occasionally do a modem shut-down before Deep Sleep; it's not always Instant. When it doesn't do the modem shut-down it saves an extra 270mS of power. +This variation doesn't do an automatic RF calibration on return, so power requirements will be slightly less. Additionally, *most* of the time it immediately goes into Deep Sleep without turning off the modem (that's the INSTANT part). There's another bug in SDK 2, and the SDK functions the WiFi-class calls occasionally do a modem shut-down before Deep Sleep; it's not always Instant. When it doesn't do the modem shut-down it saves an extra 270mS of power. ### Test 9 - Deep Sleep Instant, wake with RF_DISABLED @@ -81,7 +82,7 @@ This last variation also uses Deep Sleep Instant, but it wakes up with the modem --- -All of the Deep Sleep modes end with a RESET, so you must re-initialize everything. You can store *some* information in the RTC memory to survive a Deep Sleep reset, which was done in this demo to illustrate it. See the **RTCUserMemory** example for more on this feature. +All of the Deep Sleep modes end with a RESET, so you must re-initialize everything. You can store *some* information in the RTC memory to survive a Deep Sleep reset, which was done in this demo to illustrate the RTC memory. See the **RTCUserMemory** example for more information on this feature. The maximum Deep Sleep interval is 71.58 minutes (2^32 -1 microseconds), although the actual interval may be something less than that. @@ -92,7 +93,7 @@ If you need a longer sleep period than 72 minutes, you can pass zero as the time ### Lower Power without the WiFi library: -If all you want to do is reduce power for a sketch that doesn't need WiFi, add these SDK 2 functions to your code: +If all you want to do is reduce power for a sketch that doesn't need WiFi, add these SDK 2 functions anywhere in your code: ```c wifi_station_disconnect(); wifi_set_opmode(NULL_MODE); @@ -101,7 +102,7 @@ If all you want to do is reduce power for a sketch that doesn't need WiFi, add t wifi_fpm_do_sleep(0xFFFFFFF); delay(1); ``` -That allows you to shut down the modem *without* loading the WiFi library, dropping your average current by 50 mA, or around 1/5th of the initial power. You have to add it as shown preferably in setup(), although the delay() can be longer. It doesn't time out at 71 minutes, as you might think from the (0xFFFFFFF). The Forced Modem Sleep test does the same thing with a WiFi library call that essentially encapsulates the code above. +That allows you to shut down the modem *without* loading the WiFi library, dropping your average current by 50 mA, or around 1/5th of the initial power. You have to add it as shown (preferably in setup()), although the delay() can be longer. It doesn't time out at 71 minutes, as you might think from the (0xFFFFFFF). The Forced Modem Sleep test does the same thing with a WiFi library call that essentially encapsulates the code above. -You can also use the Deep Sleep modes without loading the WiFi library, as they use ESP API functions. The tests above try to bring the WiFi up to show you the differences after the 4 reset modes. +You can also use the Deep Sleep modes without loading the WiFi library, as they use ESP API functions. The Deep Sleep tests above try to bring the WiFi up to show you the differences after the 4 reset modes. With the WiFi turned off you always get an instant Deep Sleep. From 47b73a2ccda37541563f440190c1beb81c46b800 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Sat, 11 Jan 2020 07:23:49 -0600 Subject: [PATCH 13/51] add Low-Power demo --- .../esp8266/examples/LowPowerDemo/README.md | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md index c7e011b768..e6d17217c5 100644 --- a/libraries/esp8266/examples/LowPowerDemo/README.md +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -22,9 +22,9 @@ The table below is an expanded version of Table 1.1 from the Low-Power Solutions Notes: -(1) setting a sleep time of 0 for Deep Sleep turns off the RTC, requiring an external RESET to wake it +(1) setting a sleep time of 0 for Deep Sleep turns off or disconnects the RTC, requiring an external RESET to wake it -(2) due to a bug in SDK 2, the minimum current will never be less than 2 mA and is frequently 15 mA between DTIM beacons +(2) due to a bug in SDK 2, the minimum current will never be less than ~ 2 mA and is frequently 15 mA between DTIM beacons The Average Current with different DTIM settings is unverified, and will likely be higher in a real-world environment. All of the currents listed in this README are for the ESP8266 chip only. Modules that have voltage regulators, USB chips, LEDs or other hardware will draw additional current. @@ -46,11 +46,11 @@ The Average Current with different DTIM settings is unverified, and will likely ### Test 1 - Unconfigured modem -This is typical for programs that don't use WiFi, and is a high current drain of at least 67 mA continuous. This isn't a test as much as it sets a baseline or reference point for comparing the power savings. You can stop any time the CPU is halted or the LED is blinking to measure the current. +This is typical for programs that don't use WiFi, and is a high current drain of at least 67 mA continuous. This isn't a test as much as it sets a baseline or reference point for comparing the power savings. You can stop any time the CPU is halted or the LED is blinking during the tests to measure the current. ### Test 2 - Automatic Modem Sleep -This is the default power saving mode when you have an active WiFi connection. You don't need to add anything to your code to get it. The only time the modem sleeps is when you spend a long time in delay(), with delay times over 50mS. The LED blinks more slowly during this test as it's doing delay(350) to get the modem to sleep. While in delay() your sketch isn't doing anything worthwhile. Average current during a long delay() is 15 mA minimum. Without the delay() the average current is 67 mA with short spikes above 250 mA as transmissions occur. When the WiFi has traffic (even a couple of pings), the modem can turn on for over 2 seconds continuous at 67 mA, and it may stay on for a second after the traffic. In a high traffic environment you won't get any power savings with either of the 2 Automatic modes. Automatic Modem Sleep turns on 7-8 seconds after an active connection is established. +This is the default power saving mode when you have an active WiFi connection. You don't need to add anything to your code to get it. The only time the modem sleeps is when your program spends time in delay() frequently. Any delay() time works as long as it happens frequently. The LED blinks more slowly during this test as it's doing **delay(350)** to get the modem to sleep. While in delay() your sketch isn't doing anything worthwhile. Average current during Automatic Modem Sleep is 15 mA minimum. Without a delay() the average current is 67 mA with short spikes above 250 mA as transmissions occur. When the WiFi has traffic (even a couple of pings), the modem can turn on for over 2 seconds continuous at 67 mA, and it may stay on for a second after the traffic. In a high traffic environment you won't get any power savings with either of the 2 Automatic modes. Automatic Modem Sleep turns on 7-8 seconds after an active connection is established. ### Test 3 - Forced Modem Sleep @@ -58,40 +58,40 @@ Turns off the modem (losing the connection), and reducing the current by 50 mA. ### Test 4 - Automatic Light Sleep -Like Automatic Modem Sleep, with the same restrictions. Once configured it's immediately active when a connection is established. During periods of long delay() the average current can drop to ~2 mA. In a network with sparse traffic you might get something near 2-5 mA average current. The LED blinks more slowly during this test as it's doing delay(350) to get the modem to sleep. +Like Automatic Modem Sleep, with similar restrictions. Once configured it's immediately active when a connection is established. During periods of long delay() the average current can drop to ~ 2 mA. In a network with sparse traffic you might get something near 2-5 mA average current. The LED blinks more slowly during this test as it's doing delay(350) to get the modem to sleep. With delay() times shorter than the DTIM beacon interval (100 mS for these tests) the modem only goes into Automatic Modem Sleep, and with a longer delay() it will go into Automatic Light Sleep. ### Test 5 - Forced Light Sleep -Similar to Deep Sleep, but without the timer. The chip sleeps at 0.4 mA current until it is woken by an external interrupt. The only allowed interrupts are high level and low level; edge interrupts won't work. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using Forced Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more efficient. The chip wakes after an interrupt in about 5.1 mS, but WiFi was turned off to enter Forced Light Sleep so you may need to re-initialize it. +Similar to Deep Sleep, but without the timer. The chip sleeps at 0.4 mA current until it is woken by an external interrupt. The only allowed interrupts are high level and low level; edge interrupts won't work. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using Forced Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 5.1 mS, but WiFi was turned off to enter Forced Light Sleep so you will need to re-initialize it if you are using WiFi. ### Test 6 - Deep Sleep, wake with RF_DEFAULT -In Deep Sleep almost everything is turned off, and the chip draws ~ 20 uA. If you have D0/GPIO16 connected to RST, you can use the RTC timer to wake the chip up at a timed interval. You can also wake it with an external RESET. Waking with RF_DEFAULT means it will do an RFCAL if it needs to. Doing ESP.deepSleep(time) without the mode variable uses this wake mode. These first two Deep Sleep tests use the standard Deep Sleep function, so the WiFi connection is closed and the modem turned off, which takes about 270 mS before the Deep Sleep will begin. Deep Sleep ends with a RESET, and the boot time after that is ~ 120 mS. Any Deep Sleep less than ~ 2 seconds is wasting power due to the modem shut-off and boot time, and Forced Light Sleep will be a better choice as it recovers in 5.1 mS from the previous state. +In Deep Sleep almost everything is turned off, and the chip draws ~ 20 uA. If you have D0/GPIO16 connected to RST, you can use the RTC timer to wake the chip up at a timed interval. You can also wake it with an external RESET. Waking with RF_DEFAULT means it will do an RFCAL if it needs to. Doing **ESP.deepSleep(time)** without the mode variable uses this wake mode. These first two Deep Sleep tests use the standard Deep Sleep function, so the WiFi connection is closed and the modem turned off, which takes about 270 mS before the Deep Sleep begins. Deep Sleep ends with a RESET, and the boot time after that is ~ 120 mS. Any Deep Sleep less than ~ 2 seconds is wasting energy due to the modem shut-off and boot times, and Forced Light Sleep will be a better choice as it recovers in 5.1 mS from the previous state. ### Test 7 - Deep Sleep, wake with RFCAL -Identical to the test above, but the modem does an RF power calibration when booting. In normal use, most people would do WAKE_RF_DEFAULT instead to minimize the extra RFCAL power burst if it's not needed. +Identical to the test above, but the modem does an RF power calibration when booting. In normal use, most people would do WAKE_RF_DEFAULT instead to avoid the extra RFCAL power burst if it's not needed. ### Test 8 - Deep Sleep Instant, wake with NO_RFCAL -This variation doesn't do an automatic RF calibration on return, so power requirements will be slightly less. Additionally, *most* of the time it immediately goes into Deep Sleep without turning off the modem (that's the INSTANT part). There's another bug in SDK 2, and the SDK functions the WiFi-class calls occasionally do a modem shut-down before Deep Sleep; it's not always Instant. When it doesn't do the modem shut-down it saves an extra 270mS of power. +This variation doesn't do an automatic RF calibration on return, so power requirements will be slightly less. Additionally, *most* of the time it immediately goes into Deep Sleep without turning off the modem (that's the INSTANT part). There's another bug in SDK 2, and the SDK functions the WiFi-class calls occasionally do a modem shut-down before Deep Sleep; it's not always Instant. When it doesn't do the modem shut-down it saves an extra 270 mS of power. ### Test 9 - Deep Sleep Instant, wake with RF_DISABLED -This last variation also uses Deep Sleep Instant, but it wakes up with the modem disabled so current after Deep Sleep is only 15 mA. Each of the 4 WAKE styles has their own use, depending on what you need. +This last variation also uses Deep Sleep Instant, but it wakes up with the modem disabled so current after Deep Sleep is only 15 mA. Each of the 4 WAKE modes has their own use, depending on what you need. --- -All of the Deep Sleep modes end with a RESET, so you must re-initialize everything. You can store *some* information in the RTC memory to survive a Deep Sleep reset, which was done in this demo to illustrate the RTC memory. See the **RTCUserMemory** example for more information on this feature. +All of the Deep Sleep modes end with a RESET, so you must re-initialize everything. You can store *some* information in the RTC memory to survive a Deep Sleep reset, which was done in this demo to illustrate the RTC memory. See the **RTCUserMemory** example for more information on this feature. -The maximum Deep Sleep interval is 71.58 minutes (2^32 -1 microseconds), although the actual interval may be something less than that. +The maximum Deep Sleep interval is 71.58 minutes (2^32 -1 microseconds), although the actual interval may be slightly less than that. -If you need a longer sleep period than 72 minutes, you can pass zero as the time variable to Deep Sleep and it turns off the RTC. The only way to wake it at that point is an external RESET; D0 can't do it. Both Forced Light Sleep and Deep Sleep(0) are woken by an external signal, so short delays under 2 seconds are more efficient with Forced Light Sleep, and longer delays are more power efficient with Deep Sleep. +If you need a longer sleep time than 72 minutes, you can pass zero as the time variable to Deep Sleep and it turns off the RTC. The only way to wake it at that point is an external RESET; D0 can't do it. Both Forced Light Sleep and Deep Sleep(0) are woken by an external signal, so short delays are more efficient with Forced Light Sleep, and longer delays are more energy efficient with Deep Sleep. --- -### Lower Power without the WiFi library: +### Lower Power without the WiFi library (Forced Modem Sleep): If all you want to do is reduce power for a sketch that doesn't need WiFi, add these SDK 2 functions anywhere in your code: ```c @@ -102,7 +102,7 @@ If all you want to do is reduce power for a sketch that doesn't need WiFi, add t wifi_fpm_do_sleep(0xFFFFFFF); delay(1); ``` -That allows you to shut down the modem *without* loading the WiFi library, dropping your average current by 50 mA, or around 1/5th of the initial power. You have to add it as shown (preferably in setup()), although the delay() can be longer. It doesn't time out at 71 minutes, as you might think from the (0xFFFFFFF). The Forced Modem Sleep test does the same thing with a WiFi library call that essentially encapsulates the code above. +That allows code you to shut down the modem *without* loading the WiFi library, dropping your average current by 50 mA, or ~ 1/5th of the initial power. You have to add it as shown (preferably in **setup()** or **preinit()**), although the delay() can be longer. It doesn't time out at 71 minutes, as you might think from the (0xFFFFFFF). The Forced Modem Sleep test does the same thing with a WiFi library call that essentially encapsulates the code above. -You can also use the Deep Sleep modes without loading the WiFi library, as they use ESP API functions. The Deep Sleep tests above try to bring the WiFi up to show you the differences after the 4 reset modes. With the WiFi turned off you always get an instant Deep Sleep. +You can also use the Deep Sleep modes without loading the WiFi library, as they use ESP API functions. The Deep Sleep tests above bring the WiFi up to show you the differences after the 4 reset modes. With the modem turned off (Forced Modem Sleep) you **always** get an instant Deep Sleep; doing WiFi.mode(WIFI_OFF) doesn't help, as the SDK still spends 270 mS of time shutting the modem down before going into Deep Sleep. From 36a8dbb8f32c4e0377a27be359fb6e7149c92870 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Sat, 11 Jan 2020 17:12:46 -0600 Subject: [PATCH 14/51] add Low-Power demo --- .../examples/LowPowerDemo/LowPowerDemo.ino | 8 +++++--- .../esp8266/examples/LowPowerDemo/README.md | 19 ++++++++++--------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index 10b563fce1..2c0b7bb5fc 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -66,7 +66,7 @@ IPAddress gateway(0, 0, 0, 0); IPAddress subnet(0, 0, 0, 0); IPAddress dns1(0, 0, 0, 0); IPAddress dns2(0, 0, 0, 0); -uint32_t wifiTimeout = 30E3; // 30 second timeout on the WiFi connection +uint32_t wifiTimeout = 10E3; // 10 second timeout on the WiFi connection // This structure will be stored in RTC memory to remember the reset count (number of Deep Sleeps). // First field is CRC32, which is calculated based on the rest of the structure contents. @@ -139,11 +139,13 @@ void loop() { // 3rd test - Forced Modem Sleep Serial.println(F("\n3rd test - Forced Modem Sleep")); WiFi.forceSleepBegin(); - delay(10); // it doesn't always go to sleep unless you delay(10), yield() may also work + delay(10); // it doesn't always go to sleep unless you delay(10); yield() wasn't reliable + Serial.println(F("Doing a 10 second delay() to show the lowest possible current")); + delay(10E3); volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("press the button to continue")); - waitPushbutton(false, blinkDelay); + waitPushbutton(true, longDelay); // 4th test - Automatic Light Sleep Serial.println(F("\n4th test - Automatic Light Sleep")); diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md index e6d17217c5..f192797dd6 100644 --- a/libraries/esp8266/examples/LowPowerDemo/README.md +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -54,7 +54,7 @@ This is the default power saving mode when you have an active WiFi connection. ### Test 3 - Forced Modem Sleep -Turns off the modem (losing the connection), and reducing the current by 50 mA. This test uses the WiFi library function. It's good if there is a long interval with no expected WiFi traffic, as you can do other things while only drawing 15 mA. +Turns off the modem (losing the connection), and reducing the current by > 47 mA. This test uses the WiFi library function. It's good if there is a long interval with no expected WiFi traffic, as you can do other things while only drawing 15 to 20 mA. The longer you spend in delay(), the closer the current approaches 15 mA. The test loops on delay(350) until you press the button. The CPU will be drawing 15 to 16 mA during the looped delay(). ### Test 4 - Automatic Light Sleep @@ -93,16 +93,17 @@ If you need a longer sleep time than 72 minutes, you can pass zero as the time v ### Lower Power without the WiFi library (Forced Modem Sleep): -If all you want to do is reduce power for a sketch that doesn't need WiFi, add these SDK 2 functions anywhere in your code: +If all you want to do is reduce power for a sketch that doesn't need WiFi, add these SDK 2 functions to your code: ```c - wifi_station_disconnect(); - wifi_set_opmode(NULL_MODE); - wifi_fpm_set_sleep_type(MODEM_SLEEP_T); - wifi_fpm_open(); - wifi_fpm_do_sleep(0xFFFFFFF); - delay(1); + wifi_station_disconnect(); // disconnects Wi-Fi Station from AP + delay(10); // without at least delay(8) you might get soft WDT resets after this + wifi_set_opmode_current(NULL_MODE); // set Wi-Fi working mode to unconfigured, don't save to flash + wifi_fpm_set_sleep_type(MODEM_SLEEP_T); // set the sleep type to modem sleep + wifi_fpm_open(); // enable Forced Modem Sleep + wifi_fpm_do_sleep(0xFFFFFFF); // force CPU to enter sleep mode + delay(10); // without a delay() here it doesn't reliably enter sleep ``` -That allows code you to shut down the modem *without* loading the WiFi library, dropping your average current by 50 mA, or ~ 1/5th of the initial power. You have to add it as shown (preferably in **setup()** or **preinit()**), although the delay() can be longer. It doesn't time out at 71 minutes, as you might think from the (0xFFFFFFF). The Forced Modem Sleep test does the same thing with a WiFi library call that essentially encapsulates the code above. +This code allows you to shut down the modem *without* loading the WiFi library, dropping your average current by > 47 mA, or ~ 1/3rd of the initial power. You have to add it as shown, preferably in **setup()**. It doesn't time out at 71 minutes, as you might think from the (0xFFFFFFF). The Forced Modem Sleep test does the same thing with a WiFi library call that encapsulates something similar to the code above. You can also use the Deep Sleep modes without loading the WiFi library, as they use ESP API functions. The Deep Sleep tests above bring the WiFi up to show you the differences after the 4 reset modes. With the modem turned off (Forced Modem Sleep) you **always** get an instant Deep Sleep; doing WiFi.mode(WIFI_OFF) doesn't help, as the SDK still spends 270 mS of time shutting the modem down before going into Deep Sleep. From 5d16fcac78df243a802eb77404b8731013957856 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Sat, 11 Jan 2020 18:28:36 -0600 Subject: [PATCH 15/51] add Low-Power demo --- .../examples/LowPowerDemo/LowPowerDemo.ino | 4 +--- .../esp8266/examples/LowPowerDemo/README.md | 16 ++++++++-------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index 2c0b7bb5fc..77d701191f 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -111,7 +111,7 @@ void setup() { resetCount = rtcData.data[3]; // read the previous reset count } } -} // end of Setup() +} // end of setup() void loop() { if (resetCount == 0) { @@ -140,8 +140,6 @@ void loop() { Serial.println(F("\n3rd test - Forced Modem Sleep")); WiFi.forceSleepBegin(); delay(10); // it doesn't always go to sleep unless you delay(10); yield() wasn't reliable - Serial.println(F("Doing a 10 second delay() to show the lowest possible current")); - delay(10E3); volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("press the button to continue")); diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md index f192797dd6..2c63bbbb47 100644 --- a/libraries/esp8266/examples/LowPowerDemo/README.md +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -46,19 +46,19 @@ The Average Current with different DTIM settings is unverified, and will likely ### Test 1 - Unconfigured modem -This is typical for programs that don't use WiFi, and is a high current drain of at least 67 mA continuous. This isn't a test as much as it sets a baseline or reference point for comparing the power savings. You can stop any time the CPU is halted or the LED is blinking during the tests to measure the current. +This is typical for programs that don't use WiFi, and is a high current continuous drain of at least 67 mA. This isn't a test as much as setting a baseline or reference point for comparing the power savings. You can stop during any test while the CPU is halted or the LED is blinking to measure the current. ### Test 2 - Automatic Modem Sleep -This is the default power saving mode when you have an active WiFi connection. You don't need to add anything to your code to get it. The only time the modem sleeps is when your program spends time in delay() frequently. Any delay() time works as long as it happens frequently. The LED blinks more slowly during this test as it's doing **delay(350)** to get the modem to sleep. While in delay() your sketch isn't doing anything worthwhile. Average current during Automatic Modem Sleep is 15 mA minimum. Without a delay() the average current is 67 mA with short spikes above 250 mA as transmissions occur. When the WiFi has traffic (even a couple of pings), the modem can turn on for over 2 seconds continuous at 67 mA, and it may stay on for a second after the traffic. In a high traffic environment you won't get any power savings with either of the 2 Automatic modes. Automatic Modem Sleep turns on 7-8 seconds after an active connection is established. +This is the default power saving mode when you have an active WiFi connection. You don't need to add anything to your code to get this mode. The only time the modem sleeps is when your program spends time in delay() frequently. Any delay() time works as long as it happens frequently. The LED blinks more slowly during this test as it's doing **delay(350)** to get the modem to sleep. While in delay() your sketch isn't doing anything worthwhile. Average current during Automatic Modem Sleep is 15 mA minimum. Without a delay() the average current > 67 mA with short spikes > 250-350 mA as transmissions occur. When the WiFi has traffic (even a couple of pings), the modem can turn on for over 2 seconds continuous at 67 mA, and it may stay on for a second after the traffic. In a high traffic environment you won't get any power savings with either of the 2 Automatic modes. Automatic Modem Sleep turns on 7-8 seconds after an active connection is established. ### Test 3 - Forced Modem Sleep -Turns off the modem (losing the connection), and reducing the current by > 47 mA. This test uses the WiFi library function. It's good if there is a long interval with no expected WiFi traffic, as you can do other things while only drawing 15 to 20 mA. The longer you spend in delay(), the closer the current approaches 15 mA. The test loops on delay(350) until you press the button. The CPU will be drawing 15 to 16 mA during the looped delay(). +Turns off the modem (losing the connection), and reducing the current by 50 mA. This test uses the WiFi library function. It's good if there is a long interval with no expected WiFi traffic, as you can do other things while only drawing 15 to 20 mA. The longer you spend in delay(), the closer the current approaches 15 mA. The test loops on delay(350) until you press the button. The CPU will be drawing 15 to 16 mA during the looped delay(). ### Test 4 - Automatic Light Sleep -Like Automatic Modem Sleep, with similar restrictions. Once configured it's immediately active when a connection is established. During periods of long delay() the average current can drop to ~ 2 mA. In a network with sparse traffic you might get something near 2-5 mA average current. The LED blinks more slowly during this test as it's doing delay(350) to get the modem to sleep. With delay() times shorter than the DTIM beacon interval (100 mS for these tests) the modem only goes into Automatic Modem Sleep, and with a longer delay() it will go into Automatic Light Sleep. +Like Automatic Modem Sleep, with similar restrictions. Once configured it's immediately active when a connection is established. During periods of long delay() the average current can drop to ~ 2 mA average. In a network with sparse traffic you might get something near 2-5 mA average current. The LED blinks more slowly during this test as it's doing delay(350) to get the modem to sleep. With delay() times shorter than the DTIM beacon interval (100 mS beacons for these tests) the modem only goes into Automatic Modem Sleep, and with a longer delay() it will go into Automatic Light Sleep. ### Test 5 - Forced Light Sleep @@ -74,7 +74,7 @@ Identical to the test above, but the modem does an RF power calibration when boo ### Test 8 - Deep Sleep Instant, wake with NO_RFCAL -This variation doesn't do an automatic RF calibration on return, so power requirements will be slightly less. Additionally, *most* of the time it immediately goes into Deep Sleep without turning off the modem (that's the INSTANT part). There's another bug in SDK 2, and the SDK functions the WiFi-class calls occasionally do a modem shut-down before Deep Sleep; it's not always Instant. When it doesn't do the modem shut-down it saves an extra 270 mS of power. +This variation doesn't do an automatic RF calibration on return, so power requirements will be slightly less. Additionally, *most* of the time it immediately goes into Deep Sleep without turning off the modem (that's the INSTANT part). There's another bug in SDK 2, and the SDK functions the WiFi-class calls occasionally do a modem shut-down before Deep Sleep; it's not always Instant. When it doesn't do the modem shut-down it saves an extra 270 mS of power. With the modem turned off (Forced Modem Sleep) you **always** get an instant Deep Sleep; doing WiFi.mode(WIFI_OFF) doesn't help, as the SDK still spends 270 mS of time shutting the modem down before going into Deep Sleep. ### Test 9 - Deep Sleep Instant, wake with RF_DISABLED @@ -86,7 +86,7 @@ All of the Deep Sleep modes end with a RESET, so you must re-initialize everythi The maximum Deep Sleep interval is 71.58 minutes (2^32 -1 microseconds), although the actual interval may be slightly less than that. -If you need a longer sleep time than 72 minutes, you can pass zero as the time variable to Deep Sleep and it turns off the RTC. The only way to wake it at that point is an external RESET; D0 can't do it. Both Forced Light Sleep and Deep Sleep(0) are woken by an external signal, so short delays are more efficient with Forced Light Sleep, and longer delays are more energy efficient with Deep Sleep. +If you need a longer sleep time than 72 minutes, you can pass zero as the time variable to Deep Sleep and it turns off or disconnects the RTC. The only way to wake it at that point is an external RESET; D0 can't do it. Both Forced Light Sleep and Deep Sleep(0) are woken by an external signal, so short delays are more efficient with Forced Light Sleep, and longer delays are more energy efficient with Deep Sleep. --- @@ -103,7 +103,7 @@ If all you want to do is reduce power for a sketch that doesn't need WiFi, add t wifi_fpm_do_sleep(0xFFFFFFF); // force CPU to enter sleep mode delay(10); // without a delay() here it doesn't reliably enter sleep ``` -This code allows you to shut down the modem *without* loading the WiFi library, dropping your average current by > 47 mA, or ~ 1/3rd of the initial power. You have to add it as shown, preferably in **setup()**. It doesn't time out at 71 minutes, as you might think from the (0xFFFFFFF). The Forced Modem Sleep test does the same thing with a WiFi library call that encapsulates something similar to the code above. +This code allows you to shut down the modem *without* loading the WiFi library, dropping your average current by 50 mA, or ~ 1/4th of the initial power. You have to add it as shown, preferably in **setup()**. It doesn't time out at 71 minutes, as you might think from the (0xFFFFFFF). The Forced Modem Sleep test does the same thing with a WiFi library call that encapsulates something similar to the code above. -You can also use the Deep Sleep modes without loading the WiFi library, as they use ESP API functions. The Deep Sleep tests above bring the WiFi up to show you the differences after the 4 reset modes. With the modem turned off (Forced Modem Sleep) you **always** get an instant Deep Sleep; doing WiFi.mode(WIFI_OFF) doesn't help, as the SDK still spends 270 mS of time shutting the modem down before going into Deep Sleep. +You can also use the Deep Sleep modes without loading the WiFi library, as Deep Sleep use ESP API functions. The Deep Sleep tests above turn the WiFi on to show you the differences after the 4 reset modes. From aa4feb234878535398e88e0abd56376cc7a7bf5d Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Sat, 11 Jan 2020 20:12:07 -0600 Subject: [PATCH 16/51] add Low-Power demo --- .../examples/LowPowerDemo/LowPowerDemo.ino | 16 ++++++++-------- .../esp8266/examples/LowPowerDemo/README.md | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index 77d701191f..216bc5e179 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -66,7 +66,7 @@ IPAddress gateway(0, 0, 0, 0); IPAddress subnet(0, 0, 0, 0); IPAddress dns1(0, 0, 0, 0); IPAddress dns2(0, 0, 0, 0); -uint32_t wifiTimeout = 10E3; // 10 second timeout on the WiFi connection +uint32_t wifiTimeout = 25E3; // 25 second timeout on the WiFi connection // This structure will be stored in RTC memory to remember the reset count (number of Deep Sleeps). // First field is CRC32, which is calculated based on the rest of the structure contents. @@ -91,13 +91,13 @@ void wakeupCallback() { // unlike ISRs, you can do a print() from a callback fu void setup() { pinMode(LED, OUTPUT); // Activity and Status indicator digitalWrite(LED, LOW); // turn on the LED - pinMode(WAKE_UP_PIN, INPUT_PULLUP); // polled to advance tests, INTR for Forced Light Sleep + pinMode(WAKE_UP_PIN, INPUT_PULLUP); // polled to advance tests, interrupt for Forced Light Sleep Serial.begin(115200); Serial.print(F("\nReset reason = ")); String resetCause = ESP.getResetReason(); Serial.println(resetCause); - if (resetCause == "External System") { - Serial.println(F("I'm awake and starting the low power tests")); + if ((resetCause == "External System") || (resetCause == "Power on")) { + Serial.println(F("I'm awake and starting the Low Power tests")); resetCount = 5; updateRTC(); // if external reset, wipe the RTC memory and start all over } @@ -195,7 +195,7 @@ void loop() { delay(10); } delay(50); // debounce time for the switch, button released - waitPushbutton(false, blinkDelay); + waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep digitalWrite(LED, LOW); // turn the LED on, at least briefly Serial.println(F("going into Deep Sleep now...")); delay(10); // sometimes the \n isn't printed without a short delay @@ -219,7 +219,7 @@ void loop() { float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("press the button to continue")); - waitPushbutton(false, blinkDelay); + waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep Serial.println(F("going into Deep Sleep now...")); delay(10); // sometimes the \n isn't printed without a short delay ESP.deepSleep(10E6, WAKE_RFCAL); // good night! D0 fires a reset in 10 seconds... @@ -235,7 +235,7 @@ void loop() { float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("press the button to continue")); - waitPushbutton(false, blinkDelay); + waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep Serial.println(F("going into Deep Sleep now...")); delay(10); // sometimes the \n isn't printed without a short delay ESP.deepSleepInstant(10E6, WAKE_NO_RFCAL); // good night! D0 fires a reset in 10 seconds... @@ -251,7 +251,7 @@ void loop() { float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("press the button to continue")); - waitPushbutton(false, blinkDelay); + waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep Serial.println(F("going into Deep Sleep now...")); delay(10); // sometimes the \n isn't printed without a short delay ESP.deepSleepInstant(10E6, WAKE_RF_DISABLED); // good night! D0 fires a reset in 10 seconds... diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md index 2c63bbbb47..443865322d 100644 --- a/libraries/esp8266/examples/LowPowerDemo/README.md +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -26,7 +26,7 @@ Notes: (2) due to a bug in SDK 2, the minimum current will never be less than ~ 2 mA and is frequently 15 mA between DTIM beacons -The Average Current with different DTIM settings is unverified, and will likely be higher in a real-world environment. All of the currents listed in this README are for the ESP8266 chip only. Modules that have voltage regulators, USB chips, LEDs or other hardware will draw additional current. +The Average Current with different DTIM settings is unverified, and will likely be higher in a real-world environment. All of the currents listed in this README are for the ESP8266 chip only, compiled for 80 MHz CPU Frequency as 160 MHz uses even more current. Modules that have voltage regulators, USB chips, LEDs or other hardware will draw additional current. --- @@ -66,7 +66,7 @@ Similar to Deep Sleep, but without the timer. The chip sleeps at 0.4 mA current ### Test 6 - Deep Sleep, wake with RF_DEFAULT -In Deep Sleep almost everything is turned off, and the chip draws ~ 20 uA. If you have D0/GPIO16 connected to RST, you can use the RTC timer to wake the chip up at a timed interval. You can also wake it with an external RESET. Waking with RF_DEFAULT means it will do an RFCAL if it needs to. Doing **ESP.deepSleep(time)** without the mode variable uses this wake mode. These first two Deep Sleep tests use the standard Deep Sleep function, so the WiFi connection is closed and the modem turned off, which takes about 270 mS before the Deep Sleep begins. Deep Sleep ends with a RESET, and the boot time after that is ~ 120 mS. Any Deep Sleep less than ~ 2 seconds is wasting energy due to the modem shut-off and boot times, and Forced Light Sleep will be a better choice as it recovers in 5.1 mS from the previous state. +In Deep Sleep almost everything is turned off, and the chip draws ~ 20 uA. If you have D0/GPIO16 connected to RST, you can use the RTC timer to wake the chip up at a timed interval. You can also wake it with an external RESET. Waking with RF_DEFAULT means it will do an RFCAL if it needs to. Doing **ESP.deepSleep(time)** without the mode variable uses this wake mode. These first two Deep Sleep tests use the standard Deep Sleep function, so the WiFi connection is closed and the modem turned off, which takes about 270 mS before the Deep Sleep begins. Deep Sleep ends with a RESET, and the boot time after that is ~ 120 mS. Any Deep Sleep less than ~ 2 seconds is wasting energy due to the modem shut-off and boot times, and Forced Light Sleep will be a better choice as it recovers in 5.1 mS from the previous state. The Deep Sleep tests will not go into Automatic Modem Sleep because delay() is not used. ### Test 7 - Deep Sleep, wake with RFCAL From 8f4448de9adfb54494ae5a4a481c652e4d63c452 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Sat, 11 Jan 2020 20:25:44 -0600 Subject: [PATCH 17/51] add Low-Power demo --- libraries/esp8266/examples/LowPowerDemo/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md index 443865322d..ae799decb8 100644 --- a/libraries/esp8266/examples/LowPowerDemo/README.md +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -50,11 +50,11 @@ This is typical for programs that don't use WiFi, and is a high current continuo ### Test 2 - Automatic Modem Sleep -This is the default power saving mode when you have an active WiFi connection. You don't need to add anything to your code to get this mode. The only time the modem sleeps is when your program spends time in delay() frequently. Any delay() time works as long as it happens frequently. The LED blinks more slowly during this test as it's doing **delay(350)** to get the modem to sleep. While in delay() your sketch isn't doing anything worthwhile. Average current during Automatic Modem Sleep is 15 mA minimum. Without a delay() the average current > 67 mA with short spikes > 250-350 mA as transmissions occur. When the WiFi has traffic (even a couple of pings), the modem can turn on for over 2 seconds continuous at 67 mA, and it may stay on for a second after the traffic. In a high traffic environment you won't get any power savings with either of the 2 Automatic modes. Automatic Modem Sleep turns on 7-8 seconds after an active connection is established. +This is the default power saving mode when you have an active WiFi connection. You don't need to add anything to your code to get this mode. The only time the modem sleeps is when your program spends time in delay() frequently. Any delay() time works as long as it happens frequently. The LED blinks more slowly during this test as it's doing **delay(350)** to get the modem to sleep. While in delay() your sketch isn't doing anything worthwhile. Average current during Automatic Modem Sleep is 15 mA minimum. Without a delay() the average current is > 67 mA with brief spikes > 250-350 mA as transmissions occur. When the WiFi has traffic (even a couple of pings), the modem can turn on for over 2 seconds continuous at 67 mA, and it may stay on for a second after the traffic. In a high traffic environment you won't get any power savings with either of the 2 Automatic modes. Automatic Modem Sleep turns on 7-8 seconds after an active connection is established. ### Test 3 - Forced Modem Sleep -Turns off the modem (losing the connection), and reducing the current by 50 mA. This test uses the WiFi library function. It's good if there is a long interval with no expected WiFi traffic, as you can do other things while only drawing 15 to 20 mA. The longer you spend in delay(), the closer the current approaches 15 mA. The test loops on delay(350) until you press the button. The CPU will be drawing 15 to 16 mA during the looped delay(). +Turns off the modem (losing the connection), and reducing the current by > 50 mA. This test uses the WiFi library function. It's good if there is a long interval with no expected WiFi traffic, as you can do other things while only drawing 15 to 20 mA. The longer you spend in delay(), the closer the current approaches 15 mA. The test loops on delay(350) until you press the button. The CPU will be drawing 15 to 16 mA during the looped delay(), and 19-20 mA without a delay(). ### Test 4 - Automatic Light Sleep From b8e42e4e1a1602f74df36e9673800aef16c853e6 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Sat, 11 Jan 2020 21:41:42 -0600 Subject: [PATCH 18/51] add Low-Power demo --- .../examples/LowPowerDemo/LowPowerDemo.ino | 16 ++++----- .../esp8266/examples/LowPowerDemo/README.md | 36 +++++++++---------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index 216bc5e179..8c26cd3307 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -2,10 +2,10 @@ The initial setup was a WeMos D1 Mini with 3.3V connected to the 3V3 pin through a meter so that it bypassed the on-board voltage regulator and USB chip. There's still about - 0.3 mA worth of leakage current due to the unpowered chips. These tests should work with + 0.3 mA worth of leakage amperage due to the unpowered chips. These tests should work with any module, although on-board components will affect the actual current measurement. - While the modem is turned on the current is > 67 mA or jumping around with a minimum value. - To verify the 20 uA Deep Sleep current the voltage regulator and USB chip were removed. + While the modem is turned on the amperage is > 67 mA or jumping around with a minimum value. + To verify the 20 uA Deep Sleep amperage the voltage regulator and USB chip were removed. This test series requires an active WiFi connection to illustrate two tests. If you have problems with WiFi, uncomment the #ifdef DEBUG for additional WiFi error messages. @@ -13,7 +13,7 @@ You'll also need to connect D0/GPIO16 to RST for the Deep Sleep tests. If you forget to connect D0 to RST it will hang after the first Deep Sleep test. Additionally, you can connect an LED from any free pin through a 1K ohm resistor to the 3.3V supply, though - preferably not the 3V3 pin on the module or it adds to the measured current. When the + preferably not the 3V3 pin on the module or it adds to the measured amperage. When the LED blinks you can proceed to the next test. When the LED is lit continuously it's connecting WiFi, and when it's off the CPU is asleep. The LED blinks slowly when the tests are complete. Test progress is also shown on the serial monitor. @@ -51,9 +51,9 @@ // you can use any pin for WAKE_UP_PIN except for D0/GPIO16 as it doesn't support interrupts // uncomment one of the two lines below for your LED connection, if used -#define LED 5 // D1/GPIO5 external LED for modules with built-in LEDs so it doesn't add to the current +#define LED 5 // D1/GPIO5 external LED for modules with built-in LEDs so it doesn't add to the amperage //#define LED 2 // D4/GPIO2 LED for ESP-01,07 modules; D4 is LED_BUILTIN on most other modules -// you can use LED_BUILTIN, but it adds to the measured current by 0.3mA to 6mA. +// you can use LED_BUILTIN, but it adds to the measured amperage by 0.3mA to 6mA. ADC_MODE(ADC_VCC); // allows you to monitor the internal VCC level; it varies with WiFi load // don't connect anything to the analog input pin(s)! @@ -127,7 +127,7 @@ void loop() { Serial.println(F("connecting WiFi, please wait until the LED blinks")); init_WiFi(); if (WiFi.localIP()) { // won't go into Automatic Sleep without an active WiFi connection - Serial.println(F("The current will drop in 7 seconds.")); + Serial.println(F("The amperage will drop in 7 seconds.")); volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("press the button to continue")); @@ -203,7 +203,7 @@ void loop() { delay(10); // if you do ESP.deepSleep(0, mode); it needs a RESET to come out of sleep (RTC is off) // maximum timed Deep Sleep interval = 71.58 minutes with 0xFFFFFFFF - // the 2 uA GPIO current during Deep Sleep can't drive the LED so it's not lit now, although + // the 2 uA GPIO amperage during Deep Sleep can't drive the LED so it's not lit now, although // depending on the LED used, you might see it very dimly lit in a dark room during this test Serial.println(F("What... I'm not asleep?!?")); // it will never get here } diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md index ae799decb8..f9ef4bcbbf 100644 --- a/libraries/esp8266/examples/LowPowerDemo/README.md +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -5,28 +5,28 @@ There is a lot of confusion, out-of-date information, and poor or non-working ex The two relevant reference manuals from Espressif are the [Low-Power Solutions](https://www.espressif.com/sites/default/files/documentation/9b-esp8266-low_power_solutions__en.pdf) and the [Non-OS SDK API Reference](https://www.espressif.com/sites/default/files/documentation/2c-esp8266_non_os_sdk_api_reference_en.pdf). There is more information in the two PDFs than is presented here, so you'll want both of them for your reference. -The table below is an expanded version of Table 1.1 from the Low-Power Solutions PDF. The currents listed are absolute minimums, and most people will not get that low with typical hardware and programs. +The table below is an expanded version of Table 1.1 from the Low-Power Solutions PDF. The amperages listed are absolute minimums, and most people will not get that low with typical hardware and programs. | item | Automatic Modem Sleep | Forced Modem Sleep | Automatic Light Sleep | Forced Light Sleep | Forced Deep Sleep | |:---------------------:|:---------------------:|:------------------:|:---------------------:|:------------------:|:------------------:| | WiFi connectivity | Connected | Disconnected | Connected | Disconnected | Disconnected | -| GPIO state | Unchanged | Unchanged | Unchanged | Unchanged | Low current (2 uA) | +| GPIO state | Unchanged | Unchanged | Unchanged | Unchanged | Low amperage (2 uA) | | WiFi | ON | OFF | ON | OFF | OFF | | System Clock | ON | ON | CYCLING | OFF | OFF | | RTC | ON | ON | ON | ON | ON (1) | | CPU | ON | ON | ON | ON | OFF | -| Substrate Current | 15 mA | 15 mA | 2-15 mA (2) | 0.4 mA | 20 uA | -| Avg Current DTIM = 1 | 16.2 mA | | (1.8 mA) | | | -| Avg Current DTIM = 3 | 15.4 mA | | (0.9 mA) | | | -| Avg Current DTIM = 10 | 15.2 mA | | (0.55 mA) | | | +| Substrate Amperage | 15 mA | 15 mA | 2-15 mA (2) | 0.4 mA | 20 uA | +| Avg Amperage DTIM = 1 | 16.2 mA | | (1.8 mA) | | | +| Avg Amperage DTIM = 3 | 15.4 mA | | (0.9 mA) | | | +| Avg Amperage DTIM = 10 | 15.2 mA | | (0.55 mA) | | | Notes: (1) setting a sleep time of 0 for Deep Sleep turns off or disconnects the RTC, requiring an external RESET to wake it -(2) due to a bug in SDK 2, the minimum current will never be less than ~ 2 mA and is frequently 15 mA between DTIM beacons +(2) due to a bug in SDK 2, the minimum amperage will never be less than ~ 2 mA and is frequently 15 mA between DTIM beacons -The Average Current with different DTIM settings is unverified, and will likely be higher in a real-world environment. All of the currents listed in this README are for the ESP8266 chip only, compiled for 80 MHz CPU Frequency as 160 MHz uses even more current. Modules that have voltage regulators, USB chips, LEDs or other hardware will draw additional current. +The Average Amperage with different DTIM settings is unverified, and will likely be higher in a real-world environment. All of the amperages listed in this README are for the ESP8266 chip only, compiled for 80 MHz CPU Frequency as 160 MHz uses even more amperage. Modules that have voltage regulators, USB chips, LEDs or other hardware will draw additional amperage. --- @@ -46,23 +46,23 @@ The Average Current with different DTIM settings is unverified, and will likely ### Test 1 - Unconfigured modem -This is typical for programs that don't use WiFi, and is a high current continuous drain of at least 67 mA. This isn't a test as much as setting a baseline or reference point for comparing the power savings. You can stop during any test while the CPU is halted or the LED is blinking to measure the current. +This is typical for programs that don't use WiFi, and is a high continuous drain of at least 67 mA. This isn't a test as much as setting a baseline or reference point for comparing the power savings. You can stop during any test while the CPU is halted or the LED is blinking to measure the amperage. ### Test 2 - Automatic Modem Sleep -This is the default power saving mode when you have an active WiFi connection. You don't need to add anything to your code to get this mode. The only time the modem sleeps is when your program spends time in delay() frequently. Any delay() time works as long as it happens frequently. The LED blinks more slowly during this test as it's doing **delay(350)** to get the modem to sleep. While in delay() your sketch isn't doing anything worthwhile. Average current during Automatic Modem Sleep is 15 mA minimum. Without a delay() the average current is > 67 mA with brief spikes > 250-350 mA as transmissions occur. When the WiFi has traffic (even a couple of pings), the modem can turn on for over 2 seconds continuous at 67 mA, and it may stay on for a second after the traffic. In a high traffic environment you won't get any power savings with either of the 2 Automatic modes. Automatic Modem Sleep turns on 7-8 seconds after an active connection is established. +This is the default power saving mode when you have an active WiFi connection. You don't need to add anything to your code to get this mode. The only time the modem sleeps is when your program spends time in delay() frequently. Any delay() time works as long as it happens frequently. The LED blinks more slowly during this test as it's doing **delay(350)** to get the modem to sleep. While in delay() your sketch isn't doing anything worthwhile. Amperage during Automatic Modem Sleep is 15 mA minimum. Without a delay() the amperage is > 67 mA with brief spikes > 250-350 mA as transmissions occur. When the WiFi has traffic (even a couple of pings), the modem can turn on for over 2 seconds continuous at 67 mA, and it may stay on for a second after the traffic. In a high traffic environment you won't get any power savings with either of the 2 Automatic modes. Automatic Modem Sleep turns on 7-8 seconds after an active connection is established. ### Test 3 - Forced Modem Sleep -Turns off the modem (losing the connection), and reducing the current by > 50 mA. This test uses the WiFi library function. It's good if there is a long interval with no expected WiFi traffic, as you can do other things while only drawing 15 to 20 mA. The longer you spend in delay(), the closer the current approaches 15 mA. The test loops on delay(350) until you press the button. The CPU will be drawing 15 to 16 mA during the looped delay(), and 19-20 mA without a delay(). +Turns off the modem (losing the connection), reducing the amperage by > 50 mA. This test uses the WiFi library function. It's good if there is a long interval with no expected WiFi traffic, as you can do other things while only drawing 15 to 20 mA. The longer you spend in delay(), the closer the amperage approaches 15 mA. The test loops on delay(350) until you press the button. The CPU will be drawing 15 to 16 mA during the looped delay(), and 19-20 mA without a delay(). ### Test 4 - Automatic Light Sleep -Like Automatic Modem Sleep, with similar restrictions. Once configured it's immediately active when a connection is established. During periods of long delay() the average current can drop to ~ 2 mA average. In a network with sparse traffic you might get something near 2-5 mA average current. The LED blinks more slowly during this test as it's doing delay(350) to get the modem to sleep. With delay() times shorter than the DTIM beacon interval (100 mS beacons for these tests) the modem only goes into Automatic Modem Sleep, and with a longer delay() it will go into Automatic Light Sleep. +Like Automatic Modem Sleep, with similar restrictions. Once configured it's immediately active when a connection is established. During periods of long delay() the amperage can drop to ~ 3 mA average. In a network with sparse traffic you might get something near 2-5 mA amperage. The LED blinks more slowly during this test as it's doing delay(350) to get the modem to sleep. With delay() times shorter than the DTIM beacon interval (100 mS beacons for these tests) the modem only goes into Automatic Modem Sleep, and with a longer delay() it will go into Automatic Light Sleep. ### Test 5 - Forced Light Sleep -Similar to Deep Sleep, but without the timer. The chip sleeps at 0.4 mA current until it is woken by an external interrupt. The only allowed interrupts are high level and low level; edge interrupts won't work. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using Forced Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 5.1 mS, but WiFi was turned off to enter Forced Light Sleep so you will need to re-initialize it if you are using WiFi. +Similar to Deep Sleep, but without the timer. The chip sleeps at 0.4 mA amperage until it is woken by an external interrupt. The only allowed interrupts are high level and low level; edge interrupts won't work. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using Forced Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 5.1 mS, but WiFi was turned off to enter Forced Light Sleep so you will need to re-initialize it if you are using WiFi. ### Test 6 - Deep Sleep, wake with RF_DEFAULT @@ -74,11 +74,11 @@ Identical to the test above, but the modem does an RF power calibration when boo ### Test 8 - Deep Sleep Instant, wake with NO_RFCAL -This variation doesn't do an automatic RF calibration on return, so power requirements will be slightly less. Additionally, *most* of the time it immediately goes into Deep Sleep without turning off the modem (that's the INSTANT part). There's another bug in SDK 2, and the SDK functions the WiFi-class calls occasionally do a modem shut-down before Deep Sleep; it's not always Instant. When it doesn't do the modem shut-down it saves an extra 270 mS of power. With the modem turned off (Forced Modem Sleep) you **always** get an instant Deep Sleep; doing WiFi.mode(WIFI_OFF) doesn't help, as the SDK still spends 270 mS of time shutting the modem down before going into Deep Sleep. +This variation doesn't do an RF calibration on return, so power requirements will be slightly less. Additionally, *most* of the time it immediately goes into Deep Sleep without turning off the modem (that's the INSTANT part). There's another bug in SDK 2, and the SDK functions the WiFi-class calls occasionally do a modem shut-down before Deep Sleep; it's not always Instant. When it doesn't do the modem shut-down it saves an extra 270 mS of power. With the modem turned off (Forced Modem Sleep) you **always** get an instant Deep Sleep; doing WiFi.mode(WIFI_OFF) doesn't help, as the SDK still spends 270 mS of time shutting the modem down before going into Deep Sleep. ### Test 9 - Deep Sleep Instant, wake with RF_DISABLED -This last variation also uses Deep Sleep Instant, but it wakes up with the modem disabled so current after Deep Sleep is only 15 mA. Each of the 4 WAKE modes has their own use, depending on what you need. +This last variation also uses Deep Sleep Instant, but it wakes up with the modem disabled so amperage after Deep Sleep is only 15 mA. Each of the 4 WAKE modes has their own use, depending on what you need. --- @@ -97,13 +97,13 @@ If all you want to do is reduce power for a sketch that doesn't need WiFi, add t ```c wifi_station_disconnect(); // disconnects Wi-Fi Station from AP delay(10); // without at least delay(8) you might get soft WDT resets after this - wifi_set_opmode_current(NULL_MODE); // set Wi-Fi working mode to unconfigured, don't save to flash + wifi_set_opmode_amperage(NULL_MODE); // set Wi-Fi working mode to unconfigured, don't save to flash wifi_fpm_set_sleep_type(MODEM_SLEEP_T); // set the sleep type to modem sleep wifi_fpm_open(); // enable Forced Modem Sleep wifi_fpm_do_sleep(0xFFFFFFF); // force CPU to enter sleep mode delay(10); // without a delay() here it doesn't reliably enter sleep ``` -This code allows you to shut down the modem *without* loading the WiFi library, dropping your average current by 50 mA, or ~ 1/4th of the initial power. You have to add it as shown, preferably in **setup()**. It doesn't time out at 71 minutes, as you might think from the (0xFFFFFFF). The Forced Modem Sleep test does the same thing with a WiFi library call that encapsulates something similar to the code above. +This code allows you to shut down the modem *without* loading the WiFi library, dropping your amperage by 50 mA, or ~ 1/4th of the initial power. You have to add it as shown, preferably in **setup()**. It doesn't time out at 71 minutes, as you might think from the (0xFFFFFFF). The Forced Modem Sleep test does the same thing with a WiFi library call that encapsulates something similar to the code above. -You can also use the Deep Sleep modes without loading the WiFi library, as Deep Sleep use ESP API functions. The Deep Sleep tests above turn the WiFi on to show you the differences after the 4 reset modes. +You can also use the Deep Sleep modes without loading the WiFi library, as Deep Sleep use ESP API functions. The Deep Sleep tests above turn the WiFi on to show you the differences after the 4 reset modes. but WiFi is not required for Deep Sleep. From 068f4bd638af281ac44874d9a2225b524b50dd4e Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Sat, 11 Jan 2020 22:03:46 -0600 Subject: [PATCH 19/51] add Low-Power demo --- libraries/esp8266/examples/LowPowerDemo/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md index f9ef4bcbbf..421fd88631 100644 --- a/libraries/esp8266/examples/LowPowerDemo/README.md +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -26,7 +26,7 @@ Notes: (2) due to a bug in SDK 2, the minimum amperage will never be less than ~ 2 mA and is frequently 15 mA between DTIM beacons -The Average Amperage with different DTIM settings is unverified, and will likely be higher in a real-world environment. All of the amperages listed in this README are for the ESP8266 chip only, compiled for 80 MHz CPU Frequency as 160 MHz uses even more amperage. Modules that have voltage regulators, USB chips, LEDs or other hardware will draw additional amperage. +The Average Amperage with different DTIM settings is unverified, and will likely be higher in a real-world environment. All of the amperages listed in this README are for the ESP8266 chip only, compiled for 80 MHz CPU Frequency as 160 MHz uses even more power. Modules that have voltage regulators, USB chips, LEDs or other hardware will draw additional amperage. --- @@ -97,7 +97,7 @@ If all you want to do is reduce power for a sketch that doesn't need WiFi, add t ```c wifi_station_disconnect(); // disconnects Wi-Fi Station from AP delay(10); // without at least delay(8) you might get soft WDT resets after this - wifi_set_opmode_amperage(NULL_MODE); // set Wi-Fi working mode to unconfigured, don't save to flash + wifi_set_opmode_current(NULL_MODE); // set Wi-Fi working mode to unconfigured, don't save to flash wifi_fpm_set_sleep_type(MODEM_SLEEP_T); // set the sleep type to modem sleep wifi_fpm_open(); // enable Forced Modem Sleep wifi_fpm_do_sleep(0xFFFFFFF); // force CPU to enter sleep mode From 3118de557db21101ba03ad44946e8fa8d94252b9 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Sun, 12 Jan 2020 10:58:05 -0600 Subject: [PATCH 20/51] add Low-Power demo --- libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index 8c26cd3307..678e7b60e3 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -4,11 +4,11 @@ so that it bypassed the on-board voltage regulator and USB chip. There's still about 0.3 mA worth of leakage amperage due to the unpowered chips. These tests should work with any module, although on-board components will affect the actual current measurement. - While the modem is turned on the amperage is > 67 mA or jumping around with a minimum value. + While the modem is turned on the amperage is > 67 mA or changing with a minimum value. To verify the 20 uA Deep Sleep amperage the voltage regulator and USB chip were removed. This test series requires an active WiFi connection to illustrate two tests. If you - have problems with WiFi, uncomment the #ifdef DEBUG for additional WiFi error messages. + have problems with WiFi, uncomment the #define DEBUG for additional WiFi error messages. The test requires a pushbutton switch connected between D3 and GND to advance the tests. You'll also need to connect D0/GPIO16 to RST for the Deep Sleep tests. If you forget to connect D0 to RST it will hang after the first Deep Sleep test. Additionally, you can @@ -16,7 +16,7 @@ preferably not the 3V3 pin on the module or it adds to the measured amperage. When the LED blinks you can proceed to the next test. When the LED is lit continuously it's connecting WiFi, and when it's off the CPU is asleep. The LED blinks slowly when the - tests are complete. Test progress is also shown on the serial monitor. + tests are complete. Test progress can also be shown on the serial monitor. WiFi connections will be made over twice as fast if you can use a static IP address. From ac40b6e578735ba227678889b047bde698783775 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Sun, 12 Jan 2020 14:05:01 -0600 Subject: [PATCH 21/51] add Low-Power demo --- .../examples/LowPowerDemo/LowPowerDemo.ino | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index 678e7b60e3..da21b9d9b3 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -89,7 +89,7 @@ void wakeupCallback() { // unlike ISRs, you can do a print() from a callback fu } void setup() { - pinMode(LED, OUTPUT); // Activity and Status indicator + pinMode(LED, OUTPUT); // activity and status indicator digitalWrite(LED, LOW); // turn on the LED pinMode(WAKE_UP_PIN, INPUT_PULLUP); // polled to advance tests, interrupt for Forced Light Sleep Serial.begin(115200); @@ -106,7 +106,7 @@ void setup() { if (ESP.rtcUserMemoryRead(64, (uint32_t*) &rtcData, sizeof(rtcData))) { uint32_t crcOfData = crc32((uint8_t*) &rtcData.data[0], sizeof(rtcData.data)); if (crcOfData != rtcData.crc32) { // if the CRC is invalid - resetCount = 0; // set first test loop since power on or external reset + resetCount = 0; // set first test run since power on or external reset } else { resetCount = rtcData.data[3]; // read the previous reset count } @@ -114,7 +114,7 @@ void setup() { } // end of setup() void loop() { - if (resetCount == 0) { + if (resetCount == 0) { // first reset, else skip down to the next Deep Sleep test // 1st test - running with WiFi unconfigured, reads ~67 mA minimum Serial.println(F("\n1st test - running with WiFi unconfigured")); float volts = ESP.getVcc(); @@ -140,6 +140,7 @@ void loop() { Serial.println(F("\n3rd test - Forced Modem Sleep")); WiFi.forceSleepBegin(); delay(10); // it doesn't always go to sleep unless you delay(10); yield() wasn't reliable + // WiFi.mode(WIFI_SHUTDOWN); // alternate method of Forced Modem Sleep volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("press the button to continue")); @@ -173,7 +174,7 @@ void loop() { volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("CPU going to sleep, pull WAKE_UP_PIN low to wake it (press the button)")); - delay(100); // needs a delay() after the print or it may not print the whole message + Serial.flush(); // needs a delay(100) or Serial.flush() else it doesn't print the whole message wifi_fpm_set_sleep_type(LIGHT_SLEEP_T); gpio_pin_wakeup_enable(GPIO_ID_PIN(WAKE_UP_PIN), GPIO_PIN_INTR_LOLEVEL); // only LOLEVEL or HILEVEL interrupts work, no edge, that's an SDK or CPU limitation @@ -198,7 +199,7 @@ void loop() { waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep digitalWrite(LED, LOW); // turn the LED on, at least briefly Serial.println(F("going into Deep Sleep now...")); - delay(10); // sometimes the \n isn't printed without a short delay + Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message ESP.deepSleep(10E6, WAKE_RF_DEFAULT); // good night! D0 fires a reset in 10 seconds... delay(10); // if you do ESP.deepSleep(0, mode); it needs a RESET to come out of sleep (RTC is off) @@ -212,7 +213,7 @@ void loop() { if (resetCount < 4) { init_WiFi(); // need to reinitialize WiFi due to Deep Sleep reset } - if (resetCount == 1) { // second reset loop since power on + if (resetCount == 1) { // second reset since power on resetCount = 2; // advance to the next Deep Sleep test after the reset updateRTC(); // save the current test state in RTC memory Serial.println(F("\n7th test - in RF_DEFAULT, Deep Sleep for 10 seconds, reset and wake with RFCAL")); @@ -221,14 +222,14 @@ void loop() { Serial.println(F("press the button to continue")); waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep Serial.println(F("going into Deep Sleep now...")); - delay(10); // sometimes the \n isn't printed without a short delay + Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message ESP.deepSleep(10E6, WAKE_RFCAL); // good night! D0 fires a reset in 10 seconds... delay(10); Serial.println(F("What... I'm not asleep?!?")); // it will never get here } // 8th test - Deep Sleep Instant for 10 seconds, wake with NO_RFCAL - if (resetCount == 2) { // third reset loop since power on + if (resetCount == 2) { // third reset since power on resetCount = 3; // advance to the next Deep Sleep test after the reset updateRTC(); // save the current test state in RTC memory Serial.println(F("\n8th test - in RFCAL, Deep Sleep Instant for 10 seconds, reset and wake with NO_RFCAL")); @@ -237,14 +238,14 @@ void loop() { Serial.println(F("press the button to continue")); waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep Serial.println(F("going into Deep Sleep now...")); - delay(10); // sometimes the \n isn't printed without a short delay + Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message ESP.deepSleepInstant(10E6, WAKE_NO_RFCAL); // good night! D0 fires a reset in 10 seconds... delay(10); Serial.println(F("What... I'm not asleep?!?")); // it will never get here } // 9th test - Deep Sleep Instant for 10 seconds, wake with RF_DISABLED - if (resetCount == 3) { // fourth reset loop since power on + if (resetCount == 3) { // fourth reset since power on resetCount = 4; // advance to the next Deep Sleep test after the reset updateRTC(); // save the current test state in RTC memory Serial.println(F("\n9th test - in NO_RFCAL, Deep Sleep Instant for 10 seconds, reset and wake with RF_DISABLED")); @@ -253,7 +254,7 @@ void loop() { Serial.println(F("press the button to continue")); waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep Serial.println(F("going into Deep Sleep now...")); - delay(10); // sometimes the \n isn't printed without a short delay + Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message ESP.deepSleepInstant(10E6, WAKE_RF_DISABLED); // good night! D0 fires a reset in 10 seconds... delay(10); Serial.println(F("What... I'm not asleep?!?")); // it will never get here @@ -278,12 +279,12 @@ void waitPushbutton(bool usesDelay, unsigned int delayTime) { // loop until the if (blinkLED) { digitalWrite(LED, !digitalRead(LED)); // toggle the activity LED } - yield(); // this would be a good spot for ArduinoOTA.handle(); + yield(); // this would be a good place for ArduinoOTA.handle(); } } else { // long delay() for the 2 AUTOMATIC modes, but it misses quick button presses while (digitalRead(WAKE_UP_PIN)) { // wait for a button press digitalWrite(LED, !digitalRead(LED)); // toggle the activity LED - delay(delayTime); // another good spot for ArduinoOTA.handle(); + delay(delayTime); // another good place for ArduinoOTA.handle(); } } delay(50); // debounce time for the switch, button pressed From 662b1f2f9a304a6431e4d93ff57cb2673709358b Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Sun, 12 Jan 2020 20:56:37 -0600 Subject: [PATCH 22/51] add Low-Power demo --- libraries/esp8266/examples/LowPowerDemo/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md index 421fd88631..daa64a9e9e 100644 --- a/libraries/esp8266/examples/LowPowerDemo/README.md +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -62,11 +62,11 @@ Like Automatic Modem Sleep, with similar restrictions. Once configured it's imm ### Test 5 - Forced Light Sleep -Similar to Deep Sleep, but without the timer. The chip sleeps at 0.4 mA amperage until it is woken by an external interrupt. The only allowed interrupts are high level and low level; edge interrupts won't work. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using Forced Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 5.1 mS, but WiFi was turned off to enter Forced Light Sleep so you will need to re-initialize it if you are using WiFi. +Similar to Deep Sleep, but without the timer. The chip sleeps at 0.4 mA amperage until it is woken by an external interrupt. The only allowed interrupts are high level and low level; edge interrupts won't work. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using Forced Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 5 to 5.5 mS, but WiFi was turned off to enter Forced Light Sleep so you will need to re-initialize it if you are using WiFi. ### Test 6 - Deep Sleep, wake with RF_DEFAULT -In Deep Sleep almost everything is turned off, and the chip draws ~ 20 uA. If you have D0/GPIO16 connected to RST, you can use the RTC timer to wake the chip up at a timed interval. You can also wake it with an external RESET. Waking with RF_DEFAULT means it will do an RFCAL if it needs to. Doing **ESP.deepSleep(time)** without the mode variable uses this wake mode. These first two Deep Sleep tests use the standard Deep Sleep function, so the WiFi connection is closed and the modem turned off, which takes about 270 mS before the Deep Sleep begins. Deep Sleep ends with a RESET, and the boot time after that is ~ 120 mS. Any Deep Sleep less than ~ 2 seconds is wasting energy due to the modem shut-off and boot times, and Forced Light Sleep will be a better choice as it recovers in 5.1 mS from the previous state. The Deep Sleep tests will not go into Automatic Modem Sleep because delay() is not used. +In Deep Sleep almost everything is turned off, and the chip draws ~ 20 uA. If you have D0/GPIO16 connected to RST, you can use the RTC timer to wake the chip up at a timed interval. You can also wake it with an external RESET. Waking with RF_DEFAULT means it will do an RFCAL if it needs to. Doing **ESP.deepSleep(time)** without the mode variable uses this wake mode. These first two Deep Sleep tests use the standard Deep Sleep function, so the WiFi connection is closed and the modem turned off, which takes about 270 mS before the Deep Sleep begins. Deep Sleep ends with a RESET, and the boot time after that is ~ 120 mS. Any Deep Sleep less than ~ 2 seconds is wasting energy due to the modem shut-off and boot times, and Forced Light Sleep will be a better choice as it recovers in ~ 5 mS from the previous state. The Deep Sleep tests will not go into Automatic Modem Sleep because delay() is not used. ### Test 7 - Deep Sleep, wake with RFCAL From 56956263f409faa7afbda753911fe72305cbbd21 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Wed, 15 Jan 2020 21:24:10 -0600 Subject: [PATCH 23/51] add Low-Power demo --- .../examples/LowPowerDemo/LowPowerDemo.ino | 61 ++++++++++++++++--- .../esp8266/examples/LowPowerDemo/README.md | 20 +++--- 2 files changed, 65 insertions(+), 16 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index da21b9d9b3..f048ee0012 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -68,6 +68,8 @@ IPAddress dns1(0, 0, 0, 0); IPAddress dns2(0, 0, 0, 0); uint32_t wifiTimeout = 25E3; // 25 second timeout on the WiFi connection +//#define testPoint 4 // D2/GPIO4 used to track the timing of several test cycles, entirely optional + // This structure will be stored in RTC memory to remember the reset count (number of Deep Sleeps). // First field is CRC32, which is calculated based on the rest of the structure contents. // Any fields can go after the CRC32. The structure must be 4-byte aligned. @@ -77,18 +79,25 @@ struct { } rtcData; byte resetCount = 0; // keeps track of the number of Deep Sleep tests / resets -String resetCause = ""; const uint32_t blinkDelay = 100; // fast blink rate for the LED when waiting for the user const uint32_t longDelay = 350; // longer delay() for the two AUTOMATIC modes -esp8266::polledTimeout::periodicFastMs blinkLED(blinkDelay); +esp8266::polledTimeout::periodicMs blinkLED(blinkDelay); +esp8266::polledTimeout::oneShotFastMs altDelay(blinkDelay); // use fully qualified type and avoid importing all ::esp8266 namespace to the global namespace void wakeupCallback() { // unlike ISRs, you can do a print() from a callback function +#ifdef testPoint + digitalWrite(testPoint, LOW); // testPoint tracks latency from WAKE_UP_PIN LOW to testPoint LOW +#endif Serial.println(F("Woke from Forced Light Sleep - this is the callback")); } void setup() { +#ifdef testPoint + pinMode(testPoint, OUTPUT); // test point for Forced Light Sleep and Deep Sleep tests + digitalWrite(testPoint, LOW); // Deep Sleep reset doesn't clear GPIOs, testPoint falling shows boot time +#endif pinMode(LED, OUTPUT); // activity and status indicator digitalWrite(LED, LOW); // turn on the LED pinMode(WAKE_UP_PIN, INPUT_PULLUP); // polled to advance tests, interrupt for Forced Light Sleep @@ -131,7 +140,13 @@ void loop() { volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("press the button to continue")); - waitPushbutton(true, longDelay); + waitPushbutton(true, 90); /* This is using a special feature: below 100 mS blink delay, + the LED blink delay is padding the time with 'program cycles' to fill the 100 mS. At 90 mS + delay, 90% of the blink time is delay(), and 10% is 'your program running'. Below 90% you + will see a difference in the average amperage, less delay() = more amperage. At 100 mS + and above it's essentially all delay() time. On an oscilloscope you'll see the time + between beacons at > 67 mA more often with less delay() percentage. You can change the + '90' mS to other values to see the effect it has on Automatic Modem Sleep. */ } else { Serial.println(F("no WiFi connection, test skipped")); } @@ -144,7 +159,10 @@ void loop() { volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("press the button to continue")); - waitPushbutton(true, longDelay); + waitPushbutton(true, 99); /* Using the same < 100 mS feature. If you drop the delay below 100, you + will see the effect of program time vs. delay() time on minimum amperage. Above ~ 97 (97% of the + time in delay) there is little change in amperage, so you need to spend maximum time in delay() + to get minimum amperage. At a high percentage of delay() you will see minimum amperage. */ // 4th test - Automatic Light Sleep Serial.println(F("\n4th test - Automatic Light Sleep")); @@ -161,7 +179,9 @@ void loop() { volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("press the button to continue")); - waitPushbutton(true, longDelay); + waitPushbutton(true, 350); /* Below 100 mS delay it only goes into 'Automatic Modem Sleep', + and below ~ 350 mS delay() the 'Automatic Light Sleep' is less frequent. Above 350 mS + delay() doesn't make much improvement in power savings. */ } else { Serial.println(F("no WiFi connection, test skipped")); } @@ -171,6 +191,9 @@ void loop() { WiFi.mode(WIFI_OFF); // you must turn the modem off; using disconnect won't work yield(); digitalWrite(LED, HIGH); // turn the LED off so they know the CPU isn't running +#ifdef testPoint + digitalWrite(testPoint, HIGH); // testPoint LOW in callback tracks latency from WAKE_UP_PIN LOW to testPoint LOW +#endif volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("CPU going to sleep, pull WAKE_UP_PIN low to wake it (press the button)")); @@ -198,8 +221,13 @@ void loop() { delay(50); // debounce time for the switch, button released waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep digitalWrite(LED, LOW); // turn the LED on, at least briefly + //WiFi.mode(WIFI_SHUTDOWN); // Forced Modem Sleep for a more Instant Deep Sleep, and no long + // RFCAL as it goes into Deep Sleep Serial.println(F("going into Deep Sleep now...")); Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message +#ifdef testPoint + digitalWrite(testPoint, HIGH); // testPoint set HIGH to track Deep Sleep period, cleared at startup() +#endif ESP.deepSleep(10E6, WAKE_RF_DEFAULT); // good night! D0 fires a reset in 10 seconds... delay(10); // if you do ESP.deepSleep(0, mode); it needs a RESET to come out of sleep (RTC is off) @@ -221,8 +249,13 @@ void loop() { Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("press the button to continue")); waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep + //WiFi.mode(WIFI_SHUTDOWN); // Forced Modem Sleep for a more Instant Deep Sleep, and no RFCAL + // as it goes into Deep Sleep Serial.println(F("going into Deep Sleep now...")); Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message +#ifdef testPoint + digitalWrite(testPoint, HIGH); // testPoint set HIGH to track Deep Sleep period, cleared at startup() +#endif ESP.deepSleep(10E6, WAKE_RFCAL); // good night! D0 fires a reset in 10 seconds... delay(10); Serial.println(F("What... I'm not asleep?!?")); // it will never get here @@ -237,8 +270,13 @@ void loop() { Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("press the button to continue")); waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep + //WiFi.mode(WIFI_SHUTDOWN); // Forced Modem Sleep for a more Instant Deep Sleep, and no RFCAL + // as it goes into Deep Sleep Serial.println(F("going into Deep Sleep now...")); Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message +#ifdef testPoint + digitalWrite(testPoint, HIGH); // testPoint set HIGH to track Deep Sleep period, cleared at startup() +#endif ESP.deepSleepInstant(10E6, WAKE_NO_RFCAL); // good night! D0 fires a reset in 10 seconds... delay(10); Serial.println(F("What... I'm not asleep?!?")); // it will never get here @@ -253,8 +291,12 @@ void loop() { Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("press the button to continue")); waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep + // WiFi.mode(WIFI_SHUTDOWN); // Forced Modem Sleep for a more Instant Deep Sleep Serial.println(F("going into Deep Sleep now...")); Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message +#ifdef testPoint + digitalWrite(testPoint, HIGH); // testPoint set HIGH to track Deep Sleep period, cleared at startup() +#endif ESP.deepSleepInstant(10E6, WAKE_RF_DISABLED); // good night! D0 fires a reset in 10 seconds... delay(10); Serial.println(F("What... I'm not asleep?!?")); // it will never get here @@ -272,7 +314,7 @@ void loop() { } void waitPushbutton(bool usesDelay, unsigned int delayTime) { // loop until they press the button - // note: 2 different modes, as both of the AUTOMATIC power saving modes need a long delay() + // note: 2 different modes, as 3 of the power saving modes need a delay() to activate fully if (!usesDelay) { // quick interception of button press, no delay() used blinkLED.reset(delayTime); while (digitalRead(WAKE_UP_PIN)) { // wait for a button press @@ -281,10 +323,15 @@ void waitPushbutton(bool usesDelay, unsigned int delayTime) { // loop until the } yield(); // this would be a good place for ArduinoOTA.handle(); } - } else { // long delay() for the 2 AUTOMATIC modes, but it misses quick button presses + } else { // long delay() for the 3 modes that need it, but it misses quick button presses while (digitalRead(WAKE_UP_PIN)) { // wait for a button press digitalWrite(LED, !digitalRead(LED)); // toggle the activity LED delay(delayTime); // another good place for ArduinoOTA.handle(); + if (delayTime < 100) { + altDelay.reset(100 - delayTime); // pad the time < 100 mS with some real CPU cycles + while (!altDelay) { // this simulates 'your program running', not delay() time + } + } } } delay(50); // debounce time for the switch, button pressed diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md index daa64a9e9e..c24feca551 100644 --- a/libraries/esp8266/examples/LowPowerDemo/README.md +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -50,23 +50,25 @@ This is typical for programs that don't use WiFi, and is a high continuous drain ### Test 2 - Automatic Modem Sleep -This is the default power saving mode when you have an active WiFi connection. You don't need to add anything to your code to get this mode. The only time the modem sleeps is when your program spends time in delay() frequently. Any delay() time works as long as it happens frequently. The LED blinks more slowly during this test as it's doing **delay(350)** to get the modem to sleep. While in delay() your sketch isn't doing anything worthwhile. Amperage during Automatic Modem Sleep is 15 mA minimum. Without a delay() the amperage is > 67 mA with brief spikes > 250-350 mA as transmissions occur. When the WiFi has traffic (even a couple of pings), the modem can turn on for over 2 seconds continuous at 67 mA, and it may stay on for a second after the traffic. In a high traffic environment you won't get any power savings with either of the 2 Automatic modes. Automatic Modem Sleep turns on 7-8 seconds after an active connection is established. +This is the default power saving mode when you have an active WiFi connection. You don't need to add anything to your code to get this mode. The only time the modem sleeps is when your program spends time in delay() frequently. Any delay() time works as long as it happens frequently. The test is doing **delay(100)** to get the modem to sleep. While in delay() your sketch isn't doing anything worthwhile. Amperage during Automatic Modem Sleep is 15 mA minimum. Without a delay() the amperage is > 67 mA with brief spikes > 250-350 mA as transmissions occur. When the WiFi has traffic (even a couple of pings), the modem can turn on for over 2 seconds continuous at 67 mA, and it may stay on for a second after the traffic. In a high traffic environment you won't get any power savings with either of the 2 Automatic modes. Automatic Modem Sleep turns on 7-8 seconds after an active connection is established. ### Test 3 - Forced Modem Sleep -Turns off the modem (losing the connection), reducing the amperage by > 50 mA. This test uses the WiFi library function. It's good if there is a long interval with no expected WiFi traffic, as you can do other things while only drawing 15 to 20 mA. The longer you spend in delay(), the closer the amperage approaches 15 mA. The test loops on delay(350) until you press the button. The CPU will be drawing 15 to 16 mA during the looped delay(), and 19-20 mA without a delay(). +Turns off the modem (losing the connection), and reducing the amperage by > 50 mA. This test uses the WiFi library function. It's good if there is a long interval with no expected WiFi traffic, as you can do other things while only drawing 15 to 20 mA. The longer you spend in delay(), the closer the amperage approaches 15 mA. The test loops on delay(100) until you press the button. The CPU will be drawing 15 to 16 mA during the looped delay(), and 19-20 mA without a delay(). ### Test 4 - Automatic Light Sleep -Like Automatic Modem Sleep, with similar restrictions. Once configured it's immediately active when a connection is established. During periods of long delay() the amperage can drop to ~ 3 mA average. In a network with sparse traffic you might get something near 2-5 mA amperage. The LED blinks more slowly during this test as it's doing delay(350) to get the modem to sleep. With delay() times shorter than the DTIM beacon interval (100 mS beacons for these tests) the modem only goes into Automatic Modem Sleep, and with a longer delay() it will go into Automatic Light Sleep. +Like Automatic Modem Sleep, with similar restrictions. Once configured it's immediately active when a connection is established. During periods of long delay() the amperage can drop to ~ 3 mA average. In a network with sparse traffic you might get something near 2-5 mA amperage. The LED blinks more slowly during this test as it's doing delay(350) to get the modem to sleep. With delay() times shorter than the DTIM beacon interval (100 mS beacons for these tests) the modem only goes into Automatic Modem Sleep, and with a longer delay() it will go more fully into Automatic Light Sleep. ### Test 5 - Forced Light Sleep -Similar to Deep Sleep, but without the timer. The chip sleeps at 0.4 mA amperage until it is woken by an external interrupt. The only allowed interrupts are high level and low level; edge interrupts won't work. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using Forced Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 5 to 5.5 mS, but WiFi was turned off to enter Forced Light Sleep so you will need to re-initialize it if you are using WiFi. +Similar to Deep Sleep, but without the timer. The chip sleeps at 0.4 mA amperage until it is woken by an external interrupt. The only allowed interrupts are high level and low level; edge interrupts won't work. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using Forced Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 5 to 5.5 mS (regardless of CPU speed), but WiFi was turned off to enter Forced Light Sleep so you will need to re-initialize it if you are using WiFi. ### Test 6 - Deep Sleep, wake with RF_DEFAULT -In Deep Sleep almost everything is turned off, and the chip draws ~ 20 uA. If you have D0/GPIO16 connected to RST, you can use the RTC timer to wake the chip up at a timed interval. You can also wake it with an external RESET. Waking with RF_DEFAULT means it will do an RFCAL if it needs to. Doing **ESP.deepSleep(time)** without the mode variable uses this wake mode. These first two Deep Sleep tests use the standard Deep Sleep function, so the WiFi connection is closed and the modem turned off, which takes about 270 mS before the Deep Sleep begins. Deep Sleep ends with a RESET, and the boot time after that is ~ 120 mS. Any Deep Sleep less than ~ 2 seconds is wasting energy due to the modem shut-off and boot times, and Forced Light Sleep will be a better choice as it recovers in ~ 5 mS from the previous state. The Deep Sleep tests will not go into Automatic Modem Sleep because delay() is not used. +In Deep Sleep almost everything is turned off, and the chip draws ~ 20 uA. If you have D0/GPIO16 connected to RST, you can use the RTC timer to wake the chip up at a timed interval. You can also wake it with an external RESET. Waking with RF_DEFAULT means it will do an RFCAL if it needs to. Doing **ESP.deepSleep(time)** without the mode variable uses this wake mode. These first two Deep Sleep tests use the standard Deep Sleep function, so the WiFi connection is closed and the modem turned off, which takes up to 270 mS before Deep Sleep begins. Deep Sleep ends with a RESET, and the boot time after that is ~ 130 mS. Any Deep Sleep less than ~ 2 seconds is wasting energy due to the modem shut-off and boot times, and Forced Light Sleep will be a better choice as it recovers in ~ 5 mS from the previous state. The Deep Sleep tests will not go into Automatic Modem Sleep because delay() is not used. + +Note that a RESET during Deep Sleep (either external or from D0/GPIO16) does not clear the GPIO pins; they hold their previous state. It's unknown how much else survives a Deep Sleep reset, as it's not documented. ### Test 7 - Deep Sleep, wake with RFCAL @@ -74,7 +76,7 @@ Identical to the test above, but the modem does an RF power calibration when boo ### Test 8 - Deep Sleep Instant, wake with NO_RFCAL -This variation doesn't do an RF calibration on return, so power requirements will be slightly less. Additionally, *most* of the time it immediately goes into Deep Sleep without turning off the modem (that's the INSTANT part). There's another bug in SDK 2, and the SDK functions the WiFi-class calls occasionally do a modem shut-down before Deep Sleep; it's not always Instant. When it doesn't do the modem shut-down it saves an extra 270 mS of power. With the modem turned off (Forced Modem Sleep) you **always** get an instant Deep Sleep; doing WiFi.mode(WIFI_OFF) doesn't help, as the SDK still spends 270 mS of time shutting the modem down before going into Deep Sleep. +This variation doesn't do an RF calibration on return, so power requirements will be slightly less. Additionally, frequently it immediately goes into Deep Sleep without turning off the modem (that's the INSTANT part). There's another bug in SDK 2, and the SDK functions the WiFi-class calls occasionally do a modem shut-down before Deep Sleep; it's not always Instant. When it doesn't do the modem shut-down it saves an extra 270 mS of power. With the modem turned off (Forced Modem Sleep) you **always** get an instant Deep Sleep; doing WiFi.mode(WIFI_OFF) doesn't help, as the SDK still spends 270 mS of time shutting the modem down before going into Deep Sleep. ### Test 9 - Deep Sleep Instant, wake with RF_DISABLED @@ -82,11 +84,11 @@ This last variation also uses Deep Sleep Instant, but it wakes up with the modem --- -All of the Deep Sleep modes end with a RESET, so you must re-initialize everything. You can store *some* information in the RTC memory to survive a Deep Sleep reset, which was done in this demo to illustrate the RTC memory. See the **RTCUserMemory** example for more information on this feature. +All of the Deep Sleep modes end with a RESET, so you must re-initialize nearly everything. You can store *some* information in the RTC memory to survive a Deep Sleep reset, which was done in this demo to illustrate the RTC memory. See the **RTCUserMemory** example for more information on this feature. -The maximum Deep Sleep interval is 71.58 minutes (2^32 -1 microseconds), although the actual interval may be slightly less than that. +The theoretical maximum Deep Sleep interval is 71.58 minutes (2^32 -1 microseconds), although you should use something slightly less than that due to system time calculations. -If you need a longer sleep time than 72 minutes, you can pass zero as the time variable to Deep Sleep and it turns off or disconnects the RTC. The only way to wake it at that point is an external RESET; D0 can't do it. Both Forced Light Sleep and Deep Sleep(0) are woken by an external signal, so short delays are more efficient with Forced Light Sleep, and longer delays are more energy efficient with Deep Sleep. +If you need a longer sleep time than 71 minutes, you can pass zero as the time variable to Deep Sleep and it turns off or disconnects the RTC. The only way to wake it at that point is an external RESET; D0 can't do it. Both Forced Light Sleep and Deep Sleep(0) are woken by an external signal, so short delays are more efficient with Forced Light Sleep, and longer delays are more energy efficient with Deep Sleep. --- From 7b0e5150b97f9d482d6634ac15e31158de358129 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Thu, 16 Jan 2020 18:41:37 -0600 Subject: [PATCH 24/51] add Low-Power demo --- .../examples/LowPowerDemo/LowPowerDemo.ino | 345 ++++++++++-------- 1 file changed, 187 insertions(+), 158 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index f048ee0012..ca38ea3dc2 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -123,196 +123,225 @@ void setup() { } // end of setup() void loop() { - if (resetCount == 0) { // first reset, else skip down to the next Deep Sleep test - // 1st test - running with WiFi unconfigured, reads ~67 mA minimum - Serial.println(F("\n1st test - running with WiFi unconfigured")); + if (resetCount == 0) { + runTest1(); + runTest2(); + runTest3(); + runTest4(); + runTest5(); + runTest6(); + } + if (resetCount < 4) { + initWiFi(); + } + if (resetCount == 1) { + runTest7(); + } else if (resetCount == 2) { + runTest8(); + } else if (resetCount == 3) { + runTest9(); + } else if (resetCount == 4) { + resetTests(); + } +} //end loop + +// 1st test - running with WiFi unconfigured, reads ~67 mA minimum +void runTest1() { + Serial.println(F("\n1st test - running with WiFi unconfigured")); + float volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); + Serial.println(F("press the button to continue")); + waitPushbutton(false, blinkDelay); +} + +// 2nd test - Automatic Modem Sleep 7 seconds after WiFi is connected (LED flashes) +void runTest2() { + Serial.println(F("\n2nd test - Automatic Modem Sleep")); + Serial.println(F("connecting WiFi, please wait until the LED blinks")); + initWiFi(); + if (WiFi.localIP()) { // won't go into Automatic Sleep without an active WiFi connection + Serial.println(F("The amperage will drop in 7 seconds.")); float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("press the button to continue")); - waitPushbutton(false, blinkDelay); - - // 2nd test - Automatic Modem Sleep 7 seconds after WiFi is connected (LED flashes) - Serial.println(F("\n2nd test - Automatic Modem Sleep")); - Serial.println(F("connecting WiFi, please wait until the LED blinks")); - init_WiFi(); - if (WiFi.localIP()) { // won't go into Automatic Sleep without an active WiFi connection - Serial.println(F("The amperage will drop in 7 seconds.")); - volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); - Serial.println(F("press the button to continue")); - waitPushbutton(true, 90); /* This is using a special feature: below 100 mS blink delay, + waitPushbutton(true, 90); /* This is using a special feature: below 100 mS blink delay, the LED blink delay is padding the time with 'program cycles' to fill the 100 mS. At 90 mS delay, 90% of the blink time is delay(), and 10% is 'your program running'. Below 90% you will see a difference in the average amperage, less delay() = more amperage. At 100 mS and above it's essentially all delay() time. On an oscilloscope you'll see the time between beacons at > 67 mA more often with less delay() percentage. You can change the '90' mS to other values to see the effect it has on Automatic Modem Sleep. */ - } else { - Serial.println(F("no WiFi connection, test skipped")); - } + } else { + Serial.println(F("no WiFi connection, test skipped")); + } +} - // 3rd test - Forced Modem Sleep - Serial.println(F("\n3rd test - Forced Modem Sleep")); - WiFi.forceSleepBegin(); - delay(10); // it doesn't always go to sleep unless you delay(10); yield() wasn't reliable - // WiFi.mode(WIFI_SHUTDOWN); // alternate method of Forced Modem Sleep - volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); - Serial.println(F("press the button to continue")); - waitPushbutton(true, 99); /* Using the same < 100 mS feature. If you drop the delay below 100, you +// 3rd test - Forced Modem Sleep +void runTest3() { + Serial.println(F("\n3rd test - Forced Modem Sleep")); + WiFi.forceSleepBegin(); + delay(10); // it doesn't always go to sleep unless you delay(10); yield() wasn't reliable + // WiFi.mode(WIFI_SHUTDOWN); // alternate method of Forced Modem Sleep + float volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); + Serial.println(F("press the button to continue")); + waitPushbutton(true, 99); /* Using the same < 100 mS feature. If you drop the delay below 100, you will see the effect of program time vs. delay() time on minimum amperage. Above ~ 97 (97% of the time in delay) there is little change in amperage, so you need to spend maximum time in delay() to get minimum amperage. At a high percentage of delay() you will see minimum amperage. */ +} - // 4th test - Automatic Light Sleep - Serial.println(F("\n4th test - Automatic Light Sleep")); - Serial.println(F("reconnecting WiFi")); - Serial.println(F("it will be in Automatic Light Sleep once WiFi connects (LED blinks)")); - digitalWrite(LED, LOW); // visual cue that we're reconnecting - WiFi.setSleepMode(WIFI_LIGHT_SLEEP, 5); // Automatic Light Sleep - WiFi.forceSleepWake(); // reconnect with previous STA mode and connection settings - uint32_t wifiStart = millis(); - while ((!WiFi.localIP()) && (millis() - wifiStart < wifiTimeout)) { - delay(50); - } - if (WiFi.localIP()) { // won't go into Automatic Sleep without an active WiFi connection - volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); - Serial.println(F("press the button to continue")); - waitPushbutton(true, 350); /* Below 100 mS delay it only goes into 'Automatic Modem Sleep', +// 4th test - Automatic Light Sleep +void runTest4() { + Serial.println(F("\n4th test - Automatic Light Sleep")); + Serial.println(F("reconnecting WiFi")); + Serial.println(F("it will be in Automatic Light Sleep once WiFi connects (LED blinks)")); + digitalWrite(LED, LOW); // visual cue that we're reconnecting + WiFi.setSleepMode(WIFI_LIGHT_SLEEP, 5); // Automatic Light Sleep + WiFi.forceSleepWake(); // reconnect with previous STA mode and connection settings + uint32_t wifiStart = millis(); + while ((!WiFi.localIP()) && (millis() - wifiStart < wifiTimeout)) { + delay(50); + } + if (WiFi.localIP()) { // won't go into Automatic Sleep without an active WiFi connection + float volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); + Serial.println(F("press the button to continue")); + waitPushbutton(true, 350); /* Below 100 mS delay it only goes into 'Automatic Modem Sleep', and below ~ 350 mS delay() the 'Automatic Light Sleep' is less frequent. Above 350 mS delay() doesn't make much improvement in power savings. */ - } else { - Serial.println(F("no WiFi connection, test skipped")); - } + } else { + Serial.println(F("no WiFi connection, test skipped")); + } +} - // 5th test - Forced Light Sleep using Non-OS SDK calls - Serial.println(F("\n5th test - Forced Light Sleep using Non-OS SDK calls")); - WiFi.mode(WIFI_OFF); // you must turn the modem off; using disconnect won't work - yield(); - digitalWrite(LED, HIGH); // turn the LED off so they know the CPU isn't running -#ifdef testPoint - digitalWrite(testPoint, HIGH); // testPoint LOW in callback tracks latency from WAKE_UP_PIN LOW to testPoint LOW -#endif - volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); - Serial.println(F("CPU going to sleep, pull WAKE_UP_PIN low to wake it (press the button)")); - Serial.flush(); // needs a delay(100) or Serial.flush() else it doesn't print the whole message - wifi_fpm_set_sleep_type(LIGHT_SLEEP_T); - gpio_pin_wakeup_enable(GPIO_ID_PIN(WAKE_UP_PIN), GPIO_PIN_INTR_LOLEVEL); - // only LOLEVEL or HILEVEL interrupts work, no edge, that's an SDK or CPU limitation - wifi_fpm_set_wakeup_cb(wakeupCallback); // Set wakeup callback (optional) - wifi_fpm_open(); - wifi_fpm_do_sleep(0xFFFFFFF); // only 0xFFFFFFF works; any other value and it won't sleep - delay(10); // it goes to sleep some time during this delay() and waits for an interrupt - Serial.println(F("Woke up!")); // the interrupt callback hits before this is executed - - // 6th test - Deep Sleep for 10 seconds, wake with RF_DEFAULT - Serial.println(F("\n6th test - Deep Sleep for 10 seconds, reset and wake with RF_DEFAULT")); - init_WiFi(); // initialize WiFi since we turned it off in the last test - resetCount = 1; // advance to the next Deep Sleep test after the reset - updateRTC(); // save the current test state in RTC memory - volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); - Serial.println(F("press the button to continue")); - while (!digitalRead(WAKE_UP_PIN)) { // wait for them to release the button from the last test - delay(10); - } - delay(50); // debounce time for the switch, button released - waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep - digitalWrite(LED, LOW); // turn the LED on, at least briefly - //WiFi.mode(WIFI_SHUTDOWN); // Forced Modem Sleep for a more Instant Deep Sleep, and no long - // RFCAL as it goes into Deep Sleep - Serial.println(F("going into Deep Sleep now...")); - Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message +// 5th test - Forced Light Sleep using Non-OS SDK calls +void runTest5() { + Serial.println(F("\n5th test - Forced Light Sleep using Non-OS SDK calls")); + WiFi.mode(WIFI_OFF); // you must turn the modem off; using disconnect won't work + yield(); + digitalWrite(LED, HIGH); // turn the LED off so they know the CPU isn't running #ifdef testPoint - digitalWrite(testPoint, HIGH); // testPoint set HIGH to track Deep Sleep period, cleared at startup() + digitalWrite(testPoint, HIGH); // testPoint LOW in callback tracks latency from WAKE_UP_PIN LOW to testPoint LOW #endif - ESP.deepSleep(10E6, WAKE_RF_DEFAULT); // good night! D0 fires a reset in 10 seconds... + float volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); + Serial.println(F("CPU going to sleep, pull WAKE_UP_PIN low to wake it (press the button)")); + Serial.flush(); // needs a delay(100) or Serial.flush() else it doesn't print the whole message + wifi_fpm_set_sleep_type(LIGHT_SLEEP_T); + gpio_pin_wakeup_enable(GPIO_ID_PIN(WAKE_UP_PIN), GPIO_PIN_INTR_LOLEVEL); + // only LOLEVEL or HILEVEL interrupts work, no edge, that's an SDK or CPU limitation + wifi_fpm_set_wakeup_cb(wakeupCallback); // Set wakeup callback (optional) + wifi_fpm_open(); + wifi_fpm_do_sleep(0xFFFFFFF); // only 0xFFFFFFF works; any other value and it won't sleep + delay(10); // it goes to sleep some time during this delay() and waits for an interrupt + Serial.println(F("Woke up!")); // the interrupt callback hits before this is executed +} + +// 6th test - Deep Sleep for 10 seconds, wake with RF_DEFAULT +void runTest6() { + Serial.println(F("\n6th test - Deep Sleep for 10 seconds, reset and wake with RF_DEFAULT")); + initWiFi(); // initialize WiFi since we turned it off in the last test + resetCount = 1; // advance to the next Deep Sleep test after the reset + updateRTC(); // save the current test state in RTC memory + float volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); + Serial.println(F("press the button to continue")); + while (!digitalRead(WAKE_UP_PIN)) { // wait for them to release the button from the last test delay(10); - // if you do ESP.deepSleep(0, mode); it needs a RESET to come out of sleep (RTC is off) - // maximum timed Deep Sleep interval = 71.58 minutes with 0xFFFFFFFF - // the 2 uA GPIO amperage during Deep Sleep can't drive the LED so it's not lit now, although - // depending on the LED used, you might see it very dimly lit in a dark room during this test - Serial.println(F("What... I'm not asleep?!?")); // it will never get here } + delay(50); // debounce time for the switch, button released + waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep + digitalWrite(LED, LOW); // turn the LED on, at least briefly + //WiFi.mode(WIFI_SHUTDOWN); // Forced Modem Sleep for a more Instant Deep Sleep, and no long + // RFCAL as it goes into Deep Sleep + Serial.println(F("going into Deep Sleep now...")); + Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message +#ifdef testPoint + digitalWrite(testPoint, HIGH); // testPoint set HIGH to track Deep Sleep period, cleared at startup() +#endif + ESP.deepSleep(10E6, WAKE_RF_DEFAULT); // good night! D0 fires a reset in 10 seconds... + delay(10); + // if you do ESP.deepSleep(0, mode); it needs a RESET to come out of sleep (RTC is off) + // maximum timed Deep Sleep interval = 71.58 minutes with 0xFFFFFFFF + // the 2 uA GPIO amperage during Deep Sleep can't drive the LED so it's not lit now, although + // depending on the LED used, you might see it very dimly lit in a dark room during this test + Serial.println(F("What... I'm not asleep?!?")); // it will never get here +} - // 7th test - Deep Sleep for 10 seconds, wake with RFCAL - if (resetCount < 4) { - init_WiFi(); // need to reinitialize WiFi due to Deep Sleep reset - } - if (resetCount == 1) { // second reset since power on - resetCount = 2; // advance to the next Deep Sleep test after the reset - updateRTC(); // save the current test state in RTC memory - Serial.println(F("\n7th test - in RF_DEFAULT, Deep Sleep for 10 seconds, reset and wake with RFCAL")); - float volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); - Serial.println(F("press the button to continue")); - waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep - //WiFi.mode(WIFI_SHUTDOWN); // Forced Modem Sleep for a more Instant Deep Sleep, and no RFCAL - // as it goes into Deep Sleep - Serial.println(F("going into Deep Sleep now...")); - Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message +// 7th test - Deep Sleep for 10 seconds, wake with RFCAL +void runTest7() { + resetCount = 2; // advance to the next Deep Sleep test after the reset + updateRTC(); // save the current test state in RTC memory + Serial.println(F("\n7th test - in RF_DEFAULT, Deep Sleep for 10 seconds, reset and wake with RFCAL")); + float volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); + Serial.println(F("press the button to continue")); + waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep + //WiFi.mode(WIFI_SHUTDOWN); // Forced Modem Sleep for a more Instant Deep Sleep, and no RFCAL + // as it goes into Deep Sleep + Serial.println(F("going into Deep Sleep now...")); + Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message #ifdef testPoint - digitalWrite(testPoint, HIGH); // testPoint set HIGH to track Deep Sleep period, cleared at startup() + digitalWrite(testPoint, HIGH); // testPoint set HIGH to track Deep Sleep period, cleared at startup() #endif - ESP.deepSleep(10E6, WAKE_RFCAL); // good night! D0 fires a reset in 10 seconds... - delay(10); - Serial.println(F("What... I'm not asleep?!?")); // it will never get here - } + ESP.deepSleep(10E6, WAKE_RFCAL); // good night! D0 fires a reset in 10 seconds... + delay(10); + Serial.println(F("What... I'm not asleep?!?")); // it will never get here +} - // 8th test - Deep Sleep Instant for 10 seconds, wake with NO_RFCAL - if (resetCount == 2) { // third reset since power on - resetCount = 3; // advance to the next Deep Sleep test after the reset - updateRTC(); // save the current test state in RTC memory - Serial.println(F("\n8th test - in RFCAL, Deep Sleep Instant for 10 seconds, reset and wake with NO_RFCAL")); - float volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); - Serial.println(F("press the button to continue")); - waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep - //WiFi.mode(WIFI_SHUTDOWN); // Forced Modem Sleep for a more Instant Deep Sleep, and no RFCAL - // as it goes into Deep Sleep - Serial.println(F("going into Deep Sleep now...")); - Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message +// 8th test - Deep Sleep Instant for 10 seconds, wake with NO_RFCAL +void runTest8() { + resetCount = 3; // advance to the next Deep Sleep test after the reset + updateRTC(); // save the current test state in RTC memory + Serial.println(F("\n8th test - in RFCAL, Deep Sleep Instant for 10 seconds, reset and wake with NO_RFCAL")); + float volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); + Serial.println(F("press the button to continue")); + waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep + //WiFi.mode(WIFI_SHUTDOWN); // Forced Modem Sleep for a more Instant Deep Sleep, and no RFCAL + // as it goes into Deep Sleep + Serial.println(F("going into Deep Sleep now...")); + Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message #ifdef testPoint - digitalWrite(testPoint, HIGH); // testPoint set HIGH to track Deep Sleep period, cleared at startup() + digitalWrite(testPoint, HIGH); // testPoint set HIGH to track Deep Sleep period, cleared at startup() #endif - ESP.deepSleepInstant(10E6, WAKE_NO_RFCAL); // good night! D0 fires a reset in 10 seconds... - delay(10); - Serial.println(F("What... I'm not asleep?!?")); // it will never get here - } + ESP.deepSleepInstant(10E6, WAKE_NO_RFCAL); // good night! D0 fires a reset in 10 seconds... + delay(10); + Serial.println(F("What... I'm not asleep?!?")); // it will never get here +} - // 9th test - Deep Sleep Instant for 10 seconds, wake with RF_DISABLED - if (resetCount == 3) { // fourth reset since power on - resetCount = 4; // advance to the next Deep Sleep test after the reset - updateRTC(); // save the current test state in RTC memory - Serial.println(F("\n9th test - in NO_RFCAL, Deep Sleep Instant for 10 seconds, reset and wake with RF_DISABLED")); - float volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); - Serial.println(F("press the button to continue")); - waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep - // WiFi.mode(WIFI_SHUTDOWN); // Forced Modem Sleep for a more Instant Deep Sleep - Serial.println(F("going into Deep Sleep now...")); - Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message +// 9th test - Deep Sleep Instant for 10 seconds, wake with RF_DISABLED +void runTest9() { + resetCount = 4; // advance to the next Deep Sleep test after the reset + updateRTC(); // save the current test state in RTC memory + Serial.println(F("\n9th test - in NO_RFCAL, Deep Sleep Instant for 10 seconds, reset and wake with RF_DISABLED")); + float volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); + Serial.println(F("press the button to continue")); + waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep + // WiFi.mode(WIFI_SHUTDOWN); // Forced Modem Sleep for a more Instant Deep Sleep + Serial.println(F("going into Deep Sleep now...")); + Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message #ifdef testPoint - digitalWrite(testPoint, HIGH); // testPoint set HIGH to track Deep Sleep period, cleared at startup() + digitalWrite(testPoint, HIGH); // testPoint set HIGH to track Deep Sleep period, cleared at startup() #endif - ESP.deepSleepInstant(10E6, WAKE_RF_DISABLED); // good night! D0 fires a reset in 10 seconds... - delay(10); - Serial.println(F("What... I'm not asleep?!?")); // it will never get here - } + ESP.deepSleepInstant(10E6, WAKE_RF_DISABLED); // good night! D0 fires a reset in 10 seconds... + delay(10); + Serial.println(F("What... I'm not asleep?!?")); // it will never get here +} - if (resetCount == 4) { - resetCount = 5; // start all over, do an ESP.restart to insure it's a clean state - updateRTC(); // save the current test state in RTC memory - float volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); - Serial.println(F("\nTests completed, in RF_DISABLED, press the button to do an ESP.restart()")); - waitPushbutton(false, 1000); - ESP.restart(); - } +void resetTests() { + resetCount = 5; // start all over: do ESP.restart to insure a clean state since Deep Sleep doesn't clear everything + updateRTC(); // save the current test state in RTC memory + float volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); + Serial.println(F("\nTests completed, in RF_DISABLED, press the button to do an ESP.restart()")); + waitPushbutton(false, 1000); + ESP.restart(); } + void waitPushbutton(bool usesDelay, unsigned int delayTime) { // loop until they press the button // note: 2 different modes, as 3 of the power saving modes need a delay() to activate fully if (!usesDelay) { // quick interception of button press, no delay() used @@ -352,7 +381,7 @@ void updateRTC() { ESP.rtcUserMemoryWrite(64, (uint32_t*) &rtcData, sizeof(rtcData)); } -void init_WiFi() { +void initWiFi() { /* Explicitly set the ESP8266 as a WiFi-client (STAtion mode), otherwise by default it would try to act as both a client and an access-point and could cause network issues with other WiFi devices on your network. */ From b93c2e39acf6f7467e34c5fff35790601cfff4e4 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Thu, 16 Jan 2020 20:07:45 -0600 Subject: [PATCH 25/51] add Low-Power demo --- libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index ca38ea3dc2..e8d254bf53 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -83,7 +83,7 @@ byte resetCount = 0; // keeps track of the number of Deep Sleep tests / resets const uint32_t blinkDelay = 100; // fast blink rate for the LED when waiting for the user const uint32_t longDelay = 350; // longer delay() for the two AUTOMATIC modes esp8266::polledTimeout::periodicMs blinkLED(blinkDelay); -esp8266::polledTimeout::oneShotFastMs altDelay(blinkDelay); +esp8266::polledTimeout::oneShotFastMs altDelay(blinkDelay); // tight spin to simulate user code // use fully qualified type and avoid importing all ::esp8266 namespace to the global namespace void wakeupCallback() { // unlike ISRs, you can do a print() from a callback function @@ -139,9 +139,9 @@ void loop() { } else if (resetCount == 2) { runTest8(); } else if (resetCount == 3) { - runTest9(); + runTest9(); } else if (resetCount == 4) { - resetTests(); + resetTests(); } } //end loop From f4d00c6b597b34fae88266ed3c33a27d2d2c6a06 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Fri, 17 Jan 2020 20:53:43 -0600 Subject: [PATCH 26/51] add Low-Power demo --- .../examples/LowPowerDemo/LowPowerDemo.ino | 41 +++++++++---------- .../esp8266/examples/LowPowerDemo/README.md | 4 +- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index e8d254bf53..bd3889e84f 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -51,7 +51,7 @@ // you can use any pin for WAKE_UP_PIN except for D0/GPIO16 as it doesn't support interrupts // uncomment one of the two lines below for your LED connection, if used -#define LED 5 // D1/GPIO5 external LED for modules with built-in LEDs so it doesn't add to the amperage +#define LED 5 // D1/GPIO5 external LED for modules with built-in LEDs so it doesn't add amperage //#define LED 2 // D4/GPIO2 LED for ESP-01,07 modules; D4 is LED_BUILTIN on most other modules // you can use LED_BUILTIN, but it adds to the measured amperage by 0.3mA to 6mA. @@ -59,8 +59,8 @@ ADC_MODE(ADC_VCC); // allows you to monitor the internal VCC level; it varies w // don't connect anything to the analog input pin(s)! // enter your WiFi configuration below -const char* AP_SSID = "SSID"; // your router's SSID here -const char* AP_PASS = "password"; // your router's password here +const char* AP_SSID = "tryagain"; // your router's SSID here +const char* AP_PASS = "093774c242ccb21a3485"; // your router's password here IPAddress staticIP(0, 0, 0, 0); // parameters below are for your static IP address, if used IPAddress gateway(0, 0, 0, 0); IPAddress subnet(0, 0, 0, 0); @@ -68,7 +68,7 @@ IPAddress dns1(0, 0, 0, 0); IPAddress dns2(0, 0, 0, 0); uint32_t wifiTimeout = 25E3; // 25 second timeout on the WiFi connection -//#define testPoint 4 // D2/GPIO4 used to track the timing of several test cycles, entirely optional +#define testPoint 4 // D2/GPIO4 used to track the timing of several test cycles, entirely optional // This structure will be stored in RTC memory to remember the reset count (number of Deep Sleeps). // First field is CRC32, which is calculated based on the rest of the structure contents. @@ -81,7 +81,6 @@ struct { byte resetCount = 0; // keeps track of the number of Deep Sleep tests / resets const uint32_t blinkDelay = 100; // fast blink rate for the LED when waiting for the user -const uint32_t longDelay = 350; // longer delay() for the two AUTOMATIC modes esp8266::polledTimeout::periodicMs blinkLED(blinkDelay); esp8266::polledTimeout::oneShotFastMs altDelay(blinkDelay); // tight spin to simulate user code // use fully qualified type and avoid importing all ::esp8266 namespace to the global namespace @@ -96,7 +95,7 @@ void wakeupCallback() { // unlike ISRs, you can do a print() from a callback fu void setup() { #ifdef testPoint pinMode(testPoint, OUTPUT); // test point for Forced Light Sleep and Deep Sleep tests - digitalWrite(testPoint, LOW); // Deep Sleep reset doesn't clear GPIOs, testPoint falling shows boot time + digitalWrite(testPoint, LOW); // Deep Sleep reset doesn't clear GPIOs, testPoint LOW shows boot time #endif pinMode(LED, OUTPUT); // activity and status indicator digitalWrite(LED, LOW); // turn on the LED @@ -123,13 +122,13 @@ void setup() { } // end of setup() void loop() { - if (resetCount == 0) { + if (resetCount == 0) { // if first loop() since power on or external reset runTest1(); runTest2(); runTest3(); runTest4(); runTest5(); - runTest6(); + runTest6(); // first Deep Sleep test, all these end with a RESET } if (resetCount < 4) { initWiFi(); @@ -143,7 +142,7 @@ void loop() { } else if (resetCount == 4) { resetTests(); } -} //end loop +} //end of loop() // 1st test - running with WiFi unconfigured, reads ~67 mA minimum void runTest1() { @@ -165,12 +164,12 @@ void runTest2() { Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("press the button to continue")); waitPushbutton(true, 90); /* This is using a special feature: below 100 mS blink delay, - the LED blink delay is padding the time with 'program cycles' to fill the 100 mS. At 90 mS - delay, 90% of the blink time is delay(), and 10% is 'your program running'. Below 90% you - will see a difference in the average amperage, less delay() = more amperage. At 100 mS - and above it's essentially all delay() time. On an oscilloscope you'll see the time - between beacons at > 67 mA more often with less delay() percentage. You can change the - '90' mS to other values to see the effect it has on Automatic Modem Sleep. */ + the LED blink delay is padding 100 mS time with 'program cycles' to fill the 100 mS. + At 90 mS delay, 90% of the blink time is delay(), and 10% is 'your program running'. + Below 90% you'll see a difference in the average amperage: less delay() = more amperage. + At 100 mS and above it's essentially all delay() time. On an oscilloscope you'll see the + time between beacons at > 67 mA more often with less delay() percentage. You can change + the '90' mS to other values to see the effect it has on Automatic Modem Sleep. */ } else { Serial.println(F("no WiFi connection, test skipped")); } @@ -195,7 +194,7 @@ void runTest3() { void runTest4() { Serial.println(F("\n4th test - Automatic Light Sleep")); Serial.println(F("reconnecting WiFi")); - Serial.println(F("it will be in Automatic Light Sleep once WiFi connects (LED blinks)")); + Serial.println(F("it will be in Automatic Light Sleep when WiFi connects (LED blinks)")); digitalWrite(LED, LOW); // visual cue that we're reconnecting WiFi.setSleepMode(WIFI_LIGHT_SLEEP, 5); // Automatic Light Sleep WiFi.forceSleepWake(); // reconnect with previous STA mode and connection settings @@ -222,7 +221,8 @@ void runTest5() { yield(); digitalWrite(LED, HIGH); // turn the LED off so they know the CPU isn't running #ifdef testPoint - digitalWrite(testPoint, HIGH); // testPoint LOW in callback tracks latency from WAKE_UP_PIN LOW to testPoint LOW + digitalWrite(testPoint, HIGH); + // testPoint LOW in callback tracks latency from WAKE_UP_PIN LOW to testPoint LOW #endif float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); @@ -261,7 +261,6 @@ void runTest6() { digitalWrite(testPoint, HIGH); // testPoint set HIGH to track Deep Sleep period, cleared at startup() #endif ESP.deepSleep(10E6, WAKE_RF_DEFAULT); // good night! D0 fires a reset in 10 seconds... - delay(10); // if you do ESP.deepSleep(0, mode); it needs a RESET to come out of sleep (RTC is off) // maximum timed Deep Sleep interval = 71.58 minutes with 0xFFFFFFFF // the 2 uA GPIO amperage during Deep Sleep can't drive the LED so it's not lit now, although @@ -286,7 +285,6 @@ void runTest7() { digitalWrite(testPoint, HIGH); // testPoint set HIGH to track Deep Sleep period, cleared at startup() #endif ESP.deepSleep(10E6, WAKE_RFCAL); // good night! D0 fires a reset in 10 seconds... - delay(10); Serial.println(F("What... I'm not asleep?!?")); // it will never get here } @@ -307,7 +305,6 @@ void runTest8() { digitalWrite(testPoint, HIGH); // testPoint set HIGH to track Deep Sleep period, cleared at startup() #endif ESP.deepSleepInstant(10E6, WAKE_NO_RFCAL); // good night! D0 fires a reset in 10 seconds... - delay(10); Serial.println(F("What... I'm not asleep?!?")); // it will never get here } @@ -327,12 +324,12 @@ void runTest9() { digitalWrite(testPoint, HIGH); // testPoint set HIGH to track Deep Sleep period, cleared at startup() #endif ESP.deepSleepInstant(10E6, WAKE_RF_DISABLED); // good night! D0 fires a reset in 10 seconds... - delay(10); Serial.println(F("What... I'm not asleep?!?")); // it will never get here } void resetTests() { - resetCount = 5; // start all over: do ESP.restart to insure a clean state since Deep Sleep doesn't clear everything + resetCount = 5; // start all over: do ESP.restart to insure a clean starting state + // updateRTC(); // save the current test state in RTC memory float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md index c24feca551..c3ee2f96bd 100644 --- a/libraries/esp8266/examples/LowPowerDemo/README.md +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -66,13 +66,13 @@ Similar to Deep Sleep, but without the timer. The chip sleeps at 0.4 mA amperag ### Test 6 - Deep Sleep, wake with RF_DEFAULT -In Deep Sleep almost everything is turned off, and the chip draws ~ 20 uA. If you have D0/GPIO16 connected to RST, you can use the RTC timer to wake the chip up at a timed interval. You can also wake it with an external RESET. Waking with RF_DEFAULT means it will do an RFCAL if it needs to. Doing **ESP.deepSleep(time)** without the mode variable uses this wake mode. These first two Deep Sleep tests use the standard Deep Sleep function, so the WiFi connection is closed and the modem turned off, which takes up to 270 mS before Deep Sleep begins. Deep Sleep ends with a RESET, and the boot time after that is ~ 130 mS. Any Deep Sleep less than ~ 2 seconds is wasting energy due to the modem shut-off and boot times, and Forced Light Sleep will be a better choice as it recovers in ~ 5 mS from the previous state. The Deep Sleep tests will not go into Automatic Modem Sleep because delay() is not used. +In Deep Sleep almost everything is turned off, and the chip draws ~ 20 uA. If you have D0/GPIO16 connected to RST, you can use the RTC timer to wake the chip up at a timed interval. You can also wake it with an external RESET. Waking with RF_DEFAULT means it will do an RFCAL if it needs to. Doing **ESP.deepSleep(time)** without the mode variable uses this wake mode. These first two Deep Sleep tests use the standard Deep Sleep function, so the WiFi connection is closed and the modem turned off, which takes up to 270 mS before Deep Sleep begins. Deep Sleep ends with a RESET, and the boot time after that is ~ 130 mS. Any Deep Sleep less than ~ 2 seconds is wasting energy due to the modem shut-off and boot times, and Forced Light Sleep will be a better choice as it recovers in ~ 5 mS from the previous program state. The Deep Sleep tests will not go into Automatic Modem Sleep because delay() is not used. Note that a RESET during Deep Sleep (either external or from D0/GPIO16) does not clear the GPIO pins; they hold their previous state. It's unknown how much else survives a Deep Sleep reset, as it's not documented. ### Test 7 - Deep Sleep, wake with RFCAL -Identical to the test above, but the modem does an RF power calibration when booting. In normal use, most people would do WAKE_RF_DEFAULT instead to avoid the extra RFCAL power burst if it's not needed. +Identical to the test above, but the modem always does an RF power calibration when booting. In normal use, most people would do WAKE_RF_DEFAULT instead to avoid the extra RFCAL power burst coming out of Deep Sleep if it's not needed. Note that most of the time both of these modes (WAKE_RF_DEFAULT and WAKE_RFCAL) do a 100 mS long RFCAL *before* going into Deep Sleep (the RFCAL after Deep Sleep is much shorter). If the modem is shut down, this long RFCAL doesn't happen. ### Test 8 - Deep Sleep Instant, wake with NO_RFCAL From 841fa1b9e89bb206990323e007921f0a17bf77db Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Sat, 18 Jan 2020 12:36:11 -0600 Subject: [PATCH 27/51] add Low-Power demo --- .../examples/LowPowerDemo/LowPowerDemo.ino | 48 ++++++++++++------- .../esp8266/examples/LowPowerDemo/README.md | 4 +- 2 files changed, 33 insertions(+), 19 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index bd3889e84f..6feba7dfb2 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -59,18 +59,18 @@ ADC_MODE(ADC_VCC); // allows you to monitor the internal VCC level; it varies w // don't connect anything to the analog input pin(s)! // enter your WiFi configuration below -const char* AP_SSID = "tryagain"; // your router's SSID here -const char* AP_PASS = "093774c242ccb21a3485"; // your router's password here +const char* AP_SSID = "your_SSID"; // your router's SSID here +const char* AP_PASS = "your_password"; // your router's password here IPAddress staticIP(0, 0, 0, 0); // parameters below are for your static IP address, if used IPAddress gateway(0, 0, 0, 0); IPAddress subnet(0, 0, 0, 0); IPAddress dns1(0, 0, 0, 0); IPAddress dns2(0, 0, 0, 0); -uint32_t wifiTimeout = 25E3; // 25 second timeout on the WiFi connection +uint32_t wifiTimeout = 30E3; // 30 second timeout on the WiFi connection -#define testPoint 4 // D2/GPIO4 used to track the timing of several test cycles, entirely optional +//#define testPoint 4 // D2/GPIO4 used to track the timing of several test cycles, optional -// This structure will be stored in RTC memory to remember the reset count (number of Deep Sleeps). +// This structure is stored in RTC memory to remember the reset count (number of Deep Sleeps). // First field is CRC32, which is calculated based on the rest of the structure contents. // Any fields can go after the CRC32. The structure must be 4-byte aligned. struct { @@ -89,6 +89,8 @@ void wakeupCallback() { // unlike ISRs, you can do a print() from a callback fu #ifdef testPoint digitalWrite(testPoint, LOW); // testPoint tracks latency from WAKE_UP_PIN LOW to testPoint LOW #endif + Serial.print(F("millis() = ")); // show that RTC / millis() is slowed in Forced Light Sleep + Serial.println(millis()); Serial.println(F("Woke from Forced Light Sleep - this is the callback")); } @@ -119,6 +121,10 @@ void setup() { resetCount = rtcData.data[3]; // read the previous reset count } } + if (resetCount == 1) { // show that millis() is cleared across Deep Sleep reset + Serial.print(F("millis() = ")); + Serial.println(millis()); + } } // end of setup() void loop() { @@ -128,7 +134,7 @@ void loop() { runTest3(); runTest4(); runTest5(); - runTest6(); // first Deep Sleep test, all these end with a RESET + runTest6(); // first Deep Sleep test, all of these end with a RESET } if (resetCount < 4) { initWiFi(); @@ -200,7 +206,7 @@ void runTest4() { WiFi.forceSleepWake(); // reconnect with previous STA mode and connection settings uint32_t wifiStart = millis(); while ((!WiFi.localIP()) && (millis() - wifiStart < wifiTimeout)) { - delay(50); + yield(); } if (WiFi.localIP()) { // won't go into Automatic Sleep without an active WiFi connection float volts = ESP.getVcc(); @@ -221,12 +227,14 @@ void runTest5() { yield(); digitalWrite(LED, HIGH); // turn the LED off so they know the CPU isn't running #ifdef testPoint - digitalWrite(testPoint, HIGH); + digitalWrite(testPoint, HIGH); // testPoint LOW in callback tracks latency from WAKE_UP_PIN LOW to testPoint LOW #endif float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("CPU going to sleep, pull WAKE_UP_PIN low to wake it (press the button)")); + Serial.print(F("millis() = ")); + Serial.println(millis()); Serial.flush(); // needs a delay(100) or Serial.flush() else it doesn't print the whole message wifi_fpm_set_sleep_type(LIGHT_SLEEP_T); gpio_pin_wakeup_enable(GPIO_ID_PIN(WAKE_UP_PIN), GPIO_PIN_INTR_LOLEVEL); @@ -256,6 +264,8 @@ void runTest6() { //WiFi.mode(WIFI_SHUTDOWN); // Forced Modem Sleep for a more Instant Deep Sleep, and no long // RFCAL as it goes into Deep Sleep Serial.println(F("going into Deep Sleep now...")); + Serial.print(F("millis() = ")); + Serial.println(millis()); Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message #ifdef testPoint digitalWrite(testPoint, HIGH); // testPoint set HIGH to track Deep Sleep period, cleared at startup() @@ -329,7 +339,7 @@ void runTest9() { void resetTests() { resetCount = 5; // start all over: do ESP.restart to insure a clean starting state - // + // updateRTC(); // save the current test state in RTC memory float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); @@ -338,7 +348,6 @@ void resetTests() { ESP.restart(); } - void waitPushbutton(bool usesDelay, unsigned int delayTime) { // loop until they press the button // note: 2 different modes, as 3 of the power saving modes need a delay() to activate fully if (!usesDelay) { // quick interception of button press, no delay() used @@ -393,19 +402,24 @@ void initWiFi() { DEBUG_PRINTLN(WiFi.macAddress()); uint32_t wifiStart = millis(); while ((WiFi.status() != WL_CONNECTED) && (millis() - wifiStart < wifiTimeout)) { - delay(50); + yield(); } if (WiFi.status() == WL_CONNECTED) { DEBUG_PRINTLN(F("WiFi connected")); } else { Serial.println(F("WiFi timed out and didn't connect")); } - while (!WiFi.localIP() && (WiFi.status() == WL_CONNECTED)) { - delay(50); + wifiStart = millis(); + while ((!WiFi.localIP() && (WiFi.status() == WL_CONNECTED)) && (millis() - wifiStart < wifiTimeout)) { + yield(); } WiFi.setAutoReconnect(true); - DEBUG_PRINT(F("WiFi Gateway IP: ")); - DEBUG_PRINTLN(WiFi.gatewayIP()); - DEBUG_PRINT(F("my IP address: ")); - DEBUG_PRINTLN(WiFi.localIP()); + if (WiFi.localIP()) { + DEBUG_PRINT(F("WiFi Gateway IP: ")); + DEBUG_PRINTLN(WiFi.gatewayIP()); + DEBUG_PRINT(F("my IP address: ")); + DEBUG_PRINTLN(WiFi.localIP()); + } else { + DEBUG_PRINTLN(F("IP addresses not acquired")); + } } diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md index c3ee2f96bd..0a8af7e5b9 100644 --- a/libraries/esp8266/examples/LowPowerDemo/README.md +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -58,11 +58,11 @@ Turns off the modem (losing the connection), and reducing the amperage by > 50 m ### Test 4 - Automatic Light Sleep -Like Automatic Modem Sleep, with similar restrictions. Once configured it's immediately active when a connection is established. During periods of long delay() the amperage can drop to ~ 3 mA average. In a network with sparse traffic you might get something near 2-5 mA amperage. The LED blinks more slowly during this test as it's doing delay(350) to get the modem to sleep. With delay() times shorter than the DTIM beacon interval (100 mS beacons for these tests) the modem only goes into Automatic Modem Sleep, and with a longer delay() it will go more fully into Automatic Light Sleep. +Like Automatic Modem Sleep, with similar restrictions. Once configured it's immediately active when a connection is established. During periods of long delay() the amperage can drop to ~ 3 mA average. In a network with sparse traffic you might get something near 2-5 mA amperage. The LED blinks more slowly during this test as it's doing delay(350) to get the modem to sleep. With delay() times shorter than the DTIM beacon interval (100 mS beacons for these tests) the modem only goes into Automatic Modem Sleep, and with a longer delay() it will go more fully into Automatic Light Sleep. Although the CPU clock is cycling on and off to achieve low power, the RTC is still running so millis() and micros() are correct. ### Test 5 - Forced Light Sleep -Similar to Deep Sleep, but without the timer. The chip sleeps at 0.4 mA amperage until it is woken by an external interrupt. The only allowed interrupts are high level and low level; edge interrupts won't work. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using Forced Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 5 to 5.5 mS (regardless of CPU speed), but WiFi was turned off to enter Forced Light Sleep so you will need to re-initialize it if you are using WiFi. +Similar to Deep Sleep, but without the timer. The chip sleeps at 0.4 mA amperage until it is woken by an external interrupt. The only allowed interrupts are high level and low level; edge interrupts won't work. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using Forced Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 5 to 5.5 mS (regardless of CPU speed), but WiFi was turned off to enter Forced Light Sleep so you will need to re-initialize it if you are using WiFi. The RTC is slowed so millis() and micros() are also slowed during Forced Light Sleep. ### Test 6 - Deep Sleep, wake with RF_DEFAULT From ebc2b0a836dbbb4cc891b6bb9734d5ede55b5cfc Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Tue, 21 Jan 2020 19:09:35 -0600 Subject: [PATCH 28/51] add Low-Power demo --- .../examples/LowPowerDemo/LowPowerDemo.ino | 70 ++++++++++--------- .../esp8266/examples/LowPowerDemo/README.md | 10 +-- 2 files changed, 42 insertions(+), 38 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index 6feba7dfb2..afb1cd9b72 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -59,8 +59,8 @@ ADC_MODE(ADC_VCC); // allows you to monitor the internal VCC level; it varies w // don't connect anything to the analog input pin(s)! // enter your WiFi configuration below -const char* AP_SSID = "your_SSID"; // your router's SSID here -const char* AP_PASS = "your_password"; // your router's password here +const char* AP_SSID = "SSID"; // your router's SSID here +const char* AP_PASS = "password"; // your router's password here IPAddress staticIP(0, 0, 0, 0); // parameters below are for your static IP address, if used IPAddress gateway(0, 0, 0, 0); IPAddress subnet(0, 0, 0, 0); @@ -81,16 +81,16 @@ struct { byte resetCount = 0; // keeps track of the number of Deep Sleep tests / resets const uint32_t blinkDelay = 100; // fast blink rate for the LED when waiting for the user -esp8266::polledTimeout::periodicMs blinkLED(blinkDelay); -esp8266::polledTimeout::oneShotFastMs altDelay(blinkDelay); // tight spin to simulate user code +esp8266::polledTimeout::periodicMs blinkLED(blinkDelay); // LED blink delay without delay() +esp8266::polledTimeout::oneShotFastMs altDelay(blinkDelay); // tight loop to simulate user code // use fully qualified type and avoid importing all ::esp8266 namespace to the global namespace void wakeupCallback() { // unlike ISRs, you can do a print() from a callback function #ifdef testPoint digitalWrite(testPoint, LOW); // testPoint tracks latency from WAKE_UP_PIN LOW to testPoint LOW #endif - Serial.print(F("millis() = ")); // show that RTC / millis() is slowed in Forced Light Sleep - Serial.println(millis()); + Serial.print(F("millis() = ")); // show that RTC / millis() is stopped in Forced Light Sleep + Serial.println(millis()); // although the CPU may run for up to 800 mS before fully stopping Serial.println(F("Woke from Forced Light Sleep - this is the callback")); } @@ -121,7 +121,7 @@ void setup() { resetCount = rtcData.data[3]; // read the previous reset count } } - if (resetCount == 1) { // show that millis() is cleared across Deep Sleep reset + if (resetCount == 1) { // show that millis() is cleared across Deep Sleep reset Serial.print(F("millis() = ")); Serial.println(millis()); } @@ -134,7 +134,7 @@ void loop() { runTest3(); runTest4(); runTest5(); - runTest6(); // first Deep Sleep test, all of these end with a RESET + runTest6(); // first Deep Sleep test, all these end with a RESET } if (resetCount < 4) { initWiFi(); @@ -155,7 +155,7 @@ void runTest1() { Serial.println(F("\n1st test - running with WiFi unconfigured")); float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); - Serial.println(F("press the button to continue")); + Serial.println(F("press the switch to continue")); waitPushbutton(false, blinkDelay); } @@ -168,7 +168,7 @@ void runTest2() { Serial.println(F("The amperage will drop in 7 seconds.")); float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); - Serial.println(F("press the button to continue")); + Serial.println(F("press the switch to continue")); waitPushbutton(true, 90); /* This is using a special feature: below 100 mS blink delay, the LED blink delay is padding 100 mS time with 'program cycles' to fill the 100 mS. At 90 mS delay, 90% of the blink time is delay(), and 10% is 'your program running'. @@ -189,7 +189,7 @@ void runTest3() { // WiFi.mode(WIFI_SHUTDOWN); // alternate method of Forced Modem Sleep float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); - Serial.println(F("press the button to continue")); + Serial.println(F("press the switch to continue")); waitPushbutton(true, 99); /* Using the same < 100 mS feature. If you drop the delay below 100, you will see the effect of program time vs. delay() time on minimum amperage. Above ~ 97 (97% of the time in delay) there is little change in amperage, so you need to spend maximum time in delay() @@ -202,7 +202,9 @@ void runTest4() { Serial.println(F("reconnecting WiFi")); Serial.println(F("it will be in Automatic Light Sleep when WiFi connects (LED blinks)")); digitalWrite(LED, LOW); // visual cue that we're reconnecting - WiFi.setSleepMode(WIFI_LIGHT_SLEEP, 5); // Automatic Light Sleep + WiFi.setOutputPower(5); // lower RF output power to 1/4th the default, increase if it won't connect + WiFi.setSleepMode(WIFI_LIGHT_SLEEP, 3); // Automatic Light Sleep, DTIM listen interval = 3 + // at higher beacon intervals you'll have a hard time establishing and maintaining a connection WiFi.forceSleepWake(); // reconnect with previous STA mode and connection settings uint32_t wifiStart = millis(); while ((!WiFi.localIP()) && (millis() - wifiStart < wifiTimeout)) { @@ -211,9 +213,9 @@ void runTest4() { if (WiFi.localIP()) { // won't go into Automatic Sleep without an active WiFi connection float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); - Serial.println(F("press the button to continue")); + Serial.println(F("long press of the switch to continue")); waitPushbutton(true, 350); /* Below 100 mS delay it only goes into 'Automatic Modem Sleep', - and below ~ 350 mS delay() the 'Automatic Light Sleep' is less frequent. Above 350 mS + and below ~ 350 mS delay() the 'Automatic Light Sleep' is less frequent. Above 500 mS delay() doesn't make much improvement in power savings. */ } else { Serial.println(F("no WiFi connection, test skipped")); @@ -223,8 +225,9 @@ void runTest4() { // 5th test - Forced Light Sleep using Non-OS SDK calls void runTest5() { Serial.println(F("\n5th test - Forced Light Sleep using Non-OS SDK calls")); + Serial.flush(); WiFi.mode(WIFI_OFF); // you must turn the modem off; using disconnect won't work - yield(); + delay(10); digitalWrite(LED, HIGH); // turn the LED off so they know the CPU isn't running #ifdef testPoint digitalWrite(testPoint, HIGH); @@ -232,7 +235,7 @@ void runTest5() { #endif float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); - Serial.println(F("CPU going to sleep, pull WAKE_UP_PIN low to wake it (press the button)")); + Serial.println(F("CPU going to sleep, pull WAKE_UP_PIN low to wake it (press the switch)")); Serial.print(F("millis() = ")); Serial.println(millis()); Serial.flush(); // needs a delay(100) or Serial.flush() else it doesn't print the whole message @@ -254,11 +257,11 @@ void runTest6() { updateRTC(); // save the current test state in RTC memory float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); - Serial.println(F("press the button to continue")); - while (!digitalRead(WAKE_UP_PIN)) { // wait for them to release the button from the last test + Serial.println(F("press the switch to continue")); + while (!digitalRead(WAKE_UP_PIN)) { // wait for them to release the switch from the last test delay(10); } - delay(50); // debounce time for the switch, button released + delay(50); // debounce time for the switch, pushbutton released waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep digitalWrite(LED, LOW); // turn the LED on, at least briefly //WiFi.mode(WIFI_SHUTDOWN); // Forced Modem Sleep for a more Instant Deep Sleep, and no long @@ -285,7 +288,7 @@ void runTest7() { Serial.println(F("\n7th test - in RF_DEFAULT, Deep Sleep for 10 seconds, reset and wake with RFCAL")); float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); - Serial.println(F("press the button to continue")); + Serial.println(F("press the switch to continue")); waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep //WiFi.mode(WIFI_SHUTDOWN); // Forced Modem Sleep for a more Instant Deep Sleep, and no RFCAL // as it goes into Deep Sleep @@ -305,7 +308,7 @@ void runTest8() { Serial.println(F("\n8th test - in RFCAL, Deep Sleep Instant for 10 seconds, reset and wake with NO_RFCAL")); float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); - Serial.println(F("press the button to continue")); + Serial.println(F("press the switch to continue")); waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep //WiFi.mode(WIFI_SHUTDOWN); // Forced Modem Sleep for a more Instant Deep Sleep, and no RFCAL // as it goes into Deep Sleep @@ -325,7 +328,7 @@ void runTest9() { Serial.println(F("\n9th test - in NO_RFCAL, Deep Sleep Instant for 10 seconds, reset and wake with RF_DISABLED")); float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); - Serial.println(F("press the button to continue")); + Serial.println(F("press the switch to continue")); waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep // WiFi.mode(WIFI_SHUTDOWN); // Forced Modem Sleep for a more Instant Deep Sleep Serial.println(F("going into Deep Sleep now...")); @@ -343,23 +346,24 @@ void resetTests() { updateRTC(); // save the current test state in RTC memory float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); - Serial.println(F("\nTests completed, in RF_DISABLED, press the button to do an ESP.restart()")); + Serial.println(F("\nTests completed, in RF_DISABLED, press the switch to do an ESP.restart()")); waitPushbutton(false, 1000); ESP.restart(); } -void waitPushbutton(bool usesDelay, unsigned int delayTime) { // loop until they press the button + +void waitPushbutton(bool usesDelay, unsigned int delayTime) { // loop until they press the switch // note: 2 different modes, as 3 of the power saving modes need a delay() to activate fully - if (!usesDelay) { // quick interception of button press, no delay() used + if (!usesDelay) { // quick interception of pushbutton press, no delay() used blinkLED.reset(delayTime); - while (digitalRead(WAKE_UP_PIN)) { // wait for a button press + while (digitalRead(WAKE_UP_PIN)) { // wait for a pushbutton press if (blinkLED) { digitalWrite(LED, !digitalRead(LED)); // toggle the activity LED } yield(); // this would be a good place for ArduinoOTA.handle(); } - } else { // long delay() for the 3 modes that need it, but it misses quick button presses - while (digitalRead(WAKE_UP_PIN)) { // wait for a button press + } else { // long delay() for the 3 modes that need it, but it misses quick switch presses + while (digitalRead(WAKE_UP_PIN)) { // wait for a pushbutton press digitalWrite(LED, !digitalRead(LED)); // toggle the activity LED delay(delayTime); // another good place for ArduinoOTA.handle(); if (delayTime < 100) { @@ -369,11 +373,11 @@ void waitPushbutton(bool usesDelay, unsigned int delayTime) { // loop until the } } } - delay(50); // debounce time for the switch, button pressed - while (!digitalRead(WAKE_UP_PIN)) { // now wait for them to release the button + delay(50); // debounce time for the switch, pushbutton pressed + while (!digitalRead(WAKE_UP_PIN)) { // now wait for them to release the pushbutton delay(10); } - delay(50); // debounce time for the switch, button released + delay(50); // debounce time for the switch, pushbutton released } void updateRTC() { @@ -409,7 +413,7 @@ void initWiFi() { } else { Serial.println(F("WiFi timed out and didn't connect")); } - wifiStart = millis(); + wifiStart = millis(); // timeout if we don't get the IP addresses from DHCP while ((!WiFi.localIP() && (WiFi.status() == WL_CONNECTED)) && (millis() - wifiStart < wifiTimeout)) { yield(); } @@ -420,6 +424,6 @@ void initWiFi() { DEBUG_PRINT(F("my IP address: ")); DEBUG_PRINTLN(WiFi.localIP()); } else { - DEBUG_PRINTLN(F("IP addresses not acquired")); + DEBUG_PRINTLN(F("IP addresses not acquired from DHCP")); } } diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md index 0a8af7e5b9..d4213afd84 100644 --- a/libraries/esp8266/examples/LowPowerDemo/README.md +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -15,16 +15,16 @@ The table below is an expanded version of Table 1.1 from the Low-Power Solutions | System Clock | ON | ON | CYCLING | OFF | OFF | | RTC | ON | ON | ON | ON | ON (1) | | CPU | ON | ON | ON | ON | OFF | -| Substrate Amperage | 15 mA | 15 mA | 2-15 mA (2) | 0.4 mA | 20 uA | +| Substrate Amperage | 15 mA | 15 mA | 1-15 mA (2) | 0.4 mA | 20 uA | | Avg Amperage DTIM = 1 | 16.2 mA | | (1.8 mA) | | | | Avg Amperage DTIM = 3 | 15.4 mA | | (0.9 mA) | | | | Avg Amperage DTIM = 10 | 15.2 mA | | (0.55 mA) | | | Notes: -(1) setting a sleep time of 0 for Deep Sleep turns off or disconnects the RTC, requiring an external RESET to wake it +(1) setting a sleep time of 0 for Deep Sleep disconnects the RTC, requiring an external RESET to wake the CPU -(2) due to a bug in SDK 2, the minimum amperage will never be less than ~ 2 mA and is frequently 15 mA between DTIM beacons +(2) minimum amperage was never measured less than ~ 1 mA and is frequently 15 mA between DTIM beacons The Average Amperage with different DTIM settings is unverified, and will likely be higher in a real-world environment. All of the amperages listed in this README are for the ESP8266 chip only, compiled for 80 MHz CPU Frequency as 160 MHz uses even more power. Modules that have voltage regulators, USB chips, LEDs or other hardware will draw additional amperage. @@ -58,11 +58,11 @@ Turns off the modem (losing the connection), and reducing the amperage by > 50 m ### Test 4 - Automatic Light Sleep -Like Automatic Modem Sleep, with similar restrictions. Once configured it's immediately active when a connection is established. During periods of long delay() the amperage can drop to ~ 3 mA average. In a network with sparse traffic you might get something near 2-5 mA amperage. The LED blinks more slowly during this test as it's doing delay(350) to get the modem to sleep. With delay() times shorter than the DTIM beacon interval (100 mS beacons for these tests) the modem only goes into Automatic Modem Sleep, and with a longer delay() it will go more fully into Automatic Light Sleep. Although the CPU clock is cycling on and off to achieve low power, the RTC is still running so millis() and micros() are correct. +Like Automatic Modem Sleep, with similar restrictions. Once configured it's immediately active when a connection is established. During periods of long delay() the amperage can drop to ~ 2 mA average. In a network with sparse traffic you might get something near 2-5 mA amperage. The LED blinks more slowly during this test as it's doing delay(350) to get the modem to sleep. With delay() times shorter than the DTIM beacon interval (100 mS beacons for these tests) the modem only goes into Automatic Modem Sleep, and with a longer delay() it will go more fully into Automatic Light Sleep. Although the CPU clock is cycling on and off to achieve low power, millis() and micros() are correct. ### Test 5 - Forced Light Sleep -Similar to Deep Sleep, but without the timer. The chip sleeps at 0.4 mA amperage until it is woken by an external interrupt. The only allowed interrupts are high level and low level; edge interrupts won't work. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using Forced Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 5 to 5.5 mS (regardless of CPU speed), but WiFi was turned off to enter Forced Light Sleep so you will need to re-initialize it if you are using WiFi. The RTC is slowed so millis() and micros() are also slowed during Forced Light Sleep. +Similar to Deep Sleep, but without the timer. The chip sleeps at 0.4 mA amperage until it is woken by an external interrupt. The only allowed interrupts are high level and low level; edge interrupts won't work. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using Forced Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 3 to 5.5 mS (regardless of CPU speed), but WiFi was turned off to enter Forced Light Sleep so you will need to re-initialize it if you are using WiFi. Timers will keep the chip from going fully into Forced Light Sleep, and amperage will be ~ 2 mA with timers enabled. ### Test 6 - Deep Sleep, wake with RF_DEFAULT From 222b9e858ba7ef903776ec351b8c47bd5c6d680f Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Sat, 25 Jan 2020 15:44:43 -0600 Subject: [PATCH 29/51] add Low-Power demo --- .../examples/LowPowerDemo/LowPowerDemo.ino | 151 ++++++++++-------- .../esp8266/examples/LowPowerDemo/README.md | 12 +- 2 files changed, 86 insertions(+), 77 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index afb1cd9b72..3c751fb789 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -37,6 +37,8 @@ #include #include // crc32() #include +#include // WiFiState structure details + //#define DEBUG // prints WiFi connection info to serial, uncomment if you want WiFi messages #ifdef DEBUG @@ -48,7 +50,7 @@ #endif #define WAKE_UP_PIN 0 // D3/GPIO0, can also force a serial flash upload with RESET -// you can use any pin for WAKE_UP_PIN except for D0/GPIO16 as it doesn't support interrupts +// you can use any GPIO for WAKE_UP_PIN except for D0/GPIO16 as it doesn't support interrupts // uncomment one of the two lines below for your LED connection, if used #define LED 5 // D1/GPIO5 external LED for modules with built-in LEDs so it doesn't add amperage @@ -70,15 +72,21 @@ uint32_t wifiTimeout = 30E3; // 30 second timeout on the WiFi connection //#define testPoint 4 // D2/GPIO4 used to track the timing of several test cycles, optional -// This structure is stored in RTC memory to remember the reset count (number of Deep Sleeps). -// First field is CRC32, which is calculated based on the rest of the structure contents. -// Any fields can go after the CRC32. The structure must be 4-byte aligned. -struct { - uint32_t crc32; - byte data[4]; // the last byte stores the reset count -} rtcData; +// This structure is stored in RTC memory to save the WiFi state and reset count (number of Deep Sleeps), +// and it reconnects twice as fast as the first connection; it's used extensively in this demo +struct nv_s { + WiFiState wss; // core's WiFi save state + + struct { + uint32_t crc32; + uint32_t rstCount; // stores the Deep Sleep reset count + // you can add anything else here that you want to save + } rtcData; +}; + +static nv_s* nv = (nv_s*)RTC_USER_MEM; // user RTC RAM area -byte resetCount = 0; // keeps track of the number of Deep Sleep tests / resets +uint32_t resetCount = 0; // keeps track of the number of Deep Sleep tests / resets const uint32_t blinkDelay = 100; // fast blink rate for the LED when waiting for the user esp8266::polledTimeout::periodicMs blinkLED(blinkDelay); // LED blink delay without delay() @@ -89,11 +97,13 @@ void wakeupCallback() { // unlike ISRs, you can do a print() from a callback fu #ifdef testPoint digitalWrite(testPoint, LOW); // testPoint tracks latency from WAKE_UP_PIN LOW to testPoint LOW #endif - Serial.print(F("millis() = ")); // show that RTC / millis() is stopped in Forced Light Sleep - Serial.println(millis()); // although the CPU may run for up to 800 mS before fully stopping Serial.println(F("Woke from Forced Light Sleep - this is the callback")); } +void preinit() { + ESP8266WiFiClass::preinitWiFiOff(); // currently not working +} + void setup() { #ifdef testPoint pinMode(testPoint, OUTPUT); // test point for Forced Light Sleep and Deep Sleep tests @@ -106,21 +116,20 @@ void setup() { Serial.print(F("\nReset reason = ")); String resetCause = ESP.getResetReason(); Serial.println(resetCause); + resetCount = 0; if ((resetCause == "External System") || (resetCause == "Power on")) { Serial.println(F("I'm awake and starting the Low Power tests")); - resetCount = 5; - updateRTC(); // if external reset, wipe the RTC memory and start all over } - // Read struct from RTC memory - if (ESP.rtcUserMemoryRead(64, (uint32_t*) &rtcData, sizeof(rtcData))) { - uint32_t crcOfData = crc32((uint8_t*) &rtcData.data[0], sizeof(rtcData.data)); - if (crcOfData != rtcData.crc32) { // if the CRC is invalid - resetCount = 0; // set first test run since power on or external reset - } else { - resetCount = rtcData.data[3]; // read the previous reset count - } + // Read previous resets (Deep Sleeps) from RTC memory, if any + uint32_t crcOfData = crc32((uint8_t*) &nv->rtcData.rstCount, sizeof(nv->rtcData.rstCount)); + if ((crcOfData = nv->rtcData.crc32) && (resetCause == "Deep-Sleep Wake")) { + resetCount = nv->rtcData.rstCount; // read the previous reset count + resetCount++; } + nv->rtcData.rstCount = resetCount; // update the reset count & CRC + updateRTCcrc(); + if (resetCount == 1) { // show that millis() is cleared across Deep Sleep reset Serial.print(F("millis() = ")); Serial.println(millis()); @@ -137,7 +146,7 @@ void loop() { runTest6(); // first Deep Sleep test, all these end with a RESET } if (resetCount < 4) { - initWiFi(); + initWiFi(); // optional re-init of WiFi for the Deep Sleep tests } if (resetCount == 1) { runTest7(); @@ -184,9 +193,9 @@ void runTest2() { // 3rd test - Forced Modem Sleep void runTest3() { Serial.println(F("\n3rd test - Forced Modem Sleep")); - WiFi.forceSleepBegin(); - delay(10); // it doesn't always go to sleep unless you delay(10); yield() wasn't reliable - // WiFi.mode(WIFI_SHUTDOWN); // alternate method of Forced Modem Sleep + WiFi.mode(WIFI_SHUTDOWN, &nv->wss); // shut the modem down and save the WiFi state for faster reconnection + // WiFi.forceSleepBegin(delay_in_uS); // alternate method of Forced Modem Sleep if you want a timed shutdown + // delay(10); // it doesn't always go to sleep unless you delay(10); yield() wasn't reliable float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("press the switch to continue")); @@ -199,10 +208,10 @@ void runTest3() { // 4th test - Automatic Light Sleep void runTest4() { Serial.println(F("\n4th test - Automatic Light Sleep")); - Serial.println(F("reconnecting WiFi")); + Serial.println(F("reconnecting WiFi with forceSleepWake (slow)")); Serial.println(F("it will be in Automatic Light Sleep when WiFi connects (LED blinks)")); digitalWrite(LED, LOW); // visual cue that we're reconnecting - WiFi.setOutputPower(5); // lower RF output power to 1/4th the default, increase if it won't connect + // if you resume here and then set sleep mode, it takes 7 seconds to go into Automatic Modem Sleep WiFi.setSleepMode(WIFI_LIGHT_SLEEP, 3); // Automatic Light Sleep, DTIM listen interval = 3 // at higher beacon intervals you'll have a hard time establishing and maintaining a connection WiFi.forceSleepWake(); // reconnect with previous STA mode and connection settings @@ -246,26 +255,30 @@ void runTest5() { wifi_fpm_open(); wifi_fpm_do_sleep(0xFFFFFFF); // only 0xFFFFFFF works; any other value and it won't sleep delay(10); // it goes to sleep some time during this delay() and waits for an interrupt + Serial.print(F("millis() = ")); // show that CPU / millis() is stopped in Forced Light Sleep + Serial.println(millis()); // although the CPU may run for up to 1 second before fully stopping Serial.println(F("Woke up!")); // the interrupt callback hits before this is executed + /* Note: the Non-OS SDK API Reference says that you can do a timed Light Sleep, but due to + a bug any time delay greater than 13E3 uS will time-out and not execute the callback. + The example code in the Reference doesn't work, and the chip only goes into Modem Sleep, + not the lower-amperage Light Sleep. The only working alternative is a timed Modem Sleep. */ } // 6th test - Deep Sleep for 10 seconds, wake with RF_DEFAULT void runTest6() { Serial.println(F("\n6th test - Deep Sleep for 10 seconds, reset and wake with RF_DEFAULT")); initWiFi(); // initialize WiFi since we turned it off in the last test - resetCount = 1; // advance to the next Deep Sleep test after the reset - updateRTC(); // save the current test state in RTC memory float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("press the switch to continue")); - while (!digitalRead(WAKE_UP_PIN)) { // wait for them to release the switch from the last test + while (!digitalRead(WAKE_UP_PIN)) { // wait for them to release the switch from the previous test delay(10); } delay(50); // debounce time for the switch, pushbutton released waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep digitalWrite(LED, LOW); // turn the LED on, at least briefly - //WiFi.mode(WIFI_SHUTDOWN); // Forced Modem Sleep for a more Instant Deep Sleep, and no long - // RFCAL as it goes into Deep Sleep + //WiFi.mode(WIFI_SHUTDOWN, &nv->wss); // Forced Modem Sleep for a more Instant Deep Sleep, + // and no extended RFCAL as it goes into Deep Sleep Serial.println(F("going into Deep Sleep now...")); Serial.print(F("millis() = ")); Serial.println(millis()); @@ -274,7 +287,7 @@ void runTest6() { digitalWrite(testPoint, HIGH); // testPoint set HIGH to track Deep Sleep period, cleared at startup() #endif ESP.deepSleep(10E6, WAKE_RF_DEFAULT); // good night! D0 fires a reset in 10 seconds... - // if you do ESP.deepSleep(0, mode); it needs a RESET to come out of sleep (RTC is off) + // if you do ESP.deepSleep(0, mode); it needs a RESET to come out of sleep (RTC is disconnected) // maximum timed Deep Sleep interval = 71.58 minutes with 0xFFFFFFFF // the 2 uA GPIO amperage during Deep Sleep can't drive the LED so it's not lit now, although // depending on the LED used, you might see it very dimly lit in a dark room during this test @@ -283,15 +296,13 @@ void runTest6() { // 7th test - Deep Sleep for 10 seconds, wake with RFCAL void runTest7() { - resetCount = 2; // advance to the next Deep Sleep test after the reset - updateRTC(); // save the current test state in RTC memory Serial.println(F("\n7th test - in RF_DEFAULT, Deep Sleep for 10 seconds, reset and wake with RFCAL")); float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("press the switch to continue")); waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep - //WiFi.mode(WIFI_SHUTDOWN); // Forced Modem Sleep for a more Instant Deep Sleep, and no RFCAL - // as it goes into Deep Sleep + //WiFi.mode(WIFI_SHUTDOWN, &nv->wss); // Forced Modem Sleep for a more Instant Deep Sleep, + // and no extended RFCAL as it goes into Deep Sleep Serial.println(F("going into Deep Sleep now...")); Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message #ifdef testPoint @@ -303,15 +314,12 @@ void runTest7() { // 8th test - Deep Sleep Instant for 10 seconds, wake with NO_RFCAL void runTest8() { - resetCount = 3; // advance to the next Deep Sleep test after the reset - updateRTC(); // save the current test state in RTC memory Serial.println(F("\n8th test - in RFCAL, Deep Sleep Instant for 10 seconds, reset and wake with NO_RFCAL")); float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("press the switch to continue")); waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep - //WiFi.mode(WIFI_SHUTDOWN); // Forced Modem Sleep for a more Instant Deep Sleep, and no RFCAL - // as it goes into Deep Sleep + WiFi.mode(WIFI_SHUTDOWN, &nv->wss); // Forced Modem Sleep for a more Instant Deep Sleep Serial.println(F("going into Deep Sleep now...")); Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message #ifdef testPoint @@ -323,14 +331,12 @@ void runTest8() { // 9th test - Deep Sleep Instant for 10 seconds, wake with RF_DISABLED void runTest9() { - resetCount = 4; // advance to the next Deep Sleep test after the reset - updateRTC(); // save the current test state in RTC memory Serial.println(F("\n9th test - in NO_RFCAL, Deep Sleep Instant for 10 seconds, reset and wake with RF_DISABLED")); float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("press the switch to continue")); waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep - // WiFi.mode(WIFI_SHUTDOWN); // Forced Modem Sleep for a more Instant Deep Sleep + //WiFi.mode(WIFI_SHUTDOWN); // Forced Modem Sleep for a more Instant Deep Sleep Serial.println(F("going into Deep Sleep now...")); Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message #ifdef testPoint @@ -341,17 +347,14 @@ void runTest9() { } void resetTests() { - resetCount = 5; // start all over: do ESP.restart to insure a clean starting state - // - updateRTC(); // save the current test state in RTC memory float volts = ESP.getVcc(); Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); Serial.println(F("\nTests completed, in RF_DISABLED, press the switch to do an ESP.restart()")); + //memset(&nv->wss, 0, sizeof(nv->wss) * 2); // uncomment if you want to wipe the saved WiFi states waitPushbutton(false, 1000); ESP.restart(); } - void waitPushbutton(bool usesDelay, unsigned int delayTime) { // loop until they press the switch // note: 2 different modes, as 3 of the power saving modes need a delay() to activate fully if (!usesDelay) { // quick interception of pushbutton press, no delay() used @@ -380,30 +383,35 @@ void waitPushbutton(bool usesDelay, unsigned int delayTime) { // loop until the delay(50); // debounce time for the switch, pushbutton released } -void updateRTC() { - rtcData.data[3] = resetCount; // save the reset count for the next test run - // Update CRC32 of data - rtcData.crc32 = crc32((uint8_t*) &rtcData.data[0], sizeof(rtcData.data)); - if (resetCount == 5) { // wipe the CRC in RTC memory when we're done with all tests - rtcData.crc32 = 0; - } - // Write struct to RTC memory - ESP.rtcUserMemoryWrite(64, (uint32_t*) &rtcData, sizeof(rtcData)); +void updateRTCcrc() { // updates the reset count CRC + nv->rtcData.crc32 = crc32((uint8_t*) &nv->rtcData.rstCount, sizeof(nv->rtcData.rstCount)); } void initWiFi() { - /* Explicitly set the ESP8266 as a WiFi-client (STAtion mode), otherwise by default it - would try to act as both a client and an access-point and could cause network issues - with other WiFi devices on your network. */ digitalWrite(LED, LOW); // give a visual indication that we're alive but busy with WiFi - WiFi.persistent(false); // don't store the connection each time to save wear on the flash - WiFi.mode(WIFI_STA); - WiFi.config(staticIP, gateway, subnet); // if using static IP, enter parameters at the top - WiFi.begin(AP_SSID, AP_PASS); - Serial.print(F("connecting to WiFi ")); - Serial.println(AP_SSID); - DEBUG_PRINT(F("my MAC: ")); - DEBUG_PRINTLN(WiFi.macAddress()); + uint32_t wifiBegin = millis(); // how long does it take to connect + if ((crc32((uint8_t*) &nv->rtcData.rstCount + 1, sizeof(nv->wss)) && !WiFi.shutdownValidCRC(&nv->wss))) { + // if good copy of wss, overwrite invalid (primary) copy + memcpy((uint32_t*) &nv->wss, (uint32_t*) &nv->rtcData.rstCount + 1, sizeof(nv->wss)); + } + if (WiFi.shutdownValidCRC(&nv->wss)) { // if we have a valid WiFi saved state + memcpy((uint32_t*) &nv->rtcData.rstCount + 1, (uint32_t*) &nv->wss, sizeof(nv->wss)); // save a copy of it + Serial.println(F("resuming WiFi")); + } + if (!(WiFi.mode(WIFI_RESUME, &nv->wss))) { // couldn't resume, or no valid saved WiFi state yet + /* Explicitly set the ESP8266 as a WiFi-client (STAtion mode), otherwise by default it + would try to act as both a client and an access-point and could cause network issues + with other WiFi devices on your network. */ + WiFi.persistent(false); // don't store the connection each time to save wear on the flash + WiFi.mode(WIFI_STA); + WiFi.setOutputPower(10); // reduce RF output power, increase if it won't connect + WiFi.config(staticIP, gateway, subnet); // if using static IP, enter parameters at the top + WiFi.begin(AP_SSID, AP_PASS); + Serial.print(F("connecting to WiFi ")); + Serial.println(AP_SSID); + DEBUG_PRINT(F("my MAC: ")); + DEBUG_PRINTLN(WiFi.macAddress()); + } uint32_t wifiStart = millis(); while ((WiFi.status() != WL_CONNECTED) && (millis() - wifiStart < wifiTimeout)) { yield(); @@ -413,12 +421,15 @@ void initWiFi() { } else { Serial.println(F("WiFi timed out and didn't connect")); } - wifiStart = millis(); // timeout if we don't get the IP addresses from DHCP - while ((!WiFi.localIP() && (WiFi.status() == WL_CONNECTED)) && (millis() - wifiStart < wifiTimeout)) { + uint32_t wifiFinish = millis(); // timeout if we don't get the IP addresses from DHCP + while ((!WiFi.localIP() && (WiFi.status() == WL_CONNECTED)) && (millis() - wifiFinish < wifiTimeout)) { yield(); } WiFi.setAutoReconnect(true); if (WiFi.localIP()) { + Serial.print(F("WiFi connect time = ")); + float reConn = (millis() - wifiBegin); + Serial.printf("%1.3f seconds\n", reConn / 1000); DEBUG_PRINT(F("WiFi Gateway IP: ")); DEBUG_PRINTLN(WiFi.gatewayIP()); DEBUG_PRINT(F("my IP address: ")); diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md index d4213afd84..a6376d3658 100644 --- a/libraries/esp8266/examples/LowPowerDemo/README.md +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -54,7 +54,7 @@ This is the default power saving mode when you have an active WiFi connection. ### Test 3 - Forced Modem Sleep -Turns off the modem (losing the connection), and reducing the amperage by > 50 mA. This test uses the WiFi library function. It's good if there is a long interval with no expected WiFi traffic, as you can do other things while only drawing 15 to 20 mA. The longer you spend in delay(), the closer the amperage approaches 15 mA. The test loops on delay(100) until you press the button. The CPU will be drawing 15 to 16 mA during the looped delay(), and 19-20 mA without a delay(). +Turns off the modem (losing the connection), and reducing the amperage by > 50 mA. This test uses a WiFi library function and saves the WiFi connection state for faster reconnection later in the tests. Forced Modem Sleep is good if there is a long interval with no expected WiFi traffic, as you can do other things while only drawing 15 to 20 mA. The longer you spend in delay(), the closer the amperage approaches 15 mA. The test loops on delay(100) until you press the button. The CPU will be drawing 15 to 16 mA during the looped delay(), and 19-20 mA without a delay(). ### Test 4 - Automatic Light Sleep @@ -68,7 +68,7 @@ Similar to Deep Sleep, but without the timer. The chip sleeps at 0.4 mA amperag In Deep Sleep almost everything is turned off, and the chip draws ~ 20 uA. If you have D0/GPIO16 connected to RST, you can use the RTC timer to wake the chip up at a timed interval. You can also wake it with an external RESET. Waking with RF_DEFAULT means it will do an RFCAL if it needs to. Doing **ESP.deepSleep(time)** without the mode variable uses this wake mode. These first two Deep Sleep tests use the standard Deep Sleep function, so the WiFi connection is closed and the modem turned off, which takes up to 270 mS before Deep Sleep begins. Deep Sleep ends with a RESET, and the boot time after that is ~ 130 mS. Any Deep Sleep less than ~ 2 seconds is wasting energy due to the modem shut-off and boot times, and Forced Light Sleep will be a better choice as it recovers in ~ 5 mS from the previous program state. The Deep Sleep tests will not go into Automatic Modem Sleep because delay() is not used. -Note that a RESET during Deep Sleep (either external or from D0/GPIO16) does not clear the GPIO pins; they hold their previous state. It's unknown how much else survives a Deep Sleep reset, as it's not documented. +Note that a RESET during Deep Sleep (either external or from D0/GPIO16) does not clear the GPIO pins; some of them hold their previous state. It's unknown how much else survives a reset, as it's not documented. ### Test 7 - Deep Sleep, wake with RFCAL @@ -97,15 +97,13 @@ If you need a longer sleep time than 71 minutes, you can pass zero as the time v If all you want to do is reduce power for a sketch that doesn't need WiFi, add these SDK 2 functions to your code: ```c - wifi_station_disconnect(); // disconnects Wi-Fi Station from AP - delay(10); // without at least delay(8) you might get soft WDT resets after this wifi_set_opmode_current(NULL_MODE); // set Wi-Fi working mode to unconfigured, don't save to flash wifi_fpm_set_sleep_type(MODEM_SLEEP_T); // set the sleep type to modem sleep wifi_fpm_open(); // enable Forced Modem Sleep - wifi_fpm_do_sleep(0xFFFFFFF); // force CPU to enter sleep mode - delay(10); // without a delay() here it doesn't reliably enter sleep + wifi_fpm_do_sleep(0xFFFFFFF); // force modem to enter sleep mode + delay(10); // without a minimum of delay(1) here it doesn't reliably enter sleep ``` -This code allows you to shut down the modem *without* loading the WiFi library, dropping your amperage by 50 mA, or ~ 1/4th of the initial power. You have to add it as shown, preferably in **setup()**. It doesn't time out at 71 minutes, as you might think from the (0xFFFFFFF). The Forced Modem Sleep test does the same thing with a WiFi library call that encapsulates something similar to the code above. +This code allows you to shut down the modem *without* loading the WiFi library, dropping your amperage by 50 mA, or ~ 1/4th of the initial power. You have to add it as shown, preferably early in **setup()**. It doesn't time out at 71 minutes, as you might think from the (0xFFFFFFF). If you put a delay value smaller than 0xFFFFFFF it will end Modem Sleep at the number of uS you have entered: 10E6 would be 10 seconds of Modem Sleep. The Forced Modem Sleep test does the same thing with a WiFi library call that encapsulates something similar to the code above. You can also use the Deep Sleep modes without loading the WiFi library, as Deep Sleep use ESP API functions. The Deep Sleep tests above turn the WiFi on to show you the differences after the 4 reset modes. but WiFi is not required for Deep Sleep. From 3ffb8ecbcdd27d3dd1b102d03436c6304a8079f0 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Sat, 25 Jan 2020 21:22:28 -0600 Subject: [PATCH 30/51] add Low-Power demo --- libraries/esp8266/examples/LowPowerDemo/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md index a6376d3658..2d08b45321 100644 --- a/libraries/esp8266/examples/LowPowerDemo/README.md +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -105,5 +105,7 @@ If all you want to do is reduce power for a sketch that doesn't need WiFi, add t ``` This code allows you to shut down the modem *without* loading the WiFi library, dropping your amperage by 50 mA, or ~ 1/4th of the initial power. You have to add it as shown, preferably early in **setup()**. It doesn't time out at 71 minutes, as you might think from the (0xFFFFFFF). If you put a delay value smaller than 0xFFFFFFF it will end Modem Sleep at the number of uS you have entered: 10E6 would be 10 seconds of Modem Sleep. The Forced Modem Sleep test does the same thing with a WiFi library call that encapsulates something similar to the code above. +If you want to reduce the start-up power even more, see https://github.com/esp8266/Arduino/issues/6642#issuecomment-578462867 + You can also use the Deep Sleep modes without loading the WiFi library, as Deep Sleep use ESP API functions. The Deep Sleep tests above turn the WiFi on to show you the differences after the 4 reset modes. but WiFi is not required for Deep Sleep. From c8a59551d8b25cc1633fc8bd6d9ca57055edb914 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Sun, 26 Jan 2020 17:05:14 -0600 Subject: [PATCH 31/51] add Low-Power demo --- libraries/esp8266/examples/LowPowerDemo/README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md index 2d08b45321..775efc3dd4 100644 --- a/libraries/esp8266/examples/LowPowerDemo/README.md +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -96,14 +96,21 @@ If you need a longer sleep time than 71 minutes, you can pass zero as the time v ### Lower Power without the WiFi library (Forced Modem Sleep): If all you want to do is reduce power for a sketch that doesn't need WiFi, add these SDK 2 functions to your code: + +At the top of your program, add: +```c +#include +``` + +and in setup() add: ```c wifi_set_opmode_current(NULL_MODE); // set Wi-Fi working mode to unconfigured, don't save to flash wifi_fpm_set_sleep_type(MODEM_SLEEP_T); // set the sleep type to modem sleep wifi_fpm_open(); // enable Forced Modem Sleep - wifi_fpm_do_sleep(0xFFFFFFF); // force modem to enter sleep mode + wifi_fpm_do_sleep(0xFFFFFFF); // force the modem to enter sleep mode delay(10); // without a minimum of delay(1) here it doesn't reliably enter sleep ``` -This code allows you to shut down the modem *without* loading the WiFi library, dropping your amperage by 50 mA, or ~ 1/4th of the initial power. You have to add it as shown, preferably early in **setup()**. It doesn't time out at 71 minutes, as you might think from the (0xFFFFFFF). If you put a delay value smaller than 0xFFFFFFF it will end Modem Sleep at the number of uS you have entered: 10E6 would be 10 seconds of Modem Sleep. The Forced Modem Sleep test does the same thing with a WiFi library call that encapsulates something similar to the code above. +This code allows you to shut down the modem *without* loading the WiFi library, dropping your amperage by 50 mA, or ~ 1/4th of the initial power. It doesn't time out at 71 minutes, as you might think from the (0xFFFFFFF). If you put a delay value smaller than 0xFFFFFFF it will end Modem Sleep at the number of uS you have entered: 10E6 would be 10 seconds of Modem Sleep. The Forced Modem Sleep test does the same thing with a WiFi library call that encapsulates something similar to the code above. If you want to reduce the start-up power even more, see https://github.com/esp8266/Arduino/issues/6642#issuecomment-578462867 From 431f5dc65a27033f2e2906eb188ce364680e2485 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Mon, 27 Jan 2020 21:53:37 -0600 Subject: [PATCH 32/51] add Low-Power demo --- .../examples/LowPowerDemo/LowPowerDemo.ino | 138 +++++++++--------- .../esp8266/examples/LowPowerDemo/README.md | 31 ++-- 2 files changed, 91 insertions(+), 78 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index 3c751fb789..7757c25bff 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -39,7 +39,6 @@ #include #include // WiFiState structure details - //#define DEBUG // prints WiFi connection info to serial, uncomment if you want WiFi messages #ifdef DEBUG #define DEBUG_PRINTLN(x) Serial.println(x) @@ -97,6 +96,7 @@ void wakeupCallback() { // unlike ISRs, you can do a print() from a callback fu #ifdef testPoint digitalWrite(testPoint, LOW); // testPoint tracks latency from WAKE_UP_PIN LOW to testPoint LOW #endif + printMillis(); // show time difference across sleep Serial.println(F("Woke from Forced Light Sleep - this is the callback")); } @@ -113,6 +113,7 @@ void setup() { digitalWrite(LED, LOW); // turn on the LED pinMode(WAKE_UP_PIN, INPUT_PULLUP); // polled to advance tests, interrupt for Forced Light Sleep Serial.begin(115200); + Serial.println(); Serial.print(F("\nReset reason = ")); String resetCause = ESP.getResetReason(); Serial.println(resetCause); @@ -130,9 +131,8 @@ void setup() { nv->rtcData.rstCount = resetCount; // update the reset count & CRC updateRTCcrc(); - if (resetCount == 1) { // show that millis() is cleared across Deep Sleep reset - Serial.print(F("millis() = ")); - Serial.println(millis()); + if (resetCount == 1) { // show that millis() is cleared across the Deep Sleep reset + printMillis(); // show time difference across sleep } } // end of setup() @@ -143,40 +143,37 @@ void loop() { runTest3(); runTest4(); runTest5(); - runTest6(); // first Deep Sleep test, all these end with a RESET + runTest6(); + runTest7(); // first Deep Sleep test, all these end with a RESET } if (resetCount < 4) { initWiFi(); // optional re-init of WiFi for the Deep Sleep tests } if (resetCount == 1) { - runTest7(); - } else if (resetCount == 2) { runTest8(); - } else if (resetCount == 3) { + } else if (resetCount == 2) { runTest9(); + } else if (resetCount == 3) { + runTest10(); } else if (resetCount == 4) { resetTests(); } } //end of loop() -// 1st test - running with WiFi unconfigured, reads ~67 mA minimum void runTest1() { Serial.println(F("\n1st test - running with WiFi unconfigured")); - float volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); + readVoltage(); // read internal VCC Serial.println(F("press the switch to continue")); waitPushbutton(false, blinkDelay); } -// 2nd test - Automatic Modem Sleep 7 seconds after WiFi is connected (LED flashes) void runTest2() { Serial.println(F("\n2nd test - Automatic Modem Sleep")); Serial.println(F("connecting WiFi, please wait until the LED blinks")); initWiFi(); if (WiFi.localIP()) { // won't go into Automatic Sleep without an active WiFi connection Serial.println(F("The amperage will drop in 7 seconds.")); - float volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); + readVoltage(); // read internal VCC Serial.println(F("press the switch to continue")); waitPushbutton(true, 90); /* This is using a special feature: below 100 mS blink delay, the LED blink delay is padding 100 mS time with 'program cycles' to fill the 100 mS. @@ -190,14 +187,12 @@ void runTest2() { } } -// 3rd test - Forced Modem Sleep void runTest3() { Serial.println(F("\n3rd test - Forced Modem Sleep")); WiFi.mode(WIFI_SHUTDOWN, &nv->wss); // shut the modem down and save the WiFi state for faster reconnection // WiFi.forceSleepBegin(delay_in_uS); // alternate method of Forced Modem Sleep if you want a timed shutdown // delay(10); // it doesn't always go to sleep unless you delay(10); yield() wasn't reliable - float volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); + readVoltage(); // read internal VCC Serial.println(F("press the switch to continue")); waitPushbutton(true, 99); /* Using the same < 100 mS feature. If you drop the delay below 100, you will see the effect of program time vs. delay() time on minimum amperage. Above ~ 97 (97% of the @@ -205,23 +200,23 @@ void runTest3() { to get minimum amperage. At a high percentage of delay() you will see minimum amperage. */ } -// 4th test - Automatic Light Sleep void runTest4() { Serial.println(F("\n4th test - Automatic Light Sleep")); - Serial.println(F("reconnecting WiFi with forceSleepWake (slow)")); - Serial.println(F("it will be in Automatic Light Sleep when WiFi connects (LED blinks)")); + Serial.println(F("reconnecting WiFi with forceSleepWake")); + Serial.println(F("Automatic Light Sleep begins 7 seconds after WiFi connects (LED blinks)")); digitalWrite(LED, LOW); // visual cue that we're reconnecting - // if you resume here and then set sleep mode, it takes 7 seconds to go into Automatic Modem Sleep WiFi.setSleepMode(WIFI_LIGHT_SLEEP, 3); // Automatic Light Sleep, DTIM listen interval = 3 - // at higher beacon intervals you'll have a hard time establishing and maintaining a connection + // at higher DTIM intervals you'll have a hard time establishing and maintaining a connection WiFi.forceSleepWake(); // reconnect with previous STA mode and connection settings uint32_t wifiStart = millis(); - while ((!WiFi.localIP()) && (millis() - wifiStart < wifiTimeout)) { + while (((!WiFi.localIP()) || (WiFi.status() != WL_CONNECTED)) && (millis() - wifiStart < wifiTimeout)) { yield(); } if (WiFi.localIP()) { // won't go into Automatic Sleep without an active WiFi connection - float volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); + float reConn = (millis() - wifiStart); + Serial.print(F("WiFi connect time = ")); + Serial.printf("%1.3f seconds\n", reConn / 1000); + readVoltage(); // read internal VCC Serial.println(F("long press of the switch to continue")); waitPushbutton(true, 350); /* Below 100 mS delay it only goes into 'Automatic Modem Sleep', and below ~ 350 mS delay() the 'Automatic Light Sleep' is less frequent. Above 500 mS @@ -231,9 +226,31 @@ void runTest4() { } } -// 5th test - Forced Light Sleep using Non-OS SDK calls void runTest5() { - Serial.println(F("\n5th test - Forced Light Sleep using Non-OS SDK calls")); + Serial.println(F("\n5th test - Timed Light Sleep, wake in 10 seconds")); + Serial.println(F("Press the button when you are ready to proceed")); + waitPushbutton(true, blinkDelay); + WiFi.mode(WIFI_OFF); // you must turn the modem off; using disconnect won't work + delay(10); + digitalWrite(LED, HIGH); // turn the LED off so they know the CPU isn't running + readVoltage(); // read internal VCC + printMillis(); // show time difference across sleep, including Serial.flush(); +#ifdef testPoint + digitalWrite(testPoint, HIGH); + // testPoint LOW in callback tracks delay from testPoint HIGH to testPoint LOW +#endif + extern os_timer_t *timer_list; + timer_list = nullptr; // stop (but don't disable) the 4 OS timers + wifi_fpm_set_sleep_type(LIGHT_SLEEP_T); + wifi_fpm_set_wakeup_cb(wakeupCallback); // Set wakeup callback (optional) + wifi_fpm_open(); + wifi_fpm_do_sleep(10E6); // only 0xFFFFFFF works; any other value and it won't sleep + delay(10e3 + 1); // delay needs to be 1 mS longer than sleep or it only goes into Modem Sleep + Serial.println(F("Woke up!")); // the interrupt callback hits before this is executed +} + +void runTest6() { + Serial.println(F("\n6th test - Forced Light Sleep, wake with GPIO interrupt")); Serial.flush(); WiFi.mode(WIFI_OFF); // you must turn the modem off; using disconnect won't work delay(10); @@ -242,12 +259,9 @@ void runTest5() { digitalWrite(testPoint, HIGH); // testPoint LOW in callback tracks latency from WAKE_UP_PIN LOW to testPoint LOW #endif - float volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); + readVoltage(); // read internal VCC Serial.println(F("CPU going to sleep, pull WAKE_UP_PIN low to wake it (press the switch)")); - Serial.print(F("millis() = ")); - Serial.println(millis()); - Serial.flush(); // needs a delay(100) or Serial.flush() else it doesn't print the whole message + printMillis(); // show time difference across sleep wifi_fpm_set_sleep_type(LIGHT_SLEEP_T); gpio_pin_wakeup_enable(GPIO_ID_PIN(WAKE_UP_PIN), GPIO_PIN_INTR_LOLEVEL); // only LOLEVEL or HILEVEL interrupts work, no edge, that's an SDK or CPU limitation @@ -255,21 +269,13 @@ void runTest5() { wifi_fpm_open(); wifi_fpm_do_sleep(0xFFFFFFF); // only 0xFFFFFFF works; any other value and it won't sleep delay(10); // it goes to sleep some time during this delay() and waits for an interrupt - Serial.print(F("millis() = ")); // show that CPU / millis() is stopped in Forced Light Sleep - Serial.println(millis()); // although the CPU may run for up to 1 second before fully stopping - Serial.println(F("Woke up!")); // the interrupt callback hits before this is executed - /* Note: the Non-OS SDK API Reference says that you can do a timed Light Sleep, but due to - a bug any time delay greater than 13E3 uS will time-out and not execute the callback. - The example code in the Reference doesn't work, and the chip only goes into Modem Sleep, - not the lower-amperage Light Sleep. The only working alternative is a timed Modem Sleep. */ + Serial.println(F("Woke up!")); // the interrupt callback hits before this is executed*/ } -// 6th test - Deep Sleep for 10 seconds, wake with RF_DEFAULT -void runTest6() { - Serial.println(F("\n6th test - Deep Sleep for 10 seconds, reset and wake with RF_DEFAULT")); +void runTest7() { + Serial.println(F("\n7th test - Deep Sleep for 10 seconds, reset and wake with RF_DEFAULT")); initWiFi(); // initialize WiFi since we turned it off in the last test - float volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); + readVoltage(); // read internal VCC Serial.println(F("press the switch to continue")); while (!digitalRead(WAKE_UP_PIN)) { // wait for them to release the switch from the previous test delay(10); @@ -280,9 +286,7 @@ void runTest6() { //WiFi.mode(WIFI_SHUTDOWN, &nv->wss); // Forced Modem Sleep for a more Instant Deep Sleep, // and no extended RFCAL as it goes into Deep Sleep Serial.println(F("going into Deep Sleep now...")); - Serial.print(F("millis() = ")); - Serial.println(millis()); - Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message + printMillis(); // show time difference across sleep #ifdef testPoint digitalWrite(testPoint, HIGH); // testPoint set HIGH to track Deep Sleep period, cleared at startup() #endif @@ -294,11 +298,9 @@ void runTest6() { Serial.println(F("What... I'm not asleep?!?")); // it will never get here } -// 7th test - Deep Sleep for 10 seconds, wake with RFCAL -void runTest7() { - Serial.println(F("\n7th test - in RF_DEFAULT, Deep Sleep for 10 seconds, reset and wake with RFCAL")); - float volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); +void runTest8() { + Serial.println(F("\n8th test - in RF_DEFAULT, Deep Sleep for 10 seconds, reset and wake with RFCAL")); + readVoltage(); // read internal VCC Serial.println(F("press the switch to continue")); waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep //WiFi.mode(WIFI_SHUTDOWN, &nv->wss); // Forced Modem Sleep for a more Instant Deep Sleep, @@ -312,11 +314,9 @@ void runTest7() { Serial.println(F("What... I'm not asleep?!?")); // it will never get here } -// 8th test - Deep Sleep Instant for 10 seconds, wake with NO_RFCAL -void runTest8() { - Serial.println(F("\n8th test - in RFCAL, Deep Sleep Instant for 10 seconds, reset and wake with NO_RFCAL")); - float volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); +void runTest9() { + Serial.println(F("\n9th test - in RFCAL, Deep Sleep Instant for 10 seconds, reset and wake with NO_RFCAL")); + readVoltage(); // read internal VCC Serial.println(F("press the switch to continue")); waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep WiFi.mode(WIFI_SHUTDOWN, &nv->wss); // Forced Modem Sleep for a more Instant Deep Sleep @@ -329,11 +329,9 @@ void runTest8() { Serial.println(F("What... I'm not asleep?!?")); // it will never get here } -// 9th test - Deep Sleep Instant for 10 seconds, wake with RF_DISABLED -void runTest9() { - Serial.println(F("\n9th test - in NO_RFCAL, Deep Sleep Instant for 10 seconds, reset and wake with RF_DISABLED")); - float volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); +void runTest10() { + Serial.println(F("\n10th test - in NO_RFCAL, Deep Sleep Instant for 10 seconds, reset and wake with RF_DISABLED")); + readVoltage(); // read internal VCC Serial.println(F("press the switch to continue")); waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep //WiFi.mode(WIFI_SHUTDOWN); // Forced Modem Sleep for a more Instant Deep Sleep @@ -347,10 +345,9 @@ void runTest9() { } void resetTests() { - float volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); + readVoltage(); // read internal VCC Serial.println(F("\nTests completed, in RF_DISABLED, press the switch to do an ESP.restart()")); - //memset(&nv->wss, 0, sizeof(nv->wss) * 2); // uncomment if you want to wipe the saved WiFi states + //memset(&nv->wss, 0, sizeof(nv->wss) * 2); // uncomment if you erase to wipe the saved WiFi states waitPushbutton(false, 1000); ESP.restart(); } @@ -383,6 +380,17 @@ void waitPushbutton(bool usesDelay, unsigned int delayTime) { // loop until the delay(50); // debounce time for the switch, pushbutton released } +void readVoltage() { // read internal VCC + float volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); +} + +void printMillis() { + Serial.print(F("millis() = ")); + Serial.println(millis()); + Serial.flush(); // needs a Serial.flush() else it may not print the whole message before sleeping +} + void updateRTCcrc() { // updates the reset count CRC nv->rtcData.crc32 = crc32((uint8_t*) &nv->rtcData.rstCount, sizeof(nv->rtcData.rstCount)); } diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md index 775efc3dd4..5bf777b288 100644 --- a/libraries/esp8266/examples/LowPowerDemo/README.md +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -24,7 +24,7 @@ Notes: (1) setting a sleep time of 0 for Deep Sleep disconnects the RTC, requiring an external RESET to wake the CPU -(2) minimum amperage was never measured less than ~ 1 mA and is frequently 15 mA between DTIM beacons +(2) minimum amperage was never measured less than ~ 1 mA and is frequently 15 mA between TIM beacons The Average Amperage with different DTIM settings is unverified, and will likely be higher in a real-world environment. All of the amperages listed in this README are for the ESP8266 chip only, compiled for 80 MHz CPU Frequency as 160 MHz uses even more power. Modules that have voltage regulators, USB chips, LEDs or other hardware will draw additional amperage. @@ -36,11 +36,12 @@ The Average Amperage with different DTIM settings is unverified, and will likely 2. Automatic Modem Sleep 3. Forced Modem Sleep 4. Automatic Light Sleep -5. Forced Light Sleep (stop the clock, and wait for an interrupt) -6. Deep Sleep for 10 seconds, wake with default modem power settings -7. Deep Sleep for 10 seconds, wake with RFCAL -8. Deep Sleep Instant for 10 seconds, wake with NO_RFCAL -9. Deep Sleep Instant for 10 seconds, wake with RF_DISABLED +5. Timed Light Sleep - stop the CPU for (x microseconds) +6. Forced Light Sleep, wake with GPIO interrupt +7. Deep Sleep for 10 seconds, wake with default modem power settings +8. Deep Sleep for 10 seconds, wake with RFCAL +9. Deep Sleep Instant for 10 seconds, wake with NO_RFCAL +10. Deep Sleep Instant for 10 seconds, wake with RF_DISABLED --- @@ -58,27 +59,31 @@ Turns off the modem (losing the connection), and reducing the amperage by > 50 m ### Test 4 - Automatic Light Sleep -Like Automatic Modem Sleep, with similar restrictions. Once configured it's immediately active when a connection is established. During periods of long delay() the amperage can drop to ~ 2 mA average. In a network with sparse traffic you might get something near 2-5 mA amperage. The LED blinks more slowly during this test as it's doing delay(350) to get the modem to sleep. With delay() times shorter than the DTIM beacon interval (100 mS beacons for these tests) the modem only goes into Automatic Modem Sleep, and with a longer delay() it will go more fully into Automatic Light Sleep. Although the CPU clock is cycling on and off to achieve low power, millis() and micros() are correct. +Like Automatic Modem Sleep, with similar restrictions. Once configured it's immediately active when a connection is established. During periods of long delay() the amperage can drop to ~ 2 mA average. In a network with sparse traffic you might get something near 2-5 mA amperage. The LED blinks more slowly during this test as it's doing delay(350) to get the modem to sleep. With delay() times shorter than the TIM beacon interval (100 mS beacons for these tests) the modem only goes into Automatic Modem Sleep, and with a longer delay() it will go more fully into Automatic Light Sleep. Although the CPU clock is cycling on and off to achieve low power, millis() and micros() are correct. You can't stop OS_timers to get the low amperage recorded by Espressif as WiFi needs system timers running. -### Test 5 - Forced Light Sleep +### Test 5 - Timed Light Sleep -Similar to Deep Sleep, but without the timer. The chip sleeps at 0.4 mA amperage until it is woken by an external interrupt. The only allowed interrupts are high level and low level; edge interrupts won't work. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using Forced Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 3 to 5.5 mS (regardless of CPU speed), but WiFi was turned off to enter Forced Light Sleep so you will need to re-initialize it if you are using WiFi. Timers will keep the chip from going fully into Forced Light Sleep, and amperage will be ~ 2 mA with timers enabled. +Similar to Deep Sleep, but it wakes with an interrupt at the next line in your code and continues. The chip sleeps at 0.4 mA amperage until it is woken by the RTC timer. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using timed Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 3 to 5.5 mS (regardless of CPU speed), but WiFi was turned off to enter timed Light Sleep so you will need to re-initialize it if you are using WiFi. Any timers (including OS_timers and PWM) will keep the chip from going fully into timed Light Sleep, and it will fall through to the next line in your code if timers are enabled. -### Test 6 - Deep Sleep, wake with RF_DEFAULT +### Test 6 - Forced Light Sleep, wake with GPIO interrupt + +Similar to Deep Sleep, but without the timer. The chip sleeps at 0.4 mA amperage until it is woken by an external interrupt. The only allowed interrupts are high level and low level; edge interrupts won't work. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using Forced Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 3 to 5.5 mS (regardless of CPU speed), but WiFi was turned off to enter Forced Light Sleep so you will need to re-initialize it if you are using WiFi. Any standard timers (including PWM) will keep the chip from going fully into Forced Light Sleep, and amperage will be ~ 2 mA with timers enabled. + +### Test 7 - Deep Sleep, wake with RF_DEFAULT In Deep Sleep almost everything is turned off, and the chip draws ~ 20 uA. If you have D0/GPIO16 connected to RST, you can use the RTC timer to wake the chip up at a timed interval. You can also wake it with an external RESET. Waking with RF_DEFAULT means it will do an RFCAL if it needs to. Doing **ESP.deepSleep(time)** without the mode variable uses this wake mode. These first two Deep Sleep tests use the standard Deep Sleep function, so the WiFi connection is closed and the modem turned off, which takes up to 270 mS before Deep Sleep begins. Deep Sleep ends with a RESET, and the boot time after that is ~ 130 mS. Any Deep Sleep less than ~ 2 seconds is wasting energy due to the modem shut-off and boot times, and Forced Light Sleep will be a better choice as it recovers in ~ 5 mS from the previous program state. The Deep Sleep tests will not go into Automatic Modem Sleep because delay() is not used. Note that a RESET during Deep Sleep (either external or from D0/GPIO16) does not clear the GPIO pins; some of them hold their previous state. It's unknown how much else survives a reset, as it's not documented. -### Test 7 - Deep Sleep, wake with RFCAL +### Test 8 - Deep Sleep, wake with RFCAL Identical to the test above, but the modem always does an RF power calibration when booting. In normal use, most people would do WAKE_RF_DEFAULT instead to avoid the extra RFCAL power burst coming out of Deep Sleep if it's not needed. Note that most of the time both of these modes (WAKE_RF_DEFAULT and WAKE_RFCAL) do a 100 mS long RFCAL *before* going into Deep Sleep (the RFCAL after Deep Sleep is much shorter). If the modem is shut down, this long RFCAL doesn't happen. -### Test 8 - Deep Sleep Instant, wake with NO_RFCAL +### Test 9 - Deep Sleep Instant, wake with NO_RFCAL This variation doesn't do an RF calibration on return, so power requirements will be slightly less. Additionally, frequently it immediately goes into Deep Sleep without turning off the modem (that's the INSTANT part). There's another bug in SDK 2, and the SDK functions the WiFi-class calls occasionally do a modem shut-down before Deep Sleep; it's not always Instant. When it doesn't do the modem shut-down it saves an extra 270 mS of power. With the modem turned off (Forced Modem Sleep) you **always** get an instant Deep Sleep; doing WiFi.mode(WIFI_OFF) doesn't help, as the SDK still spends 270 mS of time shutting the modem down before going into Deep Sleep. -### Test 9 - Deep Sleep Instant, wake with RF_DISABLED +### Test 10 - Deep Sleep Instant, wake with RF_DISABLED This last variation also uses Deep Sleep Instant, but it wakes up with the modem disabled so amperage after Deep Sleep is only 15 mA. Each of the 4 WAKE modes has their own use, depending on what you need. From 7d3ee8d7a0ad1e6c3da656964bb3bfaef4114ed8 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Mon, 27 Jan 2020 22:00:51 -0600 Subject: [PATCH 33/51] add Low-Power demo --- libraries/esp8266/examples/LowPowerDemo/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md index 5bf777b288..275877b5bb 100644 --- a/libraries/esp8266/examples/LowPowerDemo/README.md +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -63,17 +63,17 @@ Like Automatic Modem Sleep, with similar restrictions. Once configured it's imm ### Test 5 - Timed Light Sleep -Similar to Deep Sleep, but it wakes with an interrupt at the next line in your code and continues. The chip sleeps at 0.4 mA amperage until it is woken by the RTC timer. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using timed Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 3 to 5.5 mS (regardless of CPU speed), but WiFi was turned off to enter timed Light Sleep so you will need to re-initialize it if you are using WiFi. Any timers (including OS_timers and PWM) will keep the chip from going fully into timed Light Sleep, and it will fall through to the next line in your code if timers are enabled. +Similar to Deep Sleep, but it wakes with an interrupt at the next line in your code and continues. The chip sleeps at 0.4 mA amperage until it is woken by the RTC timer. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using timed Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 3 to 5.5 mS (regardless of CPU speed), but WiFi was turned off to enter timed Light Sleep so you will need to re-initialize it if you are using WiFi. Any timers (including OS_timers and PWM) will keep the chip from going into timed Light Sleep, and it will fall through to the next line in your code if timers are enabled. ### Test 6 - Forced Light Sleep, wake with GPIO interrupt -Similar to Deep Sleep, but without the timer. The chip sleeps at 0.4 mA amperage until it is woken by an external interrupt. The only allowed interrupts are high level and low level; edge interrupts won't work. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using Forced Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 3 to 5.5 mS (regardless of CPU speed), but WiFi was turned off to enter Forced Light Sleep so you will need to re-initialize it if you are using WiFi. Any standard timers (including PWM) will keep the chip from going fully into Forced Light Sleep, and amperage will be ~ 2 mA with timers enabled. +Similar to ESP.deepSleep(0). The chip sleeps at 0.4 mA amperage until it is woken by an external interrupt. The only allowed interrupts are high level and low level; edge interrupts won't work. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using Forced Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 3 to 5.5 mS (regardless of CPU speed), but WiFi was turned off to enter Forced Light Sleep so you will need to re-initialize it if you are using WiFi. Any standard timers (including PWM) will keep the chip from going fully into Forced Light Sleep, and amperage will be ~ 2 mA with timers enabled. ### Test 7 - Deep Sleep, wake with RF_DEFAULT -In Deep Sleep almost everything is turned off, and the chip draws ~ 20 uA. If you have D0/GPIO16 connected to RST, you can use the RTC timer to wake the chip up at a timed interval. You can also wake it with an external RESET. Waking with RF_DEFAULT means it will do an RFCAL if it needs to. Doing **ESP.deepSleep(time)** without the mode variable uses this wake mode. These first two Deep Sleep tests use the standard Deep Sleep function, so the WiFi connection is closed and the modem turned off, which takes up to 270 mS before Deep Sleep begins. Deep Sleep ends with a RESET, and the boot time after that is ~ 130 mS. Any Deep Sleep less than ~ 2 seconds is wasting energy due to the modem shut-off and boot times, and Forced Light Sleep will be a better choice as it recovers in ~ 5 mS from the previous program state. The Deep Sleep tests will not go into Automatic Modem Sleep because delay() is not used. +In Deep Sleep almost everything is turned off, and the chip draws ~ 20 uA. If you have D0/GPIO16 connected to RST, you can use the RTC timer to wake the chip up at a timed interval. You can also wake it solely with an external RESET with ESP.deepSleep(0, wake option) which disconnects the timer. Waking with RF_DEFAULT means it will do an RFCAL if it needs to. Doing **ESP.deepSleep(time)** without the mode variable uses this wake mode. These first two Deep Sleep tests use the standard Deep Sleep function, so the WiFi connection is closed and the modem turned off, which takes up to 270 mS before Deep Sleep begins. Deep Sleep ends with a RESET, and the boot time after that is ~ 130 mS. Any Deep Sleep less than ~ 2 seconds is wasting energy due to the modem shut-off and boot times, and Forced Light Sleep will be a better choice as it recovers in ~ 5 mS from the previous program state. The Deep Sleep tests will not go into Automatic Modem Sleep because delay() is not used. -Note that a RESET during Deep Sleep (either external or from D0/GPIO16) does not clear the GPIO pins; some of them hold their previous state. It's unknown how much else survives a reset, as it's not documented. +Note that a RESET during Deep Sleep (either external or from D0/GPIO16) does not clear the GPIO pins; some of them hold their previous state. It's unknown how much else survives a reset, as it's not well documented. ### Test 8 - Deep Sleep, wake with RFCAL From b618e6c3b9fb02d357db83b409da87287ba9492e Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Tue, 28 Jan 2020 18:16:26 -0600 Subject: [PATCH 34/51] add Low-Power demo --- .../examples/LowPowerDemo/LowPowerDemo.ino | 30 +++++++++++-------- .../esp8266/examples/LowPowerDemo/README.md | 14 +++++---- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index 7757c25bff..4c4687ac6a 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -51,7 +51,7 @@ #define WAKE_UP_PIN 0 // D3/GPIO0, can also force a serial flash upload with RESET // you can use any GPIO for WAKE_UP_PIN except for D0/GPIO16 as it doesn't support interrupts -// uncomment one of the two lines below for your LED connection, if used +// uncomment one of the two lines below for your LED connection (optional) #define LED 5 // D1/GPIO5 external LED for modules with built-in LEDs so it doesn't add amperage //#define LED 2 // D4/GPIO2 LED for ESP-01,07 modules; D4 is LED_BUILTIN on most other modules // you can use LED_BUILTIN, but it adds to the measured amperage by 0.3mA to 6mA. @@ -69,7 +69,7 @@ IPAddress dns1(0, 0, 0, 0); IPAddress dns2(0, 0, 0, 0); uint32_t wifiTimeout = 30E3; // 30 second timeout on the WiFi connection -//#define testPoint 4 // D2/GPIO4 used to track the timing of several test cycles, optional +//#define testPoint 4 // D2/GPIO4 used to track the timing of several test cycles (optional) // This structure is stored in RTC memory to save the WiFi state and reset count (number of Deep Sleeps), // and it reconnects twice as fast as the first connection; it's used extensively in this demo @@ -93,11 +93,12 @@ esp8266::polledTimeout::oneShotFastMs altDelay(blinkDelay); // tight loop to si // use fully qualified type and avoid importing all ::esp8266 namespace to the global namespace void wakeupCallback() { // unlike ISRs, you can do a print() from a callback function + wifi_fpm_close(); // disable Light Sleep #ifdef testPoint digitalWrite(testPoint, LOW); // testPoint tracks latency from WAKE_UP_PIN LOW to testPoint LOW #endif printMillis(); // show time difference across sleep - Serial.println(F("Woke from Forced Light Sleep - this is the callback")); + Serial.println(F("Woke from Light Sleep - this is the callback")); } void preinit() { @@ -106,7 +107,7 @@ void preinit() { void setup() { #ifdef testPoint - pinMode(testPoint, OUTPUT); // test point for Forced Light Sleep and Deep Sleep tests + pinMode(testPoint, OUTPUT); // test point for Light Sleep and Deep Sleep tests digitalWrite(testPoint, LOW); // Deep Sleep reset doesn't clear GPIOs, testPoint LOW shows boot time #endif pinMode(LED, OUTPUT); // activity and status indicator @@ -190,7 +191,7 @@ void runTest2() { void runTest3() { Serial.println(F("\n3rd test - Forced Modem Sleep")); WiFi.mode(WIFI_SHUTDOWN, &nv->wss); // shut the modem down and save the WiFi state for faster reconnection - // WiFi.forceSleepBegin(delay_in_uS); // alternate method of Forced Modem Sleep if you want a timed shutdown + // WiFi.forceSleepBegin(delay_in_uS); // alternate method of Forced Modem Sleep for an optional timed shutdown // delay(10); // it doesn't always go to sleep unless you delay(10); yield() wasn't reliable readVoltage(); // read internal VCC Serial.println(F("press the switch to continue")); @@ -203,7 +204,8 @@ void runTest3() { void runTest4() { Serial.println(F("\n4th test - Automatic Light Sleep")); Serial.println(F("reconnecting WiFi with forceSleepWake")); - Serial.println(F("Automatic Light Sleep begins 7 seconds after WiFi connects (LED blinks)")); + Serial.println(F("Automatic Light Sleep begins after WiFi connects (LED blinks)")); + // on successive loops after power-on, WiFi shows 'connected' several seconds before Sleep happens digitalWrite(LED, LOW); // visual cue that we're reconnecting WiFi.setSleepMode(WIFI_LIGHT_SLEEP, 3); // Automatic Light Sleep, DTIM listen interval = 3 // at higher DTIM intervals you'll have a hard time establishing and maintaining a connection @@ -220,7 +222,7 @@ void runTest4() { Serial.println(F("long press of the switch to continue")); waitPushbutton(true, 350); /* Below 100 mS delay it only goes into 'Automatic Modem Sleep', and below ~ 350 mS delay() the 'Automatic Light Sleep' is less frequent. Above 500 mS - delay() doesn't make much improvement in power savings. */ + delay() doesn't make significant improvement in power savings. */ } else { Serial.println(F("no WiFi connection, test skipped")); } @@ -231,7 +233,7 @@ void runTest5() { Serial.println(F("Press the button when you are ready to proceed")); waitPushbutton(true, blinkDelay); WiFi.mode(WIFI_OFF); // you must turn the modem off; using disconnect won't work - delay(10); +// delay(10); digitalWrite(LED, HIGH); // turn the LED off so they know the CPU isn't running readVoltage(); // read internal VCC printMillis(); // show time difference across sleep, including Serial.flush(); @@ -242,9 +244,11 @@ void runTest5() { extern os_timer_t *timer_list; timer_list = nullptr; // stop (but don't disable) the 4 OS timers wifi_fpm_set_sleep_type(LIGHT_SLEEP_T); + gpio_pin_wakeup_enable(GPIO_ID_PIN(WAKE_UP_PIN), GPIO_PIN_INTR_LOLEVEL); // GPIO wakeup (optional) + // only LOLEVEL or HILEVEL interrupts work, no edge, that's an SDK or CPU limitation wifi_fpm_set_wakeup_cb(wakeupCallback); // Set wakeup callback (optional) wifi_fpm_open(); - wifi_fpm_do_sleep(10E6); // only 0xFFFFFFF works; any other value and it won't sleep + wifi_fpm_do_sleep(10E6); // Sleep Range 10000 ~ 268,435,454 uS (0xFFFFFFE, 2^28-1) delay(10e3 + 1); // delay needs to be 1 mS longer than sleep or it only goes into Modem Sleep Serial.println(F("Woke up!")); // the interrupt callback hits before this is executed } @@ -253,11 +257,11 @@ void runTest6() { Serial.println(F("\n6th test - Forced Light Sleep, wake with GPIO interrupt")); Serial.flush(); WiFi.mode(WIFI_OFF); // you must turn the modem off; using disconnect won't work - delay(10); +// delay(10); // testPoint is only low for 18 mS without this delay() digitalWrite(LED, HIGH); // turn the LED off so they know the CPU isn't running #ifdef testPoint digitalWrite(testPoint, HIGH); - // testPoint LOW in callback tracks latency from WAKE_UP_PIN LOW to testPoint LOW + // testPoint tracks latency from WAKE_UP_PIN LOW to testPoint LOW in callback #endif readVoltage(); // read internal VCC Serial.println(F("CPU going to sleep, pull WAKE_UP_PIN low to wake it (press the switch)")); @@ -267,7 +271,7 @@ void runTest6() { // only LOLEVEL or HILEVEL interrupts work, no edge, that's an SDK or CPU limitation wifi_fpm_set_wakeup_cb(wakeupCallback); // Set wakeup callback (optional) wifi_fpm_open(); - wifi_fpm_do_sleep(0xFFFFFFF); // only 0xFFFFFFF works; any other value and it won't sleep + wifi_fpm_do_sleep(0xFFFFFFF); // only 0xFFFFFFF, any other value and it won't disconnect the RTC timer delay(10); // it goes to sleep some time during this delay() and waits for an interrupt Serial.println(F("Woke up!")); // the interrupt callback hits before this is executed*/ } @@ -347,7 +351,7 @@ void runTest10() { void resetTests() { readVoltage(); // read internal VCC Serial.println(F("\nTests completed, in RF_DISABLED, press the switch to do an ESP.restart()")); - //memset(&nv->wss, 0, sizeof(nv->wss) * 2); // uncomment if you erase to wipe the saved WiFi states + memset(&nv->wss, 0, sizeof(nv->wss) * 2); // comment this if you want to keep the saved WiFi states waitPushbutton(false, 1000); ESP.restart(); } diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md index 275877b5bb..ca4c24e1b8 100644 --- a/libraries/esp8266/examples/LowPowerDemo/README.md +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -7,22 +7,24 @@ The two relevant reference manuals from Espressif are the [Low-Power Solutions]( The table below is an expanded version of Table 1.1 from the Low-Power Solutions PDF. The amperages listed are absolute minimums, and most people will not get that low with typical hardware and programs. -| item | Automatic Modem Sleep | Forced Modem Sleep | Automatic Light Sleep | Forced Light Sleep | Forced Deep Sleep | +| item | Automatic Modem Sleep | Forced Modem Sleep | Automatic Light Sleep | Timed or Forced Light Sleep | Forced Deep Sleep | |:---------------------:|:---------------------:|:------------------:|:---------------------:|:------------------:|:------------------:| | WiFi connectivity | Connected | Disconnected | Connected | Disconnected | Disconnected | | GPIO state | Unchanged | Unchanged | Unchanged | Unchanged | Low amperage (2 uA) | | WiFi | ON | OFF | ON | OFF | OFF | | System Clock | ON | ON | CYCLING | OFF | OFF | -| RTC | ON | ON | ON | ON | ON (1) | +| RTC | ON | ON | ON | ON (1) | ON (2) | | CPU | ON | ON | ON | ON | OFF | -| Substrate Amperage | 15 mA | 15 mA | 1-15 mA (2) | 0.4 mA | 20 uA | +| Substrate Amperage | 15 mA | 15 mA | 1-15 mA (3) | 0.4 mA | 20 uA | | Avg Amperage DTIM = 1 | 16.2 mA | | (1.8 mA) | | | | Avg Amperage DTIM = 3 | 15.4 mA | | (0.9 mA) | | | | Avg Amperage DTIM = 10 | 15.2 mA | | (0.55 mA) | | | Notes: -(1) setting a sleep time of 0 for Deep Sleep disconnects the RTC, requiring an external RESET to wake the CPU +(1) setting a sleep time of 0xFFFFFFF for Light Sleep disconnects the RTC, requiring a GPIO interrupt to wake the CPU + +(2) setting a sleep time of 0 for Deep Sleep disconnects the RTC, requiring an external RESET to wake the CPU (2) minimum amperage was never measured less than ~ 1 mA and is frequently 15 mA between TIM beacons @@ -63,11 +65,11 @@ Like Automatic Modem Sleep, with similar restrictions. Once configured it's imm ### Test 5 - Timed Light Sleep -Similar to Deep Sleep, but it wakes with an interrupt at the next line in your code and continues. The chip sleeps at 0.4 mA amperage until it is woken by the RTC timer. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using timed Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 3 to 5.5 mS (regardless of CPU speed), but WiFi was turned off to enter timed Light Sleep so you will need to re-initialize it if you are using WiFi. Any timers (including OS_timers and PWM) will keep the chip from going into timed Light Sleep, and it will fall through to the next line in your code if timers are enabled. +Similar to Deep Sleep, but it wakes with an interrupt at the next line in your code and continues. The chip sleeps at 0.4 mA amperage until it is woken by the RTC timer. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using timed Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 3 to 5.5 mS (regardless of CPU speed), but WiFi was turned off to enter timed Light Sleep so you will need to re-initialize it if you are using WiFi. Any timers (including OS_timers and PWM) will keep the chip from going into timed Light Sleep, and it will fall through to the next line in your code if any timers are running. You can set an optional interrupt callback, and you can set a GPIO interrupt to wake the CPU as well as the RTC timer. ### Test 6 - Forced Light Sleep, wake with GPIO interrupt -Similar to ESP.deepSleep(0). The chip sleeps at 0.4 mA amperage until it is woken by an external interrupt. The only allowed interrupts are high level and low level; edge interrupts won't work. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using Forced Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 3 to 5.5 mS (regardless of CPU speed), but WiFi was turned off to enter Forced Light Sleep so you will need to re-initialize it if you are using WiFi. Any standard timers (including PWM) will keep the chip from going fully into Forced Light Sleep, and amperage will be ~ 2 mA with timers enabled. +Similar to ESP.deepSleep(0). The chip sleeps at 0.4 mA amperage until it is woken by an external interrupt. The only allowed interrupts are high level and low level; edge interrupts won't work. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using Forced Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 3 to 5.5 mS (regardless of CPU speed), but WiFi was turned off to enter Forced Light Sleep so you will need to re-initialize it if you are using WiFi. Any user timers (including PWM) will keep the chip from going fully into Forced Light Sleep, and amperage will be ~ 2 mA with timers enabled. ### Test 7 - Deep Sleep, wake with RF_DEFAULT From 3292f9bc52186f3c231c4f4c0c55b85536e36ec9 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Tue, 28 Jan 2020 18:22:15 -0600 Subject: [PATCH 35/51] add Low-Power demo --- libraries/esp8266/examples/LowPowerDemo/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md index ca4c24e1b8..27dc136953 100644 --- a/libraries/esp8266/examples/LowPowerDemo/README.md +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -65,7 +65,7 @@ Like Automatic Modem Sleep, with similar restrictions. Once configured it's imm ### Test 5 - Timed Light Sleep -Similar to Deep Sleep, but it wakes with an interrupt at the next line in your code and continues. The chip sleeps at 0.4 mA amperage until it is woken by the RTC timer. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using timed Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 3 to 5.5 mS (regardless of CPU speed), but WiFi was turned off to enter timed Light Sleep so you will need to re-initialize it if you are using WiFi. Any timers (including OS_timers and PWM) will keep the chip from going into timed Light Sleep, and it will fall through to the next line in your code if any timers are running. You can set an optional interrupt callback, and you can set a GPIO interrupt to wake the CPU as well as the RTC timer. +Similar to timed Deep Sleep, but it wakes with an interrupt at the next line in your code and continues. The chip sleeps at 0.4 mA amperage until it is woken by the RTC timer. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using timed Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 3 to 5.5 mS (regardless of CPU speed), but WiFi was turned off to enter timed Light Sleep so you will need to re-initialize it if you are using WiFi. Any timers (including OS_timers and PWM) will keep the chip from going into timed Light Sleep, and it will fall through to the next line in your code if any timers are running. You can set an optional interrupt callback, and you can set a GPIO interrupt to wake the CPU as well as the RTC timer. ### Test 6 - Forced Light Sleep, wake with GPIO interrupt From 1e80279a465cce71dd6aa6fc2da4acf26201284b Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Tue, 28 Jan 2020 20:10:10 -0600 Subject: [PATCH 36/51] add Low-Power demo --- .../examples/LowPowerDemo/LowPowerDemo.ino | 53 ++++++++----------- 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index 4c4687ac6a..7abcb1167a 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -69,7 +69,15 @@ IPAddress dns1(0, 0, 0, 0); IPAddress dns2(0, 0, 0, 0); uint32_t wifiTimeout = 30E3; // 30 second timeout on the WiFi connection -//#define testPoint 4 // D2/GPIO4 used to track the timing of several test cycles (optional) +//#define TESTPOINT // used to track the timing of several test cycles (optional) +#ifdef TESTPOINT +#define testPointPin 4 // D2/GPIO4, you can use any pin that supports interrupts +#define testPoint_HIGH digitalWrite(testPointPin, HIGH) +#define testPoint_LOW digitalWrite(testPointPin, LOW) +#else +#define testPoint_HIGH +#define testPoint_LOW +#endif // This structure is stored in RTC memory to save the WiFi state and reset count (number of Deep Sleeps), // and it reconnects twice as fast as the first connection; it's used extensively in this demo @@ -94,10 +102,8 @@ esp8266::polledTimeout::oneShotFastMs altDelay(blinkDelay); // tight loop to si void wakeupCallback() { // unlike ISRs, you can do a print() from a callback function wifi_fpm_close(); // disable Light Sleep -#ifdef testPoint - digitalWrite(testPoint, LOW); // testPoint tracks latency from WAKE_UP_PIN LOW to testPoint LOW -#endif - printMillis(); // show time difference across sleep + testPoint_LOW; // testPoint tracks latency from WAKE_UP_PIN LOW to testPoint LOW + printMillis(); // show time difference across sleep; millis is wrong as the CPU eventually stops Serial.println(F("Woke from Light Sleep - this is the callback")); } @@ -106,9 +112,9 @@ void preinit() { } void setup() { -#ifdef testPoint - pinMode(testPoint, OUTPUT); // test point for Light Sleep and Deep Sleep tests - digitalWrite(testPoint, LOW); // Deep Sleep reset doesn't clear GPIOs, testPoint LOW shows boot time +#ifdef TESTPOINT + pinMode(testPointPin, OUTPUT); // test point for Light Sleep and Deep Sleep tests + testPoint_LOW; // Deep Sleep reset doesn't clear GPIOs, testPoint LOW shows boot time #endif pinMode(LED, OUTPUT); // activity and status indicator digitalWrite(LED, LOW); // turn on the LED @@ -233,14 +239,11 @@ void runTest5() { Serial.println(F("Press the button when you are ready to proceed")); waitPushbutton(true, blinkDelay); WiFi.mode(WIFI_OFF); // you must turn the modem off; using disconnect won't work -// delay(10); + // delay(10); digitalWrite(LED, HIGH); // turn the LED off so they know the CPU isn't running readVoltage(); // read internal VCC printMillis(); // show time difference across sleep, including Serial.flush(); -#ifdef testPoint - digitalWrite(testPoint, HIGH); - // testPoint LOW in callback tracks delay from testPoint HIGH to testPoint LOW -#endif + testPoint_HIGH; // testPoint LOW in callback tracks delay from testPoint HIGH to LOW extern os_timer_t *timer_list; timer_list = nullptr; // stop (but don't disable) the 4 OS timers wifi_fpm_set_sleep_type(LIGHT_SLEEP_T); @@ -248,7 +251,7 @@ void runTest5() { // only LOLEVEL or HILEVEL interrupts work, no edge, that's an SDK or CPU limitation wifi_fpm_set_wakeup_cb(wakeupCallback); // Set wakeup callback (optional) wifi_fpm_open(); - wifi_fpm_do_sleep(10E6); // Sleep Range 10000 ~ 268,435,454 uS (0xFFFFFFE, 2^28-1) + wifi_fpm_do_sleep(10E6); // Sleep Range = 10000 ~ 268,435,454 uS (0xFFFFFFE, 2^28-1) delay(10e3 + 1); // delay needs to be 1 mS longer than sleep or it only goes into Modem Sleep Serial.println(F("Woke up!")); // the interrupt callback hits before this is executed } @@ -257,12 +260,8 @@ void runTest6() { Serial.println(F("\n6th test - Forced Light Sleep, wake with GPIO interrupt")); Serial.flush(); WiFi.mode(WIFI_OFF); // you must turn the modem off; using disconnect won't work -// delay(10); // testPoint is only low for 18 mS without this delay() digitalWrite(LED, HIGH); // turn the LED off so they know the CPU isn't running -#ifdef testPoint - digitalWrite(testPoint, HIGH); - // testPoint tracks latency from WAKE_UP_PIN LOW to testPoint LOW in callback -#endif + testPoint_HIGH; // testPoint tracks latency from WAKE_UP_PIN LOW to testPoint LOW in callback readVoltage(); // read internal VCC Serial.println(F("CPU going to sleep, pull WAKE_UP_PIN low to wake it (press the switch)")); printMillis(); // show time difference across sleep @@ -291,9 +290,7 @@ void runTest7() { // and no extended RFCAL as it goes into Deep Sleep Serial.println(F("going into Deep Sleep now...")); printMillis(); // show time difference across sleep -#ifdef testPoint - digitalWrite(testPoint, HIGH); // testPoint set HIGH to track Deep Sleep period, cleared at startup() -#endif + testPoint_HIGH; // testPoint set HIGH to track Deep Sleep period, cleared at startup() ESP.deepSleep(10E6, WAKE_RF_DEFAULT); // good night! D0 fires a reset in 10 seconds... // if you do ESP.deepSleep(0, mode); it needs a RESET to come out of sleep (RTC is disconnected) // maximum timed Deep Sleep interval = 71.58 minutes with 0xFFFFFFFF @@ -311,9 +308,7 @@ void runTest8() { // and no extended RFCAL as it goes into Deep Sleep Serial.println(F("going into Deep Sleep now...")); Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message -#ifdef testPoint - digitalWrite(testPoint, HIGH); // testPoint set HIGH to track Deep Sleep period, cleared at startup() -#endif + testPoint_HIGH; // testPoint set HIGH to track Deep Sleep period, cleared at startup() ESP.deepSleep(10E6, WAKE_RFCAL); // good night! D0 fires a reset in 10 seconds... Serial.println(F("What... I'm not asleep?!?")); // it will never get here } @@ -326,9 +321,7 @@ void runTest9() { WiFi.mode(WIFI_SHUTDOWN, &nv->wss); // Forced Modem Sleep for a more Instant Deep Sleep Serial.println(F("going into Deep Sleep now...")); Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message -#ifdef testPoint - digitalWrite(testPoint, HIGH); // testPoint set HIGH to track Deep Sleep period, cleared at startup() -#endif + testPoint_HIGH; // testPoint set HIGH to track Deep Sleep period, cleared at startup() ESP.deepSleepInstant(10E6, WAKE_NO_RFCAL); // good night! D0 fires a reset in 10 seconds... Serial.println(F("What... I'm not asleep?!?")); // it will never get here } @@ -341,9 +334,7 @@ void runTest10() { //WiFi.mode(WIFI_SHUTDOWN); // Forced Modem Sleep for a more Instant Deep Sleep Serial.println(F("going into Deep Sleep now...")); Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message -#ifdef testPoint - digitalWrite(testPoint, HIGH); // testPoint set HIGH to track Deep Sleep period, cleared at startup() -#endif + testPoint_HIGH; // testPoint set HIGH to track Deep Sleep period, cleared at startup() ESP.deepSleepInstant(10E6, WAKE_RF_DISABLED); // good night! D0 fires a reset in 10 seconds... Serial.println(F("What... I'm not asleep?!?")); // it will never get here } From 93a527b6a4db052742c4c466a8a2dcfd083737f5 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Tue, 28 Jan 2020 20:13:22 -0600 Subject: [PATCH 37/51] add Low-Power demo --- libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index 7abcb1167a..185e8c46aa 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -239,7 +239,6 @@ void runTest5() { Serial.println(F("Press the button when you are ready to proceed")); waitPushbutton(true, blinkDelay); WiFi.mode(WIFI_OFF); // you must turn the modem off; using disconnect won't work - // delay(10); digitalWrite(LED, HIGH); // turn the LED off so they know the CPU isn't running readVoltage(); // read internal VCC printMillis(); // show time difference across sleep, including Serial.flush(); @@ -293,7 +292,7 @@ void runTest7() { testPoint_HIGH; // testPoint set HIGH to track Deep Sleep period, cleared at startup() ESP.deepSleep(10E6, WAKE_RF_DEFAULT); // good night! D0 fires a reset in 10 seconds... // if you do ESP.deepSleep(0, mode); it needs a RESET to come out of sleep (RTC is disconnected) - // maximum timed Deep Sleep interval = 71.58 minutes with 0xFFFFFFFF + // maximum timed Deep Sleep interval = 71.58 minutes with 0xFFFFFFFF but actually less than that // the 2 uA GPIO amperage during Deep Sleep can't drive the LED so it's not lit now, although // depending on the LED used, you might see it very dimly lit in a dark room during this test Serial.println(F("What... I'm not asleep?!?")); // it will never get here From 6018d0b3d5af9ab8875c5db525547ad5c0f9d692 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Wed, 29 Jan 2020 19:00:41 -0600 Subject: [PATCH 38/51] add Low-Power demo --- .../examples/LowPowerDemo/LowPowerDemo.ino | 32 +++++++++---------- .../esp8266/examples/LowPowerDemo/README.md | 2 +- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index 185e8c46aa..0980d110dd 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -101,16 +101,11 @@ esp8266::polledTimeout::oneShotFastMs altDelay(blinkDelay); // tight loop to si // use fully qualified type and avoid importing all ::esp8266 namespace to the global namespace void wakeupCallback() { // unlike ISRs, you can do a print() from a callback function - wifi_fpm_close(); // disable Light Sleep testPoint_LOW; // testPoint tracks latency from WAKE_UP_PIN LOW to testPoint LOW printMillis(); // show time difference across sleep; millis is wrong as the CPU eventually stops Serial.println(F("Woke from Light Sleep - this is the callback")); } -void preinit() { - ESP8266WiFiClass::preinitWiFiOff(); // currently not working -} - void setup() { #ifdef TESTPOINT pinMode(testPointPin, OUTPUT); // test point for Light Sleep and Deep Sleep tests @@ -139,7 +134,7 @@ void setup() { updateRTCcrc(); if (resetCount == 1) { // show that millis() is cleared across the Deep Sleep reset - printMillis(); // show time difference across sleep + printMillis(); } } // end of setup() @@ -212,6 +207,7 @@ void runTest4() { Serial.println(F("reconnecting WiFi with forceSleepWake")); Serial.println(F("Automatic Light Sleep begins after WiFi connects (LED blinks)")); // on successive loops after power-on, WiFi shows 'connected' several seconds before Sleep happens + // and WiFi reconnects after the forceSleepWake more quickly digitalWrite(LED, LOW); // visual cue that we're reconnecting WiFi.setSleepMode(WIFI_LIGHT_SLEEP, 3); // Automatic Light Sleep, DTIM listen interval = 3 // at higher DTIM intervals you'll have a hard time establishing and maintaining a connection @@ -236,21 +232,23 @@ void runTest4() { void runTest5() { Serial.println(F("\n5th test - Timed Light Sleep, wake in 10 seconds")); - Serial.println(F("Press the button when you are ready to proceed")); + Serial.println(F("Press the button when you're ready to proceed")); waitPushbutton(true, blinkDelay); WiFi.mode(WIFI_OFF); // you must turn the modem off; using disconnect won't work - digitalWrite(LED, HIGH); // turn the LED off so they know the CPU isn't running readVoltage(); // read internal VCC - printMillis(); // show time difference across sleep, including Serial.flush(); + printMillis(); // show millis() across sleep, including Serial.flush() + digitalWrite(LED, HIGH); // turn the LED off so they know the CPU isn't running testPoint_HIGH; // testPoint LOW in callback tracks delay from testPoint HIGH to LOW extern os_timer_t *timer_list; timer_list = nullptr; // stop (but don't disable) the 4 OS timers wifi_fpm_set_sleep_type(LIGHT_SLEEP_T); gpio_pin_wakeup_enable(GPIO_ID_PIN(WAKE_UP_PIN), GPIO_PIN_INTR_LOLEVEL); // GPIO wakeup (optional) // only LOLEVEL or HILEVEL interrupts work, no edge, that's an SDK or CPU limitation - wifi_fpm_set_wakeup_cb(wakeupCallback); // Set wakeup callback (optional) + wifi_fpm_set_wakeup_cb(wakeupCallback); // set wakeup callback + // the callback is optional, but without it the modem will wake in 10 seconds then delay(10 seconds) + // with the callback the sleep time is only 10 seconds total, no extra delay() afterward wifi_fpm_open(); - wifi_fpm_do_sleep(10E6); // Sleep Range = 10000 ~ 268,435,454 uS (0xFFFFFFE, 2^28-1) + wifi_fpm_do_sleep(10E6); // Sleep range = 10000 ~ 268,435,454 uS (0xFFFFFFE, 2^28-1) delay(10e3 + 1); // delay needs to be 1 mS longer than sleep or it only goes into Modem Sleep Serial.println(F("Woke up!")); // the interrupt callback hits before this is executed } @@ -260,17 +258,17 @@ void runTest6() { Serial.flush(); WiFi.mode(WIFI_OFF); // you must turn the modem off; using disconnect won't work digitalWrite(LED, HIGH); // turn the LED off so they know the CPU isn't running - testPoint_HIGH; // testPoint tracks latency from WAKE_UP_PIN LOW to testPoint LOW in callback readVoltage(); // read internal VCC Serial.println(F("CPU going to sleep, pull WAKE_UP_PIN low to wake it (press the switch)")); - printMillis(); // show time difference across sleep + printMillis(); // show millis() across sleep, including Serial.flush() + testPoint_HIGH; // testPoint tracks latency from WAKE_UP_PIN LOW to testPoint LOW in callback wifi_fpm_set_sleep_type(LIGHT_SLEEP_T); gpio_pin_wakeup_enable(GPIO_ID_PIN(WAKE_UP_PIN), GPIO_PIN_INTR_LOLEVEL); // only LOLEVEL or HILEVEL interrupts work, no edge, that's an SDK or CPU limitation wifi_fpm_set_wakeup_cb(wakeupCallback); // Set wakeup callback (optional) wifi_fpm_open(); wifi_fpm_do_sleep(0xFFFFFFF); // only 0xFFFFFFF, any other value and it won't disconnect the RTC timer - delay(10); // it goes to sleep some time during this delay() and waits for an interrupt + delay(10); // it goes to sleep during this delay() and waits for an interrupt Serial.println(F("Woke up!")); // the interrupt callback hits before this is executed*/ } @@ -292,7 +290,7 @@ void runTest7() { testPoint_HIGH; // testPoint set HIGH to track Deep Sleep period, cleared at startup() ESP.deepSleep(10E6, WAKE_RF_DEFAULT); // good night! D0 fires a reset in 10 seconds... // if you do ESP.deepSleep(0, mode); it needs a RESET to come out of sleep (RTC is disconnected) - // maximum timed Deep Sleep interval = 71.58 minutes with 0xFFFFFFFF but actually less than that + // maximum timed Deep Sleep interval = 71.58 minutes with 0xFFFFFFFF // the 2 uA GPIO amperage during Deep Sleep can't drive the LED so it's not lit now, although // depending on the LED used, you might see it very dimly lit in a dark room during this test Serial.println(F("What... I'm not asleep?!?")); // it will never get here @@ -341,7 +339,7 @@ void runTest10() { void resetTests() { readVoltage(); // read internal VCC Serial.println(F("\nTests completed, in RF_DISABLED, press the switch to do an ESP.restart()")); - memset(&nv->wss, 0, sizeof(nv->wss) * 2); // comment this if you want to keep the saved WiFi states + memset(&nv->wss, 0, sizeof(nv->wss) * 2); // wipe saved WiFi states, comment this if you want to keep them waitPushbutton(false, 1000); ESP.restart(); } @@ -380,7 +378,7 @@ void readVoltage() { // read internal VCC } void printMillis() { - Serial.print(F("millis() = ")); + Serial.print(F("millis() = ")); // show that millis() isn't correct across most Sleep modes Serial.println(millis()); Serial.flush(); // needs a Serial.flush() else it may not print the whole message before sleeping } diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md index 27dc136953..f32082574e 100644 --- a/libraries/esp8266/examples/LowPowerDemo/README.md +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -65,7 +65,7 @@ Like Automatic Modem Sleep, with similar restrictions. Once configured it's imm ### Test 5 - Timed Light Sleep -Similar to timed Deep Sleep, but it wakes with an interrupt at the next line in your code and continues. The chip sleeps at 0.4 mA amperage until it is woken by the RTC timer. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using timed Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 3 to 5.5 mS (regardless of CPU speed), but WiFi was turned off to enter timed Light Sleep so you will need to re-initialize it if you are using WiFi. Any timers (including OS_timers and PWM) will keep the chip from going into timed Light Sleep, and it will fall through to the next line in your code if any timers are running. You can set an optional interrupt callback, and you can set a GPIO interrupt to wake the CPU as well as the RTC timer. +Similar to timed Deep Sleep, but it wakes with an interrupt at the next line in your code and continues. The chip sleeps at 0.4 mA amperage until it is woken by the RTC timer. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using timed Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 3 to 5.5 mS (regardless of CPU speed), but WiFi was turned off to enter timed Light Sleep so you will need to re-initialize it if you are using WiFi. Any timers (including OS_timers and PWM) will keep the chip from going into timed Light Sleep, and it will fall through to the next line in your code if any timers are running. If you do a print() before Sleep, be sure to do Serial.flush() to stop the UART. The interrupt callback is recommended, and you can set a optional GPIO interrupt to wake the CPU as well as the RTC timer. ### Test 6 - Forced Light Sleep, wake with GPIO interrupt From b990e597d107246ba7e096971a991cb362f4b023 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Thu, 30 Jan 2020 18:32:34 -0600 Subject: [PATCH 39/51] add Low-Power demo --- .../examples/LowPowerDemo/LowPowerDemo.ino | 5 +++-- .../esp8266/examples/LowPowerDemo/README.md | 22 +++++++++---------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index 0980d110dd..4dda9a583d 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -192,14 +192,15 @@ void runTest2() { void runTest3() { Serial.println(F("\n3rd test - Forced Modem Sleep")); WiFi.mode(WIFI_SHUTDOWN, &nv->wss); // shut the modem down and save the WiFi state for faster reconnection - // WiFi.forceSleepBegin(delay_in_uS); // alternate method of Forced Modem Sleep for an optional timed shutdown + // WiFi.forceSleepBegin(delay_in_uS); // alternate method of Forced Modem Sleep for an optional timed shutdown, + // with WiFi.forceSleepBegin(0xFFFFFFF); the modem sleeps until you wake it, with values <= 0xFFFFFFE it's timed // delay(10); // it doesn't always go to sleep unless you delay(10); yield() wasn't reliable readVoltage(); // read internal VCC Serial.println(F("press the switch to continue")); waitPushbutton(true, 99); /* Using the same < 100 mS feature. If you drop the delay below 100, you will see the effect of program time vs. delay() time on minimum amperage. Above ~ 97 (97% of the time in delay) there is little change in amperage, so you need to spend maximum time in delay() - to get minimum amperage. At a high percentage of delay() you will see minimum amperage. */ + to get minimum amperage.*/ } void runTest4() { diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md index f32082574e..88f04a3712 100644 --- a/libraries/esp8266/examples/LowPowerDemo/README.md +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -26,7 +26,7 @@ Notes: (2) setting a sleep time of 0 for Deep Sleep disconnects the RTC, requiring an external RESET to wake the CPU -(2) minimum amperage was never measured less than ~ 1 mA and is frequently 15 mA between TIM beacons +(3) minimum amperage was never measured less than ~ 1 mA and is frequently 15 mA between TIM beacons The Average Amperage with different DTIM settings is unverified, and will likely be higher in a real-world environment. All of the amperages listed in this README are for the ESP8266 chip only, compiled for 80 MHz CPU Frequency as 160 MHz uses even more power. Modules that have voltage regulators, USB chips, LEDs or other hardware will draw additional amperage. @@ -53,27 +53,27 @@ This is typical for programs that don't use WiFi, and is a high continuous drain ### Test 2 - Automatic Modem Sleep -This is the default power saving mode when you have an active WiFi connection. You don't need to add anything to your code to get this mode. The only time the modem sleeps is when your program spends time in delay() frequently. Any delay() time works as long as it happens frequently. The test is doing **delay(100)** to get the modem to sleep. While in delay() your sketch isn't doing anything worthwhile. Amperage during Automatic Modem Sleep is 15 mA minimum. Without a delay() the amperage is > 67 mA with brief spikes > 250-350 mA as transmissions occur. When the WiFi has traffic (even a couple of pings), the modem can turn on for over 2 seconds continuous at 67 mA, and it may stay on for a second after the traffic. In a high traffic environment you won't get any power savings with either of the 2 Automatic modes. Automatic Modem Sleep turns on 7-8 seconds after an active connection is established. +This is the default power saving mode when you have an active WiFi connection. You don't need to add anything to your code to get this mode. The only time the modem sleeps is when your program spends time in delay() frequently in STA mode. Any delay() time works as long as it happens frequently. The test is doing **delay(100)** to get the modem to sleep. While in delay() your sketch isn't doing anything worthwhile. Amperage during Automatic Modem Sleep is 15 mA minimum. Without a delay() the amperage is > 67 mA with brief spikes > 250-350 mA as transmissions occur. When the WiFi has traffic (even a couple of pings), the modem can turn on for over 2 seconds continuous at 67 mA, and it may stay on for a second after the traffic. In a high traffic environment you won't get any power savings with either of the 2 Automatic modes. Automatic Modem Sleep turns on 7-8 seconds after an active connection is established. ### Test 3 - Forced Modem Sleep -Turns off the modem (losing the connection), and reducing the amperage by > 50 mA. This test uses a WiFi library function and saves the WiFi connection state for faster reconnection later in the tests. Forced Modem Sleep is good if there is a long interval with no expected WiFi traffic, as you can do other things while only drawing 15 to 20 mA. The longer you spend in delay(), the closer the amperage approaches 15 mA. The test loops on delay(100) until you press the button. The CPU will be drawing 15 to 16 mA during the looped delay(), and 19-20 mA without a delay(). +Turns off the modem (losing the connection), and reducing the amperage by > 50 mA. This test uses a WiFi library function and saves the WiFi connection state for faster reconnection later in the tests. Forced Modem Sleep is good if there is a long interval with no expected WiFi traffic, as you can do other things while only drawing 15 to 20 mA. The longer you spend in delay(), the closer the amperage approaches 15 mA. The test loops on delay(100) until you press the button. The CPU will be drawing 15 to 16 mA during the looped delay(), and 19-20 mA without a delay(). Doing WiFi.forceSleepWake() to wake the modem later can take twice as long as a re-initialize of WiFi. ### Test 4 - Automatic Light Sleep -Like Automatic Modem Sleep, with similar restrictions. Once configured it's immediately active when a connection is established. During periods of long delay() the amperage can drop to ~ 2 mA average. In a network with sparse traffic you might get something near 2-5 mA amperage. The LED blinks more slowly during this test as it's doing delay(350) to get the modem to sleep. With delay() times shorter than the TIM beacon interval (100 mS beacons for these tests) the modem only goes into Automatic Modem Sleep, and with a longer delay() it will go more fully into Automatic Light Sleep. Although the CPU clock is cycling on and off to achieve low power, millis() and micros() are correct. You can't stop OS_timers to get the low amperage recorded by Espressif as WiFi needs system timers running. +Like Automatic Modem Sleep, with similar restrictions. Once configured it's immediately active when a connection is established. During periods of long delay() the amperage can drop to ~ 2 mA average. In a network with sparse traffic you might get something near 2-5 mA average. The LED blinks more slowly during this test as it's doing delay(350) to get the modem to sleep. With delay() times shorter than the TIM beacon interval (100 mS beacons for these tests) the modem only goes into Automatic Modem Sleep, and with a longer delay() it will go more fully into Automatic Light Sleep. Although the CPU clock is cycling on and off to achieve low power, millis() and micros() are correct. You can't stop OS_timers to get the low amperage recorded by Espressif as WiFi needs system timers running. ### Test 5 - Timed Light Sleep -Similar to timed Deep Sleep, but it wakes with an interrupt at the next line in your code and continues. The chip sleeps at 0.4 mA amperage until it is woken by the RTC timer. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using timed Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 3 to 5.5 mS (regardless of CPU speed), but WiFi was turned off to enter timed Light Sleep so you will need to re-initialize it if you are using WiFi. Any timers (including OS_timers and PWM) will keep the chip from going into timed Light Sleep, and it will fall through to the next line in your code if any timers are running. If you do a print() before Sleep, be sure to do Serial.flush() to stop the UART. The interrupt callback is recommended, and you can set a optional GPIO interrupt to wake the CPU as well as the RTC timer. +Similar to timed Deep Sleep, but it wakes with an interrupt at the next line in your code and continues. The chip sleeps at 0.4 mA amperage until it is woken by the RTC timer. If you have a design that needs to be woken more often than every 2 seconds then you should consider using Timed Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 3 to 5.5 mS (regardless of CPU speed), but WiFi was turned off to enter timed Light Sleep so you will need to re-initialize it if you are using WiFi. Any timers (including OS_timers and PWM) will keep the chip from going into timed Light Sleep, and it will fall through to the next line in your code if any timers are running. If you do a print() before Sleep, be sure to do Serial.flush() to stop the UART. The interrupt callback is recommended, and you can set a optional GPIO interrupt to wake the CPU as well as the RTC timer. ### Test 6 - Forced Light Sleep, wake with GPIO interrupt -Similar to ESP.deepSleep(0). The chip sleeps at 0.4 mA amperage until it is woken by an external interrupt. The only allowed interrupts are high level and low level; edge interrupts won't work. If you have a design that needs to be woken frequently (more often than every 2 seconds) then you should consider using Forced Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 3 to 5.5 mS (regardless of CPU speed), but WiFi was turned off to enter Forced Light Sleep so you will need to re-initialize it if you are using WiFi. Any user timers (including PWM) will keep the chip from going fully into Forced Light Sleep, and amperage will be ~ 2 mA with timers enabled. +Similar to ESP.deepSleep(0). The chip sleeps at 0.4 mA amperage until it is woken by an external interrupt. The only allowed interrupts are high level and low level; edge interrupts won't work. If you have a design that needs to be woken more often than every 2 seconds then you should consider using Forced Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 3 to 5.5 mS (regardless of CPU speed), but WiFi was turned off to enter Forced Light Sleep so you will need to re-initialize it if you are using WiFi. Any user timers (including PWM) will keep the chip from going fully into Forced Light Sleep, and amperage will be ~ 2 mA with timers enabled. ### Test 7 - Deep Sleep, wake with RF_DEFAULT -In Deep Sleep almost everything is turned off, and the chip draws ~ 20 uA. If you have D0/GPIO16 connected to RST, you can use the RTC timer to wake the chip up at a timed interval. You can also wake it solely with an external RESET with ESP.deepSleep(0, wake option) which disconnects the timer. Waking with RF_DEFAULT means it will do an RFCAL if it needs to. Doing **ESP.deepSleep(time)** without the mode variable uses this wake mode. These first two Deep Sleep tests use the standard Deep Sleep function, so the WiFi connection is closed and the modem turned off, which takes up to 270 mS before Deep Sleep begins. Deep Sleep ends with a RESET, and the boot time after that is ~ 130 mS. Any Deep Sleep less than ~ 2 seconds is wasting energy due to the modem shut-off and boot times, and Forced Light Sleep will be a better choice as it recovers in ~ 5 mS from the previous program state. The Deep Sleep tests will not go into Automatic Modem Sleep because delay() is not used. +In Deep Sleep almost everything is turned off, and the chip draws ~ 20 uA. If you have D0/GPIO16 connected to RST, you can use the RTC timer to wake the chip up at a timed interval. You can also wake it solely with an external RESET with ESP.deepSleep(0, wake option), which disconnects the timer. Waking with RF_DEFAULT means it will do an RFCAL if it needs to. Doing **ESP.deepSleep(time)** without the mode variable uses this wake mode. These first two Deep Sleep tests use the standard Deep Sleep function, so the WiFi connection is closed and the modem turned off, which takes up to 270 mS before Deep Sleep begins. Deep Sleep ends with a RESET, and the boot time after that is ~ 130 mS. Any Deep Sleep less than 2 seconds is wasting energy due to the modem shut-off and boot times, and Forced Light Sleep will be a better choice as it recovers in < 5.5 mS from the previous program state. The Deep Sleep tests will not go into Automatic Modem Sleep because delay() is not used. Note that a RESET during Deep Sleep (either external or from D0/GPIO16) does not clear the GPIO pins; some of them hold their previous state. It's unknown how much else survives a reset, as it's not well documented. @@ -91,11 +91,11 @@ This last variation also uses Deep Sleep Instant, but it wakes up with the modem --- -All of the Deep Sleep modes end with a RESET, so you must re-initialize nearly everything. You can store *some* information in the RTC memory to survive a Deep Sleep reset, which was done in this demo to illustrate the RTC memory. See the **RTCUserMemory** example for more information on this feature. +All of the Deep Sleep modes end with a RESET, so you must re-initialize nearly everything. You can store *some* information in the RTC memory to survive a Deep Sleep reset, which was done in this demo to illustrate the RTC memory. See the **RTCUserMemory** and **WiFiShutdown** examples for more on this feature. -The theoretical maximum Deep Sleep interval is 71.58 minutes (2^32 -1 microseconds), although you should use something slightly less than that due to system time calculations. +The theoretical maximum Deep Sleep interval is 71.58 minutes (2^32 -1 microseconds), although you should use something less than that due to system time calculations. Realistic maximum is around 68 minutes. -If you need a longer sleep time than 71 minutes, you can pass zero as the time variable to Deep Sleep and it turns off or disconnects the RTC. The only way to wake it at that point is an external RESET; D0 can't do it. Both Forced Light Sleep and Deep Sleep(0) are woken by an external signal, so short delays are more efficient with Forced Light Sleep, and longer delays are more energy efficient with Deep Sleep. +If you need a longer sleep time than 68 minutes, you can pass zero as the time variable to Deep Sleep and it turns off or disconnects the RTC. The only way to wake it at that point is an external RESET; D0 can't do it. Both Forced Light Sleep and Deep Sleep(0) are woken by an external signal, so short delays are more efficient with Forced Light Sleep, and longer delays are more energy efficient with Deep Sleep. --- @@ -117,7 +117,7 @@ and in setup() add: wifi_fpm_do_sleep(0xFFFFFFF); // force the modem to enter sleep mode delay(10); // without a minimum of delay(1) here it doesn't reliably enter sleep ``` -This code allows you to shut down the modem *without* loading the WiFi library, dropping your amperage by 50 mA, or ~ 1/4th of the initial power. It doesn't time out at 71 minutes, as you might think from the (0xFFFFFFF). If you put a delay value smaller than 0xFFFFFFF it will end Modem Sleep at the number of uS you have entered: 10E6 would be 10 seconds of Modem Sleep. The Forced Modem Sleep test does the same thing with a WiFi library call that encapsulates something similar to the code above. +This code allows you to shut down the modem *without* loading the WiFi library, dropping your amperage by > 50 mA, or ~ 1/4th of the initial power. It doesn't time out at 268 seconds, as you might think from the (0xFFFFFFF). If you put a delay value smaller than 0xFFFFFFF it will end Modem Sleep at the number of uS you have entered: 10E6 would be 10 seconds of Modem Sleep. The Forced Modem Sleep test does the same thing with a WiFi library call that encapsulates something similar to the code above. If you want to reduce the start-up power even more, see https://github.com/esp8266/Arduino/issues/6642#issuecomment-578462867 From c107c43d9ce047cd104a3b2cbdd378311091f791 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Thu, 30 Jan 2020 18:57:03 -0600 Subject: [PATCH 40/51] add Low-Power demo --- .../examples/LowPowerDemo/LowPowerDemo.ino | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index 4dda9a583d..11aa184af7 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -11,12 +11,15 @@ have problems with WiFi, uncomment the #define DEBUG for additional WiFi error messages. The test requires a pushbutton switch connected between D3 and GND to advance the tests. You'll also need to connect D0/GPIO16 to RST for the Deep Sleep tests. If you forget to - connect D0 to RST it will hang after the first Deep Sleep test. Additionally, you can - connect an LED from any free pin through a 1K ohm resistor to the 3.3V supply, though - preferably not the 3V3 pin on the module or it adds to the measured amperage. When the - LED blinks you can proceed to the next test. When the LED is lit continuously it's - connecting WiFi, and when it's off the CPU is asleep. The LED blinks slowly when the - tests are complete. Test progress can also be shown on the serial monitor. + connect D0 to RST it will hang after the first Deep Sleep test. D0 is driven high during + Deep Sleep, so you should use a Schottky diode between D0 and RST if you want to use a + reset switch; connect the anode of the diode to RST, and the cathode to D0. + + Additionally, you can connect an LED from any free pin through a 1K ohm resistor to the + 3.3V supply, though preferably not the 3V3 pin on the module or it adds to the measured + amperage. When the LED blinks you can proceed to the next test. When the LED is lit + continuously it's connecting WiFi, and when it's off the CPU is asleep. The LED blinks + slowly when the tests are complete. Test progress can also be shown on the serial monitor. WiFi connections will be made over twice as fast if you can use a static IP address. From fecacfd5d2ff556d4bb09d88c3e22a9d187c4f2c Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Thu, 30 Jan 2020 19:01:28 -0600 Subject: [PATCH 41/51] add Low-Power demo --- libraries/esp8266/examples/LowPowerDemo/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md index 88f04a3712..b8a71192ea 100644 --- a/libraries/esp8266/examples/LowPowerDemo/README.md +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -7,7 +7,7 @@ The two relevant reference manuals from Espressif are the [Low-Power Solutions]( The table below is an expanded version of Table 1.1 from the Low-Power Solutions PDF. The amperages listed are absolute minimums, and most people will not get that low with typical hardware and programs. -| item | Automatic Modem Sleep | Forced Modem Sleep | Automatic Light Sleep | Timed or Forced Light Sleep | Forced Deep Sleep | +| item | Automatic Modem Sleep | Forced Modem Sleep | Automatic Light Sleep | Timed / Forced Light Sleep | Forced Deep Sleep | |:---------------------:|:---------------------:|:------------------:|:---------------------:|:------------------:|:------------------:| | WiFi connectivity | Connected | Disconnected | Connected | Disconnected | Disconnected | | GPIO state | Unchanged | Unchanged | Unchanged | Unchanged | Low amperage (2 uA) | From 601a5aeb638b67081d2a9f430bcf16935977a7fc Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Thu, 30 Jan 2020 21:12:40 -0600 Subject: [PATCH 42/51] add Low-Power demo --- .../examples/LowPowerDemo/LowPowerDemo.ino | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index 11aa184af7..13791eff56 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -1,41 +1,41 @@ /* This example demonstrates the different low-power modes of the ESP8266 - The initial setup was a WeMos D1 Mini with 3.3V connected to the 3V3 pin through a meter - so that it bypassed the on-board voltage regulator and USB chip. There's still about - 0.3 mA worth of leakage amperage due to the unpowered chips. These tests should work with - any module, although on-board components will affect the actual current measurement. - While the modem is turned on the amperage is > 67 mA or changing with a minimum value. - To verify the 20 uA Deep Sleep amperage the voltage regulator and USB chip were removed. - - This test series requires an active WiFi connection to illustrate two tests. If you - have problems with WiFi, uncomment the #define DEBUG for additional WiFi error messages. - The test requires a pushbutton switch connected between D3 and GND to advance the tests. - You'll also need to connect D0/GPIO16 to RST for the Deep Sleep tests. If you forget to - connect D0 to RST it will hang after the first Deep Sleep test. D0 is driven high during - Deep Sleep, so you should use a Schottky diode between D0 and RST if you want to use a - reset switch; connect the anode of the diode to RST, and the cathode to D0. - - Additionally, you can connect an LED from any free pin through a 1K ohm resistor to the - 3.3V supply, though preferably not the 3V3 pin on the module or it adds to the measured - amperage. When the LED blinks you can proceed to the next test. When the LED is lit - continuously it's connecting WiFi, and when it's off the CPU is asleep. The LED blinks - slowly when the tests are complete. Test progress can also be shown on the serial monitor. - - WiFi connections will be made over twice as fast if you can use a static IP address. - - This example is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This example is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this example; if not, write to the Free Software Foundation, Inc., - 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + The initial setup was a WeMos D1 Mini with 3.3V connected to the 3V3 pin through a meter + so that it bypassed the on-board voltage regulator and USB chip. There's still about + 0.3 mA worth of leakage amperage due to the unpowered chips. These tests should work with + any module, although on-board components will affect the actual current measurement. + While the modem is turned on the amperage is > 67 mA or changing with a minimum value. + To verify the 20 uA Deep Sleep amperage the voltage regulator and USB chip were removed. + + This test series requires an active WiFi connection to illustrate two tests. If you + have problems with WiFi, uncomment the #define DEBUG for additional WiFi error messages. + The test requires a pushbutton switch connected between D3 and GND to advance the tests. + You'll also need to connect D0/GPIO16 to RST for the Deep Sleep tests. If you forget to + connect D0 to RST it will hang after the first Deep Sleep test. D0 is driven high during + Deep Sleep, so you should use a Schottky diode between D0 and RST if you want to use a + reset switch; connect the anode of the diode to RST, and the cathode to D0. + + Additionally, you can connect an LED from any free pin through a 1K ohm resistor to the + 3.3V supply, though preferably not the 3V3 pin on the module or it adds to the measured + amperage. When the LED blinks you can proceed to the next test. When the LED is lit + continuously it's connecting WiFi, and when it's off the CPU is asleep. The LED blinks + slowly when the tests are complete. Test progress can also be shown on the serial monitor. + + WiFi connections will be made over twice as fast if you can use a static IP address. + + This example is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This example is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this example; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include // crc32() From a3ddde148d5da993443e011dbd518755eaa15e15 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Thu, 30 Jan 2020 21:45:47 -0600 Subject: [PATCH 43/51] add Low-Power demo --- .../examples/LowPowerDemo/LowPowerDemo.ino | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index 13791eff56..9dfe24c74c 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -1,41 +1,41 @@ /* This example demonstrates the different low-power modes of the ESP8266 - The initial setup was a WeMos D1 Mini with 3.3V connected to the 3V3 pin through a meter - so that it bypassed the on-board voltage regulator and USB chip. There's still about - 0.3 mA worth of leakage amperage due to the unpowered chips. These tests should work with - any module, although on-board components will affect the actual current measurement. - While the modem is turned on the amperage is > 67 mA or changing with a minimum value. - To verify the 20 uA Deep Sleep amperage the voltage regulator and USB chip were removed. - - This test series requires an active WiFi connection to illustrate two tests. If you - have problems with WiFi, uncomment the #define DEBUG for additional WiFi error messages. - The test requires a pushbutton switch connected between D3 and GND to advance the tests. - You'll also need to connect D0/GPIO16 to RST for the Deep Sleep tests. If you forget to - connect D0 to RST it will hang after the first Deep Sleep test. D0 is driven high during - Deep Sleep, so you should use a Schottky diode between D0 and RST if you want to use a - reset switch; connect the anode of the diode to RST, and the cathode to D0. - - Additionally, you can connect an LED from any free pin through a 1K ohm resistor to the - 3.3V supply, though preferably not the 3V3 pin on the module or it adds to the measured - amperage. When the LED blinks you can proceed to the next test. When the LED is lit - continuously it's connecting WiFi, and when it's off the CPU is asleep. The LED blinks - slowly when the tests are complete. Test progress can also be shown on the serial monitor. - - WiFi connections will be made over twice as fast if you can use a static IP address. - - This example is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This example is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this example; if not, write to the Free Software Foundation, Inc., - 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + The initial setup was a WeMos D1 Mini with 3.3V connected to the 3V3 pin through a meter + so that it bypassed the on-board voltage regulator and USB chip. There's still about + 0.3 mA worth of leakage amperage due to the unpowered chips. These tests should work with + any module, although on-board components will affect the actual current measurement. + While the modem is turned on the amperage is > 67 mA or changing with a minimum value. + To verify the 20 uA Deep Sleep amperage the voltage regulator and USB chip were removed. + + This test series requires an active WiFi connection to illustrate two tests. If you + have problems with WiFi, uncomment the #define DEBUG for additional WiFi error messages. + The test requires a pushbutton switch connected between D3 and GND to advance the tests. + You'll also need to connect D0/GPIO16 to RST for the Deep Sleep tests. If you forget to + connect D0 to RST it will hang after the first Deep Sleep test. D0 is driven high during + Deep Sleep, so you should use a Schottky diode between D0 and RST if you want to use a + reset switch; connect the anode of the diode to RST, and the cathode to D0. + + Additionally, you can connect an LED from any free pin through a 1K ohm resistor to the + 3.3V supply, though preferably not the 3V3 pin on the module or it adds to the measured + amperage. When the LED blinks you can proceed to the next test. When the LED is lit + continuously it's connecting WiFi, and when it's off the CPU is asleep. The LED blinks + slowly when the tests are complete. Test progress can also be shown on the serial monitor. + + WiFi connections will be made over twice as fast if you can use a static IP address. + + This example is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This example is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this example; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include // crc32() From 535d4832bfd91d4cf4de1617fa4ed61fd5a2dcc3 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Fri, 31 Jan 2020 05:53:36 -0600 Subject: [PATCH 44/51] add Low-Power demo --- .../examples/LowPowerDemo/LowPowerDemo.ino | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index 9dfe24c74c..25c8e23bf7 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -9,7 +9,7 @@ This test series requires an active WiFi connection to illustrate two tests. If you have problems with WiFi, uncomment the #define DEBUG for additional WiFi error messages. - The test requires a pushbutton switch connected between D3 and GND to advance the tests. + The test needs a pushbutton switch connected between D3/GPIO0 and GND to advance the tests. You'll also need to connect D0/GPIO16 to RST for the Deep Sleep tests. If you forget to connect D0 to RST it will hang after the first Deep Sleep test. D0 is driven high during Deep Sleep, so you should use a Schottky diode between D0 and RST if you want to use a @@ -21,7 +21,7 @@ continuously it's connecting WiFi, and when it's off the CPU is asleep. The LED blinks slowly when the tests are complete. Test progress can also be shown on the serial monitor. - WiFi connections will be made over twice as fast if you can use a static IP address. + WiFi connections will be made over twice as fast if you use a static IP address. This example is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -38,9 +38,9 @@ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include -#include // crc32() +#include // crc32() #include -#include // WiFiState structure details +#include // WiFiState structure details //#define DEBUG // prints WiFi connection info to serial, uncomment if you want WiFi messages #ifdef DEBUG @@ -65,14 +65,14 @@ ADC_MODE(ADC_VCC); // allows you to monitor the internal VCC level; it varies w // enter your WiFi configuration below const char* AP_SSID = "SSID"; // your router's SSID here const char* AP_PASS = "password"; // your router's password here -IPAddress staticIP(0, 0, 0, 0); // parameters below are for your static IP address, if used +IPAddress staticIP(0, 0, 0, 0); // parameters below are for your static IP address, if used IPAddress gateway(0, 0, 0, 0); IPAddress subnet(0, 0, 0, 0); IPAddress dns1(0, 0, 0, 0); IPAddress dns2(0, 0, 0, 0); uint32_t wifiTimeout = 30E3; // 30 second timeout on the WiFi connection -//#define TESTPOINT // used to track the timing of several test cycles (optional) +//#define TESTPOINT // used to track the timing of several test cycles (optional) #ifdef TESTPOINT #define testPointPin 4 // D2/GPIO4, you can use any pin that supports interrupts #define testPoint_HIGH digitalWrite(testPointPin, HIGH) @@ -85,7 +85,7 @@ uint32_t wifiTimeout = 30E3; // 30 second timeout on the WiFi connection // This structure is stored in RTC memory to save the WiFi state and reset count (number of Deep Sleeps), // and it reconnects twice as fast as the first connection; it's used extensively in this demo struct nv_s { - WiFiState wss; // core's WiFi save state + WiFiState wss; // core's WiFi save state struct { uint32_t crc32; @@ -94,11 +94,11 @@ struct nv_s { } rtcData; }; -static nv_s* nv = (nv_s*)RTC_USER_MEM; // user RTC RAM area +static nv_s* nv = (nv_s*)RTC_USER_MEM; // user RTC RAM area uint32_t resetCount = 0; // keeps track of the number of Deep Sleep tests / resets -const uint32_t blinkDelay = 100; // fast blink rate for the LED when waiting for the user +const uint32_t blinkDelay = 100; // fast blink rate for the LED when waiting for the user esp8266::polledTimeout::periodicMs blinkLED(blinkDelay); // LED blink delay without delay() esp8266::polledTimeout::oneShotFastMs altDelay(blinkDelay); // tight loop to simulate user code // use fully qualified type and avoid importing all ::esp8266 namespace to the global namespace @@ -133,7 +133,7 @@ void setup() { resetCount = nv->rtcData.rstCount; // read the previous reset count resetCount++; } - nv->rtcData.rstCount = resetCount; // update the reset count & CRC + nv->rtcData.rstCount = resetCount; // update the reset count & CRC updateRTCcrc(); if (resetCount == 1) { // show that millis() is cleared across the Deep Sleep reset @@ -163,7 +163,7 @@ void loop() { } else if (resetCount == 4) { resetTests(); } -} //end of loop() +} //end of loop() void runTest1() { Serial.println(F("\n1st test - running with WiFi unconfigured")); @@ -253,7 +253,7 @@ void runTest5() { // with the callback the sleep time is only 10 seconds total, no extra delay() afterward wifi_fpm_open(); wifi_fpm_do_sleep(10E6); // Sleep range = 10000 ~ 268,435,454 uS (0xFFFFFFE, 2^28-1) - delay(10e3 + 1); // delay needs to be 1 mS longer than sleep or it only goes into Modem Sleep + delay(10e3 + 1); // delay needs to be 1 mS longer than sleep or it only goes into Modem Sleep Serial.println(F("Woke up!")); // the interrupt callback hits before this is executed } From 3775b1ba540f74a2954e7af7e37000aae25fa333 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Fri, 31 Jan 2020 18:39:36 -0600 Subject: [PATCH 45/51] add Low-Power demo --- .../examples/LowPowerDemo/LowPowerDemo.ino | 444 ------------------ 1 file changed, 444 deletions(-) delete mode 100644 libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino deleted file mode 100644 index 25c8e23bf7..0000000000 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ /dev/null @@ -1,444 +0,0 @@ -/* This example demonstrates the different low-power modes of the ESP8266 - - The initial setup was a WeMos D1 Mini with 3.3V connected to the 3V3 pin through a meter - so that it bypassed the on-board voltage regulator and USB chip. There's still about - 0.3 mA worth of leakage amperage due to the unpowered chips. These tests should work with - any module, although on-board components will affect the actual current measurement. - While the modem is turned on the amperage is > 67 mA or changing with a minimum value. - To verify the 20 uA Deep Sleep amperage the voltage regulator and USB chip were removed. - - This test series requires an active WiFi connection to illustrate two tests. If you - have problems with WiFi, uncomment the #define DEBUG for additional WiFi error messages. - The test needs a pushbutton switch connected between D3/GPIO0 and GND to advance the tests. - You'll also need to connect D0/GPIO16 to RST for the Deep Sleep tests. If you forget to - connect D0 to RST it will hang after the first Deep Sleep test. D0 is driven high during - Deep Sleep, so you should use a Schottky diode between D0 and RST if you want to use a - reset switch; connect the anode of the diode to RST, and the cathode to D0. - - Additionally, you can connect an LED from any free pin through a 1K ohm resistor to the - 3.3V supply, though preferably not the 3V3 pin on the module or it adds to the measured - amperage. When the LED blinks you can proceed to the next test. When the LED is lit - continuously it's connecting WiFi, and when it's off the CPU is asleep. The LED blinks - slowly when the tests are complete. Test progress can also be shown on the serial monitor. - - WiFi connections will be made over twice as fast if you use a static IP address. - - This example is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This example is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this example; if not, write to the Free Software Foundation, Inc., - 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include -#include // crc32() -#include -#include // WiFiState structure details - -//#define DEBUG // prints WiFi connection info to serial, uncomment if you want WiFi messages -#ifdef DEBUG -#define DEBUG_PRINTLN(x) Serial.println(x) -#define DEBUG_PRINT(x) Serial.print(x) -#else -#define DEBUG_PRINTLN(x) -#define DEBUG_PRINT(x) -#endif - -#define WAKE_UP_PIN 0 // D3/GPIO0, can also force a serial flash upload with RESET -// you can use any GPIO for WAKE_UP_PIN except for D0/GPIO16 as it doesn't support interrupts - -// uncomment one of the two lines below for your LED connection (optional) -#define LED 5 // D1/GPIO5 external LED for modules with built-in LEDs so it doesn't add amperage -//#define LED 2 // D4/GPIO2 LED for ESP-01,07 modules; D4 is LED_BUILTIN on most other modules -// you can use LED_BUILTIN, but it adds to the measured amperage by 0.3mA to 6mA. - -ADC_MODE(ADC_VCC); // allows you to monitor the internal VCC level; it varies with WiFi load -// don't connect anything to the analog input pin(s)! - -// enter your WiFi configuration below -const char* AP_SSID = "SSID"; // your router's SSID here -const char* AP_PASS = "password"; // your router's password here -IPAddress staticIP(0, 0, 0, 0); // parameters below are for your static IP address, if used -IPAddress gateway(0, 0, 0, 0); -IPAddress subnet(0, 0, 0, 0); -IPAddress dns1(0, 0, 0, 0); -IPAddress dns2(0, 0, 0, 0); -uint32_t wifiTimeout = 30E3; // 30 second timeout on the WiFi connection - -//#define TESTPOINT // used to track the timing of several test cycles (optional) -#ifdef TESTPOINT -#define testPointPin 4 // D2/GPIO4, you can use any pin that supports interrupts -#define testPoint_HIGH digitalWrite(testPointPin, HIGH) -#define testPoint_LOW digitalWrite(testPointPin, LOW) -#else -#define testPoint_HIGH -#define testPoint_LOW -#endif - -// This structure is stored in RTC memory to save the WiFi state and reset count (number of Deep Sleeps), -// and it reconnects twice as fast as the first connection; it's used extensively in this demo -struct nv_s { - WiFiState wss; // core's WiFi save state - - struct { - uint32_t crc32; - uint32_t rstCount; // stores the Deep Sleep reset count - // you can add anything else here that you want to save - } rtcData; -}; - -static nv_s* nv = (nv_s*)RTC_USER_MEM; // user RTC RAM area - -uint32_t resetCount = 0; // keeps track of the number of Deep Sleep tests / resets - -const uint32_t blinkDelay = 100; // fast blink rate for the LED when waiting for the user -esp8266::polledTimeout::periodicMs blinkLED(blinkDelay); // LED blink delay without delay() -esp8266::polledTimeout::oneShotFastMs altDelay(blinkDelay); // tight loop to simulate user code -// use fully qualified type and avoid importing all ::esp8266 namespace to the global namespace - -void wakeupCallback() { // unlike ISRs, you can do a print() from a callback function - testPoint_LOW; // testPoint tracks latency from WAKE_UP_PIN LOW to testPoint LOW - printMillis(); // show time difference across sleep; millis is wrong as the CPU eventually stops - Serial.println(F("Woke from Light Sleep - this is the callback")); -} - -void setup() { -#ifdef TESTPOINT - pinMode(testPointPin, OUTPUT); // test point for Light Sleep and Deep Sleep tests - testPoint_LOW; // Deep Sleep reset doesn't clear GPIOs, testPoint LOW shows boot time -#endif - pinMode(LED, OUTPUT); // activity and status indicator - digitalWrite(LED, LOW); // turn on the LED - pinMode(WAKE_UP_PIN, INPUT_PULLUP); // polled to advance tests, interrupt for Forced Light Sleep - Serial.begin(115200); - Serial.println(); - Serial.print(F("\nReset reason = ")); - String resetCause = ESP.getResetReason(); - Serial.println(resetCause); - resetCount = 0; - if ((resetCause == "External System") || (resetCause == "Power on")) { - Serial.println(F("I'm awake and starting the Low Power tests")); - } - - // Read previous resets (Deep Sleeps) from RTC memory, if any - uint32_t crcOfData = crc32((uint8_t*) &nv->rtcData.rstCount, sizeof(nv->rtcData.rstCount)); - if ((crcOfData = nv->rtcData.crc32) && (resetCause == "Deep-Sleep Wake")) { - resetCount = nv->rtcData.rstCount; // read the previous reset count - resetCount++; - } - nv->rtcData.rstCount = resetCount; // update the reset count & CRC - updateRTCcrc(); - - if (resetCount == 1) { // show that millis() is cleared across the Deep Sleep reset - printMillis(); - } -} // end of setup() - -void loop() { - if (resetCount == 0) { // if first loop() since power on or external reset - runTest1(); - runTest2(); - runTest3(); - runTest4(); - runTest5(); - runTest6(); - runTest7(); // first Deep Sleep test, all these end with a RESET - } - if (resetCount < 4) { - initWiFi(); // optional re-init of WiFi for the Deep Sleep tests - } - if (resetCount == 1) { - runTest8(); - } else if (resetCount == 2) { - runTest9(); - } else if (resetCount == 3) { - runTest10(); - } else if (resetCount == 4) { - resetTests(); - } -} //end of loop() - -void runTest1() { - Serial.println(F("\n1st test - running with WiFi unconfigured")); - readVoltage(); // read internal VCC - Serial.println(F("press the switch to continue")); - waitPushbutton(false, blinkDelay); -} - -void runTest2() { - Serial.println(F("\n2nd test - Automatic Modem Sleep")); - Serial.println(F("connecting WiFi, please wait until the LED blinks")); - initWiFi(); - if (WiFi.localIP()) { // won't go into Automatic Sleep without an active WiFi connection - Serial.println(F("The amperage will drop in 7 seconds.")); - readVoltage(); // read internal VCC - Serial.println(F("press the switch to continue")); - waitPushbutton(true, 90); /* This is using a special feature: below 100 mS blink delay, - the LED blink delay is padding 100 mS time with 'program cycles' to fill the 100 mS. - At 90 mS delay, 90% of the blink time is delay(), and 10% is 'your program running'. - Below 90% you'll see a difference in the average amperage: less delay() = more amperage. - At 100 mS and above it's essentially all delay() time. On an oscilloscope you'll see the - time between beacons at > 67 mA more often with less delay() percentage. You can change - the '90' mS to other values to see the effect it has on Automatic Modem Sleep. */ - } else { - Serial.println(F("no WiFi connection, test skipped")); - } -} - -void runTest3() { - Serial.println(F("\n3rd test - Forced Modem Sleep")); - WiFi.mode(WIFI_SHUTDOWN, &nv->wss); // shut the modem down and save the WiFi state for faster reconnection - // WiFi.forceSleepBegin(delay_in_uS); // alternate method of Forced Modem Sleep for an optional timed shutdown, - // with WiFi.forceSleepBegin(0xFFFFFFF); the modem sleeps until you wake it, with values <= 0xFFFFFFE it's timed - // delay(10); // it doesn't always go to sleep unless you delay(10); yield() wasn't reliable - readVoltage(); // read internal VCC - Serial.println(F("press the switch to continue")); - waitPushbutton(true, 99); /* Using the same < 100 mS feature. If you drop the delay below 100, you - will see the effect of program time vs. delay() time on minimum amperage. Above ~ 97 (97% of the - time in delay) there is little change in amperage, so you need to spend maximum time in delay() - to get minimum amperage.*/ -} - -void runTest4() { - Serial.println(F("\n4th test - Automatic Light Sleep")); - Serial.println(F("reconnecting WiFi with forceSleepWake")); - Serial.println(F("Automatic Light Sleep begins after WiFi connects (LED blinks)")); - // on successive loops after power-on, WiFi shows 'connected' several seconds before Sleep happens - // and WiFi reconnects after the forceSleepWake more quickly - digitalWrite(LED, LOW); // visual cue that we're reconnecting - WiFi.setSleepMode(WIFI_LIGHT_SLEEP, 3); // Automatic Light Sleep, DTIM listen interval = 3 - // at higher DTIM intervals you'll have a hard time establishing and maintaining a connection - WiFi.forceSleepWake(); // reconnect with previous STA mode and connection settings - uint32_t wifiStart = millis(); - while (((!WiFi.localIP()) || (WiFi.status() != WL_CONNECTED)) && (millis() - wifiStart < wifiTimeout)) { - yield(); - } - if (WiFi.localIP()) { // won't go into Automatic Sleep without an active WiFi connection - float reConn = (millis() - wifiStart); - Serial.print(F("WiFi connect time = ")); - Serial.printf("%1.3f seconds\n", reConn / 1000); - readVoltage(); // read internal VCC - Serial.println(F("long press of the switch to continue")); - waitPushbutton(true, 350); /* Below 100 mS delay it only goes into 'Automatic Modem Sleep', - and below ~ 350 mS delay() the 'Automatic Light Sleep' is less frequent. Above 500 mS - delay() doesn't make significant improvement in power savings. */ - } else { - Serial.println(F("no WiFi connection, test skipped")); - } -} - -void runTest5() { - Serial.println(F("\n5th test - Timed Light Sleep, wake in 10 seconds")); - Serial.println(F("Press the button when you're ready to proceed")); - waitPushbutton(true, blinkDelay); - WiFi.mode(WIFI_OFF); // you must turn the modem off; using disconnect won't work - readVoltage(); // read internal VCC - printMillis(); // show millis() across sleep, including Serial.flush() - digitalWrite(LED, HIGH); // turn the LED off so they know the CPU isn't running - testPoint_HIGH; // testPoint LOW in callback tracks delay from testPoint HIGH to LOW - extern os_timer_t *timer_list; - timer_list = nullptr; // stop (but don't disable) the 4 OS timers - wifi_fpm_set_sleep_type(LIGHT_SLEEP_T); - gpio_pin_wakeup_enable(GPIO_ID_PIN(WAKE_UP_PIN), GPIO_PIN_INTR_LOLEVEL); // GPIO wakeup (optional) - // only LOLEVEL or HILEVEL interrupts work, no edge, that's an SDK or CPU limitation - wifi_fpm_set_wakeup_cb(wakeupCallback); // set wakeup callback - // the callback is optional, but without it the modem will wake in 10 seconds then delay(10 seconds) - // with the callback the sleep time is only 10 seconds total, no extra delay() afterward - wifi_fpm_open(); - wifi_fpm_do_sleep(10E6); // Sleep range = 10000 ~ 268,435,454 uS (0xFFFFFFE, 2^28-1) - delay(10e3 + 1); // delay needs to be 1 mS longer than sleep or it only goes into Modem Sleep - Serial.println(F("Woke up!")); // the interrupt callback hits before this is executed -} - -void runTest6() { - Serial.println(F("\n6th test - Forced Light Sleep, wake with GPIO interrupt")); - Serial.flush(); - WiFi.mode(WIFI_OFF); // you must turn the modem off; using disconnect won't work - digitalWrite(LED, HIGH); // turn the LED off so they know the CPU isn't running - readVoltage(); // read internal VCC - Serial.println(F("CPU going to sleep, pull WAKE_UP_PIN low to wake it (press the switch)")); - printMillis(); // show millis() across sleep, including Serial.flush() - testPoint_HIGH; // testPoint tracks latency from WAKE_UP_PIN LOW to testPoint LOW in callback - wifi_fpm_set_sleep_type(LIGHT_SLEEP_T); - gpio_pin_wakeup_enable(GPIO_ID_PIN(WAKE_UP_PIN), GPIO_PIN_INTR_LOLEVEL); - // only LOLEVEL or HILEVEL interrupts work, no edge, that's an SDK or CPU limitation - wifi_fpm_set_wakeup_cb(wakeupCallback); // Set wakeup callback (optional) - wifi_fpm_open(); - wifi_fpm_do_sleep(0xFFFFFFF); // only 0xFFFFFFF, any other value and it won't disconnect the RTC timer - delay(10); // it goes to sleep during this delay() and waits for an interrupt - Serial.println(F("Woke up!")); // the interrupt callback hits before this is executed*/ -} - -void runTest7() { - Serial.println(F("\n7th test - Deep Sleep for 10 seconds, reset and wake with RF_DEFAULT")); - initWiFi(); // initialize WiFi since we turned it off in the last test - readVoltage(); // read internal VCC - Serial.println(F("press the switch to continue")); - while (!digitalRead(WAKE_UP_PIN)) { // wait for them to release the switch from the previous test - delay(10); - } - delay(50); // debounce time for the switch, pushbutton released - waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep - digitalWrite(LED, LOW); // turn the LED on, at least briefly - //WiFi.mode(WIFI_SHUTDOWN, &nv->wss); // Forced Modem Sleep for a more Instant Deep Sleep, - // and no extended RFCAL as it goes into Deep Sleep - Serial.println(F("going into Deep Sleep now...")); - printMillis(); // show time difference across sleep - testPoint_HIGH; // testPoint set HIGH to track Deep Sleep period, cleared at startup() - ESP.deepSleep(10E6, WAKE_RF_DEFAULT); // good night! D0 fires a reset in 10 seconds... - // if you do ESP.deepSleep(0, mode); it needs a RESET to come out of sleep (RTC is disconnected) - // maximum timed Deep Sleep interval = 71.58 minutes with 0xFFFFFFFF - // the 2 uA GPIO amperage during Deep Sleep can't drive the LED so it's not lit now, although - // depending on the LED used, you might see it very dimly lit in a dark room during this test - Serial.println(F("What... I'm not asleep?!?")); // it will never get here -} - -void runTest8() { - Serial.println(F("\n8th test - in RF_DEFAULT, Deep Sleep for 10 seconds, reset and wake with RFCAL")); - readVoltage(); // read internal VCC - Serial.println(F("press the switch to continue")); - waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep - //WiFi.mode(WIFI_SHUTDOWN, &nv->wss); // Forced Modem Sleep for a more Instant Deep Sleep, - // and no extended RFCAL as it goes into Deep Sleep - Serial.println(F("going into Deep Sleep now...")); - Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message - testPoint_HIGH; // testPoint set HIGH to track Deep Sleep period, cleared at startup() - ESP.deepSleep(10E6, WAKE_RFCAL); // good night! D0 fires a reset in 10 seconds... - Serial.println(F("What... I'm not asleep?!?")); // it will never get here -} - -void runTest9() { - Serial.println(F("\n9th test - in RFCAL, Deep Sleep Instant for 10 seconds, reset and wake with NO_RFCAL")); - readVoltage(); // read internal VCC - Serial.println(F("press the switch to continue")); - waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep - WiFi.mode(WIFI_SHUTDOWN, &nv->wss); // Forced Modem Sleep for a more Instant Deep Sleep - Serial.println(F("going into Deep Sleep now...")); - Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message - testPoint_HIGH; // testPoint set HIGH to track Deep Sleep period, cleared at startup() - ESP.deepSleepInstant(10E6, WAKE_NO_RFCAL); // good night! D0 fires a reset in 10 seconds... - Serial.println(F("What... I'm not asleep?!?")); // it will never get here -} - -void runTest10() { - Serial.println(F("\n10th test - in NO_RFCAL, Deep Sleep Instant for 10 seconds, reset and wake with RF_DISABLED")); - readVoltage(); // read internal VCC - Serial.println(F("press the switch to continue")); - waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep - //WiFi.mode(WIFI_SHUTDOWN); // Forced Modem Sleep for a more Instant Deep Sleep - Serial.println(F("going into Deep Sleep now...")); - Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message - testPoint_HIGH; // testPoint set HIGH to track Deep Sleep period, cleared at startup() - ESP.deepSleepInstant(10E6, WAKE_RF_DISABLED); // good night! D0 fires a reset in 10 seconds... - Serial.println(F("What... I'm not asleep?!?")); // it will never get here -} - -void resetTests() { - readVoltage(); // read internal VCC - Serial.println(F("\nTests completed, in RF_DISABLED, press the switch to do an ESP.restart()")); - memset(&nv->wss, 0, sizeof(nv->wss) * 2); // wipe saved WiFi states, comment this if you want to keep them - waitPushbutton(false, 1000); - ESP.restart(); -} - -void waitPushbutton(bool usesDelay, unsigned int delayTime) { // loop until they press the switch - // note: 2 different modes, as 3 of the power saving modes need a delay() to activate fully - if (!usesDelay) { // quick interception of pushbutton press, no delay() used - blinkLED.reset(delayTime); - while (digitalRead(WAKE_UP_PIN)) { // wait for a pushbutton press - if (blinkLED) { - digitalWrite(LED, !digitalRead(LED)); // toggle the activity LED - } - yield(); // this would be a good place for ArduinoOTA.handle(); - } - } else { // long delay() for the 3 modes that need it, but it misses quick switch presses - while (digitalRead(WAKE_UP_PIN)) { // wait for a pushbutton press - digitalWrite(LED, !digitalRead(LED)); // toggle the activity LED - delay(delayTime); // another good place for ArduinoOTA.handle(); - if (delayTime < 100) { - altDelay.reset(100 - delayTime); // pad the time < 100 mS with some real CPU cycles - while (!altDelay) { // this simulates 'your program running', not delay() time - } - } - } - } - delay(50); // debounce time for the switch, pushbutton pressed - while (!digitalRead(WAKE_UP_PIN)) { // now wait for them to release the pushbutton - delay(10); - } - delay(50); // debounce time for the switch, pushbutton released -} - -void readVoltage() { // read internal VCC - float volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); -} - -void printMillis() { - Serial.print(F("millis() = ")); // show that millis() isn't correct across most Sleep modes - Serial.println(millis()); - Serial.flush(); // needs a Serial.flush() else it may not print the whole message before sleeping -} - -void updateRTCcrc() { // updates the reset count CRC - nv->rtcData.crc32 = crc32((uint8_t*) &nv->rtcData.rstCount, sizeof(nv->rtcData.rstCount)); -} - -void initWiFi() { - digitalWrite(LED, LOW); // give a visual indication that we're alive but busy with WiFi - uint32_t wifiBegin = millis(); // how long does it take to connect - if ((crc32((uint8_t*) &nv->rtcData.rstCount + 1, sizeof(nv->wss)) && !WiFi.shutdownValidCRC(&nv->wss))) { - // if good copy of wss, overwrite invalid (primary) copy - memcpy((uint32_t*) &nv->wss, (uint32_t*) &nv->rtcData.rstCount + 1, sizeof(nv->wss)); - } - if (WiFi.shutdownValidCRC(&nv->wss)) { // if we have a valid WiFi saved state - memcpy((uint32_t*) &nv->rtcData.rstCount + 1, (uint32_t*) &nv->wss, sizeof(nv->wss)); // save a copy of it - Serial.println(F("resuming WiFi")); - } - if (!(WiFi.mode(WIFI_RESUME, &nv->wss))) { // couldn't resume, or no valid saved WiFi state yet - /* Explicitly set the ESP8266 as a WiFi-client (STAtion mode), otherwise by default it - would try to act as both a client and an access-point and could cause network issues - with other WiFi devices on your network. */ - WiFi.persistent(false); // don't store the connection each time to save wear on the flash - WiFi.mode(WIFI_STA); - WiFi.setOutputPower(10); // reduce RF output power, increase if it won't connect - WiFi.config(staticIP, gateway, subnet); // if using static IP, enter parameters at the top - WiFi.begin(AP_SSID, AP_PASS); - Serial.print(F("connecting to WiFi ")); - Serial.println(AP_SSID); - DEBUG_PRINT(F("my MAC: ")); - DEBUG_PRINTLN(WiFi.macAddress()); - } - uint32_t wifiStart = millis(); - while ((WiFi.status() != WL_CONNECTED) && (millis() - wifiStart < wifiTimeout)) { - yield(); - } - if (WiFi.status() == WL_CONNECTED) { - DEBUG_PRINTLN(F("WiFi connected")); - } else { - Serial.println(F("WiFi timed out and didn't connect")); - } - uint32_t wifiFinish = millis(); // timeout if we don't get the IP addresses from DHCP - while ((!WiFi.localIP() && (WiFi.status() == WL_CONNECTED)) && (millis() - wifiFinish < wifiTimeout)) { - yield(); - } - WiFi.setAutoReconnect(true); - if (WiFi.localIP()) { - Serial.print(F("WiFi connect time = ")); - float reConn = (millis() - wifiBegin); - Serial.printf("%1.3f seconds\n", reConn / 1000); - DEBUG_PRINT(F("WiFi Gateway IP: ")); - DEBUG_PRINTLN(WiFi.gatewayIP()); - DEBUG_PRINT(F("my IP address: ")); - DEBUG_PRINTLN(WiFi.localIP()); - } else { - DEBUG_PRINTLN(F("IP addresses not acquired from DHCP")); - } -} From 56cb2397d0c08f3218a108949e152245ec58c7a0 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Sat, 1 Feb 2020 10:14:33 -0600 Subject: [PATCH 46/51] add Low-Power demo --- .../examples/LowPowerDemo/LowPowerDemo.ino | 444 ++++++++++++++++++ .../esp8266/examples/LowPowerDemo/README.md | 4 +- 2 files changed, 446 insertions(+), 2 deletions(-) create mode 100644 libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino new file mode 100644 index 0000000000..ab85a4ce5a --- /dev/null +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -0,0 +1,444 @@ +/* This example demonstrates the different low-power modes of the ESP8266 + + The initial setup was a WeMos D1 Mini with 3.3V connected to the 3V3 pin through a meter + so that it bypassed the on-board voltage regulator and USB chip. There's still about + 0.3 mA worth of leakage amperage due to the unpowered chips. These tests should work with + any module, although on-board components will affect the actual current measurement. + While the modem is turned on the amperage is > 67 mA or changing with a minimum value. + To verify the 20 uA Deep Sleep amperage the voltage regulator and USB chip were removed. + + This test series requires an active WiFi connection to illustrate two tests. If you + have problems with WiFi, uncomment the #define DEBUG for additional WiFi error messages. + The test requires a pushbutton switch connected between D3 and GND to advance the tests. + You'll also need to connect D0/GPIO16 to RST for the Deep Sleep tests. If you forget to + connect D0 to RST it will hang after the first Deep Sleep test. D0 is driven high during + Deep Sleep, so you should use a Schottky diode between D0 and RST if you want to use a + reset switch; connect the anode of the diode to RST, and the cathode to D0. + + Additionally, you can connect an LED from any free pin through a 1K ohm resistor to the + 3.3V supply, though preferably not the 3V3 pin on the module or it adds to the measured + amperage. When the LED blinks you can proceed to the next test. When the LED is lit + continuously it's connecting WiFi, and when it's off the CPU is asleep. The LED blinks + slowly when the tests are complete. Test progress can also be shown on the serial monitor. + + WiFi connections will be made over twice as fast if you can use a static IP address. + + This example is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This example is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this example; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include +#include // crc32() +#include +#include // WiFiState structure details + +//#define DEBUG // prints WiFi connection info to serial, uncomment if you want WiFi messages +#ifdef DEBUG +#define DEBUG_PRINTLN(x) Serial.println(x) +#define DEBUG_PRINT(x) Serial.print(x) +#else +#define DEBUG_PRINTLN(x) +#define DEBUG_PRINT(x) +#endif + +#define WAKE_UP_PIN 0 // D3/GPIO0, can also force a serial flash upload with RESET +// you can use any GPIO for WAKE_UP_PIN except for D0/GPIO16 as it doesn't support interrupts + +// uncomment one of the two lines below for your LED connection (optional) +#define LED 5 // D1/GPIO5 external LED for modules with built-in LEDs so it doesn't add amperage +//#define LED 2 // D4/GPIO2 LED for ESP-01,07 modules; D4 is LED_BUILTIN on most other modules +// you can use LED_BUILTIN, but it adds to the measured amperage by 0.3mA to 6mA. + +ADC_MODE(ADC_VCC); // allows you to monitor the internal VCC level; it varies with WiFi load +// don't connect anything to the analog input pin(s)! + +// enter your WiFi configuration below +const char* AP_SSID = "SSID"; // your router's SSID here +const char* AP_PASS = "password"; // your router's password here +IPAddress staticIP(0, 0, 0, 0); // parameters below are for your static IP address, if used +IPAddress gateway(0, 0, 0, 0); +IPAddress subnet(0, 0, 0, 0); +IPAddress dns1(0, 0, 0, 0); +IPAddress dns2(0, 0, 0, 0); +uint32_t wifiTimeout = 30E3; // 30 second timeout on the WiFi connection + +//#define TESTPOINT // used to track the timing of several test cycles (optional) +#ifdef TESTPOINT +#define testPointPin 4 // D2/GPIO4, you can use any pin that supports interrupts +#define testPoint_HIGH digitalWrite(testPointPin, HIGH) +#define testPoint_LOW digitalWrite(testPointPin, LOW) +#else +#define testPoint_HIGH +#define testPoint_LOW +#endif + +// This structure is stored in RTC memory to save the WiFi state and reset count (number of Deep Sleeps), +// and it reconnects twice as fast as the first connection; it's used extensively in this demo +struct nv_s { + WiFiState wss; // core's WiFi save state + + struct { + uint32_t crc32; + uint32_t rstCount; // stores the Deep Sleep reset count + // you can add anything else here that you want to save + } rtcData; +}; + +static nv_s* nv = (nv_s*)RTC_USER_MEM; // user RTC RAM area + +uint32_t resetCount = 0; // keeps track of the number of Deep Sleep tests / resets + +const uint32_t blinkDelay = 100; // fast blink rate for the LED when waiting for the user +esp8266::polledTimeout::periodicMs blinkLED(blinkDelay); // LED blink delay without delay() +esp8266::polledTimeout::oneShotFastMs altDelay(blinkDelay); // tight loop to simulate user code +// use fully qualified type and avoid importing all ::esp8266 namespace to the global namespace + +void wakeupCallback() { // unlike ISRs, you can do a print() from a callback function + testPoint_LOW; // testPoint tracks latency from WAKE_UP_PIN LOW to testPoint LOW + printMillis(); // show time difference across sleep; millis is wrong as the CPU eventually stops + Serial.println(F("Woke from Light Sleep - this is the callback")); +} + +void setup() { +#ifdef TESTPOINT + pinMode(testPointPin, OUTPUT); // test point for Light Sleep and Deep Sleep tests + testPoint_LOW; // Deep Sleep reset doesn't clear GPIOs, testPoint LOW shows boot time +#endif + pinMode(LED, OUTPUT); // activity and status indicator + digitalWrite(LED, LOW); // turn on the LED + pinMode(WAKE_UP_PIN, INPUT_PULLUP); // polled to advance tests, interrupt for Forced Light Sleep + Serial.begin(115200); + Serial.println(); + Serial.print(F("\nReset reason = ")); + String resetCause = ESP.getResetReason(); + Serial.println(resetCause); + resetCount = 0; + if ((resetCause == "External System") || (resetCause == "Power on")) { + Serial.println(F("I'm awake and starting the Low Power tests")); + } + + // Read previous resets (Deep Sleeps) from RTC memory, if any + uint32_t crcOfData = crc32((uint8_t*) &nv->rtcData.rstCount, sizeof(nv->rtcData.rstCount)); + if ((crcOfData = nv->rtcData.crc32) && (resetCause == "Deep-Sleep Wake")) { + resetCount = nv->rtcData.rstCount; // read the previous reset count + resetCount++; + } + nv->rtcData.rstCount = resetCount; // update the reset count & CRC + updateRTCcrc(); + + if (resetCount == 1) { // show that millis() is cleared across the Deep Sleep reset + printMillis(); + } +} // end of setup() + +void loop() { + if (resetCount == 0) { // if first loop() since power on or external reset + runTest1(); + runTest2(); + runTest3(); + runTest4(); + runTest5(); + runTest6(); + runTest7(); // first Deep Sleep test, all these end with a RESET + } + if (resetCount < 4) { + initWiFi(); // optional re-init of WiFi for the Deep Sleep tests + } + if (resetCount == 1) { + runTest8(); + } else if (resetCount == 2) { + runTest9(); + } else if (resetCount == 3) { + runTest10(); + } else if (resetCount == 4) { + resetTests(); + } +} //end of loop() + +void runTest1() { + Serial.println(F("\n1st test - running with WiFi unconfigured")); + readVoltage(); // read internal VCC + Serial.println(F("press the switch to continue")); + waitPushbutton(false, blinkDelay); +} + +void runTest2() { + Serial.println(F("\n2nd test - Automatic Modem Sleep")); + Serial.println(F("connecting WiFi, please wait until the LED blinks")); + initWiFi(); + if (WiFi.localIP()) { // won't go into Automatic Sleep without an active WiFi connection + Serial.println(F("The amperage will drop in 7 seconds.")); + readVoltage(); // read internal VCC + Serial.println(F("press the switch to continue")); + waitPushbutton(true, 90); /* This is using a special feature: below 100 mS blink delay, + the LED blink delay is padding 100 mS time with 'program cycles' to fill the 100 mS. + At 90 mS delay, 90% of the blink time is delay(), and 10% is 'your program running'. + Below 90% you'll see a difference in the average amperage: less delay() = more amperage. + At 100 mS and above it's essentially all delay() time. On an oscilloscope you'll see the + time between beacons at > 67 mA more often with less delay() percentage. You can change + the '90' mS to other values to see the effect it has on Automatic Modem Sleep. */ + } else { + Serial.println(F("no WiFi connection, test skipped")); + } +} + +void runTest3() { + Serial.println(F("\n3rd test - Forced Modem Sleep")); + WiFi.mode(WIFI_SHUTDOWN, &nv->wss); // shut the modem down and save the WiFi state for faster reconnection + // WiFi.forceSleepBegin(delay_in_uS); // alternate method of Forced Modem Sleep for an optional timed shutdown, + // with WiFi.forceSleepBegin(0xFFFFFFF); the modem sleeps until you wake it, with values <= 0xFFFFFFE it's timed + // delay(10); // it doesn't always go to sleep unless you delay(10); yield() wasn't reliable + readVoltage(); // read internal VCC + Serial.println(F("press the switch to continue")); + waitPushbutton(true, 99); /* Using the same < 100 mS feature. If you drop the delay below 100, you + will see the effect of program time vs. delay() time on minimum amperage. Above ~ 97 (97% of the + time in delay) there is little change in amperage, so you need to spend maximum time in delay() + to get minimum amperage.*/ +} + +void runTest4() { + Serial.println(F("\n4th test - Automatic Light Sleep")); + Serial.println(F("reconnecting WiFi with forceSleepWake")); + Serial.println(F("Automatic Light Sleep begins after WiFi connects (LED blinks)")); + // on successive loops after power-on, WiFi shows 'connected' several seconds before Sleep happens + // and WiFi reconnects after the forceSleepWake more quickly + digitalWrite(LED, LOW); // visual cue that we're reconnecting + WiFi.setSleepMode(WIFI_LIGHT_SLEEP, 3); // Automatic Light Sleep, DTIM listen interval = 3 + // at higher DTIM intervals you'll have a hard time establishing and maintaining a connection + WiFi.forceSleepWake(); // reconnect with previous STA mode and connection settings + uint32_t wifiStart = millis(); + while (((!WiFi.localIP()) || (WiFi.status() != WL_CONNECTED)) && (millis() - wifiStart < wifiTimeout)) { + yield(); + } + if (WiFi.localIP()) { // won't go into Automatic Sleep without an active WiFi connection + float reConn = (millis() - wifiStart); + Serial.print(F("WiFi connect time = ")); + Serial.printf("%1.3f seconds\n", reConn / 1000); + readVoltage(); // read internal VCC + Serial.println(F("long press of the switch to continue")); + waitPushbutton(true, 350); /* Below 100 mS delay it only goes into 'Automatic Modem Sleep', + and below ~ 350 mS delay() the 'Automatic Light Sleep' is less frequent. Above 500 mS + delay() doesn't make significant improvement in power savings. */ + } else { + Serial.println(F("no WiFi connection, test skipped")); + } +} + +void runTest5() { + Serial.println(F("\n5th test - Timed Light Sleep, wake in 10 seconds")); + Serial.println(F("Press the button when you're ready to proceed")); + waitPushbutton(true, blinkDelay); + WiFi.mode(WIFI_OFF); // you must turn the modem off; using disconnect won't work + readVoltage(); // read internal VCC + printMillis(); // show millis() across sleep, including Serial.flush() + digitalWrite(LED, HIGH); // turn the LED off so they know the CPU isn't running + testPoint_HIGH; // testPoint LOW in callback tracks delay from testPoint HIGH to LOW + extern os_timer_t *timer_list; + timer_list = nullptr; // stop (but don't disable) the 4 OS timers + wifi_fpm_set_sleep_type(LIGHT_SLEEP_T); + gpio_pin_wakeup_enable(GPIO_ID_PIN(WAKE_UP_PIN), GPIO_PIN_INTR_LOLEVEL); // GPIO wakeup (optional) + // only LOLEVEL or HILEVEL interrupts work, no edge, that's an SDK or CPU limitation + wifi_fpm_set_wakeup_cb(wakeupCallback); // set wakeup callback + // the callback is optional, but without it the modem will wake in 10 seconds then delay(10 seconds) + // with the callback the sleep time is only 10 seconds total, no extra delay() afterward + wifi_fpm_open(); + wifi_fpm_do_sleep(10E6); // Sleep range = 10000 ~ 268,435,454 uS (0xFFFFFFE, 2^28-1) + delay(10e3 + 1); // delay needs to be 1 mS longer than sleep or it only goes into Modem Sleep + Serial.println(F("Woke up!")); // the interrupt callback hits before this is executed +} + +void runTest6() { + Serial.println(F("\n6th test - Forced Light Sleep, wake with GPIO interrupt")); + Serial.flush(); + WiFi.mode(WIFI_OFF); // you must turn the modem off; using disconnect won't work + digitalWrite(LED, HIGH); // turn the LED off so they know the CPU isn't running + readVoltage(); // read internal VCC + Serial.println(F("CPU going to sleep, pull WAKE_UP_PIN low to wake it (press the switch)")); + printMillis(); // show millis() across sleep, including Serial.flush() + testPoint_HIGH; // testPoint tracks latency from WAKE_UP_PIN LOW to testPoint LOW in callback + wifi_fpm_set_sleep_type(LIGHT_SLEEP_T); + gpio_pin_wakeup_enable(GPIO_ID_PIN(WAKE_UP_PIN), GPIO_PIN_INTR_LOLEVEL); + // only LOLEVEL or HILEVEL interrupts work, no edge, that's an SDK or CPU limitation + wifi_fpm_set_wakeup_cb(wakeupCallback); // Set wakeup callback (optional) + wifi_fpm_open(); + wifi_fpm_do_sleep(0xFFFFFFF); // only 0xFFFFFFF, any other value and it won't disconnect the RTC timer + delay(10); // it goes to sleep during this delay() and waits for an interrupt + Serial.println(F("Woke up!")); // the interrupt callback hits before this is executed*/ +} + +void runTest7() { + Serial.println(F("\n7th test - Deep Sleep for 10 seconds, reset and wake with RF_DEFAULT")); + initWiFi(); // initialize WiFi since we turned it off in the last test + readVoltage(); // read internal VCC + Serial.println(F("press the switch to continue")); + while (!digitalRead(WAKE_UP_PIN)) { // wait for them to release the switch from the previous test + delay(10); + } + delay(50); // debounce time for the switch, pushbutton released + waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep + digitalWrite(LED, LOW); // turn the LED on, at least briefly + //WiFi.mode(WIFI_SHUTDOWN, &nv->wss); // Forced Modem Sleep for a more Instant Deep Sleep, + // and no extended RFCAL as it goes into Deep Sleep + Serial.println(F("going into Deep Sleep now...")); + printMillis(); // show time difference across sleep + testPoint_HIGH; // testPoint set HIGH to track Deep Sleep period, cleared at startup() + ESP.deepSleep(10E6, WAKE_RF_DEFAULT); // good night! D0 fires a reset in 10 seconds... + // if you do ESP.deepSleep(0, mode); it needs a RESET to come out of sleep (RTC is disconnected) + // maximum timed Deep Sleep interval ~ 3 to 4 hours depending on the RTC timer, see the README + // the 2 uA GPIO amperage during Deep Sleep can't drive the LED so it's not lit now, although + // depending on the LED used, you might see it very dimly lit in a dark room during this test + Serial.println(F("What... I'm not asleep?!?")); // it will never get here +} + +void runTest8() { + Serial.println(F("\n8th test - in RF_DEFAULT, Deep Sleep for 10 seconds, reset and wake with RFCAL")); + readVoltage(); // read internal VCC + Serial.println(F("press the switch to continue")); + waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep + //WiFi.mode(WIFI_SHUTDOWN, &nv->wss); // Forced Modem Sleep for a more Instant Deep Sleep, + // and no extended RFCAL as it goes into Deep Sleep + Serial.println(F("going into Deep Sleep now...")); + Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message + testPoint_HIGH; // testPoint set HIGH to track Deep Sleep period, cleared at startup() + ESP.deepSleep(10E6, WAKE_RFCAL); // good night! D0 fires a reset in 10 seconds... + Serial.println(F("What... I'm not asleep?!?")); // it will never get here +} + +void runTest9() { + Serial.println(F("\n9th test - in RFCAL, Deep Sleep Instant for 10 seconds, reset and wake with NO_RFCAL")); + readVoltage(); // read internal VCC + Serial.println(F("press the switch to continue")); + waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep + WiFi.mode(WIFI_SHUTDOWN, &nv->wss); // Forced Modem Sleep for a more Instant Deep Sleep + Serial.println(F("going into Deep Sleep now...")); + Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message + testPoint_HIGH; // testPoint set HIGH to track Deep Sleep period, cleared at startup() + ESP.deepSleepInstant(10E6, WAKE_NO_RFCAL); // good night! D0 fires a reset in 10 seconds... + Serial.println(F("What... I'm not asleep?!?")); // it will never get here +} + +void runTest10() { + Serial.println(F("\n10th test - in NO_RFCAL, Deep Sleep Instant for 10 seconds, reset and wake with RF_DISABLED")); + readVoltage(); // read internal VCC + Serial.println(F("press the switch to continue")); + waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep + //WiFi.mode(WIFI_SHUTDOWN); // Forced Modem Sleep for a more Instant Deep Sleep + Serial.println(F("going into Deep Sleep now...")); + Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message + testPoint_HIGH; // testPoint set HIGH to track Deep Sleep period, cleared at startup() + ESP.deepSleepInstant(10E6, WAKE_RF_DISABLED); // good night! D0 fires a reset in 10 seconds... + Serial.println(F("What... I'm not asleep?!?")); // it will never get here +} + +void resetTests() { + readVoltage(); // read internal VCC + Serial.println(F("\nTests completed, in RF_DISABLED, press the switch to do an ESP.restart()")); + memset(&nv->wss, 0, sizeof(nv->wss) * 2); // wipe saved WiFi states, comment this if you want to keep them + waitPushbutton(false, 1000); + ESP.restart(); +} + +void waitPushbutton(bool usesDelay, unsigned int delayTime) { // loop until they press the switch + // note: 2 different modes, as 3 of the power saving modes need a delay() to activate fully + if (!usesDelay) { // quick interception of pushbutton press, no delay() used + blinkLED.reset(delayTime); + while (digitalRead(WAKE_UP_PIN)) { // wait for a pushbutton press + if (blinkLED) { + digitalWrite(LED, !digitalRead(LED)); // toggle the activity LED + } + yield(); // this would be a good place for ArduinoOTA.handle(); + } + } else { // long delay() for the 3 modes that need it, but it misses quick switch presses + while (digitalRead(WAKE_UP_PIN)) { // wait for a pushbutton press + digitalWrite(LED, !digitalRead(LED)); // toggle the activity LED + delay(delayTime); // another good place for ArduinoOTA.handle(); + if (delayTime < 100) { + altDelay.reset(100 - delayTime); // pad the time < 100 mS with some real CPU cycles + while (!altDelay) { // this simulates 'your program running', not delay() time + } + } + } + } + delay(50); // debounce time for the switch, pushbutton pressed + while (!digitalRead(WAKE_UP_PIN)) { // now wait for them to release the pushbutton + delay(10); + } + delay(50); // debounce time for the switch, pushbutton released +} + +void readVoltage() { // read internal VCC + float volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); +} + +void printMillis() { + Serial.print(F("millis() = ")); // show that millis() isn't correct across most Sleep modes + Serial.println(millis()); + Serial.flush(); // needs a Serial.flush() else it may not print the whole message before sleeping +} + +void updateRTCcrc() { // updates the reset count CRC + nv->rtcData.crc32 = crc32((uint8_t*) &nv->rtcData.rstCount, sizeof(nv->rtcData.rstCount)); +} + +void initWiFi() { + digitalWrite(LED, LOW); // give a visual indication that we're alive but busy with WiFi + uint32_t wifiBegin = millis(); // how long does it take to connect + if ((crc32((uint8_t*) &nv->rtcData.rstCount + 1, sizeof(nv->wss)) && !WiFi.shutdownValidCRC(&nv->wss))) { + // if good copy of wss, overwrite invalid (primary) copy + memcpy((uint32_t*) &nv->wss, (uint32_t*) &nv->rtcData.rstCount + 1, sizeof(nv->wss)); + } + if (WiFi.shutdownValidCRC(&nv->wss)) { // if we have a valid WiFi saved state + memcpy((uint32_t*) &nv->rtcData.rstCount + 1, (uint32_t*) &nv->wss, sizeof(nv->wss)); // save a copy of it + Serial.println(F("resuming WiFi")); + } + if (!(WiFi.mode(WIFI_RESUME, &nv->wss))) { // couldn't resume, or no valid saved WiFi state yet + /* Explicitly set the ESP8266 as a WiFi-client (STAtion mode), otherwise by default it + would try to act as both a client and an access-point and could cause network issues + with other WiFi devices on your network. */ + WiFi.persistent(false); // don't store the connection each time to save wear on the flash + WiFi.mode(WIFI_STA); + WiFi.setOutputPower(10); // reduce RF output power, increase if it won't connect + WiFi.config(staticIP, gateway, subnet); // if using static IP, enter parameters at the top + WiFi.begin(AP_SSID, AP_PASS); + Serial.print(F("connecting to WiFi ")); + Serial.println(AP_SSID); + DEBUG_PRINT(F("my MAC: ")); + DEBUG_PRINTLN(WiFi.macAddress()); + } + uint32_t wifiStart = millis(); + while ((WiFi.status() != WL_CONNECTED) && (millis() - wifiStart < wifiTimeout)) { + yield(); + } + if (WiFi.status() == WL_CONNECTED) { + DEBUG_PRINTLN(F("WiFi connected")); + } else { + Serial.println(F("WiFi timed out and didn't connect")); + } + uint32_t wifiFinish = millis(); // timeout if we don't get the IP addresses from DHCP + while ((!WiFi.localIP() && (WiFi.status() == WL_CONNECTED)) && (millis() - wifiFinish < wifiTimeout)) { + yield(); + } + WiFi.setAutoReconnect(true); + if (WiFi.localIP()) { + Serial.print(F("WiFi connect time = ")); + float reConn = (millis() - wifiBegin); + Serial.printf("%1.3f seconds\n", reConn / 1000); + DEBUG_PRINT(F("WiFi Gateway IP: ")); + DEBUG_PRINTLN(WiFi.gatewayIP()); + DEBUG_PRINT(F("my IP address: ")); + DEBUG_PRINTLN(WiFi.localIP()); + } else { + DEBUG_PRINTLN(F("IP addresses not acquired from DHCP")); + } +} diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md index b8a71192ea..886eacc499 100644 --- a/libraries/esp8266/examples/LowPowerDemo/README.md +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -93,9 +93,9 @@ This last variation also uses Deep Sleep Instant, but it wakes up with the modem All of the Deep Sleep modes end with a RESET, so you must re-initialize nearly everything. You can store *some* information in the RTC memory to survive a Deep Sleep reset, which was done in this demo to illustrate the RTC memory. See the **RTCUserMemory** and **WiFiShutdown** examples for more on this feature. -The theoretical maximum Deep Sleep interval is 71.58 minutes (2^32 -1 microseconds), although you should use something less than that due to system time calculations. Realistic maximum is around 68 minutes. +Since SDK 2.1 the maximum Deep Sleep time has changed. The old maximum was based on uint32_t(micros) or ~71.58 minutes (2^32-1 microseconds). The new maximum is calculated from the RTC clock, which drifts with temperature from 5 to 7 timer ticks per microsecond, and will return a different number each time you read **system_rtc_clock_cali_proc()**. Depending on CPU and temperature, you will get between 3 and 4 hours maximum Deep Sleep. You can read the current theoretical maximum with **uint64_t deepSleepMax = ESP.deepSleepMax();** although you should set your time a little less than that due to the RTC drift. If you go over the maximum time when you finally enter Deep Sleep, it disconnects the timer and won't wake without an external RESET. -If you need a longer sleep time than 68 minutes, you can pass zero as the time variable to Deep Sleep and it turns off or disconnects the RTC. The only way to wake it at that point is an external RESET; D0 can't do it. Both Forced Light Sleep and Deep Sleep(0) are woken by an external signal, so short delays are more efficient with Forced Light Sleep, and longer delays are more energy efficient with Deep Sleep. +If you need a longer sleep time than 3 hours, you can pass zero as the time variable to Deep Sleep and it turns disconnects the RTC. The only way to wake it at that point is an external RESET; D0 can't do it. Both Forced Light Sleep and Deep Sleep(0) are woken by an external signal, so short delays are more efficient with Forced Light Sleep, and longer delays are more energy efficient with Deep Sleep. --- From c26ce4af813771d85dca1f13a4d6a6a45ca2a7fb Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Sat, 1 Feb 2020 10:18:40 -0600 Subject: [PATCH 47/51] add Low-Power demo --- libraries/esp8266/examples/LowPowerDemo/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md index 886eacc499..f080348116 100644 --- a/libraries/esp8266/examples/LowPowerDemo/README.md +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -95,7 +95,7 @@ All of the Deep Sleep modes end with a RESET, so you must re-initialize nearly e Since SDK 2.1 the maximum Deep Sleep time has changed. The old maximum was based on uint32_t(micros) or ~71.58 minutes (2^32-1 microseconds). The new maximum is calculated from the RTC clock, which drifts with temperature from 5 to 7 timer ticks per microsecond, and will return a different number each time you read **system_rtc_clock_cali_proc()**. Depending on CPU and temperature, you will get between 3 and 4 hours maximum Deep Sleep. You can read the current theoretical maximum with **uint64_t deepSleepMax = ESP.deepSleepMax();** although you should set your time a little less than that due to the RTC drift. If you go over the maximum time when you finally enter Deep Sleep, it disconnects the timer and won't wake without an external RESET. -If you need a longer sleep time than 3 hours, you can pass zero as the time variable to Deep Sleep and it turns disconnects the RTC. The only way to wake it at that point is an external RESET; D0 can't do it. Both Forced Light Sleep and Deep Sleep(0) are woken by an external signal, so short delays are more efficient with Forced Light Sleep, and longer delays are more energy efficient with Deep Sleep. +If you need a longer sleep time than 3 hours, you can pass zero as the time variable to Deep Sleep and it disconnects the RTC. The only way to wake it at that point is an external RESET; D0 can't do it. Both Forced Light Sleep and Deep Sleep(0) are woken by an external signal, so short delays are more efficient with Forced Light Sleep, and longer delays are more energy efficient with Deep Sleep. --- From a76ec12b42090590adda10ce560df0dca1fc3bb1 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Sat, 1 Feb 2020 10:50:59 -0600 Subject: [PATCH 48/51] add Low-Power demo --- libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index ab85a4ce5a..45f594c9b5 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -12,13 +12,13 @@ The test requires a pushbutton switch connected between D3 and GND to advance the tests. You'll also need to connect D0/GPIO16 to RST for the Deep Sleep tests. If you forget to connect D0 to RST it will hang after the first Deep Sleep test. D0 is driven high during - Deep Sleep, so you should use a Schottky diode between D0 and RST if you want to use a + Deep Sleep, so you should use a Schottky diode between D0 and RST if you want to use a reset switch; connect the anode of the diode to RST, and the cathode to D0. Additionally, you can connect an LED from any free pin through a 1K ohm resistor to the 3.3V supply, though preferably not the 3V3 pin on the module or it adds to the measured amperage. When the LED blinks you can proceed to the next test. When the LED is lit - continuously it's connecting WiFi, and when it's off the CPU is asleep. The LED blinks + continuously it's connecting WiFi, and when it's off the CPU is asleep. The LED blinks slowly when the tests are complete. Test progress can also be shown on the serial monitor. WiFi connections will be made over twice as fast if you can use a static IP address. From a79f48c34eff99b6dc4ac285ed6d66d47195df35 Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Sat, 1 Feb 2020 13:50:31 -0600 Subject: [PATCH 49/51] add Low-Power demo --- .../examples/LowPowerDemo/LowPowerDemo.ino | 42 ++++++++----------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index 45f594c9b5..eac966aa94 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -70,7 +70,7 @@ IPAddress gateway(0, 0, 0, 0); IPAddress subnet(0, 0, 0, 0); IPAddress dns1(0, 0, 0, 0); IPAddress dns2(0, 0, 0, 0); -uint32_t wifiTimeout = 30E3; // 30 second timeout on the WiFi connection +uint32_t timeout = 30E3; // 30 second timeout on the WiFi connection //#define TESTPOINT // used to track the timing of several test cycles (optional) #ifdef TESTPOINT @@ -83,14 +83,14 @@ uint32_t wifiTimeout = 30E3; // 30 second timeout on the WiFi connection #endif // This structure is stored in RTC memory to save the WiFi state and reset count (number of Deep Sleeps), -// and it reconnects twice as fast as the first connection; it's used extensively in this demo +// and it reconnects twice as fast as the first connection; it's used several places in this demo struct nv_s { WiFiState wss; // core's WiFi save state struct { uint32_t crc32; uint32_t rstCount; // stores the Deep Sleep reset count - // you can add anything else here that you want to save + // you can add anything else here that you want to save, must be 4-byte aligned } rtcData; }; @@ -100,7 +100,8 @@ uint32_t resetCount = 0; // keeps track of the number of Deep Sleep tests / res const uint32_t blinkDelay = 100; // fast blink rate for the LED when waiting for the user esp8266::polledTimeout::periodicMs blinkLED(blinkDelay); // LED blink delay without delay() -esp8266::polledTimeout::oneShotFastMs altDelay(blinkDelay); // tight loop to simulate user code +esp8266::polledTimeout::oneShotMs altDelay(blinkDelay); // tight loop to simulate user code +esp8266::polledTimeout::oneShotMs wifiTimeout(timeout); // 30 second timeout on WiFi connection // use fully qualified type and avoid importing all ::esp8266 namespace to the global namespace void wakeupCallback() { // unlike ISRs, you can do a print() from a callback function @@ -212,18 +213,19 @@ void runTest4() { Serial.println(F("Automatic Light Sleep begins after WiFi connects (LED blinks)")); // on successive loops after power-on, WiFi shows 'connected' several seconds before Sleep happens // and WiFi reconnects after the forceSleepWake more quickly - digitalWrite(LED, LOW); // visual cue that we're reconnecting + digitalWrite(LED, LOW); // visual cue that we're reconnecting WiFi + uint32_t wifiBegin = millis(); + WiFi.forceSleepWake(); // reconnect with previous STA mode and connection settings WiFi.setSleepMode(WIFI_LIGHT_SLEEP, 3); // Automatic Light Sleep, DTIM listen interval = 3 // at higher DTIM intervals you'll have a hard time establishing and maintaining a connection - WiFi.forceSleepWake(); // reconnect with previous STA mode and connection settings - uint32_t wifiStart = millis(); - while (((!WiFi.localIP()) || (WiFi.status() != WL_CONNECTED)) && (millis() - wifiStart < wifiTimeout)) { + wifiTimeout.reset(timeout); + while (((!WiFi.localIP()) || (WiFi.status() != WL_CONNECTED)) && (!wifiTimeout)) { yield(); } if (WiFi.localIP()) { // won't go into Automatic Sleep without an active WiFi connection - float reConn = (millis() - wifiStart); + float reConn = (millis() - wifiBegin); Serial.print(F("WiFi connect time = ")); - Serial.printf("%1.3f seconds\n", reConn / 1000); + Serial.printf("%1.2f seconds\n", reConn / 1000); readVoltage(); // read internal VCC Serial.println(F("long press of the switch to continue")); waitPushbutton(true, 350); /* Below 100 mS delay it only goes into 'Automatic Modem Sleep', @@ -416,29 +418,21 @@ void initWiFi() { DEBUG_PRINT(F("my MAC: ")); DEBUG_PRINTLN(WiFi.macAddress()); } - uint32_t wifiStart = millis(); - while ((WiFi.status() != WL_CONNECTED) && (millis() - wifiStart < wifiTimeout)) { + wifiTimeout.reset(timeout); + while (((!WiFi.localIP()) || (WiFi.status() != WL_CONNECTED)) && (!wifiTimeout)) { yield(); } - if (WiFi.status() == WL_CONNECTED) { - DEBUG_PRINTLN(F("WiFi connected")); - } else { - Serial.println(F("WiFi timed out and didn't connect")); - } - uint32_t wifiFinish = millis(); // timeout if we don't get the IP addresses from DHCP - while ((!WiFi.localIP() && (WiFi.status() == WL_CONNECTED)) && (millis() - wifiFinish < wifiTimeout)) { - yield(); - } - WiFi.setAutoReconnect(true); if (WiFi.localIP()) { + DEBUG_PRINTLN(F("WiFi connected")); Serial.print(F("WiFi connect time = ")); float reConn = (millis() - wifiBegin); - Serial.printf("%1.3f seconds\n", reConn / 1000); + Serial.printf("%1.2f seconds\n", reConn / 1000); DEBUG_PRINT(F("WiFi Gateway IP: ")); DEBUG_PRINTLN(WiFi.gatewayIP()); DEBUG_PRINT(F("my IP address: ")); DEBUG_PRINTLN(WiFi.localIP()); } else { - DEBUG_PRINTLN(F("IP addresses not acquired from DHCP")); + Serial.println(F("WiFi timed out and didn't connect")); } + WiFi.setAutoReconnect(true); } From ee4c701fca797f66be97260fb4b52c2b03505fcb Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Sat, 1 Feb 2020 14:15:04 -0600 Subject: [PATCH 50/51] add Low-Power demo --- libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index eac966aa94..e5d5e8264e 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -222,7 +222,8 @@ void runTest4() { while (((!WiFi.localIP()) || (WiFi.status() != WL_CONNECTED)) && (!wifiTimeout)) { yield(); } - if (WiFi.localIP()) { // won't go into Automatic Sleep without an active WiFi connection + if ((WiFi.status() == WL_CONNECTED) && WiFi.localIP()) { + // won't go into Automatic Sleep without an active WiFi connection float reConn = (millis() - wifiBegin); Serial.print(F("WiFi connect time = ")); Serial.printf("%1.2f seconds\n", reConn / 1000); @@ -380,7 +381,7 @@ void waitPushbutton(bool usesDelay, unsigned int delayTime) { // loop until the void readVoltage() { // read internal VCC float volts = ESP.getVcc(); - Serial.printf("The internal VCC reads %1.3f volts\n", volts / 1000); + Serial.printf("The internal VCC reads %1.2f volts\n", volts / 1000); } void printMillis() { @@ -422,7 +423,7 @@ void initWiFi() { while (((!WiFi.localIP()) || (WiFi.status() != WL_CONNECTED)) && (!wifiTimeout)) { yield(); } - if (WiFi.localIP()) { + if ((WiFi.status() == WL_CONNECTED) && WiFi.localIP()) { DEBUG_PRINTLN(F("WiFi connected")); Serial.print(F("WiFi connect time = ")); float reConn = (millis() - wifiBegin); From d37810214c1b8d0cb815746f91eb8a443c3fe38c Mon Sep 17 00:00:00 2001 From: StanJ <53401742+Tech-TX@users.noreply.github.com> Date: Sat, 1 Feb 2020 14:50:14 -0600 Subject: [PATCH 51/51] add Low-Power demo --- libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino index e5d5e8264e..7556c58820 100644 --- a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -223,7 +223,7 @@ void runTest4() { yield(); } if ((WiFi.status() == WL_CONNECTED) && WiFi.localIP()) { - // won't go into Automatic Sleep without an active WiFi connection + // won't go into Automatic Sleep without an active WiFi connection float reConn = (millis() - wifiBegin); Serial.print(F("WiFi connect time = ")); Serial.printf("%1.2f seconds\n", reConn / 1000);