ESP32-C6 power consumption

A quick article to post the relevant power profile of ESP32-C6.

ESP32-C6 is a embedded micro-controller with a dual RISC-V cores running up to 160MHz and 20MHz. It's main selling point is that it's complete, it can talk Wifi (802.11ax), Bluetooth (BLE) and Zigbee (802.15.4). It's a direct competitor to ESP32-S3 (which is using a Tensilica Xtensa core running up to 240MHz) which doesn't do 802.15.14 networking.

The software is mainly open source (available in esp-idf repository except for the low level network stack that's distributed as pre-compiled libraries.

The documentation for these processors is plentiful, although it is lacking in some domains that I consider as very important. So let's sort it out:

Operating modes

The following section are specific to ESP32-C6. Unlike ESP32-S3, the power profile for the C6 is very different, so I'm focusing on those only.

In ESP32-C6, there are 2 RISC-V cores that can execute your binary. The high power (HP) core and the low power (LP) core. They both can execute the same binary since they support the same instruction set, however they are many limitations for the LP core (limited static RAM memory, access to peripherals, and so on). So the software stack is built to blend with the other ESP32 core, thus the LP core is specialized to run size limited program while the HP core is sleeping (that's the main documented usage, but you can also run the LP core and the HP core at the same time).

The HP core typically run software for communication (WIFI/BT/ZB) and is a huge power hog (WIFI can drain up to 350mA of current, cf page 63 of the datasheet).

However, the LP core is typically used to run an embedded (and simple) logic when the HP core is put to sleep, in order to save power. The main idea being: wake up the HP core when you need to communicate (or if you don't care about power consumption), else sleep it and let the LP core perform the monitoring work.

HP core sleeps mode

The HP core has 4 working mode:

  1. Nominal mode: All peripherals and clocks are enabled, RF is powered, can draw up to 350mA
  2. Modem sleep: All peripherals and clocks but RF and modem are powered, can draw up to 38mA
  3. Light sleep: All peripherals and clock are disabled but RAM is preserved, can draw up to 180µA
  4. Deep sleep: HP core is powered off, its own RAM is not powered either, can draw up to 7µA

The consumption number are from the datasheet, not from measures I've made.

The software stack is made to make it easy for you to automatically go from 1 to 3 (it's a configuration to enable in the menuconfig), but going to deep sleep is not automatic, since when entering deep sleep, everything is lost, it'll be amnesic when it wakes up (actually, it resets for waking up).

The ESP32-C6 also have interesting hardware features here, like STM32: it has few "deep sleep" surviving memories:

  1. The RTC memory (that is: a 16KB RAM area that can be left powered on while deep sleeping, and can be used by both the HP and the LP core)
  2. 10 always-on 32 bits registers (of which 7 are usable by user code, called Low-power Always-on Register (LP_AON) described at page 467 of the TRM). The software stack make use of them to provide interesting features, such as storing the boot time, storing a small wake up handler that can be run by the HP core before its main function

The always on registers are declared in esp-idf as:

  *     RTC store registers     usage
  *     LP_AON_STORE0_REG       Reserved
  *     LP_AON_STORE1_REG       RTC_SLOW_CLK calibration value
  *     LP_AON_STORE2_REG       Boot time, low word
  *     LP_AON_STORE3_REG       Boot time, high word
  *     LP_AON_STORE4_REG       External XTAL frequency
  *     LP_AON_STORE5_REG       FAST_RTC_MEMORY_LENGTH
  *     LP_AON_STORE6_REG       FAST_RTC_MEMORY_ENTRY
  *     LP_AON_STORE7_REG       FAST_RTC_MEMORY_CRC
  *     LP_AON_STORE8_REG       Store light sleep wake stub addr
  *     LP_AON_STORE9_REG       Store the sleep mode at bit[0]  (0:light sleep 1:deep sleep)

The register 5/6 and 7 are used to store a fingerprint of the RTC memory. If the memory at @entry, with length @length match the @CRC, then the @wake_stub_address is considered valid and the ESP32-C6's HP core will boot directly from this address in RTC memory. This happens before the bootloader even run, allowing the HP core to directly execute some limited code and decide to continue or prevent the normal boot process.

LP core capabilities

Although the LP core is able to access almost all peripherals (exception is for some obscure debug registers), the default software stack doesn't provide any reference code for this.

The expected usage is either:

  1. Have the HP core deep sleeps and be woken up by a GPIO change (in that case the LP core is powered off and not run)
  2. Have the HP core deep sleeps and be woken up at a given duration (in that case the LP core is powered off and not run)
  3. Have the HP core deep sleeps and some complex operation be done in the LP core (like doing some I2C or UART transactions, monitor and change some GPIO or simply wait for some time)

The software stack thus focus on the point 3 and provide the minimum library interface to monitor a GPIO from the LP core (with limitations), to start a I2C transaction (with limitations) or to sleep the LP core for some timer's elapsing.

Please notice that it's possible to actually run the LP core while the HP core is running, and it's possible to trigger an ADC reading from the LP core although, this implies keeping the SAR ADC peripheral powered on (which, as we'll see, doesn't actually save any power). Similarly, the other peripherals can still be used by the LP core is kept powered on, but again, without a real advantage.

IO limitations

There's only 8 GPIO that are controlable by the LP core (GPIO0-7) and since the ADC capable pins are also located on these GPIO (GPIO0-6) and they can't be used in low power mode, this is a very short sighting from Espressif since it means that any ADC need limits the already sparse low power GPIO.

Power consumption

Let's get straight to the information you can't find in the TRM or the datasheet.

  • The LP core, when running at 20MHz (which is the slow clock) consumes ~245 µA.
  • A isolated (often called "high impedance") IO pad draws 50 nA (but often more, see below).
  • Entering deep sleep consumes 30 µA for ~10s or so and then the chip consumption decreases to ~7 µA
  • Typically [no RF, no external peripheral] for HP core consume ~12 mA
  • Average WIFI consumption is around ~60 mA, with large variation

    Things to account for when doing low power

Talking about current consumption for the ESP32-C6 chip is often useless, because you can't operate such a chip alone on your board. You need a 3.3V voltage source, you need some peripherals (well, if you don't, it means that you probably missed the interest of this chip). And so on.

In the end, you should measure the consumption at the power source which will often by much larger than the actual consumption of this chip alone.

For example, if you have an I2C device on your board, this means that you have some 1 to 10 kΩ pull up resistors on two pins. When the chip is entering sleep, you can either isolate the GPIO (in that case, you'll get, at least, 100 nA current drain on this pins. You can also force hold the pin to VCC (in that case, you'll have a current drain that's equal to (VCC - Vds) / 10 kΩ in each resistor, with Vds being the voltage drop in the high level transistor. In the datasheet, this Vds can be as high as 0.2 * VCC which gives a leaking current of 66 µA).

If you enable a internal pull up or pull down for a peripheral, then you have an additional consumption for it (~76 µA for a typical pull up).

If you have an boot button (very likely), you typically have a capacitor in parallel to charge it, then there's its ESR resistance leakage to add.

Said differently, you can take the actual connected GPIO (which is maximum 23 on ESP32-C6) and multiply by 50 nA to get an ideal minimum consumption current. This alone can increase the deep sleep consumption by 1.15 µA.

Also you need to account for electrical oscillation. An isolated pin is just a pin where each connection to a lower circuit is opened by a transistor (the drain is disconnected from the source, showing the high impedance of the transistor). This means that if the pin captures some electrical field, its potential can increase and overcome the transistor's series diode, it'll pass some current. The voltage will then drop below the diode threshold, that will stop the current until the transistor parasitic capacitor charges and the cycle restarts. So an isolated pin can actually consume more than a fixed output pin if left floating.

I've tried to play with isolating pins myself or holding them at the appropriate level so they cannot oscillate, and I was able to drop the deep sleep consumption by ~ 0.7 µA.

You need to add the power drop inside the voltage regulator (depends on your schematic), the power drop in each peripheral's chip (for example, the I2C devices, the motor controller and so on).

By default, the software stack tries to be smart and will first try to isolate (disabling pull up/down, input buffer, ...) all pins that are unused while sleeping. Yet, it doesn't know your circuit and some device must keep some known electrical state to keep operating, and as such, it's not always possible to isolate all pins.

Previous Post

Related Posts