I was working on a project called BigTime where low power operation was a necessity. Here's a tutorial to show you some of the tricks I found to get the power consumption down to about 1uA (that's micro, not milli = 0.000001A). I'm pretty sure rubbing your fingers together produces more heat energy than 1 microamp.
My overall goal was to get an ATmega328 to go to the deepest sleep possible, waking up only with an external INT button interrupt or with a 32.768kHz TMR2 overflow interrupt (for an RTC). To make this happen you'll need to tweak the bootloader and some other settings.
Here's the example code that I used. Various parts of the code where commented out to take the measurements for the following tutorial.
Why is this important? If we are using a 200mAh CR2032 20mm coin cell battery, we have a very limited power supply. If you use 10mA, you'll get 20hrs of use out of your project (200mAh / 10mA = 20hr). If you manage to reduce the power a little to 100uA, you'll get (200mAh / 0.1mA = 2000hr) 83 days of use - a huge difference! Let's see just how low the ATmega328 will go.
Because we're playing with bootloaders and fuses, be sure to get a good hardware programmer and supporting software that allow for easy editing of the fuses. My programmer of choice is the MKII but it doesn't always play well with avrdude. I'm lazy so I downloaded AVR Studio 5. This ghastly beast of software from Atmel is just under 400MB. I need nothing within it except the programming tool.
There must be better/smaller options out there but AVR Studio 5 is the only one that I know of that works seamlessly with my MKII programmer and the ATmega328.
When playing with low power projects I find it best to use a breadboard. A finished development board like an Arduino or Arduino Pro is great, but has extra components (FT232RL, voltage regulators, MOSFETs, LEDs) that will use lots of power and disrupt your measurements. A breadboard makes it much easier to isolate the microcontroller and experiment.
Before we can really get rocking with our breadboard, we need to get the bootloader onto the ATmega. There are various tutorials showing how to do this so I'll give a very quick overview.
Open up the AVR programming menu so that we can control the MKII. Deep inside Arduino (C:\arduino-0022\hardware\arduino\bootloaders\atmega) you can find the old bootloader found on the Duemilanove and Diecimila. I need to use this bootloader for my project because I want to use the internal 8MHz oscillator and the newer bootloader for the Arduino Uno (Optiboot) doesn't currently support 115200bps using the internal osc. This is mostly due to the crummy tolerance of the internal osc (+/-10%).
You will need to compile the bootloader for the Arduino ATmega328 Pro 8MHz variant. Do this from a command prompt within the atmega directory by typing:
A HEX file should now be located in the bootloader directory:
Your file or directory structure may be slightly different.
From within AVR Studio, load the HEX file onto your ATmega328.
From the makefile located in the bootloader directory, we can find find the fuse bytes we should use. For my purposes, I started with the regular ATmega328/Duemilanove bootloader fuses, but changed it from an external crystal to internal 8MHz:
Original: EFUSE = 05
Original: HFUSE = DA
Original: LFUSE = FF
Don't program the above fuses unless you have an external crystal laying around! For this project, I changed these fuses to use the internal oscillator:
New: EFUSE = 05
New: HFUSE = DA
New: LFUSE = E2
Program these fuses to your ATmega328.
The final step is to set the lock bits. The Lock Bits tell the ATmega328 to not write anything to the bootloader area so that you can't corrupt it. This is a great way to be sure that no matter what code you put onto the ATmega, it will always take new code. Set the lockbit to 0xCF to set BLB1 to zeros (programmed). From the datasheet:
BLB1 Mode 00: SPM is not allowed to write to the Boot Loader section, and LPM executing from the Application section is not allowed to read from the Boot Loader section. If Interrupt Vectors are placed in the Application section, interrupts are disabled while executing from the Boot Loader section.
Now try loading some code under the Arduino IDE using the 'Arduino Pro Mini 8MHz w/ ATmega 328' setting. You should be able to load code, if yes, then continue.
The whole goal here is to push the ATmega as low power as it will go, so get a multimeter attached permanently measuring current. You can see I'm starting at around 8mA with the LED display still active. Let's turn that off:
From a 3.3V source, our circuit is pulling ~3mA doing nothing but spinning in an infinite loop. Let's try some power saving tricks.
Experiment 1) Checkout avr/power.h. This is an easy to use library to turn off all sorts of peripherals. Disabling TWI, SPI, and going to sleep got me down to 233uA.
Note: At this point I had problems bootloading (it would fail) when my multimeter was set to 2mA (measuring up to 2mA). The ATmega328 would be choked to a max of 2mA of power during bootloading where it needs ~5mA. If you run into problems bootloading, try increasing your multimeter setting during programming.
Experiment 2) Timer 0 is used for delay() calls. Disabling Timer 0 will cause all your delay loops to break. Be careful. Disabling Timer 0, Timer 1, and UART0 got me nowhere (still 233uA). Timer 0/1 and UART are shut down during sleep so this makes sense. However, when we wake up for an interrupt call we will be using much less power. We will keep these peripherals turned off to save power during the interrupt handlers. Note that Timer 2 must stay active so that we can roll-over interrupt and correctly control the RTC variables.
Experiment 3) Turning off the ADC and analog comparator dropped us to 31uA. Now we are getting somewhere! We have a fully functioning (albeit sleeping) system at 31uA!
Experiment 4) Turning off the digital input buffers had little effect. We remained at 31uA.
Experiment 5) Turning all the unused pins to inputs and writing them low did not help, but writing low with pullups did hurt (62uA). You need to be careful with this. Enabling pull up resistors or driving a load can use a lot of power. Test both ways: drive outputs low or set everything to high impedance and see which is lower power - it's very specific to your particular project.
So we've made it to 31uA. The datasheet says the ATmega328 should be at around 1uA. What's the deal? Realize that anything attached to the circuit will draw power. An FTDI programming cable, a hardware programmer, even a 10k pull up resistor. Be very aware of what you've got attached to your project. I detached the MKII programmer and magically we dropped to 15uA! YES! I then detached the FTDI programmer and power increased to 18uA - wtf?
Some attached devices (like the MKII) draw just a tiny bit of power. Some devices (such as the FTDI Basic) supply the target application with a miniscule amount of power. I won't even wager a bet as to how the digital multimeter may be affecting the circuit. The moral of the story is that no attached device has the theoretical 'infinite impedance'.
So here we are at 18uA - that's 18x what the datasheet says... Be sure to read section 9.10 of the ATmega328 datasheet to turn off all the bits of hardware you don't need. The major breakthrough was turning off the brown out detect. For my project, I really didn't need a brown out reset feature. The problem is that we have to disable the BODLEVEL by modifying the fuse bits. Reattach your programmer and change your fuse bits. For me:
New: EFUSE = FF
New: HFUSE = DA
New: LFUSE = E2
This will disable the brown out detect mechanism.
The DMM still reads 15uA? Oh wait! The MKII programmer is still attached!
Whoa. 1uA. Really?! Yep! The brown out detect will use 15-20uA. Disabling it will change how your project operates at very low voltage, but if you're ok with low voltage wiggyness, turn it off.
And there we are! When an interrupt fires, the microcontroller comes alive using milliamps of current, but then after a very small number of cycles at 8MHz, it then returns to sleep.
You'll notice the image shows a coin cell instead of a bread board power supply. If you really want to get crazy, lowering the input voltage should help the lower draw as well. Instead of 3.3V, I use a coin cell to drop the system voltage to ~3V. Be sure to test your system with the actual power supply that you will be using.
At 1.01uA we have to consider a few things:
1) The DMM. Looking around SparkFun, surprisingly our really expensive Fluke DMMs did not go below 1mA. I actually used our cheap $15 DMM (I love these multimeters!) to measure down into the microamps. You should check to see if your meter can measure at this low of current.
What's the accuracy of any given DMM? I didn't know the answer (here's a great cheap DMM comparison) but I did know that I had a few DMMs laying around so I hooked them all together. Somewhat amazingly they all read the same value within a very small margin of error. Could my DMM be inaccurate? Sure. Do they all come from the same manufacturer? Yep. But I'm not going for NASA scientific here, just a rough idea of where the ATmega is at. The ATmega328 should be around 1uA (remember, RTFM) so I'm fairly confident in the meter readings.
These graphs are from the ATmega328 datasheet. Above is the expected current consumption at 25C. I wish they showed the other temperatures as well.
The ATmega328's current consumption does vary widely at low voltage and temperature changes.
2) At <10uA ambient temperature becomes a significant factor. Depending on the day, I could almost extrapolate the ambient temperature of my apartment based on the current readings of my ATmega328. I know, crazy - but the thermal temperature of the die will affect the current consumption of most microcontrollers at this low of power.
3) I was fairly surprised that there was little difference between ATmegas: I tried three different ATmegas under the same conditions (breadboard). I would expect some production variance between ICs but under testing 3 ATmegas with different date codes tested nearly identical (within 0.01uA) to each other.
4) Remember that you can throttle the internal clock of the ATmega328 on the fly. Search the datasheet for CLKPR. You can actually reduce the internal 8MHz clock to 31.250kHz with two lines of code. What does this mean? When the ATmega wakes up, it will use much less power (because the core is running slower) but the ATmega will spend more time awake because the processor takes more time to execute each cycle in your interrupt routine. You'll have to evaluate the net affect for your own project. For me, I found it was best to wake up, process everything at 8MHz and get back to sleep as soon as possible.
In the end I was able to get a ATmega328 to run at room temperature at about 1uA with an active 32kHz RTC and external interrupts enabled. This is fairly phenomenal. Atmel has engineered the ATmega328 to the point that rubbing your fingers together produces more electrical power than a computer capable of 8MIPS on the fly. Crazy.
I hope to get (200mAh / 0.001mA = 200,000hrs = 8,333 days) 22 years of use out of a CR2032 coin cell. Will we actually get 20 years? Most likely not because the battery will discharge at a rate of about 250nA per year (this article was all I could find for supporting numbers). However, that's a fine place to be - I'd rather worry about my battery's discharge rate (shelf life) than my system gobbling up power.
I hope this helps! Have fun with your next uber-low-power coin cell powered device.