Measuring low power modes on the ESP32C3

https://github.com/orndorffgrant/lowpoweresp32c3rust

This was a course project for my Master's Degree in Computer Engineering at the University of Maryland.

Abstract

I explored the power consumption of several firmware iterations for a simple embedded systems application. The application was an internet connected temperature sensor. The application would read a temperature sensor every 5 seconds and report the reading over WiFi. Each iteration of the firmware had different power consumption characteristics. I was able to reduce the power consumption of a naively written firmware by over 70%.

Experiment Setup

Components

Here is a picture of everything hooked up together

Source Code

Contained within this repo are 4 folders, each of which contains a small software project that is a part of the overall final project.

powersensor/

This folder contains the Arduino project loaded on to the Arduino-compatible board that is hooked up to the Gravity I2C power sensor. This firmware reads the current consumption from the sensor every 100ms and writes the value to its serial port.

sensordisplay/

This folder contains a small python script for displaying the sensor readings. It runs on a host connected to the Arduino power sensor. It reads each current value over serial and adds it to a graph that updates live as new readings come in. It keeps a window of 300 values. A new reading comes in every 100ms, so 300 samples comprises 30 seconds of time. The Y-axis of the graph adjusts for the minimum and maximum values within the current window. The script also calculates the average, min, and max values of the 300-sample window and prints those to the terminal.

Here are a couple examples of the terminal output of this script:

And here is an example screenshot of the graph generated by the script:

Note: This script depends on the numpy and live_plotter python libraries. They must be installed for the script to function.

testserver/

This folder contains a simple python server. It listens on a hardcoded IP address and port and logs temperature readings it receives. It also sends back a prettified representation of the temperature reading.

Here is an example of its output while receiving temperature values.

wifitempsensor/

This folder contains the firmware for the WiFi temperature sensor, running on the ESP32C3. It is written in rust and primarily uses the community esp-hal, esp-wifi, and sensor-temp-humidity-sht40 libraries for hardware support.

There are 5 iterations of the firmware. They are located in src/bin/.

1_busy_wait.rs

This version of the firmware is the most naive. It is the most straightforward implementation of connecting to WiFi, reading a temperature measurement, sending it to a server and waiting for 5 seconds. Notably, this implementation calls socket.work() while waiting for 5 seconds.

2_delay.rs

This version of the firmware replaces the call to socket.work() for 5 seconds with a delay_ms call. This call essentially loops until the 5 seconds have passed.

3_light_sleep.rs

This version of the firmware goes into light sleep, as defined by the community driver. Going into light sleep saves CPU state but turns off the WiFi peripheral. That means it needs to properly clean up the WiFi peripheral state by disconnecting before going to sleep. Then, on wake up, it needs to re-scan and re-connect to WiFi before reading the temperature and sending it.

4_deep_sleep.rs

This version of the firmware goes into deep sleep. Deep sleep turns off everything except the RTC, which is what wakes up the CPU again after 5 seconds via interrupt. On waking up from deep sleep, the MCU has to boot up again, since no CPU state is saved. It then needs to re-scan and re-connect to WiFi before reading the temperature and sending it.

5_light_sleep_turn_off_sensor.rs

This version of the firmware is a slight modification of 3_light_sleep.rs to use a GPIO pin to turn on and off power to the sensor. Power to the sensor is only turned on long enough to read a temperature measurement.

Results

Here are graphs showing the current consumption over a 30 second span for each version of the WiFi temperature sensor firmware.

busy_wait

delay

light_sleep

deep_sleep

light_sleep_turn_off_sensor

Summary

And here is a table summarizing the average current consumption for each version. I also calculated the estimated maximum run time for the 2000mAh battery used in the experiment.

FirmwareAverage current (mA)Run time on 2Ah battery (hours)
busy_wait11018.18
delay10419.23
light_sleep3164.52
deep_sleep4940.82
light_sleep_turn_off_sensor3066.67

Observations

The delay firmware only has a slight benefit over the original busy_wait firmware.

Light sleep does better than deep sleep because it has a smaller wake up cost. Waking up from deep sleep requires a full boot, including running the boot loader code, which takes time and outweighs the benefit of lower power consumption during the 5 seconds of sleep.

Turning off the sensor only helps a little bit and only because there is an LED on the development board for the SHT40 temperature sensor. The sensor itself uses so little current we wouldn't notice it using our power measurement setup.

Future work

Some things to try in the future to further decrease power consumption are: