How to make Spresense run on a battery for over half a year

In this tutorial, we will explain some basic ways to make Spresense applications power efficient. This is crucial when running Spresense on a battery to make a charging last for as long as possible. This tutorial uses the LowPower class of the Spresense Arduino extension library to explain the steps, but you can just as well implement it using the Power Management API of the Spresense SDK.

This tutorial explains how use the advanced power management on an application level. The Spresense board can achieve an even greater power efficiency by modifying the hardware. Note that this requires professional soldering skills and will void the warranty. Please see the Hardware Guide for instructions for how to do this.

First, we'll go through the key parameters to optimize the power efficiency:

  • Sleep modes
  • Clock speed
  • Data storage
  • Extension board
  • Battery and peripherals

Then we'll go through a GPS tracker demo use case along with the Arduino code for it.

1. Sleep modes

In many applications it is not needed to have the Spresense active at all times. If, for example, it is used as a goods tracking device then maybe it is enough to record its current GPS location etc a few times per hour. When it is not doing any active work it is good to shut it down as much as possible to preserve the battery, and Spresense supports two different sleep modes that it can enter to do this:

  • Deep sleep is a state where only the power and audio management unit (CXD5247) and the real time clock (RTC) are powered on. Since the main CPU is shut down it is not able to act upon e.g. interrupts from external components, but since the real time clock unit is still running it is able to trigger on RTC alarms. This makes the deep sleep mode suitable for applications where you want to wake up periodically to e.g. do some kind of measurement.
  • Cold sleep is a state where the MCU is still powered on but inactive, so it draws a bit more power than deep sleep but is also able to receive and react upon other events than just clock based ones, e.g. an interrupt from a sensor. This makes it suitable for applications where some external event should trigger an action and the sleep period is not deterministic.

Entering these modes from the Arduino library is done by calling the coldSleep() and deepSleep() functions in the LowPower class. For more information about power modes please see the SDK Power Management documentation.

2. Clock frequency

It is not only how often the application works that matters but also how quickly it does it. The clock frequency can be dynamically changed between 156, 32 or 8 MHz.

Note that there are some limitations when limiting the clock frequency. For example:

  • High quality audio playback requires 156 MHz but if playback sample rate can be reduced to 44.1 you can probably get away with using 32 MHz.
  • Camera requires 32 MHz or 156 MHz
  • GNSS requires at least 32 MHz. Trying to run it in 8 MHz will only cause it to automatically switch to a higher speed.

However, since the frequency can be set dynamically you can increase it temporarily only when needed and run at a lower speed the rest of the time. This is especially useful if your app is just idling while waiting for some external event, such as receiving updated positioning data from GNSS.

Setting clock frequency from the Arduino library is done by calling the clockMode() function in the LowPower class. For more details about clock frequency control please see the SDK Power Saving Control documentation.

3. Data storage

Accessing data storage will affect power consumption, especially if it is frequently accessed for reading or writing.

  • SD card is good for storing larger amounts of data and is a flexible solution since it can be replaced. It does however draw quite a bit of power when data is read or written on it. Exactly how much depends on the type of card being used but as an example, a really old SD card might average above 60 mA during write operations while a newer SDHC card averages around 40 mA.
  • SPI flash is the internal storage of the Spresense board. The space available for use is limited, but no peripheral device is needed and power consumption is significantly lower compared to using an SD card.

EEPROM is a memory type that is traditionally used for small amounts of non-volatile data. In Spresense there is an API for accessing EEPROM, but this implementation is just an emulation that actually uses flash storage, so from a power consumption point of view there is no difference.

4. The extension board

Having the extension board connected will cause a slight increase in power consumption of approximately 700 μA. Also, having uart RX and TX on the expansion board, e.g. for debugging Spresense without USB connected, will cause it to draw approximately 3.5 mA extra. This is good to know when doing any power measurements.

5. Battery and peripherals

Any kind of peripherals connected to the board and the type of battery selected will of course also affect the power consumption and battery life of an application, but the vast number of possible combinations makes this discussion out of scope for this short tutorial.

6. The low power demo

Here is a simple demo showing how GNSS updates might be handled in e.g. a goods tracking use case where low frequency position updates are enough. A more realistic application would probably process the collected data and then transmit it to some host, but to keep this demo simple and avoid external modules it just prints the data on the uart. For an introduction to the GNSS related concepts please see the How to read GPS information using the Arduino IDE tutorial. For this tutorial, we're using a standard LiPo battery with 3.7v.

Application outline

Here is a basic outline of the demo application (download the Arduino sketch here):

  1. Set clock speed to 32MHz
  2. Start GNSS and wait for an initial position reading
  3. When a first position is attained, prepare for going into deep sleep by:
    1. Updating RTC with GNSS time. RTC keeps ticking while we sleep so we can keep time in sync with the satellites
    2. Saving ephemeris data retrieved from the satellites
  4. Deep sleep for a set number of seconds to save power
  5. On wakeup provide RTC time (which should be aligned with the satellites' time) to GNSS to enable starting in “HOT_START” mode.
  6. Do another GNSS reading and prepare for going back to deep sleep again,

This is what the main loop looks like in the demo Arduino sketch:

void loop() {
  tries++;
  if (getGnssUpdate() ||
      (tries >= GNSS_UPDATE_MAX_TRIES && isRtcValid())) {

    /* Position aquired, go to sleep */
    Serial.print("Sleep for ");
    Serial.println(GNSS_SLEEP_PERIOD_S);
 
    Gnss.saveEphemeris();

    /* Note: "tries" is reset when the application is reloaded on wake up */
    LowPower.deepSleep(GNSS_SLEEP_PERIOD_S);
  }
}
Sample measurements

One wake cycle (wake up -> read GNSS -> write SD card -> sleep) consumes approximately 7 mA while during sleep it uses about 300 μA. The application tries to update GNSS data a number of times until it gets a valid update (i.e. not cached data), and assuming it takes on average five attempts to achieve this the board will be awake for approximately 10 seconds. Using this we can calculate an approximate number for how much current the board draws per hour for different wake-up frequencies:

#

Cawake [mA]

Csleep [mA]

Tawake [s]

Consumption per hour [mA]*

800 mAh [h]

2000 mAh [h]

#

1

Cawake [mA]

7

Csleep [mA]

0.3

Tawake [s]

10

Consumption per hour [mA]*

0.3186111111

800 mAh [h]

2511

2000 mAh [h]

6277

#

2

Cawake [mA]

7

Csleep [mA]

0.3

Tawake [s]

20

Consumption per hour [mA]*

0.3372222222

800 mAh [h]

2372

2000 mAh [h]

5931

#

3

Cawake [mA]

7

Csleep [mA]

0.3

Tawake [s]

60

Consumption per hour [mA]*

0.4116666667

800 mAh [h]

1943

2000 mAh [h]

4858

There are 3600 seconds in an hour so hourly consumption is calculated as:

Cawake × (Tawake / 3600) + Csleep × ((3600-Tawake) / 3600)

So in theory, if we wake up and check the position every 10th minute, i.e. run for 60 s per hour, it will last for 4858 hours or about 200 days on a 2000 mAh battery. In reality however, the battery life will also depend quite a lot on battery discharge characteristic and environmental factors such as temperature.

Below are graphs showing examples of measurements calculating the numbers above:

Average consumption during sleep for the shaded area between the white lines (AVG = 303 μA).

Average consumption when awake and working for gray area between the white lines (AVG = 6.81 mA).

As a side note it's worth mentioning that by selecting clock frequency 32 MHZ instead of 156 MHz it only consumes about half the power, especially while waiting for GNSS to respond. This is illustrated in the graph below where the purple line shows power consumption when running in 32 MHz and the blue line when running in 156 MHz. The averages (AVG) are calculated for the GNSS wait period, i.e. the shaded area between the white lines in the graph.

More information

Spresense Arduino LowPowerClass

Spresense SDK Power Management documentation