I'm working on a battery powered remote control. It uses a touch screen, so needs the A/D converter, and uses an RF transmitter, so I'm currently using VirtualWire for the data transmission. However, I'm willing to change anything to get this going. I'm using the Arduino board to program the chip, and then transplanting it to a breadboard, which has a 5V supply, 20MHz crystal, a few capacitors and resistors (nothing too unusual).
I'm struggling to get battery consumption below 20-40mA (even when very little is going on). This seems awfully high; I'd imagine <10ma would be much more suitable (remember: I'm not measuring the USB interfacing - just the atmega chip).
I can work out the specifics of my code, but I'm trying to find a way to get the nearly-idle current down first. I've tried the 'blink' code, and even with no LED connected, consumption is up at 40mA. I realise that delay() isn't very efficient, but even with a proper sleep and watchdog wake up, it's about 20mA some of the time, and around 40mA the rest of the time.
For example's sake, what's the lowest current consumption possible for a 'blink' style application (let's just say it waggles a digital pin, but doesn't light up an LED)? I've attached the basic code I'm using, but I'm looking for ways to turn stuff I don't need off, and stop the Arduino libraries doing anything that I'm not aware of. Any help much appreciated!
Actually, I'm using the Arduino board (minus the chip), plugged into the USB of my computer. I'm then connecting the +5V from the Arduino to the breadboard (via an ammeter). Something like this:
Arduino (minus chip) -> ammeter -> breadboard (chip, crystal + a couple of caps/resistors etc)
I have a similar RF remote control, based on a promini.
I am running 8MHz from a LiPo battery ~4V.
It goes into power down sleep mode after each key press, a keypress interrupts it out of sleep to read the key, transmit, and go back to sleep.
Draws ~9mA in sleep, ~15mA while sending.
Power LED draws some, battery charging chip draws some, RF transmitter draws some, atmega draws some.
Can you post schematic of your design?
Why 20MHz vs 16MHz?
Oops - I should have said 16Mhz (not sure where I got 20 from, but it's definitely 16).
Right now, whilst trying to get this thing down to sleep, I've literally only got the chip on the board. I want to connect a touch screen (eg. a Nintendo DS screen), which requires 2 analogue pins and 2 digital. The RF module takes one data pin, although I've found it can be powered by an arduino digital pin (so I can control the power consumption of it). I'll see if I can knock up a diagram or something...
Having hacked about with this a bit more, I'm starting to wonder if I need a physical button to wake up the remote, and then use the touch screen. That's absolutely not the design I want, so maybe I'll look at some other interrupt source (tilt switch?). All of this isn't really where I want to go though - I'd prefer to find a way of stripping the atmega chip down to the bare bones so that it draws <10mA while idle (I'm not too worried what it draws when you're using it). To get that far, I'm going to need to work out some way keep the chip in sleep mode (as deep as possible), but with occasional (eg. every 500ms) interrupts to see if you've touched the screen.
Any idea what difference dropping to 8Mhz might make? Maybe I could use the internal oscillator and save a few components too...?
Here's some bits that I found were needed. In my case, a keypress causes a hardware interrupt on pin 2.
I think hardware interrupt will let you put more stuff to sleep for lower current draw.
// * Name: pin2Interrupt, "ISR" to run when interrupted in Sleep Mode
void pin2Interrupt()
{
/* This brings us back from sleep. */
}
// * Name: enterSleep
void enterSleep()
{
/* Setup pin2 as an interrupt and attach handler. */
attachInterrupt(0, pin2Interrupt, LOW);
delay(50); // need this?
/* the sleep modes
SLEEP_MODE_IDLE - the least power savings
SLEEP_MODE_ADC
SLEEP_MODE_PWR_SAVE
SLEEP_MODE_STANDBY
SLEEP_MODE_PWR_DOWN - the most power savings
*/
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // setting up for sleep ...
sleep_enable(); // setting up for sleep ...
// Disable ADC
ADCSRA &= ~(1 << ADEN);
// Power down functions
PRR = 0xFF;
sleep_mode(); // now goes to Sleep and waits for the interrupt
/* The program will continue from here after the interrupt. */
detachInterrupt(0); //disable interrupts while we get ready to read the keypad
// Power up functions
PRR = 0x00;
/* First thing to do is disable sleep. */
sleep_disable();
// then go to the void Loop()
}
and finally, calling sleep from within void loop()
void loop(){
if (sleep_count>1000){ // check if we should go to sleep because of "time" i.e. 1000 times thru loop with no action
sleep_count=0; // turn it off for when we wake up
delay(100); // need this?
enterSleep(); // call Sleep function to put us out
// THE PROGRAM CONTINUEs FROM HERE after waking up in enterSleep()
} // end of checking to go to sleep
// code here that does other stuff ...
sleep_count = sleep_count+1; // start counting to go to sleep
}
I've done a bit more experimenting... When in full sleep, the chip itself seems to take almost nothing (maybe 0.1mA or something). The really cool thing is that it seems to leave it's output stages enabled, so that means any pins left as outputs, and set to 0 or 1 stay that way when it's asleep (this is cool because I can set one axis of my touch screen up for reading, and have an op-amp provide me with the hardware interrupt).
I'm now looking at dropping the chip down to 8MHz - I tried to do it by bootloader/fuses etc, but for the life of me, couldn't get it working properly (it just refuses to be programmed) - that's another problem. I've done something similar by using the clock pre-scaler:
CLKPR = (1<<CLKPCE);
CLKPR = 1; // this is actually "divide by 2"
In my case, I had to write some outputs Low so that the interrupt could be created by a key press, then write them back high again before the keypad library would work. Glad to see you found a way to get your interrupt created as well.
I have a 8MHz promini, and ended up doubling the serial.begin(speed) to have it talk correctly via serial port for debugging, and doubling the speed set for Virtualwire RF to have that work as well. Am guessing the chip is set for 16MHz operation (maybe something I did during downloading without realizing it?) but with 8MHz xtal, external comms need to be set to 2X so operate at the correct speed.
Your biggest power savings are reducing the voltage and frequency. Try 8mhz is easy because you can call it a lilypad but 1mhz will use way less power.
I found that messing with CLKPR messes with delay(), millis() and just about everything else. However, it's possible to 'fix' them by making a new boards.txt file with all the same details as your usual board, but with the correct clock speed in it (just use that stanza as your board - there's no need to burn a bootloader or anything - it seems that uploading a sketch is enough to specify the CPU speed). A bit of a hack, but saves having to put multipliers all through your code.
Now I've got to variable clock speeds, I'm thinking I should work out a low_power_delay() function for all those 50 and 100ms delays I'm ending up with. Even though clock scaling messes with millis(), I'm sure I can calculate compensation and end up delaying for the right amount of time. I'll put my thinking cap on...
I'll also look at dropping down to really low speeds for easy grunt work, and maybe going to 8MHz for VirtualWire or something.
Thanks for the help - I never did strip the chip down to the bare bones, but it's hard to improve on a current consumption of nearly zero!
Thanks everyone for your help with this. I've tried to put a few things together and test out various ways of lowering power consumption. This post http://arduino.cc/forum/index.php/topic,57067.0.html asks about unused pins, which as it turns out makes quite a lot of difference.
I've written up what I've found here: http://electronicsfordogs.com/node/15 . In short though, set all your unused pins as inputs, and enable the internal pull ups on them, use the PRR register for anything you absolutely don't use (eg. SPI, TWI, maybe the ADC, timers, etc), and think seriously about reducing the clock speed to 8Mhz or less if you can get away with it. Any long delay()s in code could be candidates for sleep mode, or else a slow clock and ordinary waiting. Obviously, any time you're hanging around waiting for something external to happen, then use an external interrupt whilst you put the CPU into a deep sleep.
In short, it's possible to make some serious current savings, so long as you're willing to spend a bit of time doing it. Reasonable savings take almost no effort at all, so it's really easy to save some power in most applications, if it's something you care about.
I have blatantly copied Crossroads' sleep mode collection on my current project ( except I have a separate interrupt pushbutton to ground ), and I also power my transmitter and 3 cmos counter chips from an output pin ( make sure you switch all inputs to the cmos chips to low before powering them down or the protection diodes will short the input to ground via the vcc being low - I blew one micro that way )
I am using a 9v battery and a micropower 5 volt regulator that is always on , and my unit draws 110 microamps in sleep mode, which with a 580mAh duracell should last about 5000 hours = about 7 months.
The setup of the last example will bring the controller down to 0.4uA while sleeping and 214uA while running.
With regard to unused pins:
You must ensure that no pin floats. Floating pins will increase current consumption.
It does not matter if you pull them low or high. Unless of course there is some external component connected to it. Then it does matter. Depending on the external components (e.g. external pull up or pull down) it may depend.
One thing though: being able to run with 0.4uA does not imply being able to start with 0.4uA. During startup the AVR will always draw significantly more current (>>10uA). This is the "over the hump" problem that prevents starting from very high impedance power sources unless you add some additional components for power control.