Getting Longer Battery Run Time



  • There are articles describing getting years of ESP32 operating time from one set of batteries, relying on it being in low current sleep mode most of the time. The Esp32 consumes about 0.01 mA duing deep sleep.

    A simple scenario may be waking up for 200 milliseconds to log a sensor reading, then sleeping for a minute (60,000 millisecond) so it's active only 0.3% of the time.

    Using the official m5stack Arduino Lib DeepSleep function, I checked the M5stickC battery voltage in a series of 1 hour sleep periods, it averaged 0.90 volts drop per hour, which is inline with someone in the forum who reported getting no more than 5 hours of battery life with their watch, this may amount to perhaps 5-10mA of current drawn during sleep. (I have to wonder if something else can be turned off)

    M5stack Engineers: I just tested the Sleep function in the standalone StickWatch2PowerManagment demo, it delivered 16 hours of sleep time, which may be a big deal for some users. (Total voltage drop was 0.398v, that's 25mv/hr)
    The difference from the official DeepSleep() code used in the sleep.ino example may be trivial, they are shutting down the IMU chip which has a current spec. of 2.5ma, the added function that handles it is: shutdownSH200Q() (example code seems to need the same Arduino setup as the StickWatch2 described below)
    https://github.com/eggfly/M5StickCProjects/tree/master/demo/StickWatch2PowerManagment

    I tested am M5stickC running with the LCD back-light at full brightness and found the battery reached a "dangerously low" 8% charge condition after 20 minutes. (Relying on the AXP192 battery management chip's voltage and idischarge readings)

    (The processor seems to start up with the radio sleeping, WiFi and Bluetooth are the biggest energy eating offenders.)

    THE SIMPLEST WAY TO GET A LONGER LIFE is to lower the brightness of the LCD backlight, at full brightness you may see a total battery load of 125 mA, one could predict a 38 minute to totally discharge the 80 mAH battery with that load, while the real world life is more like 20 minutes.

    This user reports the battery current for various LCD backlight brightness setting, which is a close match to my findings.
    http://community.m5stack.com/topic/1119/unreal-power-discharge-charge-current

    idischg: 42mA @ ScreenBreath(7)
    idischg: 44mA @ ScreenBreath(8)
    idischg: 51mA @ ScreenBreath(9)
    idischg: 58mA @ ScreenBreath(10)
    idischg: 65mA @ ScreenBreath(11)
    idischg: 75mA @ ScreenBreath(12)
    idischg: 90mA @ ScreenBreath(13)
    idischg: 105mA @ ScreenBreath(14)
    idischg: 116mA @ ScreenBreath(15)

    ScreenBreath(10) seems quite usable, doubling your battery life. Another benefit of lower backlight energy is lower operating temperature, components tightly packed in a little box tend to run hotter, battery performance degrades and charge time increases under higher temperatures. (on my copy of the stick ScreenBreath(6) gave a very dim image readable in a blacked out room, but the energy saving is negligible)

    The AXP192 (Power management) Document shows: ScreenBreath(), GetVbatData(), GetIchargeData()
    https://docs.m5stack.com/#/en/api/axp192_m5stickc

    The AXP192 power management chip example uses more functions to provide a detailed report
    https://github.com/m5stack/M5StickC/tree/master/examples/Basics/AXP192

    This article touching on Coulomb Counting in a Battery Fuel Gauge, might show the value of Coulomb reporting by the AXP192.
    https://batteryuniversity.com/learn/article/the_battery_fuel_gauge

    I made some battery tests using the Power reporting section of StickWatch2, which display the percentage of power remaining, their algorithm uses a 12 segment lookup table apparently to fit a discharge curve, (it's not a linear calculation)
    https://github.com/eggfly/M5StickCProjects

    There is a trick to get the updated StickWatch2 code to run on the M5stickC in the Arduino IDE:
    You have to change the Board setting to "ESP32 Pico Kit" and correct the upload speed to 115200.

    Here is a rough guideline for estimating remaining energy, developed by the RC people:
    4.2 volts 100%
    4.1 about 90%
    4.0 about 80%
    3.9 about 60%
    3.8 about 40%
    3.7 about 20%
    3.6 empty for practical purposes

    The AXP192 sleep example can be useful for extending battery life in some applications.
    https://github.com/m5stack/M5StickC/tree/master/examples/Advanced/AXP192/sleep

    M5stack engineers could help those attempting to further extend battery life, with further documentation, perhaps in a tutorial on battery conservation describing what goes on behind the sleep command.

    A block diagram showing the power supply path of the various components may help, (I would like to see what the power manager LDO, LDO2, LDO3 & LDOIO drives) those chips that are not powered down by the AXP192 might be reprogrammed to a lower power idle mode, (it appears that 2ma would be saved with an LCD controler Sleep-in setting)

    Here are a few tutorials on ESP32 Sleep modes, the essential thing to know is you code is lost when memory is powered down, waking up amounts to rebooting the board, you can store the state of your program in the RTC processor's 8K of ram before sleeping.

    ESP32 Deep Sleep with Arduino IDE and Wake Up Sources
    https://randomnerdtutorials.com/esp32-deep-sleep-arduino-ide-wake-up-sources/

    ESP32 Deep Sleep Tutorial -- speaks of 5 year battery life
    https://www.hackster.io/nickthegreek82/esp32-deep-sleep-tutorial-4398a7

    ESP32 Timer Wake Up from Deep Sleep
    https://randomnerdtutorials.com/esp32-timer-wake-up-deep-sleep/



  • Nice list.

    Espressif recommends you turn off BT, ADC and WiFi yourself before going to deep sleep, as the ESP32 doesn't do it "gracefully". Something like this:

    esp_wifi_stop();
    esp_bluedroid_disable();
    esp_bluedroid_deinit();
    esp_bt_controller_disable();
    esp_bt_controller_deinit();
    esp_bt_mem_release(ESP_BT_MODE_BTDM);
    adc_power_off();
    esp_deep_sleep_start();


  • Thank you so much, Good job!



  • Other hints:

    • Switch off various IC on the boards by cutting their power supply. See here for the screen. M5 Stack committed to release at least power management part of the schematic, should help a lot.
    • M5StickC first batch had an issue and need a 680 Ohm resistor between G0 and 3.3 V, see here

    I plan to de-solder the two boards tonight so I will be able to measure power consumption and see which settings works.



  • So here are my measurements. I replaced the battery by an OTII tool, range 1uA - 5A

    Power Off (long press on power switch): 1.92 mA
    esp deep sleep (wifi/bt/adc): 8.37 mA
    LDO2/EXTEN off: 6.68 mA
    DC-DC1, OLED_VPP, 5V V_Ext: 2.43 mA
    Disable battery charge: 2.44 mA
    Diable Coulomb meter: 2.44 mA

    Bias: register 35h: 200 uA for charging RTC which is not disabled

    So there is obviously something consuming more power than it should. @m5stack , did you measure power consumption ? I am surprised that we have 1.92 mA in "AXP 192 power off state".
    There is also 0.5 mA from something activated after AXP.Begin() as the power consumption stays at 2.44 mA instead of 1.92 mA. It is not the esp32 as I measure a consumption of 4.5 uA with the same sleep code with an esp32 dev board.

    Here is the code I used:

    uint8_t AXP192::SetSleep2(uint8_t reg)
      // Disable LDO2 (OLED_VDD) and EXTEN (?)
      // Those 2 bits seems to be a copy of 0x12. To be tested
      buf = readI2C8(0x10);
      buf &= 0b11111010;
      writeI2C8(0x10, buf);
    
      // Reset ADC to default state.
      // Test to set 0x00 ?
      writeI2C8(0x82, 0x83);
      // Disable DC-DC1, OLED_VDD, 5B V_EXT
      // DC-DC2 and EXTEN should already be disabled
      writeI2C8(0x12, 0x00);
    
      // Disable charge
      buf = readI2C8(0x10);
      buf &= 0b01111111;
      writeI2C8(0x33, buf);
    
      // Disable Coulomb meter
      writeI2C8(0xB8, 0x00);
    
      // // Disable ADC GPIO0
      buf = readI2C8(0x90);
      buf |= 0b00000111;
      writeI2C8(0x90, buf);
    
      // Sleep bit
      buf = readI2C8(0x31);
      buf = (1 << 3) | buf;
      writeI2C8(0x31, buf);
    }
    
    uint8_t AXP192::readI2C8(uint8_t reg)
    {
      Wire1.beginTransmission(0x34);
      Wire1.write(reg);
      Wire1.endTransmission();
      Wire1.requestFrom(0x34, 1);
      return Wire1.read();
    }
    void AXP192::writeI2C8(uint8_t reg, uint8_t data)
    {
      Wire1.beginTransmission(0x34);
      Wire1.write(reg);
      Wire1.write(data);
      Wire1.endTransmission();
    }
    
    void myDeepSleep(gpio_num_t PIN)
    {
      // Rewrite M5.Axp.DeepSleep() in order to enable ext0 wakep up.
      esp_sleep_enable_ext0_wakeup(PIN, LOW);
      esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_AUTO);
      esp_wifi_stop();
      adc_power_off();
      M5.Axp.SetSleep2();
      esp_deep_sleep_start();
    }
    
    


  • Good going oliv, looks like you have all the right electronic and intellectual tools.

    @oliv said in Getting Longer Battery Run Time:

    There is also 0.5 mA from something activated after AXP.Begin()

    The microphone uses 0.5 mA when it has the active 1 Mhz clock, 0.025 mA with < 1 khz clock.

    (Power off current rating of the ESP32 chip 0.1 μA) 1.92 mA power off must be the AXP192? which must still be active when shutdown, even with charging disabled.


    My getting 16+ hours of sleep time with the StickWatch2 sleep code suggests a sleep battery current < 5ma (80mah/16)


    LDO2 is controling just? the LCD backlight, not the chip power.

    Fumbling around with attempting to make LCD controler chip sleep to save 2mA:

    M5.Lcd.writecommand(ST7735_SLPIN); // this line compiles under arduino

    (It didn't reduce the sleep load)

    May needs to be put in a proper command object structure? including a delay.


    // Here's the IMU sleep code from the StickWatch2PowerManagment demo

    void shutdownSH200Q() {
    Wire.beginTransmission(0x6C);
    Wire.write(0x75);
    byte success = Wire.endTransmission(false);
    Serial.printf("success: %d \n", success);
    byte byteCount = Wire.requestFrom(0x6C, 1);
    Serial.printf("byteCount: %d \n", byteCount);
    uint8_t data = Wire.read();
    // uint8_t b = read_register(0x6C, 0x0E);
    Serial.print("byte: ");
    Serial.println(data, BIN);

    Wire.beginTransmission(0x6C);
    Wire.write(0x75);
    Wire.write(0x80); // SH200Q shutdown mode (only i2c alive)
    byte succ = Wire.endTransmission();
    Serial.printf("succ: %d \n", succ);
    }



  • Putting the LCD on "off" with ST7735_DISPOFF and the controller in sleep thanks to ST7735_SLPIN does not change power consumption. Putting SH200Q to sleep does not help neither so their power supply should be correctly shut down by the AXP192.

    So we really need help from @m5stack here: did you measure the off/sleep power consumption of the board. Which values do you get ?

    Thank you