In this post, I have a go at measuring and reducing the power consumption of an ESP32-H2-Mini running a Matter sample.

I’ve done a lot of investigation into power consumption on a Nordic nRF52840. It’s very energy efficient and I wanted to compare it to an ESP32. I have a few battery projects on the drawing board, and I want to make sure I use the right MCU.

Why an ESP32-H2?

The ESP32-H2 variant has no WiFi, so I feel like it’s a better choice for low power applications. I also decided to give the H2 Mini dev board that I got a whilst back. I also soldered some wires to the battery terminals on the reverse of the board.

Getting started

To explore the power consumption, I’m going to be using the icd_app example provided by the espressif Matter SDK. ICD stands for Intermittent Connected App and is designed for low power devices.

I started by setting up my esp environment, which I run on Ubuntu (via WSL in Windows)

. ~/esp/esp-idf/export.sh
. ~/esp/esp-matter/export.sh

I then opened the example, which lives under esp-matter/examples/icd_app

Next, you must set the target device. Normally, I’d set the target using this command

idf.py set-target esp32-h2

but as we’re in the icd_app, they have provided a specific set of defaults (check the README.md), so we need to run this instead

idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults.esp32h2.lit" set-target esp32h2

The lit part of the file stands for Long Idle Time, which is part of the ICD approach. More on this later.

With the target set, we can now compile and flash the application

idf.py build flash

Once installed, I used my phone to commission the device.

The LED on the device didn’t respond to the Switch. That was expected, as there is no code to toggle the LED. I figured it would be worth getting that working first. That way I can be absolutely sure the device was responding.

I started by blinking an LED. I switched to my Waveshare ESP32-H2-DEV-KIT-N4 devkit for this. The DevKit is easier to flash, since I don’t need to enter DFU mode. That’s a special mode that lets you flash firmware. On non-devkit devices, it involves holding RST and hitting Boot. Annoying with small buttons.

Using a DevKit is just a case of plugging it in and flashing it.

With that working, I flashed the same code onto the super mini and got the same result.

The light blinks. Amazing.

I then wired up the app_attribute_update_cb callback function to set the LED status. This callback gets invoked during an attribute change. In this case it’s the OnOff attribute of the Light.

I made the changes and flashed, but got weird flicking behaviour when I turned on the “Light” via my iPhone.

The LED just doesn’t seem to want to stay on!

After a little bit of tinkering with this, I realised the issue! The ESP32 is entering light sleep as it’s an ICD. This means that all the GPIOs get turned off. What you see is the ESP32 waking up and doing some stuff for a split second, before sleeping.

There is absolutely no point in trying to keep the LED on 🤣🤣

A First Look at Power Consumption

With my code in place and definitely sleeping, it was time to hook up a power monitor. As always, I use my trusty Nordic Power Profiler Kit II.

Not a great start with an average of 840µA over a minute. This is with a supply voltage of 3.3V.

I then cranked the supply voltage up to 3.7V to better reflect a LIPO battery. There are different types of voltage regulators and their current draw changes based on the voltage. I found this when working on the ESP32-C6.

This pulled the 1-minute rolling average down to 650µA. A pretty significant drop.

That said, according to the datasheet, the ESP32-H2-MINI-1 should do quite a bit better than that.

From the icd_app example itself, espressif included an image showing power consumption. I read this as a 46µA average over 160 seconds.

My 650µA is a far cry from that.

Accounting for peripherals etc.

One of the things I learned with power consumption on the Nordic nRF52840 DevKit is that peripherals take up power. These are things like LEDs and UART. LEDs themselves can add several mA of power draw. The Nordic Developer Kit actually has a switch to isolate peripherals. This makes it easy to separate the power consumption of the chip itself from everything else. Very, very helpful.

Unfortunately, the H2 development kit I got from Waveshare doesn’t have this. That means when measuring power, it includes all the peripherals. This makes it difficult to see if my chip is asleep or awake.

I decided to see if Espressif offered a way to isolate the H2 module, like Nordic do. I found their ESP32-H2-DevKitM-1 offered this:

This looked like what I needed. I could remove the jumper to disconnect the peripherals and then measure the power of the module.

Me being me, I didn’t have this particular DevKit. The Waveshare DevKit I had was a different variation 🤦🏼‍♂. I️ also discovered they did a ESP32-C6-DevKitM-1 with the same jumper. Of course, I had the C6 Waveshare variations without the jumper.

FML, but this is becoming an expensive hobby!

I ordered two of these boards from PiHut. More of my YouTube earning going on something that isn’t a 3D printer 🤣

Fancy packaging for a dev kit. Now I know where my money went 🤣

I flashed the new DevKit with the same code and wired in the PPKII. This time I would be using it in Ampere mode. https://docs.nordicsemi.com/bundle/ug_ppk2/page/UG/ppk/measure_current_ampere_meter.html

Using the PPKII in Ampere mode across the jumper

I fired up iOS and paired the device.

I turned on the PPKII and hit the reset button on the DevKit (poorly located under the connectors!)

Drawing a lot of power as it established its Thread networking

After a while it settled down and oh boy, was it beautiful.

30µA

The chip was consuming just 30µA.

It would then spike, which I’m assuming is the radio. The spikes were about 15 seconds apart.

Over one minute, it was averaging 191µA, which consumed 11.47mC.

It’s an impressive figure, but it dwarfs the nRF52840. In a similar test, my nRF52840DK, taking ADC readings every 30 seconds, draws 3mC. About a quarter of the H2’s consumption.

Reducing power even further?

At this point, I didn’t know what I could do next. Despite a lot of searching, I couldn’t find an Espressif guide to reducing power consumption.

I looked at the deep_sleep and light_sleep examples and all they really offered was reducing clock speed of the CPU.

Given the light-sleep design consumption of 24µA and my 30µA measured consumption, I think I was in pretty good shape. The 100mA the radio spikes didn’t really help.

I was also still confused by the 15s intervals. The setting ICD_SLOW_POLL_INTERVAL_MS was set to 30000, meaning the radio should only wake every 30 seconds. I set it to 60s and tried again.

Same result.

I began to wonder if this might be some Thread configuration. I found this setting: OPENTHREAD_ADDRESS_QUERY_RETRY_DELAY which was set to 15 seconds and changed it to 30.

This had no impact.

Around this time, I received a comment from Rakesh, pointing me to a Github issue opened with esp-matter. This was a user seeing the same thing as me. I added my two cents to this discussion. Hopefully Espressif will shed some light on this.

Back to the SuperMini

This post started with the SuperMini, so I want to give it one final go!

The result was pretty much the same.

What’s interesting here is that the ESP32-H2 itself accounts for 11mC of that 44mC. That means the power converter and other peripherals are using three times as much power!! That’s insane!

I will investigate this in a future post as this one is getting a little long!

Conclusion

An informative outcome, I think. I managed to get my ESP32-H2 down to around 30µA when idle.

As ever, that’s not the whole story. As we’ve seen with the SuperMini, the consumption of the board is much, much higher.

So, what about battery life of this SuperMini?

A 1Ah battery contains 3,600,000 mC. If my SuperMini uses 44mC a minute, we would get ≈81,818 minutes of usage and that works out to be around 56 days!!!

That’s actually pretty rubbish. Compare it to the Nordic nRF52840 and on the same battery that would run for over 800 days. 16 times as long.

Now I just need to find that jumper for by DevKit…..I’m sure it’s on my desk somewhere…

Support

If you learn something from my posts, you can always say thanks by buying me a coffee. Your support is appreciated!

Buy Me a Coffee at ko-fi.com

Be sure to check out my YouTube channel.

12 responses

  1. Hi,

    remove that WS2812 Neopixel from the Supermini board. It draws around 300µA of quiescence current!

    Powering my ESP32C6 Supermini with 3.3V on the 3.3V pin results in 9,5µA deep sleep current. You can use a LiFePO4 battery for your project, there’s no need for a voltage converter.

    Nice blog btw. I’ve learned a lot.

    Best Regards
    Stefan

  2. Thanks.

    Deep sleep isn’t an option for Matter & Thread, so I’m stuck with light sleep.

    I didn’t think of removing the LED. I’ll look at that a little further!

    1. Hi! Why the deep sleep is not an option for Matter-over-Thread?

      1. I think it’s because of the CASE session. If it goes into deep sleep, the memory does and the CASE session needs to be established again. It’s computationally expensive for the CASE.

        I think that’s the reason anyway.

  3. Hi,

    I’ve got my Hands on a ESP32H2 Supermini, here a my results (measured with PPK2):

    • 3.3V Input to the 3.3V PIN
    • deep sleep TimerWakeup Example from the Arduino ESP32 core
    • Board unmodified: 488 µA
    • WS2812 removed: 223 µA
    • LDO regulator removed: 148 µA
    • Batter charger IC removed: 115 µA
    • Charger LED removed: 85 µA at the start, 17 µA after 20s (probably due to charging capacitors)

    Usually I use LiFePO4 batteries with a voltage range of 3.6 -3.0V which can directly drive 3.3V circuits. No power losses by LDOs…

    I will give your Matter & Thread example a try and will report back the current draw.

    Best Regards

    Stefan

    1. I just removed The RGB led WS2812 and sleep current dropped from 350uA to just 7 uA. Your comment really hepled. I was investigating for months. Thanks alot🙌

  4. Hi,

    I’ve flashed the icd_app example from the esp-idf on my modified ESP32H2 Supermini and measured with my PPK2 for 1 minute (after 3 minutes wait):

    average: 189.01 µA
    max: 9.56 mA
    time: 1:00 m
    charge: 11.36 mC

    floor consumption in light sleep: 81 µA

    I’am seeing the 15s spikes too.

    Best Regards
    Stefan

    PS: A LiFePO4 battery (AA format) with 700 mAh would last for around 150 days

    1. Thanks for looking at that!

      The average is still quite high. I’ve been looking at the Nordic offerings too and the power consumption is so much less.

      I think I’ll stick to the Nordic boards for anything battery powered 🙂

      1. Hi,

        I have tried Matter/Thread with the nRF52840 two years ago and it was a rather frustrating experience. The Zephyr environment had a very steep learning curve (I’m not a professional developer) and the nRF52840 Dongle has not enough flash memory for matter…
        Zephyr didn’t allow me to power off the i2c sensor breakout board during sleep (powering the breakout via GPIO pin), wasting a lot of electrons.

        Using the Arduino IDE and a modified nRF52840 dev board I’ve been using BTHome for sensor nodes. Came down to 2.7 µA deep sleep current…

        Out of curiosity, I’ve just ordered a XIAO nRF54L15…

        Best Regards

        Stefan

  5. Hi,

    about the 15s activity spikes… I’ve found this information on the Nordic docs:

    The Matter specification divides ICD into short idle time (SIT) and long idle time (LIT) devices. The division is based on the Slow Polling Interval parameter: equal to or shorter than 15 seconds for SIT, and longer than 15 seconds for LIT.

    The LIT device starts operation in the SIT mode and remains in this state until the first ICD client registers to it. This is necessary because the device is not responsive in the LIT mode, so client registration would be difficult. Once the ICD client is registered, the ICD device switches to LIT mode in order to save energy.

    so, works as designed

    Best Regards

    Stefan

    1. Does it not switch to LIT automatically?

      I didn’t think the ICD client was necessary, so I may have been completely misunderstanding the behaviour.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.