Posted on 16 Comments

Max deep sleep for ESP8266

max deep sleep for ESP8266

In light of our recent power-consumption related posts 1 & 2 it seemed logical to ask ourselves about max deep sleep for ESP8266. Yet, it took a comment from a curious reader to set things in motion. I replied

…the maximum value for a 32-bit unsigned integer is 4294967295 or 0xffffffff. Hence, the max deep sleep interval appears to be ~71 minutes.

You can’t argue with that first statement but the second is a bit in the air without clear evidence. My co-founder Dani quite rightly then asked “are you sure, didn’t they change that recently?” (“they” being Espressif and/or the Arduino devs).

So then, what is the current max deep sleep for ESP8266 i.e. the maximum duration the ESP8266 can sleep deeply – and still wake up afterwards.

Deep sleep basics

The intention of this post is not primarily to talk about ESP8266 deep sleep in general but about max deep sleep for ESP8266. If you’re interested in the former there’s a very nice article from Losant with great explanations and sample code for Arduino. Below are just the absolutely essential corner stones.

Hardware

The RST pin is held HIGH while the ESP8266 is running. When it receives a LOW signal, it restarts the microcontroller. Once your device is in deep sleep, it will send a LOW signal to GPIO 16 when the sleep timer is up. Now, if you connect GPIO 16 to RST the device will wake up (i.e. reset) when deep sleep is over.

Ideally you put a low-valued resistor, like 330Ω – 1kΩ, between the two pins. For development boards like the NodeMCU v2 or the WeMOS D1 mini this is essential in order for flashing over serial-to-usb to work or for receiving serial output.

Side note: on the NodeMCU modules, GPIO 16 is marked as D0.

See some impressions below and note the resistor in the 2nd image.

ESP8266 deep sleep impressions
Connecting GPIO16/D0 with RST on an ESP8266

Software/API

The Espressif NON-OS SDK, on which the ESP8266 Arduino integration is based,  offers the  system_deep_sleep function (and the more adventurous system_deep_sleep_instant) to send the MCU to sleep. It accepts a single parameter that denotes the sleep duration in μs. Why microseconds? Can you image a situation in which you’d want the MCU to sleep less than a second? If you consider that it might take up to 100ms until it actually sleeps after you issued the command this becomes even more absurd. But it is what it is.

In Arduino land that deep sleep function is made available as ESP.deepSleep(duration, wakeMode) with the second parameter being effectively optional. It is used to set system_deep_sleep_set_option internally.

Changes with Espressif SDK 2.1

Remember my initial “…32-bit unsigned integer is 4294967295 or 0xffffffff…” statement? It referred to the data type of the system_deep_sleep parameter (that μs thing).

Well, it used to be a 32-bit unsigned integer; a uint32_t in Arduino lingo. Hence, deep sleep could last at most 4294967295μs or ~71min. You simply can’t fit a larger number than that into a uint32_t. If you tried, it would overflow and you’d possibly get a much lower value.

With SDK 2.1 Espressif changed the data type of that parameter to a 64-bit unsigned integer; a uint64_t. So, in theory you could send the MCU to deep sleep for some 5’124’095’576 hours ((2^64-1)/(3600 * 10^6) i.e. (2^64-1)/μs-per-hour). As this is neither useful nor practical they also documented the realistic limit which Arduino calculates in ESP.deepSleepMax().

Note that in order to test this you need ESP8266 Arduino core 2.4.1 or higher!

Max deep sleep for ESP8266

Theory

So, if you wanted to find the effective max deep sleep for ESP8266 you would simply have to print ESP.deepSleepMax() to console or make it otherwise visible, right?

Turns out Arduino String/toInt/Serial.print() can’t handle printing 64 bit values.

So, let’s write a helper function first then:


// source: https://github.com/markszabo/IRremoteESP8266/blob/master/src/IRutils.cpp#L48
String uint64ToString(uint64_t input) {
String result = "";
uint8_t base = 10;
do {
char c = input % base;
input /= base;
if (c < 10)
c +='0';
else
c += 'A' – 10;
result = c + result;
} while (input);
return result;
}

If you test this with

Serial.println("max deep sleep: " + uint64ToString(ESP.deepSleepMax()))

you will get something like 13612089337μs ≙ 13612s ≙ 3.78h ≙ 3h 46min. This is less than what you might have hoped for but still 5x 3x more than the 71min from pre-SDK-2.1 times.

Except that this is not a static value. Meaning it changes with every invocation of ESP.deepSleepMax()!

A quick glance into the Arduino source code reveals why. The calculation, originally provided by Espressif, is based on the RTC clock period. Since the RTC clock tends to drift with changes in temperature results may vary over time. My tests yielded results in the range of 3:35 – 3:50h.

Practice

The big question of course is: is the ESP8266 able to deliver? When will it wake up if you send it to sleep for exactly ESP.deepSleepMax() microseconds? What if you go beyond? Will there be dragons?

When I tried ESP.deepSleep(ESP.deepSleepMax()) with the max deep sleep value being around 3:46h the ESP8266 woke up after 3:25h. That’s 20min early but hey, the early bird catches the worm they say.

How about setting the deep sleep interval to 4h? 6h?

Nothing failed, all looked good. Except that the ESP8266 never woke up; it literally slept forever. Kind of at least; I stopped the test after 24h.

How about NodeMCU?

As I have been a committer with the NodeMCU firmware project (Lua on ESP8266/ESP32) since summer 2015 one question seems inevitable: how about 64-bit support for deep sleep in NodeMCU?

Thanks to friendly nudge from yours truly 64-bit support was introduced shortly after this post was published. The documentation for node.dsleep() and node.dsleepMax() was updated accordingly (it links to this post).

NOTE that you need the float firmware for that!

Conclusion

In that brief ESP8266 deep sleep primer I called to mind that on the hardware side the precondition is to wire GPIO16 to RST. Then we saw that the deep sleep interval in the SDK is now an 64-bit unsigned integer – a potentially really large number of microseconds.

I was able to demonstrate that the effective max deep sleep for ESP8266 is around 3.5h hours which is a significant improvement over the earlier 71 minutes. To send the ESP8266 to sleep for as long as possible use ESP.deepSleep(ESP.deepSleepMax()).

16 thoughts on “Max deep sleep for ESP8266

  1. So does this extended sleep time also apply if you are using the Arduino IDE as compiling tool?

    1. Chris, would you care to elaborate? I’m not sure I understand what you mean by “Arduino IDE as compiling tool”.

      1. If I understand you correctly the deep sleep duration is now a 64 bit variable rather than 32 bit. I use the arduino IDE to program my ESP devices so my question is simply can I use the extended variable already within the Arduino IDE Environment or do I need to wait for an update to the compiler

        1. As I mentioned you need the ESP8266 Arduino core 2.4.1 (currently the latest). We documented at https://docs.thingpulse.com/how-tos/Arduino-IDE-for-ESP8266/ how to install & update it via the Boards Manager but I’m sure you already know how that works.

          1. Thanks. Embarrassingly overlooked and that certainly answers my query

  2. Good and very useful article, but in the second image it’s a diode, not a resistor, between GPIO16 and RST 🙂

  3. I have been doing a number of experiments with ESP.deepSleep(x);

    My objective has been to get the processor to wake up at a fairly exact time so a sample can be taken. I know what time it is now and what time I want to take the next reading. I use 5 minutes as a trial and find that the device wakes up substantially early. Further experimentation finds that my ESP-12-E built with Arduino 1.8.12 takes about 1150 microseconds to sleep a millisecond. (1150 * 1000* 300) to sleep 5 minutes!!!

    Comparing the microsecond timer to the seconds time shows a close match. The seconds timer matches an external clock chip fairly well too.

  4. Nice article, thanks! I think you mean that 3 hours 46 mins is about 3x rather than 5x longer than 71 minutes though? 🙂

    1. Good catch, thanks! I’m wondering what mental shortcut I took here. Maybe 5*70min = 350min which looks a lot like 3h46min?

      1. Heheh yes that sounds likely! If only we used base 60 like the ancient Babylonians or had decimalised time it would be easier to do mental maths like this… maybe! 😉

        Great website!

  5. Using ESP.deepSleep(ESP.deepSleepMax()), the system stops but it is not in deep sleep.
    ESP.deepSleep(0xffffffff) works fine.
    (arduino ide)

  6. Do these limits to length of deep sleep time also exist if you are using the external wake up sources, like ext1 or ext0? Or do they only apply to using a timer as the deep sleep wake up method? Is there any method that allows the chip to sleep indefinitely?

    1. This applies to timer-based deep-sleep. It’s maybe counter intuitive but you can pass 0 to sleep indefinitely. See https://www.espressif.com/sites/default/files/documentation/2c-esp8266_non_os_sdk_api_reference_en.pdf#page=29

  7. Hey! Create article.

    I have a nodemcu esp12e dev kit, I tried using the same uint64ToString function and am getting deepSleepMax values around 12563513338, which only lead me to about 3.4 hrs. I have esp8266 core v3.1.2 installed (and also tried 2.4.1).

    I have been able to get 64 bit values with other modules (like the esp32 c3 dev kits), but no luck with this one.

    Is there anything else I should check?

    Thanks!

  8. Using a ESP8266 D1 Mini Pro, I found a permanent 10R resistor between both RST and D0 (GP16) pint, permits both programming AND wakeup without removal. 😀

    1. thx ! Just to be sure, really just 10R not 10kR ?

Leave a Reply

Your email address will not be published. Required fields are marked *