Adventures in Low Power Land

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:

  • make clean
  • make atmega328_pro8

A HEX file should now be located in the bootloader directory:

  • C:\arduino-0022\hardware\arduino\bootloaders\atmega\ATmegaBOOT_168_atmega328_pro_8MHz.hex

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: 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.

There is some additional information in these two tutorials.

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: 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.

Comments 32 comments

  • Nate - thanks for a very interesting insight into low power. Based on your work, I have got the ATmega328P running code (very slowly 31250Hz) at 1.45V and 40uA of current. My findings are here

  • Regarding BOD. Why is it that we can power cycle the AVR’s w/o problem but they are sensitive to running at low voltage?
    When you power cycle an AVR won’t it run a few clock cycles at decreasing voltage? What if you have caps in your power supply, won’t the voltage drop slowly (relative to mcu cycles)through the critical voltage? If so, is BOD really needed to protect during even fast voltage changes like turning on/off, changing batteries, etc. I’ve always thought of it as only being necessary in a slow voltage drop situation like battery discharge. Seems like it might be otherwise.

  • Something possibly worth mentioning to the viewers is the “Safe voltage” per clock speed one can readup in the datasheet. Basicly the lower the clock speed the lower the minimal voltage has to be for the mcu to operate without risking corruption. For the ATMega328 @ 8mhz you would be fine aslong as supply voltage was 2.4v>.

    With Lithium batteries (Bless their awesome discharge characteristics providing a stable 3v most of their life) this is less important, But if you are planning to work with say alkaline you may want to take care, afterall you wont have BOD to cover you.

    Awesome tutorial btw. I never noticed there was a easy to use Power management library in AVR in the first place!! Now i can ensure that my AVR projects draw as little power as possible at all time. To test my knowledge im now working on a small smd led pocket watch similiar to the bigtime that displays time in BCD code (if going Geek you may aswell go all the way!). In order to get rid of the Delay library and its Timer0 reliance (and processing overhead) i ripped out the Delay loop for microseconds out of the Delay_Basic.h file. Turns out its a tiny 2 line assemby loop that keeps going whatever is given as input * 4 cycles. so if given the time you need it to delay in us * 2 (increasing it to take 8 cycles which is 1 millionth of the internal clock) you get a very small handy delay cycle without having to rely on messy NOP loops nor on the delay library and its Timer0 use. it may be only as accurate as the internal clock, but for slow humans its good enough.

    3 cheers for inspiring projects giving way to learning. ive learned so much about AVRs and how to reduce power use since i read this and got inspired. Thanks Nate and yes the cheap SF-DMM are quite awesome!

  • You don’t need to disable BOD completely. You can use the sleep_bod_disable function so that it only disables BOD while you’re sleeping, when you’re not running any code and don’t need to worry about brownouts anyway. See here.

    • I thought I had to disable the BOD with fuse bit enable/disable. If I can do it in code it would make things a lot easier. Thanks! I’ll try to test this soon.

  • Hi, just saw the Big Time Watch Kit project, (SparkFun product KIT-10870), is the display on this watch always on, or do you have to push a button to activate the display?

    If it’s not always on, can you make is so that when turned on, it stays on, until turned off?

    The battery life estimates given here are for time with the display off? What about with display on? Edit: OK I just read the blurb closer and I see it says… ‘To check the time, just press the button on the side of the watch and it pops up on a 4-digit 7-segment LED display.’

    Is there any way to have it on display all the time, say while at work during the day, or is the batter just not going to cope with this? Bump!

  • Sorry, but when I got to this sentence it instantly made me stop reading … “I’m pretty sure rubbing your fingers together produces more heat energy than 1 microamp.”

  • can i power my arduino pro mini board 3.3v/8Mhz with a 3.6v rechargeable coin battery without using the on-board regulator? will this burn my atmega? Thanks

  • Interesting experiment. I tried replicating it in my workshop with mega168V, but could not go below 61mA with sleep mode. That is not even nearby what datasheet says. Am I missing something ?

    Moreover, my cheap multimeter could not read current when connected in series (chocked up) and just blocked the supply of mega168V. So I connected 1E resistor in series and tried voltage measurement across the resistor. With this method I got above value (61mA). Any other way to get correct measurements in microamp level ?

  • This info is ok but if you want to get something done and see some code examples try this instead:

  • In your schematic, you have Aref tied high. If the ref mux isn’t set to external reference, you can be drawing some current thru it (worst case, if you set it to internal reference, you are tying the output of the on-chip bandgap to Vcc)

  • Hi! Will it work with Arduino UNO REV.3 ?

    thank you! marC:)

  • How would I set those specific fuse values using avrdude??? I am trying to program an Atmega 328pu, and my programmer is freaking with avr studio

  • Thanks for the tutorial, it inspired me on my latest project. I’m using an ATtiny85 as glue logic between an off the shelf programmable timer and an off the shelf rf relay controller to control a pneumatic actuator. Up to now, I have had an external battery pack on the project with two AAA batteries rather than tapping directly into the 1S lipo in the timer for fear of over discharging the lipo if the user let it sit too long between charges. The user has asked me to eliminate the extra batteries. Last night, with this post as a guide, I measured my circuit power consumption and started turning off unneeded hardware. Initial consumption was 4mA when actively running and reading pins and powering optoisolators and 1.06mA when idling. Duty cycle is very low during active use by the user it will do I/O for a few cycles spaced apart by a few seconds up to several minutes so the in use duty cycle is less than 1% and it then will sit for hours or days unused.
    Turning off hw dropped the idle consumption in little chunks down to 0.47mA with everything shut down that I could. Next I started trying to figure out the interrupts and sleep modes. Putting it into a powerdown sleep wasn’t too hard but it took me awhile to get the 3 PCINT interrupts I needed working. The code ended up being a mashup between a library or two and some assembler I found in this example adjusted using the ATtiny85 data sheet.
    The bottom line, on each user input, the code executes for less than a second and then the uC powers down to 0.1uA! Amazing! From the users standpoint it behaves as if it is always running full speed but from a power consumption standpoint it is as if it is always (almost) turned off. No need for a power switch on this one!
    BTW, I disabled BOD and plan to leave it off since the timer shuts down well above the recommended AVR BOD level and thus indicates to the user that a charge is necessary. The time it would take the AVR to discharge the battery from the timer shutdown voltage to the BOD voltage is measured in years.

  • Im trying to program a brand new ATMEGA 328P for 3.3 volts operation with the ARDUINO BOOTLOADER using the internal RC 8 mHZ
    As per the setting you give in the above tutorial with the BROWNOUT selection I get
    EFUSE = FD
    HFUSE = DA
    LFUSE = E2
    which seems to coincide with the settings you got.
    However then you say to change the settings to:
    New: EFUSE = 05
    New: HFUSE = DA
    New: LFUSE = E2
    How do you do this? cause if i manually try to program EFUSE = 05 i get an error in STK500 programmer and it reverts back to
    EFUSE = FD
    Also, Ive use the already existing hex files that come in the ATMEGA folder under hardware and chose the “ATmegaBOOT_168_atmega328_pro_8MHz.hex”. this is because when i run the makefile that came with the ARDUINO-0022 I get errors.
    The thing is i cannot communicate at all with the new chip in the arduino environment.
    Im programming the chip on the STK500 environment. All i see after uploading hex is a regular led blink activity on the PB5 pin of PORTB.

  • Since it’s sleeping anyway…
    Can’t we skip the fuse and bootloader programming?
    Wouldn’t it still be 100ua asleep?

  • A shameless plug…
    You can build your own ISP, for this project and other Atmel chips. Tutorial link below.

  • Interesting project, I want to give it a try because I will use RTC sometime soon.
    Do you have a schematic of your experimental set-up, I think it is useful for some DIY re experimenting.
    Good job, cheers!

  • You’re going to corrupt the flash memory without brown out detection. At least PICs do. So it can do 1uA, but not in any practical design.

    • Perhaps that is why AVRs have a ‘disable self-programmed-memory’ fuse? I’m not sure how robust this is.

  • Thanks for the article, I was actually just reading about low power stuff with Arduino yesterday, psychic points.

  • And what about the picoPower branded avr? Try the 328P :-) The datasheet says 0.1uA in power down mode, 0.75uA in power save (with 32kHz RTC) and 0.2mA in active mode.

    • Ok, actually I read more carefully the datasheet and the only difference of picoPower is the cability to disable the Brown-Out detector by software. Otherwise the figures are the same.

  • Great Tutorial. Nice to see someone pushing the limits and keeping those datasheet folks in check.

  • OMG, Avr studio V. This thing is such a PIG. It took over an hour to download and it seems to take as long to boot up! Atmel really sucked up to M$ for the core of this one (it’s based on visual studio). I’m almost tempted to go back to PICs, MPlab even runs on Linux under Wine (and this POS never will).

    • i just use vim, avg-gcc, and avrdude
      aslong as your programer plays nicely with avrdude, you dont need to get the whole beast

    • Use AVR Studio 4. It’s been used for years. No need to use AVRdude with the MK II. Studio 5 is beta and uses Microsoft’s Visual Studio IDE which is too bloated.
      Studio 4 supports all the flash burners, debuggers, etc.
      And the compiler in Studio 4 is WinAVR which is GCC.

  • The thing is your ATmega isn’t actually DOING anything when it’s running at 1uA. So it’s a bit misleading to say “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”, because it hasn’t… it’s simply engineered a chip that’s capable of sitting idle and draw 1uA of parasitic current, which is likely 70-80%+ leakage current in the transistors.
    Still, a good tutorial none the less.
    I do wonder though if you might have been able to eek a little more overall system efficiency out of just running a bare AVR programed in C. I’m also curious as to why, if you’re able to disable that many peripherals, do you even need a ATMega328? It seems to me that you could have saved a lot of money (relatively speaking), and likely power (certainly power while it’s running), by using an AVR that only had what you needed on it.

    • In a cents-count volume manufacturing situation, you’d of course want to tailor the processor to the requirements as tightly as possible. But the nice thing about this trick is, that by disabling everything you don’t need while sleeping, you gain the power benefits of a smaller chip, but everything’s still available to use once you’re awake again.

      • I suppose my point was that, in my opinion, shouldn’t the first step in optimizing a system for power be to, well, optimize components for power use?
        Still, it’s definitely a good guide for DIY'ers that want to stick to an Arduino base and have likely never looked at an actual AVR datasheet on how to go about improving their systems :)

  • The TI MSP430 FRAM stuff is supposed to be really low power. They quote 9uA for 12kB/s memory writes. It would be interesting to compare that with figures for the AVR.

  • Nice. This tutorial caught my eye because I happened to be playing with MSP430 Launchpad low-power stuff yesterday, and found a carefully configured MSP430G2231 with timer and button interrupts enabled idles in LPM3 at 0.8uA with a 32768Hz crystal (XCAP_0), or 0.5uA if the internal 12kHz VLOCLK is used. All this low-power stuff is pretty impressive.