My e-Paper weather display finally ran out of juice a few weeks ago.
In total the 1000mAh battery lasted almost exactly two months.
This would probably have been considerably longer if my home WiFi was a bit more robust.
The e-Paper weather display achieves its long battery life by going into deep sleep for
most of the time and only waking up every 30 minutes to connect to the internet and
update the display.
This is a pretty interesting and powerful aspect of the ESP32 and I think it deserves
a deep dive.
What are we going to do cover in this video?
We'll start off with a quick overview of how to get the ESP32 into deep sleep.
We'll then cover the ways that the ESP32 can be woken up.
We can use a timer to wake up after some time.
We can wake up using a single GPIO pin or multiple pins.
And we can wake up using the touch sensors.
We'll then cover the code that is required to know why the ESP32 was woken up.
And finally talk about how to maintain state when going into deep sleep.
There is another way of waking the ESP32 device up which uses the Ultra Low Power co-processor,
but this deserves a deep dive all to itself.
So there'll be another video coming soon where we cover that in detail.
So don't forget to subscribe!
But first, a quick word from the channel sponsor PCBWay.
They've been sponsoring the channel for a while and we've built a few PCBs with them.
We'll be making some more PCBs in some future videos as I want to learn a bit more about KiCad.
They also do 3D printing and CNC work.
Check out the link to PCBWay in the description.
So how do we put the ESP32 into deep sleep?
We just need a single function call - esp_deep_sleep_start.
Just make sure you've setup some kind of trigger or you won't wake up until you reset the device.
Setting up a timer to wake up the ESP32 is very simple, we just call esp_sleep_enable_timer_wakeup
before we go into deep sleep.
This takes one argument which is the amount of time in microseconds that we want to sleep.
Although this is specified in microseconds the exact resolution depends on the source
for the RTC slow clock - which is normally only 150KHz.
So don't expect this to be a super accurate time delay.
Once we've setup the timer, we just call esp_deep_sleep_start.
It's important to remember that nothing runs after this call, so don't put any code after it.
It's also important to remember that before entering deep sleep you should make sure you
put any external peripherals you are using into power saving mode or turn them off.
You should also shutdown the WiFi and Bluetooth peripherals if you are using them.
I've set this demo up to sleep for 30 seconds, I've set up the sketch to trigger deep sleep
when we push the built in button.
After 30 seconds has passed the device automatically wakes up and runs our setup function.
The next method we'll look at for waking up the ESP32 uses the External wakeup mode.
This lets us wake up the device when the RTC GPIOs are in a certain state.
Note, that not all the GPIO_PINS are wired up the RTC module.
These are the pins that can be used to wake up the ESP32.
There are two different options for using GPIO_PINS for wake up, we can use a single
GPIO pin by using esp_sleep_enable_ext0_wakeup or we can use multiple pins using esp_sleep_enable_ext1_wakeup.
You can configure pull up and pull down resistors using the rtc_gpio_pullup_en and rtc_gpio_pulldown_en
on the pins, but I find it a bit simpler to configure the pin as you would normally and
then use the rtc_gpio_hold_en function which will maintain the pin configuration when going
into deep sleep.
For esp_sleep_enable_ext0_wakeup you specify the GPIO pin that you want to monitor and
the logic level you are triggering on.
We can test this out using the built in button on TTGO, this button connects GPIO35 to ground
so we need an internal pull up resistor and we want to trigger the wake up when the pin
goes low.
Once again we go into deep sleep.
And then when we push the button we wake up.
To monitor multiple GPIO pins we use the esp_sleep_enable_ext1_wakeup function.
This lets us specify multiple GPIO pins using a bit mask.
We can choose to wake up when any of the pins go high, or wake up when all the pins are low.
Here I'm setting up pulldown resistors on two pins and then configuring the wakeup to
trigger if any of the pins go high.
We go into deep sleep and now if any of the pins go high we wake up.
We can also work out which pin woke us up.
This is really handy if you have multiple buttons and you want the device to respond
in different ways depending on which button is pushed in deep sleep.
If we want to wait for all the pins to go low then setup internal pull resistors to
pull them high.
And change the trigger to all low.
Once again we enter deep sleep, now we only wake up if all the pins are taken low - one
interesting point is that you can't really tell which pin actually woke the device up.
It will always tell you the lowest GPIO pin was responsible.
The final simple thing we can do is wake up using one of the touch pins.
There are 9 pins that can be configured to receive touch input.
To make wakeup from touch work we need to first setup an interupt on the touch pad - the
interrupt handler can be left empty.
We then call the esp_sleep_enable_touchpad_wakeup before entering deep sleep.
You can setup multiple touchpads and any touchpad that has an interrupt attached to is will
trigger the device to wake up.
To get a sensible value for the threshold you can experiment using the touchRead function
to see what values you get when the pins are touched.
Once again we go into deep sleep, and now when I touch the cable the ESP32 wakes up.
That's it for the simple wake modes of the ESP32 - as I said earlier we'll cover using
the Ultra Low Power coprocessor in a follow up video.
As you've seen in the demos - I'm able to show the reason the ESP32 woke up along with
the GPIO pins that caused the wake up - this is what makes the deep sleep mode so powerful.
We can go to sleep and then wake up and respond to user input.
It's really simple to get the wake up cause, we just call esp_sleep_get_wakeup_cause, this
will either give us:
Undefined - which in my case I've treated as a normal boot up after reset or power down.
EXT0, EXT1, TIMER, TOUCHPAD and ULP - as I said earlier we'll cover the ULP in a later video.
With EXT0, we know which GPIO pin causes the wake up as we can only use one GPIO pin.
For EXT1 we can query which GPIO pins caused the wake up to happen by using esp_sleep_get_ext1_wakeup_status.
This returns a bit mask indicating which GPIO pins caused the wakeup - but note, this is
only useful if we are using the any pin high mode, if we are using the wake up when all
pins are low we don't get any usable information.
For Touch we can call esp_sleep_get_touchpad_wakeup_status - this returns the touch pad that caused the
device to wake up.
This is all pretty cool, but deep sleep turns everything off, including the RAM that your
program is using to store variables.
Everything gets lost when you go into deep sleep mode.
How do we solve this problem?
Going back to our original block diagram we can see that there is some memory associated
with the RTC module - this memory is kept alive when we go into deep sleep.
We have 16KB of RTC memory.
We can store data in this memory by using the RTC_DATA_ATTR flag.
You can store basic types and even structures in this memory by using this flag.
One thing to be aware of is that this memory will persist during deep sleep, but it won't
persist if power is removed or the reset button is pushed.
If you want persistant state between power and reset cycles then you need to write your
data to flash or some external persistent storage such as an SD card.
How much power can we save by going into deep sleep?
I don't really have the right equipment for measuring low current usage, but The Guy With
the Swiss Accent has done some really great videos measuring the deep sleep current of
various different dev boards, I've linked to one of his videos in the description and
you can get a link to his spreadsheet that shows a variety of boards along with their
deep sleep current.
I've done a quick test with my TTGO display board, I'm measuring the voltage drop over
a 10ohm resistor so this is showing about 60 to 80mA in normal mode.
When we drop down to deep sleep this drops to less than a milliamp.
As you can tell from the spreadsheet you can get much lower than this with the right hardware
and by powering down all the peripherals.
Some boards go down to 10s of micro amps.
It's pretty amazing stuff.
I've got a project coming soon that will make use of deep sleep - so stay tuned!
And I'll see you in the next video!