Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Forced Light Sleep Mode not working #6642

Closed
downsider7 opened this issue Oct 14, 2019 · 24 comments
Closed

Forced Light Sleep Mode not working #6642

downsider7 opened this issue Oct 14, 2019 · 24 comments

Comments

@downsider7
Copy link

downsider7 commented Oct 14, 2019

I've followed the steps in the ESP8266 Non-OS SDK API Reference manual (v2.0.0,2016) page 97 (just checked no change in v3.0.1 of the manual)

Running on SDK 2.2.1, Core 2.5.2
Board ESP-12E

Serial.println("going to sleep");
wifi_station_disconnect();
wifi_set_opmode(NULL_MODE); // set WiFi mode to null mode.
wifi_fpm_set_sleep_type(LIGHT_SLEEP_T); // light sleep
wifi_fpm_open(); // enable force sleep
wifi_fpm_set_wakeup_cb(fpm_wakup_cb_func1); // Set wakeup callback
wifi_fpm_do_sleep(50*1000000);
delay(1000);
Serial.println("Awake")

What I see is the awake message 1 second after the going to sleep message. (I've tried with delays of 1,2,5 or 10s just incase it was taking time to sleep)

  • The current consumed is 14mA.
  • The callback function is never triggered.
  • The wifi_fpm_do_sleep() returns a status of 0, indicating success.
  • I have no timers enabled.
  • If I set the _do_sleep time as 0xFFFFFFF then the current does drop to < 1mA
  • If I add delays of 500ms between all the steps (to allow each instruction such as serial print to complete), then it still doesn't work
  • if the delay(1000) function is made longer than the wakeup time, then the callback function is triggered (but the current doesn't drop below 14mA)

Deep sleep works, the current drops to almost 0.
Modem sleep works.

I can't make force Light sleep work at all. The RF should be off, the CPU unclocked.

Does force light sleep work with any time other than 0xFFFFFFF? am I doing something daft?

@downsider7 downsider7 changed the title Light Sleep Mode not working Forced Light Sleep Mode not working Oct 16, 2019
@Tech-TX
Copy link
Contributor

Tech-TX commented Dec 30, 2019

@downsider7 try this

pinMode(WAKE_UP_PIN, INPUT_PULLUP);
// ...
WiFi.mode(WIFI_OFF);
delay(100);
Serial.println("Going to sleep, pull WAKE_UP_PIN low to wake me");
delay(3);  // needs a brief delay or the whole message above doesn't print
wifi_fpm_set_sleep_type(LIGHT_SLEEP_T);
gpio_pin_wakeup_enable(GPIO_ID_PIN(WAKE_UP_PIN), GPIO_PIN_INTR_LOLEVEL);
// or LOLEVEL or HILEVEL interrupt, no edge allowed, sorry, that's the SDK limitation
wifi_fpm_open();
wifi_fpm_do_sleep(0xFFFFFFF);
delay(100);
Serial.println("Woke up!");

I'm not using the callback, but the code above puts it in Forced Light Sleep for me. After the GPIO interrupt it falls through to the 'Woke up!' message.

Forced Light Sleep only works with wifi_fpm_do_sleep(0xFFFFFFF); any other value and it doesn't sleep.

I tried the WiFi disconnect, and it wouldn't go to Forced Light Sleep, only the WiFi.mode(WIFI_OFF); worked for me. Try that little chunk first to verify for yourself that Forced Light Sleep is working before you start adding your callback and other things. It's very sensitive to what's going on with WiFi.

If you're running a 12E DevKit, there's a minimum current of around 6 to 15mA due to the 3.3V voltage regulator and whatever USB <> serial chip you have on your board. You might be able to power it by feeding 3.3V into the 3V3 pin, although I'm unsure what state that leave the USB chip in. The CH340G might go into 'suspend' mode, I can't tell from the datasheet. I'll try it this weekend.

@Tech-TX
Copy link
Contributor

Tech-TX commented Jan 2, 2020

Here's an expanded set of low power tests with every power-saving mode I could think of or read about. If I've missed any, please let me know and I'll expand it a bit further. 😄 This should work with any build from 2.5 onward, unknown with builds before that but probably not.

/* 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.  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 <ESP8266WiFi.h>
#include <coredecls.h>         // crc32()
#include <PolledTimeout.h>
#include <include/WiFiState.h> // 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 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 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 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).
// non volatile data
struct nv_s {
  WiFiState wss; // core's wifi save state

  struct {
    uint32_t crc32;
    uint32_t rstCount;  // stores the Deep Sleep reset count
  } 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
#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 1000 mS before fully stopping
  Serial.println(F("Woke from Forced Light Sleep - this is the callback"));
}

void preinit() {
  ESP8266WiFiClass::preinitWiFiOff();
}

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 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.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 CRC from RTC memory
  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
  updateRTC();

  if (resetCount == 1) {  // show that millis() is cleared across Deep Sleep reset
    Serial.print(F("millis() = "));
    Serial.println(millis());
  }
}  // end of setup()

void loop() {
  if (resetCount == 0) {  // if first loop() since power on or external reset
    runTest1();
    runTest2();
    runTest3();
    runTest4();
    runTest5();
    runTest6();  // first Deep Sleep test, all these end with a RESET
  }
  if (resetCount < 4) {
    initWiFi();
  }
  if (resetCount == 1) {
    runTest7();
  } else if (resetCount == 2) {
    runTest8();
  } else if (resetCount == 3) {
    runTest9();
  } 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);
  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);
    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"));
  }
}

// 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
  //  WiFi.forceSleepBegin();  // alternate method of Forced Modem Sleep without saving WiFi state
  //  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"));
  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
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 when WiFi connects (LED blinks)"));
  digitalWrite(LED, LOW);  // visual cue that we're reconnecting
  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)) {
    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);
    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. */
  } else {
    Serial.println(F("no WiFi connection, test skipped"));
  }
}

// 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
  delay(10);
  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
  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 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
  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
  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 previous test
    delay(10);
  }
  delay(50);  // debounce time for the switch, pushbutton released
  waitPushbutton(true, 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..."));
  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()
#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)
  // 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
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 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
#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...
  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);
  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
#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...
  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);
  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
#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...
  Serial.println(F("What... I'm not asleep?!?"));  // it will never get here
}

void resetTests() {
  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()"));
  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 updateRTC() {  // 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 (WiFi.shutdownValidCRC(&nv->wss)) {  // if we have a valid WiFi saved state
    Serial.println(F("attempting to resume WiFi"));
    if (!(WiFi.mode(WIFI_RESUME, &nv->wss))) {  // try to resume it
      Serial.println(F("issue resuming WiFi\n"));
    }
  } else {
    /* 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"));
  }
  wifiStart = millis();  // timeout if we don't get the IP addresses from DHCP
  while ((!WiFi.localIP() && (WiFi.status() == WL_CONNECTED)) && (millis() - wifiStart < 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"));
  }
}

If you're connected through USB, this is what the serial monitor will show, plus my current measurements in BOLD with the extra chips cut off of the D1 Mini:

{boot message}
Reset reason = External System
I'm awake and starting the low power tests

1st test - running with WiFi unconfigured
The internal VCC reads 3.042 volts {current reads 67mA}
press the button to continue

2nd test - Automatic Modem Sleep
connecting WiFi, please wait until the LED blinks
{WiFi connection messages}
The current will drop in 7 seconds.
The internal VCC reads 3.041 volts {current reads 18mA minimum}
press the button to continue

3rd test - Forced Modem Sleep
The internal VCC reads 3.065 volts {current reads 15mA}
press the button to continue

4th test - Automatic Light Sleep
reconnecting WiFi
it will be in Automatic Light Sleep once WiFi connects (LED blinks)
The internal VCC reads 3.041 volts {current reads 5mA minimum}
press the button to continue

5th test - Forced Light Sleep using NONOS SDK calls
CPU going to sleep, pull WAKE_UP_PIN low to wake it (press the button)
The internal VCC reads 3.042 volts {current reads 4mA}
Woke from Forced Light Sleep - this is the callback
Woke up!

6th test - Deep Sleep for 10 seconds, wake with RF_DEFAULT
{WiFi connection messages}
The internal VCC reads 3.065 volts {current reads 16uA during Deep Sleep}
press the button to continue
going into Deep Sleep now...
{boot message}
Reset reason = Deep-Sleep Wake
{WiFi connection messages}

7th test - in RF_DEFAULT, Deep Sleep for 10 seconds, wake with RFCAL
The internal VCC reads 3.045 volts {current reads 16uA during Deep Sleep}
press the button to continue
going into Deep Sleep now...
{boot message}
Reset reason = Deep-Sleep Wake
{WiFi connection messages}

8th test - in RFCAL, Deep Sleep for 10 seconds, wake with NO_RFCAL
The internal VCC reads 3.042 volts {current reads 16uA during Deep Sleep}
press the button to continue
going into Deep Sleep now...
{boot message}
Reset reason = Deep-Sleep Wake
{WiFi connection messages}

9th test - in NO_RFCAL, Deep Sleep for 10 seconds, wake with RF_DISABLED
The internal VCC reads 3.041 volts {current reads 16uA during Deep Sleep}
press the button to continue
going into Deep Sleep now...
{boot message}
Reset reason = Deep-Sleep Wake
The internal VCC reads 3.313 volts {current reads 18mA}

Tests completed, in RF_DISABLED, press the button to do an ESP.restart()

{end of tests, it restarts from here}

The tests were all run with 80MHz CPU since most ICs use more power at higher speeds. The current for Forced Light Sleep and Deep Sleep was the same for both 80 and 160MHz as the clock was stopped.

@downsider7
Copy link
Author

Thank you for this - I will start having a look at it as soon as I get home from work.

:-)

@downsider7
Copy link
Author

downsider7 commented Jan 2, 2020

@Tech-TX Looking through your comments, it seems to confirm what I have found - you can only wake from light forced sleep with an I/O pin - you can't wake from that state with a sleep time OR a pin wiggle wake.

I need to think through my application and see if I can work with that, or whether its possible to get a pin wiggle from the RTC and simply diode-OR that with my external wake-up signal.

Thank you for confirming "Forced Light Sleep only works with wifi_fpm_do_sleep(0xFFFFFFF); any other value and it doesn't sleep." - that saves me a lot of heartache and frustration thinking I was doing something wrong.

I don't want to use Deep Sleep + RTC to reset the chip as I want to preserve status (without having to write into the RTC memory).

@Tech-TX
Copy link
Contributor

Tech-TX commented Jan 3, 2020

@downsider7 I edited the file a little to make it more user friendly, but it still works the same. I removed everything that wasn't absolutely needed to put the chip into the various power modes. There's a LOT of examples of people with different solutions, many now out of date. Everything works with the current core & lwIP, unknown if it works on anything before 2.5.0.

The table in the Espressif 'Low Power Solutions' PDF is both out of date and incomplete or confusing on the various low-power modes. Here's my revision to it:

Table 1 1 Differences Between the Three Sleep Modes

I haven't re-verified the average current in the 3 DTIM modes as I don't yet have a good way to do that. It's hard to calculate average power by visually reading a Fluke meter. 😝

I'm guessing that the CPU clock is cycling slower periodically during Automatic Light Sleep, as I see the current drop to 5mA (see the scope trace below). I suspect that will mess with the system timer that tracks time since boot / power on, but haven't verified that yet.

Automatic Light Sleep

@d-a-v
Copy link
Collaborator

d-a-v commented Jan 6, 2020

@Tech-TX

There's a LOT of examples of people with different solutions, many now out of date

This is true. There is also #6356 which tries to address this issue, with its example.

Would you have a chance to test it with your hardware tools, and possibly update the core functions with your findings, in #6989 ?

@Tech-TX
Copy link
Contributor

Tech-TX commented Jan 11, 2020

@d-a-v I'm sorry David, I didn't notice your request until late last night. It looks like your example runs OK and does what you're expecting, although I'm having a hard time following what your state machine is doing on the scope as it's frequently changing states. Was there anything in particular you wanted me to look at?

I get slightly different current readings on an unmodified clone D1 Mini:
~80mA during normal operations
~25mA during wifi shutdown
~6mA during deepsleep

compared to your readings
~85mA during normal operations
~30mA during wifi shutdown
~5mA during deepsleep

On the board I've cut the chips off, it's even lower:
~71mA during normal operations
~18-20mA during wifi shutdown (for some reason I'm not getting the 15mA I got last weekend)
~16uA during deepsleep

I agree on updating the core functions to force the selected sleep mode independent of what the user has done. That eliminates a couple of the extra steps I had to do in my example. I see you're doing a delay() after WIFI_OFF in one place. I've just verified that the minimum is either delay(5) or yield() to insure that it goes into modem shutdown, otherwise it's erratic whether it goes to sleep or not. The most reliable seems to be delay(10) across the range of boards I've tried today.

By the way, I'm walking down a bug with the SDK calls to put the chip in Forced Modem Sleep. On one of my boards I was getting soft WDT resets. The delay(5) below seems to have fixed it.

wifi_station_disconnect();
delay(10);  // without at least delay(5) here I get soft WDT resets on the delay() at the bottom
wifi_set_opmode(NULL_MODE);
wifi_fpm_set_sleep_type(MODEM_SLEEP_T);
wifi_fpm_open();
wifi_fpm_do_sleep(0xFFFFFFF);
delay(10);  // without this minimum delay it infrequently goes into Forced Modem Sleep

I don't know if this is related to the WDT resets that were described in #6266 and #6172

edit: the Forced Modem Sleep current only gets to a low of 15mA when you're in a long delay(). When your code is running it's around 19-20mA. Looping on delay(350) the current bounces around between 15 and 16mA.

@Tech-TX
Copy link
Contributor

Tech-TX commented Jan 12, 2020

David, the only thing I noted was that WiFi.mode(WIFI_RESUME) doesn't bring it out of Forced Modem Sleep. It turns the modem on (current goes up to 67mA) but there aren't any spikes from the WiFi trying to reconnect.
The WiFi.mode(WIFI_SHUTDOWN) works to put it in Forced Modem Sleep, but requires WiFi.forceSleepWake() or a full re-initialization of WiFi to bring the WiFi back up.

Interestingly, WiFi.mode(WIFI_SHUTDOWN) doesn't require a delay(10) after it like WiFi.forceSleepBegin() does. I've been running yours all day without the delay() and never seen it fail once. I've probably hit it over 100 times on 6 different boards. With WiFi.forceSleepBegin() it would fail about 25-50% of the time and not go into Forced Modem Sleep without the delay().

@d-a-v
Copy link
Collaborator

d-a-v commented Jan 17, 2020

@Tech-TX
Your findings are very valuable.
My initial attempt was to hide this complexity under an updated API for, like you say in #6989, helping others. This was an old idea made real by #6356 (see refs inside) with the same motivation as yours.
I knew SHUTDOWN and RESUME wouldn't be perfect (I am glad anyway that we have close numbers when regulator and serial chips are VCCed).
You claim my example and its state machine is not clear. And despite my efforts you are right. Yours is also quite hairy :) This highlights the fact that it needs to be hidden under an API for everyone's mind health.
You seem to have reviewed the API update from #6356 and have proposals to fix it.

What do you think of adding in #6989 :

It may be too much to do at once but your feeling about that is interesting to know.

@Tech-TX
Copy link
Contributor

Tech-TX commented Jan 18, 2020

David, I think you're taking offense where none was meant. I didn't say your example was unclear, only that I couldn't follow the state changes on the 'scope. It was changing too frequently to take more than a brief measurement, and I'd have needed to bring out a bunch of test points to the pins to add into my mixed-signal oscilloscope so I could identify each state and the result.

That's why I stopped everything at each of the tests: it allows the user to take a breath and look at what it's doing in each sleep mode. If they're trying to integrate average current over time then it's simpler when it's only doing one thing. I don't yet have a way to monitor average current/amperage, but I have all the parts. It just needs time and code.

My snarky comment in the README about 'poor examples' was what I'd found on arduino.cc, Espressif's BBS and esp8266.com. I hadn't seen your example until you mentioned it, as 'WiFiShutdown' doesn't immediately bring to mind 'sleep modes'; I knew how to turn WiFi off already. 😃 I'd read a lot of pages from other people trying to get different types of sleep to work, and many were failing. That's why I did a demonstrator of the minimum required to get into all of the sleep modes.

From what I understand of your demo, it's a stress-test trying to see if repeated WiFi connects/resumes are OK across Deep Sleep and/or Forced Modem Sleep, and it illustrates the new SHUTDOWN/RESUME class.

You don't need to do anything with #6356 as it works. I wasn't able to use the WiFi.mode(WIFI_RESUME) as I can't figure out how it works. I'm only barely functional at C and not competent at C++ so I don't understand much of ESP8266WiFiGeneric.cpp and the relevant parts of WiFiShutdown.ino. I presume it's C++ as I don't recognize the symbols in those positions.

@d-a-v
Copy link
Collaborator

d-a-v commented Jan 19, 2020

No offense taken :) I take for granted that some of my examples are not clear enough.
Regarding the WiFiShutdown-to-be-renamed one, we can make the delay configurable between states.
Regarding WIFI_RESUME, ::resumeFromShutdown() is called in which wifi is restarted with what was saved in the nv/rtc-ram-argument.

Anyway I look forward your example to be merged so I can try and improve the internal API then propose another example based on yours but using the API in the usual arduino way (simple example so one help me until it is simple enough).

@Tech-TX
Copy link
Contributor

Tech-TX commented Jan 20, 2020

Yes, I understand what you're doing and how... I got that quickly from simple inspection. The SHUTDOWN routine stores the details from the connection in the WiFiState struct (if it exists), and the RESUME then uses that struct to restore the connection more quickly. It's a nice arrangement, and essentially halves the reconnect time (or faster). That would be handy as my router is VERY slow at reconnects at times, taking over 20 seconds. The pointers are what's tripping me up, as I've only dealt with them from the other direction (writing assembly drivers that our C folks used). I never got into C until summer, so I'm going through the learning pains now that you sailed through years ago. ;-)

@Tech-TX
Copy link
Contributor

Tech-TX commented Jan 22, 2020

I'm almost done integrating your new modes into my tests, just need to fix one pointer I goofed up last night. I'm getting about the same resume times you are, which is encouraging. Twice as fast on reconnect is great!

@Tech-TX
Copy link
Contributor

Tech-TX commented Jan 23, 2020

@d-a-v am I correct in assuming that WiFi.mode(WIFI_RESUME, (struct)) invalidates the stored CRC / struct once it's done resuming? That's the effect I'm seeing, and I'm not sure if it's intended. I can resume once, but when trying to resume a second time the saved state is no longer valid. It only works once after doing WiFi.mode(WIFI_SHUTDOWN, (struct)). I could copy the whole struct to another area of RTC memory as it's only 152 bytes / 38 words long, and then copy it back if the saved state isn't valid.

I've updated the demo above with my latest version, including pasting bits of your WiFiShutdown code in. It's all working OK.

@d-a-v
Copy link
Collaborator

d-a-v commented Jan 23, 2020

Yes, nvram data is invalidated on success on purpose.

It's all working OK.

Thanks for testing this api and putting it into a better example !

@Tech-TX
Copy link
Contributor

Tech-TX commented Jan 24, 2020

Not better, merely different. You were looking at other problems than I was. I was frustrated in summer trying to get the Sleep modes to work, and the documentation didn't help much. When I saw downsider7 struggling with the same issues I'd had, I needed to correct the docs or make them more clear.

I was a teacher for a while (and still am occasionally) so I'm a bit more wordy than most people. I write for 14 year old kids, as that's about when I started microprocessors back in the Dark Ages with a CDP1802 as my first computer. The ESP8266 with the IDE is a much nicer 'first micro' trainer today.

I think I have a final copy of the demo, just going through it line-by-line to make sure everything is correct and works where I give them easy options to change things. It's both a demo and an experimenter's kit.

@Tech-TX
Copy link
Contributor

Tech-TX commented Jan 25, 2020

@d-a-v maybe you can suggest something here. I'm trying to get the preinitWiFiOff(); to work, as it apparently got broken sometime in the last (year?). I presume it worked at one point.
The problem is two-fold:

  1. Forced Modem Sleep won't reliably go to sleep without the CPU executing an 'idle task'
    modem sleep note
    I have 1 CPU that's 2 years old and several that are new, and I can verify that all 6 chips need at least delay(1) to sleep the modem.

  2. delay() in core_esp8266_wiring.cpp has not been initialized before the preinit() stage of boot, so attempting to call delay(10) inside ESP8266WiFiGeneric.cpp returns immediately without calling esp_schedule() for 10ms (the 'idle task').

Here's the quick test I did, and what I attempted in ESP8266WiFiGeneric.cpp to fix it so that preinitWiFiOff() works again. The circled numbers relate to the pin wiggles further below so you can see what is happening, and when:

preinit code

Here's the result on the 'scope, first a wide view of the boot + setup(), then zooming in on the preinit(), zooming again, then scrolled over to setup() in the last screen. The top trace is my pin wiggle, the lower trace is CPU amps/current. The time per division for the 'scope is at the top of the display. The last two screens are 100us per division.

preinit 1
preinit 2
preinit 3
preinit 4

wifi_set_opmode_current(NULL_MODE); is the same as wifi_set_opmode_current(WIFI_OFF); as both variables are zero. I'd copied my code (cloned and fixed from the Espressif example) in place of what's in ESP8266WiFiGeneric.cpp for the preinitWiFiOff() function during this investigation. The same sequence is used in setup() in the example. The delay() in preinitWiFiOff() never executes, nor does the one at the bottom of preinit(). Short of cloning the delay() code into preinitWiFiOff() so that I can force it to idle, I don't see a way to make this work.

Here's the example I used above with GPIO4 used for the pin wiggles:

#include <ESP8266WiFi.h>

void preinit() {
  pinMode(4, OUTPUT);
  digitalWrite(4, LOW);  // pin wiggle (1)
  ESP8266WiFiClass::preinitWiFiOff();  // currently not working
  delay(10);  // never executes
  digitalWrite(4, LOW);  // pin wiggle (4)
}

void setup() {
  pinMode(4, OUTPUT);
  digitalWrite(4, HIGH);  // pin wiggle (5)
  digitalWrite(4, LOW);  // pin wiggle
  digitalWrite(4, HIGH);  // pin wiggle
  digitalWrite(4, LOW);  // pin wiggle
  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
  delay(1);  // without a delay() here it doesn't reliably enter sleep
  digitalWrite(4, HIGH);  // pin wiggle (6)
  digitalWrite(4, LOW);  // pin wiggle
  digitalWrite(4, HIGH);  // pin wiggle
}

void loop() {
}

@Tech-TX
Copy link
Contributor

Tech-TX commented Jan 26, 2020

Never mind, I just re-found something that accomplishes nearly the same end that igrr did back in 2016. Tested, and it somewhat works with the current git. His old code from back then doesn't work any longer as-written. It won't sleep at all, but it does stop the RFCAL.
#2111 (comment)

First cut, turn off the RFCAL in boot, and put as much of the Forced Modem Sleep inside preinit() as possible, with the delay(1) the first thing in setup(),

#include <ESP8266WiFi.h>

RF_PRE_INIT() {
  pinMode(4, OUTPUT);
  digitalWrite(4, HIGH);  // pin wiggle (1)
  system_phy_set_powerup_option(2);  // shut down the RFCAL at boot
  digitalWrite(4, LOW);  // pin wiggle (2)
}

void preinit() {
  pinMode(4, OUTPUT);
  digitalWrite(4, HIGH);  // pin wiggle (3)
  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, can't put this in RF_PRE_INIT or it doesn't sleep
  wifi_fpm_do_sleep(0xFFFFFFF);  // force modem to enter sleep mode, in RF_PRE_INIT this causes exceptions
  digitalWrite(4, LOW);  // pin wiggle (4)
  // won't go into Forced Modem Sleep until it sees the delay(1) in setup()
}

void setup() {
  digitalWrite(4, HIGH);  // pin wiggle (5)
  delay(1);  // G'night, John-Boy
  digitalWrite(4, LOW);  // pin wiggle (6)
}

void loop() {
}

and the result is:
RF_PRE_INIT1

Second cut, move as much inside RF_PRE_INIT() as will work, saving another 600+us of that modem power burst,

#include <ESP8266WiFi.h>

RF_PRE_INIT() {
  pinMode(4, OUTPUT);
  digitalWrite(4, HIGH);  // pin wiggle (1)
  system_phy_set_powerup_option(2);  // shut the RFCAL at boot
  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
  digitalWrite(4, LOW);  // pin wiggle (2)
}

void preinit() {
  pinMode(4, OUTPUT);
  digitalWrite(4, HIGH);  // pin wiggle (3)
  wifi_fpm_open();  // enable Forced Modem Sleep, can't put this in RF_PRE_INIT or it doesn't sleep
  wifi_fpm_do_sleep(0xFFFFFFF);  // force modem to enter sleep mode, in RF_PRE_INIT this causes exceptions
  digitalWrite(4, LOW);  // pin wiggle (4)
  // won't go into Forced Modem Sleep until it sees the delay(1) in setup()
}

void setup() {
  digitalWrite(4, HIGH);  // pin wiggle (5)
  delay(1);  // G'night, John-Boy
  digitalWrite(4, LOW);  // pin wiggle (6)
}

void loop() {
}

Slightly better power management, but you still can't boot it with a 50mA power supply unless you have a small supercap to hold the power up during the modem turn-on, That's too long of a burst for a regular electrolytic capacitor to supply unless you have a huge capacitor. I used a 1 ohm shunt for the current measurements, so the scope readings here are 50mA per major vertical division.
RF_PRE_INIT2

I don't think it's worth trying to move the delay() inside preinit() as that only saves another 150us of that 70mA modem burst, The effort would be better spent moving the modem turn-on after preinit(). Looks like the second cut above is the best we'll get today.

RF_PRE_INIT3

Third and final cut, using a write to the system RTC area to sort-of sleep the modem for lower power,
#7055 (comment)

modem shutdown working

@d-a-v
Copy link
Collaborator

d-a-v commented Jan 27, 2020

Thanks for the very fine detailed analysis and clear explanation.
I understand your current issue is delay() not able to run at that step of the booting process: delay() is executed without error but no delay is really introduced.

  • Did you try to call delay(0) or esp_schedule() multiple times for 1ms (using esp_get_cycle_count()) ?
    (side note: I don't really know the effect of esp_schedule() which is ets_post(LOOP_TASK_PRIORITY, 0, 0); before the main arduino user task is started)
  • What happens when all preinit() code is moved to RF_PRE_INIT() ?
  • If it is better to have both functions, you can try to save more usecs by moving preinit() earlier from inside its caller
    preinit(); // Prior to C++ Dynamic Init (not related to above init() ). Meant to be user redefinable.

@Tech-TX
Copy link
Contributor

Tech-TX commented Jan 31, 2020

@d-a-v Calling delay(0), delay(1) or esp_schedule() 1000 times inside preinit() adds about a millisecond to the preinit(), but doesn't turn off the modem. I also tried them with a 2000 count, adding 2ms: still no joy.

When I individually move these out of preinit() into RF_PRE_INIT()

  wifi_fpm_open();
  wifi_fpm_do_sleep(0xFFFFFFF);

The wifi_fpm_open() apparently doesn't execute in RF_PRE_INIT(), as it won't sleep. It must need (unknown conditions) set up before it executes that aren't there by the time of RF_PRE_INIT(). When I also move wifi_fpm_do_sleep(0xFFFFFFF) inside RF_PRE_INIT() I get this in loop():

ets Jan 8 2013,rst cause:2, boot mode:(3,6)

load 0x4010f000, len 3456, room 16
tail 0
chksum 0x84
csum 0x84
vfecacfd5
~ld

which looks like a software WDT every 4 seconds, but without the WDT message and no stack trace.

From what I can glean from the API reference, 'idle' (delay) does something in the blob or CPU that allows the power management modes to execute. It needs the OS_timer running, and I'd guess it's not initialized before preinit() happens. I found delay() in core_esp8266_wiring.cpp but don't understand what happens there as I haven't played with the OS_timer. It sets & arms the timer, executes a yield(), then disarms the timer and falls through. I get lost in the yield() and esp_schedule() code, and don't see control passing to the blob anywhere there. I know from previous tests that yield() alone won't set the power management mode, it needs delay() (so whatever is underneath esp_schedule(), or yield() and then esp_schedule()).

edit: I looked in an object dump for 'idle' and found it. Unfortunately I'm not that good at reading Xtensa assembly yet, so I can see some of what it's doing in idle but not why. Looks like the idle timer is nearly the same code as something called a 'noise timer' so it merged the two routines in the compiler, which confuses things a bit.

@Tech-TX
Copy link
Contributor

Tech-TX commented Feb 1, 2020

@downsider7 I don't know if you've been following my pull request for the demo, but I got Timed Light Sleep running several days ago. It's solid. On the boards that don't have voltage regs or USB chips, I read ~ 360uA when it's in Timed or Forced Light Sleep. Since the Timed version is only using 7 nybbles for the time, the maximum timed sleep is 2^28-1 microseconds, ~ 268 seconds. I really wish they'd used a millisecond timebase for the timed sleep modes instead of microsecond. The microsecond 'accuracy' is a complete waste, due to the irregularity in restarting the CPU clock (baseband PLL). Having a sleep that would last over a day would have been more handy.

@TD-er
Copy link
Contributor

TD-er commented Feb 1, 2020

I read ~ 360uA

Just curious, how do you measure those low currents?
It is very easy to be off by a big factor with those low currents.
Still it will be very clear to see if a node is in sleep mode or not, but for truly deep sleep applications it is good to know the right order of current it draws.

@Tech-TX
Copy link
Contributor

Tech-TX commented Feb 1, 2020

@TD-er I'm running a Wavetek DM27XT DVM in-line with the power to the chip. The DVM's minimum range is 200uA full-scale, and it goes up to a 10A range. It's repeatable and at least as accurate as my Fluke, but has a lower current range than the Fluke does (2mA full-scale minimum range). I'm also monitoring on the 'scope with a 1 ohm shunt, but the 'scope isn't nearly as accurate.

@devyte
Copy link
Collaborator

devyte commented Feb 2, 2020

Given that #6989 is merged, and the length and weight of this thread, I'm closing. For discussions on @d-a-v 's comments about the pseudo modes and a user-facing api, please see #7055. For other power mode issues, please open a new issue and fill out the required info.

@devyte devyte closed this as completed Feb 2, 2020
@devyte devyte added this to the 2.7.0 milestone Feb 2, 2020
freemandealer added a commit to freemandealer/IsRestroomOccupied that referenced this issue Jun 30, 2022
ref: esp8266/Arduino#6642

Signed-off-by: freemandealer <freeman.zhang1992@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants