One of the biggest challenge for the Internet of Things, especially for those devices using RF communication, is the power consumption. In many situations it’s normal to expect the wireless equipment to have their own source of power, instead of relying on an AC-DC power supply connected to the wall outlet. In the IoT world there is a real demand for 100% wireless devices, powered by battery or any kind of power harvesting.
The first question you need to answer yourself before start building battery powered circuits is: For how long I wish the device to run on new batteries? One day, a whole week, maybe a year? Or just be brave and say 2 decades.
On this post we’ll talk about the low power world, how you can plan, design and implement circuits that can work for years on a pair of wide available AA batteries. We’ll also present the common trade-off and techniques necessary to reduce power consumption, as well discuss how RF communication can be implemented with minimal power requirements.
This can be a very complex and long topic and we’ll try to keep it as much practical and simple as possible. Bear in mind that we won’t offer a ready-to-use, kind of copy and paste code. The whole idea is to be broader and educate how to identify and solve common problems.
Talking about Power
Starting with some real life scenario, probably the most important thing is to understand how much a circuit can consume. If you’re reading this blog you probably already have connected a multimeter in series with a power source to measure how much current your circuit consumes. Let’s say you read something like 20.12mA, the first lesson to learn is: that’s too little information!
For power sensitive applications, you won’t have a single and stable power consumption as the circuit needs to be designed to turn on and off according to the demand. But before you learn how to do that, you need to know how to measure the energy required for those multiple power states. Have a look on the following approaches below.
As the name say, you just let your circuit run for some time, log all the current consumption and you can easily get the average. To easily monitor your current consumption you’ll need some multimeter with logging capabilities. Another option is use some current sense IC, like the INA219, which has an I2C interface and is quite easy to find ready-to-use boards at very low cost.
But the approach above has a major problems. It’s very unlikely you’ll be able to capture quick changes on the consumption, for example, a 10ms LED blink might never be visible. An improved technique could be simply monitor the battery voltage every 5 minutes, estimating the power consumption over time and comparing with the battery datasheet.
The chart above is from one of our test circuits, which among other things, transmits the batteries voltage level every 5 minutes over RF. It’s easy to identify the main battery (blue line) voltage drop over the 4 months period, slowly falling from 3.10V to 2.97V. The circuit uses 2xAA, which gives around 3.2V when new batteries are connected in series. The circuit also has a boost switching regulator, delivering 3.3V to all components.
Based on a popular battery’s datasheet, we should expect to have some juice down to 1.8V (or 0.9 per cell), in other words, at least additional 20 months running – considering we’re burning less than 0.05V/month.
The last things to note is the big voltage drop, just in the middle, where board was re-programmed to slow down the MCU from 16Mhz to 8Mhz. Can you spot the voltage drop difference before and after?
Be aware that the average measurement technique might be useful only in the late development phase or pilot stage, not so much when you’re design the circuit. This approach won’t give you details about which part of the circuit could be optimized, as well it can take some valuable time before you can get enough data to estimate consumption.
A totally different approach is to start with datasheets and spreadsheets. We all know, a spreadsheet sounds ultra boring, but if you really expect your project to last for more than a couple of days on a pair of AA battery you need to go there!
If you’re not familiar with the term, a power budget is the place where you list all parts of you system that might consumes a significant amount of power and for how long each component will be running. Significant here means is anything over 0.1mA when in running state or over 0.01mA (10µA) in sleeping state.
Here how a Power Budget might looks like for an ATMega328P application:
Take your time and start thinking about how the tasks above could be improved. Note that we’re executing only two simple tasks and already using some of the MCU sleeping features. According to our calculations, a pair of AA batteries wouldn’t last much longer than 4 months considering having a perfect step-up regulator boosting from 3.2V (2xAA) to 5V. We’ll come back to this same power budget later on this post and see how we can make the batteries to last 5 times longer.
The current consumption is always specified on the component’s datasheets. Make sure you understand all power modes supported by the IC, specially for MCUs and I2C/SPI devices as those silicons always offer some kind of power saving feature.
Some practical experimentations also have its place and could even save your time. Just run your circuit in every single state and record the consumption for each mode. For example, instead of making a LED turn on for 10ms, code it to run for 5 seconds and check the consumption of your circuit. Do the same now with the LED off and just do the maths. Repeat this process for other components, tasks, sleeping modes, peripherals, etc. Make sure you cover all combinations you’re planning to implement in your project.
How can I save energy?
Now that you know how to measure the power consumption and create a power budget for your project, it’s time to understand where all those milliamps are going to and the techniques to save some energy.
Coding for Low Power
One of the biggest villain, but at the same time the hero, is the MCU. It might be one of the biggest consumer of your project but it also offers great power saving features. Reducing the speed, disabling peripherals and multiple running modes are just a few option you’ll find in most chips. The MCU’s documentation is normally huge, but reserve some time get familiar with the running modes available.
It’s not possible to cover every single MCU or architecture here, but the true is, doesn’t really matter if you’re working with an AVR, ARM or PIC, they all will offer a way to reduce the power and enter in sleeping mode. Here some ideas you might find useful when coding for low power:
If you don’t need it, shut it down
Once your application starts, remember to turn off everything you won’t use. Every peripherals, including I2C, Timers, SPI and specially ADC/DAC. If you any other ICs on your project, like a temperature sensor or RTC, make sure you put all in the lowest power mode possible.
Do some experimentations with different MCU speeds and compare the power usage. Is common sense that running fast is the best, as you can finish the job quicker and go back to sleep. But in reality, many times the MCU needs to talk with slower components, for example, getting a temperature reading a sensor over I2C might take some milliseconds. In this case running at full speed doesn’t help much.
Another point to consider are the internal and external clocks. If you’re not planning to do any asynchronous communication, there is no much benefit in using an external clock all the time. The internal clock is a pretty good source of time for all kinds of code execution, including SPI and I2C communication as both are synchronous. Have a look on the table below to see how much power can be saved using the internal clock:
Finally, we all love our blinking LEDs. Be brave and make sure they only blink when really necessary, and don’t do that for more than a 10ms. If really needs to call user’s attention use multiple blinks instead of a long one.
There is only one rule here: make sure you put all devices to sleep on every opportunity. If you’re doing nothing for 10ms, there’s no excuse to keep your MCU running.
Most MCUs won’t take more than a few micro-seconds to wake-up. Even if you stop and start a couple of peripherals every cycle, still a great deal to put the silicon to sleep between almost every task. Just make sure you chose the right sleep mode as some might save more power but won’t preserve RAM and also can take a bit longer to wake up. One more time, it all depends on your project’s requirement to define the most appropriated sleeping mode. You might decide to keep it simple or mix multiple modes, adding complexity but saving some extra milliamps at the end of the day.
Have a look on the two tables below and compare the time taken to wake up the micro-controller and the power consumption during sleep.
Note that for the MCU above, the Standby mode won’t preserve RAM content, saving additional power when sleeping. In the other hand your application will basically restart every time it gets back to running state and take a bit longer to come back alive.
Another strategy to save some additional power is to wake-up your MCU at lower speed. Instead of waking up at 16MHz, why not simply wake up at 1MHz using the internal oscillator and use the first lines of code to verify if you really need to run that fast?! It’s not unusual to wake up the micro-controller just to increment some counter and get back to sleep.
Another challenge when using sleeping on your code is to find a way to keep track of elapsed time. Not all applications need to be time aware, but it’s a good idea to know the approximated running time. If you’re using some clock or watch dog to sleep for a pre-determined amount of time, you should be able add this time to any counter you have just before go to sleep, something like that:
sleepForMs = 10; myMillis += sleepForMs; goToSleep(sleepForMs);
Now if you’re using an external interrupt to wake-up your code, you won’t have this information, but you can still estimate it:
sleepForMs = 1000; myMillis += sleepForMs; goToSleep(sleepForMs); //sleeping here if(wakeByInterrupt) myMillis -= (sleepForMs/2);
At last, if you wish to sleep for long periods, like 5 minutes or more, you might be better using an RTC and re-syncing when necessary. Even better, make the RTC generate an alarm interrupt to wake your code so you could event turn the internal timers off to save a few micro-amps.
Power Budget Review
Getting back to our power budget, have a look the some changes we’ve made to increase the battery life from 4 months to over 20 months:
Probably the most important changes are the voltage and CPU speed. People normally underestimate how fast is a 8MHz MCU. Our project doesn’t need to be ultra-fast, we could go even slower or mix speeds according to the tasks. Lowering the voltage not only save significant power when everything is running but also reduced the consumption during sleep.
Another very important change is the reduction of running time. We now sleep the MCU for additional 9ms every second, while the LED is blinking. Finally, changing the 1s blink by 2 quick flashes saves energy and shouldn’t affect the final result. We could also consider some lower power usage by turning off unused peripherals, like BOD and ADC.
To go even further we could consider reducing the LEDs power. A simple reduction from 10mA to 7mA on each LED, maybe using a bigger resistor, could give additional 8 months of battery life in exchange for a slightly dimmed blink.
To be continued…
This was only the post 1 of 2 for this topic. Soon the next part will be published, check below some of the additional subjects we’ll discuss about:
Controlling your Hardware
- Lower your voltage: Brown Out Detection (BOD) for AVRs or Programmable Voltage Detector (PVD) for STM32s
- Load Switches
Monitor your Power
- Rail voltage
- Battery Voltage and Alerts
- Power outages
RF, the hungry player
- RF power consumption: RX vs. TX
- Outbox technique for TX
- Pooling technique for RX
- RSSI is your friend
- Resistor and capacitor choices to help saving power
- Ambient temperature