Arduino Forum

Using Arduino => Programming Questions => Topic started by: Yeast on Oct 27, 2011, 06:36 pm

Title: Preserve battery with Sleep ?
Post by: Yeast on Oct 27, 2011, 06:36 pm
I am working with arduino pro mini 3.3V connecting with IR temperature sensors, openlog, a few RGB LEDs and a buzzer. I followed the example on  sleep function here http://www.arduino.cc/playground/Learning/ArduinoSleepCode (http://www.arduino.cc/playground/Learning/ArduinoSleepCode) and put arduino to sleep when it is inactive for 8 seconds while it will wake when a interrupt button is pressed.

I attached a Li-Po battery 110mAh to it and after a day it run out of battery.
I also found another example on battery saving at http://interface.khm.de/index.php/lab/experiments/sleep_watchdog_battery/ (http://interface.khm.de/index.php/lab/experiments/sleep_watchdog_battery/)
Will watchdog + sleep help to save more battery power ? I need to have it running without changing battery for at least 5 days.
Title: Re: Preserve battery with Sleep ?
Post by: nickgammon on Oct 27, 2011, 09:50 pm
Why wait 8 seconds? Anyway you need to measure the current consumption. It sounds like it is using a lot more than sleep current.

I did an example here:

http://www.gammon.com.au/forum/?id=11149

That used sleep plus a watchdog. Whilst asleep it used 25 uA so that should last quite a few days on a 110 mAh battery.

You will need a LOW level interrupt to wake it, as other interrupts are not processed when asleep (RISING, FALLING, CHANGE).

You may need to minimize the use of LEDs and buzzers. Also, as illustrated on the page I linked to, you can turn off internal functions like the ADC converter, to save power while asleep.
Title: Re: Preserve battery with Sleep ?
Post by: Yeast on Oct 28, 2011, 05:05 am
How do I measure the current consumption ??

The program is actually consist of a few steps of task to be perform.
Which also include changing of location of measurement but the between task time shouldn't exceed 8 seconds, it could be minimize to 4 or 3 seconds but it wouldn't make much difference I guess.
I am currently used HIGH interrupt as when the button is press then wake up. "attachInterrupt(1, wakeUpNow, HIGH);"
It is intended to be used like once a day so the used of LED and buzzer is only use during the performance of task so I hope to keep it the way it is.
Is the sensors other component still consuming the power even when arduino sleep?


Title: Re: Preserve battery with Sleep ?
Post by: CrossRoads on Oct 28, 2011, 06:15 am
Put your multimeter in mA mode.
Disconnect the battery + connection, connect it to red meter probe.
Connect black meter probe to Vcc pin on the promini.

So now the meter is in series between the battery+ and the arduino VCC. Turn it on. Should see  a  jump in current as the part wakes up and does the readings.
If it does the functions really fast you won't get a good reading - have them repeat  for a second or so in that case.
Title: Re: Preserve battery with Sleep ?
Post by: pekkaa on Oct 28, 2011, 06:34 am
Depending on how you designed it, the other parts of you circuit may (and probably will) draw current while the Arduino is sleeping. Post the shematic that we can check is it possible to minimize the power consumption.
Title: Re: Preserve battery with Sleep ?
Post by: nickgammon on Oct 28, 2011, 06:42 am

I am currently used HIGH interrupt as when the button is press then wake up. "attachInterrupt(1, wakeUpNow, HIGH);"


That won't work. Only a LOW interrupt wakes the processor from sleep.

Besides which, there is no such thing as a HIGH interrupt:

http://arduino.cc/en/Reference/AttachInterrupt

Only LOW, CHANGE, RISING, FALLING.

Quote
Is the sensors other component still consuming the power even when arduino sleep?


Yes, which is why I said above:


Also, as illustrated on the page I linked to, you can turn off internal functions like the ADC converter, to save power while asleep.
Title: Re: Preserve battery with Sleep ?
Post by: Yeast on Oct 28, 2011, 08:38 am
@Nick
Thanks Nick :)
I will try that out later on today.

@Pekkaa
I will get working on the schematic right away
Title: Re: Preserve battery with Sleep ?
Post by: Yeast on Oct 28, 2011, 09:45 am
Please excuse my bad drawing skill.
Title: Re: Preserve battery with Sleep ?
Post by: pekkaa on Oct 28, 2011, 10:31 am
Don't you have current limiting resistors in the front of the RGB leds? What what are the two boxes in the top right corner? I can't read the text above them.
Title: Re: Preserve battery with Sleep ?
Post by: nickgammon on Oct 28, 2011, 10:34 am
"soft button"
Title: Re: Preserve battery with Sleep ?
Post by: pekkaa on Oct 28, 2011, 10:40 am
I  have newer used buzzers, but shouldn't you have a resistor in the front of it also?
Title: Re: Preserve battery with Sleep ?
Post by: Yeast on Oct 28, 2011, 02:32 pm
I am currently using the RGB from the lilypad series (http://www.sparkfun.com/products/8467).
The soft button made up of two layers of conductive fabric separated by a layer of sponge.
One side is connected to ground and input. The another is connected to VCC.
How can I make one that produce LOW when it is press to be replace with this one ??
Are the resistors necessary ??? Will it help in reducing power consumption or does it provide more stability ?
Title: Re: Preserve battery with Sleep ?
Post by: pekkaa on Oct 28, 2011, 05:46 pm
You absolutely need to add the resistors. Check the shematic from the page you linked. It shows how to wire the resistors. Without the resistors the leds draw to much current. It may damage both the Arduino and the leds. And yes, the resistors will reduce the power consumption.

Check also the buzzer's specs. It may need a resistor as well. Btw, do you know how much current the openlog in your diagram draws while idling?
Title: Re: Preserve battery with Sleep ?
Post by: pekkaa on Oct 28, 2011, 06:16 pm
Quote
How can I make one that produce LOW when it is press to be replace with this one ??


Wire the other end of the button into the GND pin.  Remove the pull down resistor R from your diagram and enable the Arduino's internal pull up, http://www.arduino.cc/en/Tutorial/DigitalPins (http://www.arduino.cc/en/Tutorial/DigitalPins). Or if you want use an external pull up, connect it into the Arduino's Vcc pin.

And the most important thing: What is the battery's voltage? Is it 3.3V? If it is higher than that, you need to connect it into the RAW pin instead of Vcc.

Btw, the schematic on the Sparkfun's page is for 5V. You need the calculate resistor values for 3.3V yourself.
Title: Re: Preserve battery with Sleep ?
Post by: Yeast on Oct 28, 2011, 06:41 pm
Quote
What is the battery's voltage?

It is 3.7V and I totally forget about the RAW pin - -"
And I have no idea how much openlog (http://www.sparkfun.com/products/9530) consume while idling.

Next question will be do I need a watchdog or just sleep function is enough?
Title: Re: Preserve battery with Sleep ?
Post by: pekkaa on Oct 28, 2011, 07:42 pm
Quote
And I have no idea how much openlog (http://www.sparkfun.com/products/9530) consume while idling.


Read the page you linked:

Quote
2mA idle, 6mA at maximum recording rate
Title: Re: Preserve battery with Sleep ?
Post by: pekkaa on Oct 28, 2011, 08:22 pm
Quote
You absolutely need to add the resistors


I'll take that back. I looked at the picture on the Sparfun's webpage again and noticed the leds on the pcb already seem to have the resistors in front of them. However, this leads to an other problem: If the resistors are rated for 5V, then the led's wont be very bright if you power them from 3.3V.

Title: Re: Preserve battery with Sleep ?
Post by: nickgammon on Oct 28, 2011, 10:52 pm

Next question will be do I need a watchdog or just sleep function is enough?


It depends what you are trying to achieve. Once asleep, either an interrupt (a LOW interrupt) or the watchdog (and various other things, read the data sheet) will wake it up.

If you just want it awake when you press the button, the interrupt will do. If you want it to take a reading every 5 minutes, you need the watchdog. If you want both, you need both.
Title: Re: Preserve battery with Sleep ?
Post by: Yeast on Oct 30, 2011, 04:36 pm
I already changed the circuit to LOW on button press and attach interrupt as attachInterrupt(1, wakeUpNow, LOW);
And when ideal time exceed 8 seconds it called upon sleepNow() function which is almost identical to the example.
The battery still only run for a day. Did I forget something ??

Code: [Select]

void sleepNow()         
{
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);   
    sleep_enable();
    attachInterrupt(1,wakeUpNow, LOW);
    sleep_mode();     
    sleep_disable();   
    detachInterrupt(1);   
}


**I haven't check the mA yet, I need to find a multimeter first.
Title: Re: Preserve battery with Sleep ?
Post by: nickgammon on Oct 30, 2011, 09:48 pm
I think we need to see more of your code - like all of it.
Title: Re: Preserve battery with Sleep ?
Post by: Yeast on Oct 31, 2011, 04:07 am
Code: [Select]

#include <i2cmaster.h>
#include <avr/sleep.h>
#include <NewSoftSerial.h>

//data logger TX/RX pins
NewSoftSerial logger(7,8);
boolean enable_log = true;
//boolean enable_log = false;

int ledPins[] = {10,9,4,11,12,4};

//sleep function()
boolean sleep_enable = true;
//boolean sleep_enable = false;
int inactive_counter;
int softButtonPin = 3;

//temperature-related variable
float r_temperature;
float avg_temperature;
int sample_rate = 250;

//stability
int dcheck = 15;

//application variables
int current_position;
double reading_a1;
double reading_a2;
double reading_b1;
double reading_b2;
boolean debug_mode = true;
boolean is_sleeping;
//boolean debug_mode = false;

//buzzer
boolean soundon = true;
//boolean soundon = false;
int buzzerPin = 5;
int noteFreqArr[] = {
49.4, 52.3, 55.4, 58.7, 62.2, 65.9, 69.9, 74, 78.4, 83.1, 88, 93.2,
98.8, 105, 111, 117, 124, 132, 140, 148, 157, 166, 176, 186,
198, 209, 222, 235, 249, 264, 279, 296, 314, 332, 352, 373,
395, 419, 444, 470, 498, 527, 559, 592, 627, 665, 704, 746,
790, 837, 887, 940, 996, 1050, 1110, 1180, 1250, 1320, 1400, 1490,
1580, 1670, 1770, 1870, 1990, 2100};

void setup()
{
   
 
 current_position=0;
 
 //IR Sensor
 i2c_init(); //Initialise the i2c bus
 PORTC = (1 << PORTC4) | (1 << PORTC5);//enable pullups
   
 if(soundon)
   pinMode(buzzerPin, OUTPUT);
 
 is_sleeping = false;
 inactive_counter=0;
 pinMode(softButtonPin, INPUT);
 attachInterrupt(1, wakeUpNow, LOW);
 
 for(int i=0; i<6; i++)
 {  
   pinMode(ledPins[i], OUTPUT);
   analogWrite(ledPins[i], 0);
 }
 
 Serial.begin(9600);
 
 if(enable_log)
 {
   logger.begin(9600);
   logger.println("Time,Result,A1,A2,B1,B2,Difference");
 }
}

void loop()
{    
 if(current_position%2==0 && dcheck_high())
 {
   inactive_counter =0;
   switch(current_position)
   {
      case 0: if(debug_mode)
                Serial.print("Check 1.1: ");
              nextStep();
              break;
      case 2: if(debug_mode)
                Serial.print("Check 1.2: ");
              nextStep();
              break;
      case 4: if(debug_mode)
                Serial.print("Check 2.1:");
              nextStep();
              break;
      case 6: if(debug_mode)
                Serial.print("Check 2.2:");
              nextStep();
              break;
   }
   while(dcheck_high()){}
   delay(100);
 }
 else if(current_position%2==1 && dcheck_low())
 {
   inactive_counter =0;
   if(current_position<6)
   {
     nextStep();
     if(debug_mode)
        Serial.println("Released, change side");
      delay(100);
   }
 }else
 {  
    if(sleep_enable)
    {
      inactive_counter++;
      delay(50);
     
      if(inactive_counter > 150)
      {
        if(debug_mode){Serial.println("Enter Sleep Mode"); delay(100);}
        is_sleeping = true;
        LED_clear();
        sleepNow();
      }
    }
 }
}

void nextStep()
{
 if(sleep_enable)
     inactive_counter=0;
 current_position++;
 action(current_position);
}

void action(int current_pos)
{
 switch(current_pos)
 {
   case 0: LED_clear();
           break;
   case 1: LED_clear();
           reading_a1 = take_measurement(1);
          if(debug_mode)
             Serial.println(reading_a1);
          LED_1stcompleted(false);
          if(soundon)
                playsound();
         
          break;  
   case 3: LED_clear();
           reading_a2 = take_measurement(1);
          if(debug_mode)
             Serial.println(reading_a2);
          LED_1stcompleted(true);
          if(soundon)
          {
              playsound();
              delay(200);
              playswitch();
          }
           break;          
   case 5: //LED_1stcompleted();
           reading_b1 = take_measurement(2);
           if(debug_mode)
             Serial.println(reading_b1);
           LED_2ndcompleted(false);
            if(soundon)
             playsound();
           break;
   case 7: //LED_1stcompleted();
           reading_b2 = take_measurement(2);
           if(debug_mode)
             Serial.println(reading_b2);
           LED_2ndcompleted(true);
            if(soundon)
             playsound();
          delay(100);
          action(8);
          break;
   
   case 8: LED_clear();
           playcompleted();
           if(is_okie()){LED_OK();}
           else
           {
             if(((reading_a1+reading_a2)/2) > ((reading_b1+reading_b2)/2))
               LED_NOT(1);
             else if(((reading_b1+reading_b2)/2)>((reading_a1+reading_a2)/2))
               LED_NOT(2);          
           }
           if(enable_log)
             logging();
           delay(1000);
           reset_application();
           break;
   default:break;
 }
}
Title: Re: Preserve battery with Sleep ?
Post by: Yeast on Oct 31, 2011, 04:08 am
Code: [Select]

void logging()
{
 unsigned long m = millis();
 m = m/1000;
 
 logger.print(m);
 logger.print(",");
 if(is_okie())
   logger.print("OKIE,");
 else
   logger.print("NOT OKIE,");
 logger.print(reading_a1);
 logger.print(",");
 logger.print(reading_a2);
 logger.print(",");
 logger.print(reading_b1);
 logger.print(",");
 logger.print(reading_b2);  
 logger.print(",");
 logger.println(((reading_a1+reading_a2)/2) - ((reading_b1+reading_b2)/2));
}

boolean dcheck_high()
{
 int check = dcheck;
 while(check>0)
 {
   check--;
   if(digitalRead(softButtonPin)==HIGH)
     return false;
 }
 return true;
}

boolean dcheck_low()
{
 int check = dcheck;
 
 while(check>0)
 {
   check--;
   if(digitalRead(softButtonPin)==LOW)
     return false;
 }
 return true;
}

double read_temperature()
{
 int dev = 0x5A<<1;
 int data_low = 0;
 int data_high = 0;
 int pec = 0;
 
 i2c_start_wait(dev+I2C_WRITE);
 i2c_write(0x07);
 
 // read
 i2c_rep_start(dev+I2C_READ);
 data_low = i2c_readAck(); //Read 1 byte and then send ack
 data_high = i2c_readAck(); //Read 1 byte and then send ack
 pec = i2c_readNak();
 i2c_stop();
 
 //This converts high and low bytes together and processes temperature, MSB is a error bit and is ignored for temps
 double tempFactor = 0.02; // 0.02 degrees per LSB (measurement resolution of the MLX90614)
 double tempData = 0x0000; // zero out the data
 int frac; // data past the decimal point
 
 // This masks off the error bit of the high byte, then moves it left 8 bits and adds the low byte.
 tempData = (double)(((data_high & 0x007F) << 8) + data_low);
 tempData = (tempData * tempFactor)-0.01;
 
 return tempData - 273.15;
}

double take_measurement(int index)
{
 avg_temperature = 0.0;
 
 for(int i=0;i<3;i++)
 {
   LED_inprogress(index);
   delay(100);
 }
 
 for(int i=0;i<sample_rate;i++){
   if(i%25==0) {LED_inprogress(index);}
   r_temperature = read_temperature();
   avg_temperature += r_temperature;    
 }
 return avg_temperature/sample_rate;
}

boolean is_okie()
{
 float temperature_diff = abs(((reading_a1+reading_a2)/2) - ((reading_b1+reading_b2)/2));
 if(debug_mode)
   Serial.println(temperature_diff);
 return (temperature_diff < 2.0);
}

void LED_clear()
{
 setcolor(1,0,0,0);
 setcolor(2,0,0,0);
}

void LED_1stcompleted(boolean both)
{
 if(both)
   setcolor(1,0,255,0);
 else
   setcolor(1,255,255,0);
 setcolor(2,0,0,0);
}

void LED_2ndcompleted(boolean both)
{
 setcolor(1,0,255,0);
 if(both)
   setcolor(2,0,255,0);
 else
   setcolor(2,255,255,0);
}

void LED_OK()
{
 setcolor(1,0,255,0);
 setcolor(2,0,255,0);
 delay(2000);
 setcolor(1,0,0,0);
 setcolor(2,0,0,0);
}

void LED_NOT(int index)
{
 switch(index)
 {
   case 1: setcolor(1,255,0,0);
           setcolor(2,0,255,0);
           break;
   case 2: setcolor(1,0,255,0);
           setcolor(2,255,0,0);
           break;
 }
 delay(2000);
}

void LED_inprogress(int index)
{
 setcolor(index,200,200,0);
 delay(100);
 setcolor(index,0,0,0);
 delay(100);  
}

void setcolor (int ledset, unsigned char red, unsigned char green, unsigned char blue)    
{
         ledset = (ledset-1)*3;
         analogWrite(ledPins[ledset], red);          
         analogWrite(ledPins[ledset+1], green);
         analogWrite(ledPins[ledset+2], blue);
}

//Buzzer related function()
void playNote(int noteInt, long length, long breath = 100) {
   length = length - breath;
   buzz(buzzerPin, noteFreqArr[noteInt], length);
   if(breath > 0) { //take a short pause or 'breath' if specified
       delay(breath);
   }
}

void playcompleted()
{
   playNote(51,200);
   playNote(52,200);
   playNote(53,200);
   playNote(54,200);    
   playNote(55,200);
}

void playswitch()
{
 playNote(50,200);
 playNote(53,200);
 playNote(55,200);
}

void playsound()
{
    playNote(50,200);
    playNote(60,150);
    playNote(50,200);
}

void buzz(int targetPin, long frequency, long length) {
   long delayValue = 1000000/frequency/2;
   long numCycles = frequency * length/ 1000;
   for (long i=0; i < numCycles; i++){
       digitalWrite(targetPin,HIGH);
       delayMicroseconds(delayValue);
       digitalWrite(targetPin,LOW);
       delayMicroseconds(delayValue);
   }
}

void reset_application()
{
//  if(debug_mode)
//      Serial.print("reset_application");
 delay(100);
 inactive_counter=0;
 current_position = 0;
 LED_clear();  
}

//sleep related funtion()
void wakeUpNow()        
{
 if(is_sleeping)
 {
   Serial.println("is up");
   is_sleeping = false;
   reset_application();
 }
}

void sleepNow()        
{   set_sleep_mode(SLEEP_MODE_PWR_DOWN);  
   sleep_enable();        
   attachInterrupt(1,wakeUpNow, LOW);
   sleep_mode();            
   sleep_disable();        
   detachInterrupt(1);    
}
Title: Re: Preserve battery with Sleep ?
Post by: 48X24X48X on Oct 31, 2011, 04:19 am
In PWR_DOWN mode, there's 3 things that *can* be on: WDT, ADC, BOD. The ADC consumes about 90-100 uA. BOD consumes about 17 uA. And WDT consumes about 4 uA. I believe there's something else is consuming rather than these 3 possible factor as if you add those 3 up, it would still let you run more than a day.
Title: Re: Preserve battery with Sleep ?
Post by: nickgammon on Oct 31, 2011, 05:04 am
Well I can't get that to compile - various multiply defined symbols relating to the I2C library. Anyway I don't understand this:

Code: [Select]
void reset_application()
{
//  if(debug_mode)
//      Serial.print("reset_application");
 delay(100);
 inactive_counter=0;
 current_position = 0;
 LED_clear();  
}

//sleep related funtion()
void wakeUpNow()        
{
 if(is_sleeping)
 {
   Serial.println("is up");
   is_sleeping = false;
   reset_application();
 }
}

void sleepNow()        
{   set_sleep_mode(SLEEP_MODE_PWR_DOWN);  
   sleep_enable();        
   attachInterrupt(1,wakeUpNow, LOW);
   sleep_mode();            
   sleep_disable();        
}


Now wakeUpNow is an ISR, right? So interrupts are disabled. So when it calls  reset_application then interrupts are disabled. So delay (100) won't work.

Why test is_sleeping? You won't be there unless it is sleeping, will you?

You should detach the interrupt in is_sleeping. Then do the rest once interrupts are active again. eg.

Here:


Code: [Select]
//sleep related funtion()
void wakeUpNow()        
{
   detachInterrupt(1);    
}

void sleepNow()        
{  
   set_sleep_mode(SLEEP_MODE_PWR_DOWN);  
   sleep_enable();        
   attachInterrupt(1,wakeUpNow, LOW);
   sleep_mode();            
   sleep_disable();        
   Serial.println("is up");
   is_sleeping = false;
   reset_application();
}


Here:

Code: [Select]
void setup()
{
   
...

 pinMode(softButtonPin, INPUT);
 attachInterrupt(1, wakeUpNow, LOW);
 


Don't attach that interrupt until you are ready. And in any case I would enable the pull-up resistor.

Also I don't see you turning stuff off before going to sleep. The LED pins are still configured as outputs. You haven't turned off the ADC or anything. To turn off the various internal modules (just before sleeping):

Code: [Select]
// turn off various modules
 PRR = 0b11101111;


(EDIT: changed 0x11101111 to 0b11101111)

After you wake put them back:

Code: [Select]
// stop power reduction
 PRR = 0;

Title: Re: Preserve battery with Sleep ?
Post by: Yeast on Oct 31, 2011, 08:19 am
So I need to convert the OUTPUT pins to INPUT before sleep and reassign them after wake up?
I change the code as such...

Code: [Select]

void wakeUpNow()       
{
  detachInterrupt(1);
  // stop power reduction
  PRR = 0;
  pinMode(buzzerPin, OUTPUT);
  for(int i=0; i<6; i++)
  { 
    pinMode(ledPins[i], OUTPUT);
  }
}

void sleepNow()         
{   
    // turn off various modules
    PRR = 0x11101111;
     
    pinMode(buzzerPin, INPUT);
    for(int i=0; i<6; i++)
    { 
      pinMode(ledPins[i], INPUT);
    }
   
    set_sleep_mode(SLEEP_MODE_PWR_DOWN); 
    sleep_enable();         
    attachInterrupt(1,wakeUpNow, LOW);
    sleep_mode();           
    sleep_disable();         
    reset_application();     
}



I already have a 10K resistor connected to the button pin. Do I still need to enable the internal pull-up resistor?
Did the PRR = 0x11101111; just turn off the internal module of arduino or everything connected to it too?

Did I have everything off now ?? If not how do I switch everything off except the interrupt pin.
(I attach the i2cmaster and newsoftserial together with this post)

Anyway I tried to take the reading for running, sleeping
on Arduino Fio: running 8mA, Running Max at 20mA and sleep at 4mA
on Arduino Pro Mini: running 10mA, Running Max at 20mA and sleep at 6mA

**In previous sketch I forget to detach the interrupt and it keep falling into wakeup() function so I did another check but it is all unnecessary so now I remove it all as suggested.
Title: Re: Preserve battery with Sleep ?
Post by: nickgammon on Oct 31, 2011, 09:47 pm
As I measured here:

http://www.gammon.com.au/forum/?id=11149

When asleep you should be consuming 25 uA or thereabouts. You are getting 4 mA which is about 240 times that much. So something is seriously wrong. I'll try getting the sketch to compile later and see what I measure.
Title: Re: Preserve battery with Sleep ?
Post by: nickgammon on Nov 01, 2011, 01:10 am
I'm wondering about your hardware setup when it consumes so much power.

I measured about 270 uA with your original code, which is a lot less than the 4 mA you are getting.

I've just looked at the circuit for the Arduino Pro Mini. As far as I can see, it has a permanent LED connected between Vcc and Gnd via a 10K resistor. That would use close to a 1 mA wouldn't it? I would be trying to disconnect that.

Anyway, I amended your sleepNow to add a couple of things, and got the current consumption down to 75 uA.

In particular:



Code: [Select]
void sleepNow()         
{   

  pinMode(buzzerPin, INPUT);
  for(int i=0; i<6; i++)
  { 
    pinMode(ledPins[i], INPUT);
  }

  // turn off I2C
  TWCR &= ~(_BV(TWEN) | _BV(TWIE) | _BV(TWEA));

  // turn off I2C pull-ups
  digitalWrite (A4, LOW);
  digitalWrite (A5, LOW);

  // disable ADC
  ADCSRA = 0; 

  // turn off various modules
  PRR = 0b11101111;

  set_sleep_mode(SLEEP_MODE_PWR_DOWN); 
  sleep_enable();         
  digitalWrite (3, HIGH);
  pinMode (3, INPUT);   
  attachInterrupt(1,wakeUpNow, LOW);
  sleep_mode();           
  sleep_disable();         
  reset_application();     
}


Title: Re: Preserve battery with Sleep ?
Post by: Yeast on Nov 01, 2011, 03:52 am
I did have a few changes to the original hardware.
I no longer used the lilypad RGB but use RGB Diffused (http://www.sparkfun.com/products/9264).
I connect R to 180 ohm resistor and G to 100 ohm before linking to respective pins.

Question: Why do I need to have it in the sleepnow() since it is already declare in the setup?
Code: [Select]

digitalWrite (3, HIGH);
pinMode (3, INPUT);


Even with the additional turning off code it still only goes down to 4mA for arduino fio.
Title: Re: Preserve battery with Sleep ?
Post by: Yeast on Nov 01, 2011, 04:01 am
While the IR sensor uses the exact same setting as

(http://bildr.org/blog/wp-content/uploads/2011/01/MLX90614_hookup.png)
Title: Re: Preserve battery with Sleep ?
Post by: nickgammon on Nov 01, 2011, 04:15 am
Before addressing those questions, following up from an idea here:

http://jeelabs.org/2009/05/16/power-consumption-more-savings/

I discovered that by programming the fuse to disable brown-out detection it reduced the consumption on my test from about 75 uA to 6 uA, a huge saving.

Quote
Question: Why do I need to have it in the sleepnow() since it is already declare in the setup?


You don't, I had it there because I was experimenting with turning all pins to inputs, and low, then I put that one back.




The diagram you posted doesn't seem to match the Arduino Fio or the Arduino Pro Mini.

If you are using a board with an on-board LED, a USB conversion chip, or a voltage regulator, these are all likely to consume power. I am testing with a "bare bones" board which is basically the processor chip, a couple of decoupling capacitors, and a resonator. This, basically:

(http://www.gammon.com.au/images/Wire_Wrapped_Atmega132_a.jpg)
Title: Re: Preserve battery with Sleep ?
Post by: 48X24X48X on Nov 01, 2011, 04:33 am
I would suggest if you start from the Pro Mini/Fio alone without any external peripheral.
It will be very hard to pin point where the current consumption is going into when you have several possible contributors.
Then, once the main board is low in current, start adding the external peripheral one by one.
Eventually you'll get there. :)

You can disable the BOD on the fly but with strict timing and sequence.
You might want to check a simple library I wrote some time ago:
http://www.rocketscream.com/blog/2011/07/04/lightweight-low-power-arduino-library/ (http://www.rocketscream.com/blog/2011/07/04/lightweight-low-power-arduino-library/)
Title: Re: Preserve battery with Sleep ?
Post by: nickgammon on Nov 01, 2011, 05:40 am
There's something wrong with that URL, I can't load it by clicking.

Anyway, working around that, the BOD disable doesn't seem as effective as setting the fuse. I still measure 61 uA using the test sketch compared to 6 uA with setting the fuse.
Title: Re: Preserve battery with Sleep ?
Post by: 48X24X48X on Nov 01, 2011, 05:59 am

There's something wrong with that URL, I can't load it by clicking.

Anyway, working around that, the BOD disable doesn't seem as effective as setting the fuse. I still measure 61 uA using the test sketch compared to 6 uA with setting the fuse.


Fixed the link!

The software BOD disable works in my case. I always get a reduce of ~17 uA when disabling them through software. I also started using the hard coded way of disabling the fuse but I thought the BOD is an important feature to keep. So, I went with the software method and only disabling them when needed.
Title: Re: Preserve battery with Sleep ?
Post by: Yeast on Nov 01, 2011, 12:53 pm
I am actually using pro mini and arduino fio but the diagram I posted is from the example I find on IR sensor.
Sorry for the confusion.  :smiley-sweat:
I have already solder everything together so removing everything and adding them back one by one doesn't seem like a preferable choice.  :smiley-roll-sweat:
Title: Re: Preserve battery with Sleep ?
Post by: Yeast on Nov 01, 2011, 01:26 pm

You can disable the BOD on the fly but with strict timing and sequence.
You might want to check a simple library I wrote some time ago:
http://www.rocketscream.com/blog/2011/07/04/lightweight-low-power-arduino-library/ (http://www.rocketscream.com/blog/2011/07/04/lightweight-low-power-arduino-library/)


I check out for library by loading the current hardware setting with your "Wake External Interrupt" example and it is still 4mA.
So it is definitely something to do with the hardware setting !!!!
Title: Re: Preserve battery with Sleep ?
Post by: nickgammon on Nov 01, 2011, 09:06 pm

I have already solder everything together so removing everything and adding them back one by one doesn't seem like a preferable choice.  :smiley-roll-sweat:


You can make, as a test, a "bare bones" board, even on a breadboard. Also there are cheap circuit boards, for example this one for $US 3:

http://evilmadscience.com/productsmenu/tinykitlist/74-atmegaxx8

Then solder on a chip header (eg. the ZIF socket they have on the page), a couple of decoupling caps, a resonator, and then the wires leading to your circuit.

Then you are in a position to test the sketch/hardware combination. You can power it, for testing, from an external 5V supply. For example, I powered my test board by simply connecting to the 5V/Gnd pins on an Arduino Uno, which supplies me with regulated 5V.
Title: Re: Preserve battery with Sleep ?
Post by: wayneft on Feb 06, 2012, 11:40 pm
I know this is an old thread but I can tell you where your extra 4 mA is coming from because I've spent the last few hours trying to figure out the exact same problem.  NewSoftSerial adds 4mA of extra current to all of your sleep mode settings.  I was following some of Nick's code to use as a baseline.  Try the simple sketch below with and without creating an instance of NSS and you'll see a 4mA difference. The numbers on the left are without NSS and on the right with NSS.  Now my question is can you delete an instance of NewSoftSerial after you've created one?

Code: [Select]
#include <avr/sleep.h>
#include <NewSoftSerial.h>

//NewSoftSerial ThisIsKillingME(8,9);


void setup ()
{
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);  //480uA  4.35mA
//  set_sleep_mode (SLEEP_MODE_STANDBY);  //636uA  4.5mA
//  set_sleep_mode (SLEEP_MODE_EXT_STANDBY);  //775uA  4.65mA
//  set_sleep_mode (SLEEP_MODE_PWR_SAVE);  //775uA  4.648mA
//  set_sleep_mode (SLEEP_MODE_ADC);  //967uA  4.84mA
//  set_sleep_mode (SLEEP_MODE_IDLE);  //1.16mA  5.03mA
  sleep_enable();
  // disable ADC
  ADCSRA = 0; 
  // turn off various modules
  PRR = 0xFF;
  // turn off brown-out enable in software
  MCUCR = _BV (BODS) | _BV (BODSE);  // turn on brown-out enable select
  MCUCR = _BV (BODS);        // this must be done within 4 clock cycles of above
  sleep_cpu ();              // sleep within 3 clock cycles of above
}  // end of setup

void loop () { }
Title: Re: Preserve battery with Sleep ?
Post by: nickgammon on Feb 06, 2012, 11:53 pm
You could do new and delete rather than statically allocating it. But that may or may not return the power consumed. There would be an underlying reason (it has configured an interrupt to fire for example). So unless it has a destructor, and the destructor is designed to undo whatever the constructor does, you may not achieve much.

I'm sure it can be done, but you will need to figure out exactly what, in NewSoftSerial, is consuming the power.
Title: Re: Preserve battery with Sleep ?
Post by: nickgammon on Feb 07, 2012, 12:05 am
A quick browse indicates the constructor doesn't do much apart from configuring the input and output pins (although that might have a small effect, eg. the pull-ups).

But it does link in the pin change interrupts, possibly activating the pin change interrupts causes a higher power consumption. I'm guessing a bit here. Probably best to make a copy of NewSoftSerial, use that, and then comment out stuff until the current consumption drops.
Title: Re: Preserve battery with Sleep ?
Post by: wayneft on Feb 07, 2012, 12:08 am
Thanks Nick.  I had a different response but just found the problem so I deleted it. 

It looks like NSS is using (or not) Timer0 and that is what is consuming all the power.  If you look through the code there's actually a public function to enable Timer0 so if you send this:
Code: [Select]
ThisIsKillingME.enable_timer0(1);
it seems to knock out the 4mA  :) .  I'll have to test further to see if setting back to 0 after wake up causes any problems.
Title: Re: Preserve battery with Sleep ?
Post by: nickgammon on Feb 07, 2012, 01:08 am
I thought sleep mode "power down" stopped timer 0? There are some figures on page 404 of the datasheet that show the consumption of various modules. At 5V Timer 0 apparently consumes around 61 uA. However a side-effect of it running is it cancels sleep mode (because of the interrupt).

I would be starting to wonder if your code stays asleep. Try flashing an LED or something in loop() to see if you exit sleep mode when you don't think you do.
Title: Re: Preserve battery with Sleep ?
Post by: wayneft on Feb 07, 2012, 01:52 am
I did confirm it was staying asleep, I set it up to toggle a pin in a loop and it didn't toggle.  I also need to rescind the observation I made about calling that function.  I was making multiple changes in the sketches before finishing up at work and the last change I made before calling that function was create an instance using pins 0 and 1 instead of 8 and 9 just to see what would happen.  I think that in combination with the function dropped the power.  I'm going to try it again after dinner but if that's the case it may be related to the pin change interrupts.  Which kind of sucks because I wanted to use one to be able to wake up from a low battery alert.
Title: Re: Preserve battery with Sleep ?
Post by: Coding Badly on Feb 07, 2012, 05:03 am

I don't see where you are enabling the internal pullups on unused pins.
Title: Re: Preserve battery with Sleep ?
Post by: nickgammon on Feb 07, 2012, 06:23 am
If pin change interrupts were enabled, which I didn't think the constructor did, then they would probably fire like crazy if there were floating voltages on the pins.
Title: Re: Preserve battery with Sleep ?
Post by: nickgammon on Feb 07, 2012, 06:45 am
Actually I can't reproduce your problem.

Running this exact code:

Code: [Select]
#include <avr/sleep.h>
#include <NewSoftSerial.h>

NewSoftSerial ThisIsKillingME(8,9);


void setup ()
{
  pinMode (9, OUTPUT);
  digitalWrite (9, HIGH);
  delay (1000);
  digitalWrite (9, LOW);
 
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);  //480uA  4.35mA
//  set_sleep_mode (SLEEP_MODE_STANDBY);  //636uA  4.5mA
//  set_sleep_mode (SLEEP_MODE_EXT_STANDBY);  //775uA  4.65mA
//  set_sleep_mode (SLEEP_MODE_PWR_SAVE);  //775uA  4.648mA
//  set_sleep_mode (SLEEP_MODE_ADC);  //967uA  4.84mA
//  set_sleep_mode (SLEEP_MODE_IDLE);  //1.16mA  5.03mA
  sleep_enable();
  // disable ADC
  ADCSRA = 0; 
  // turn off various modules
  PRR = 0xFF;
  // turn off brown-out enable in software
  MCUCR = _BV (BODS) | _BV (BODSE);  // turn on brown-out enable select
  MCUCR = _BV (BODS);        // this must be done within 4 clock cycles of above
  sleep_cpu ();              // sleep within 3 clock cycles of above
}  // end of setup

void loop () { }


I got a reading of 0.42 uA (420 nA). And that was with the NewSoftSerial object there.

(http://gammon.com.au/images/Arduino_forum_76939.jpg)

I added the stuff to flash an LED because I could hardly believe my eyes. But yes, the LED comes on for one second, and then the current drops to that reading.

Oh, wait. Pin 9 is what you are using for NSS. Well anyway there is the proof.

But this is interesting. I commented out the 4 lines that flashed the LED. And now look what happens:

(http://gammon.com.au/images/Arduino_forum_76939b.jpg)

Not only is it now using 4.345 mA (a big jump!) but the LED lights up! Well that's where your power is going.
Title: Re: Preserve battery with Sleep ?
Post by: wayneft on Feb 07, 2012, 02:08 pm
I should have posted this last night but I was too tired.  The problem is the Tx pin on NewSoftSerial because the idle state is HIGH which means the pin is still sourcing current when you put it too sleep.  Simply changing the pinMode to input and disabling the internal pull up resistors seems to fix the issue.  This would probably be a handy function to add to the sleep file, one function to scan all the digital ports, record their states and change them all to high impedance and then another wakeup function to restore the previous states.  Any way... thanks for the help.