Go Down

Topic: When sleeping helps (Read 11677 times) previous topic - next topic

tlharv

Is there a threshold where having the microprocessor sleep has a noticible benefit on power consumption?  For example, if you have a delay(1000) statement in your loop() function, would it make sense to put the chip to sleep (or use watchdog timer) during that time?

Assuming there's a benefit to sleeping (one second is an eternity for a microprocessor), I'll need help writing that code into my sketch for the ATtiny85.

Thanks,
Tom

JChristensen

Depends on the sleep-vs.-wake ratio. It doesn't take many instructions to sleep an AVR MCU, so that represents little overhead. If the application truly has many seconds of CPU-bound processing to do, then sleeping for a second wouldn't make much difference. But that's an extreme example.

I heard a rumor that the Arduino-Tiny core might have a version of delay that sleeps the MCU in a future version. @Coding Badly may know something about that, maybe he can comment.

Another option, check out the sleep code in my Million Ohms project.

I've been playing with low-power data loggers that sleep between samples. I added a DS18B20 temperature sensor to one, but it takes the DS18B20 750ms to do a temperature conversion. So as you suggested, I used the WDT. I send the command to the sensor to start the conversion, set the WDT for one second and sleep the MCU, then read the sensor when the WDT wakes it.

Coding Badly

Is there a threshold where having the microprocessor sleep has a noticible benefit on power consumption?


The threshold is "always".  If there is no work to do, Idle sleep mode reduces the power consumption enough to make it worth the effort.  Essentially, the processor takes a short nap at the end of loop.

Quote
For example, if you have a delay(1000) statement in your loop() function, would it make sense to put the chip to sleep (or use watchdog timer) during that time?


Yes.

Quote
Assuming there's a benefit to sleeping (one second is an eternity for a microprocessor), I'll need help writing that code into my sketch for the ATtiny85.


Going to need more details.  And, typically, you will get more and better help if you make an attempt on your own.

Coding Badly

I heard a rumor that the Arduino-Tiny core might have a version of delay that sleeps the MCU in a future version. @Coding Badly may know something about that, maybe he can comment.


I did what?   :D  I've stopped using delay to the point that it will be the very last thing added to version 2.

What I have done is made it possible to put the processor into any sleep mode (i.e. Power Down) without having to fiddle with millis.  I have a timer gadget that's used several times a day, is never turned off, is accurate to ±1% (stable temperature), and has been running from the same batteries for over a year.  It's essentially a blink-without-delay plus a Power Down sleep.  Oh, and it runs on an ATtiny13.  There two downsides: 1. The tuning tool is crude.  Currently it's a hodge-podge of Python, my eyeballs, and my brain.  2. Too much low-level stuff has to be included in the sketch.  (The Night Light should move version 2 along nicely.  My boards arrive Monday!)

Quote
Another option, check out the sleep code in my Million Ohms project.


@tlharv, Jack's work is definately worth investigating!

JChristensen

@CB, thanks for the kind words, I will pay you later. You'd be surprised at the people investigating me :smiley-eek:

westfw

Do we have data on how much power is consumed by an actual Arduino board in Sleep vs running, for various power sources?
I think I've dismissed this as "it doesn't get low enough for long-lived battery operation", but it occurs to me that that is not at all the same as "not significantly lower."

JChristensen


Do we have data on how much power is consumed by an actual Arduino board in Sleep vs running, for various power sources?
I think I've dismissed this as "it doesn't get low enough for long-lived battery operation", but it occurs to me that that is not at all the same as "not significantly lower."


My assumption has been the same. I remember measuring an Uno at 42mA and about 11mA less with the MCU in power-down mode, but I couldn't swear as to the power source.

Seems like the best-case scenario would be to power it via the 5V pin, would you agree? That would minimize losses from the voltage regulator. I could test that scenario without too much trouble. The power LED would still be on, but that could always be removed with a soldering iron.

Coding Badly

Do we have data on how much power is consumed by an actual Arduino board in Sleep vs running, for various power sources?


I can't recall anyone publishing numbers.  Everything I can find and everything I can remember starts with a single number for an Arduino running from external power and goes straight to direct 5V power to skip the hungry regulator.  (And then various combinations of sleep mode and peripheral control are tried.)

Quote
I think I've dismissed this as "it doesn't get low enough for long-lived battery operation"...


I'm in that camp as well.  I just assume the voltage regulator burns so much power as to make sleeping essentially irrelevant.

Quote
...but it occurs to me that that is not at all the same as "not significantly lower."


That is an excellent point.  Half of a bigger number is still half.

tlharv

#8
May 04, 2013, 06:58 am Last Edit: May 04, 2013, 07:11 am by tlharv Reason: 1
First things first: where does one download the avr/sleep.h and avr/power.h libraries?  I see them in others' code but it's not in the general Arduino set of libraries.  If I can get those, then I can start tinkering and post code with more specific questions.

*update*
I went ahead and included it in my sketch, and it worked.  So it's already part of my Arduino load.  (whew).

Commencing tinkering...

dc42


Do we have data on how much power is consumed by an actual Arduino board in Sleep vs running, for various power sources?
I think I've dismissed this as "it doesn't get low enough for long-lived battery operation", but it occurs to me that that is not at all the same as "not significantly lower."


The main problem with battery operation of an actual Arduino Uno, Mega etc. is that the USB-to-serial converter chip is still drawing power when the main mcu is sleeping. Barebones designs without a USB-to-serial converter are a different matter entirely. If your design needs a voltage regulator, you can get micropower regulators such as MCP1702.
Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

westfw

Quote
avr/sleep.h and avr/power.h libraries [are] not in the general Arduino set of libraries.

They're part of avr-libc, which is "underneath" the arduino libraries, and included with the Arduino distribution.

tlharv

#11
May 04, 2013, 10:37 am Last Edit: May 04, 2013, 10:40 am by tlharv Reason: 1
Ok, after much reading tonight about sleeping, timers and interrupts, I'm ready to ask for more guidance as I attempt to put it all together.  For starters, I'm trying to improve upon an existing sketch that samples a One-Wire temperature sensor, then flashes an RGB LED either red, blue or green according to the temperature read.  It does this once per second, so the improvement is to have the chip sleeping during its one-second break thereby improving upon battery life.  It's a simple blinky application, but if I understand this I can apply it to other projects I have going.

Would a correct approach be:
1. In setup(), initiate a timer and define a one-second ISR requirement, then put the chip to sleep
2. In loop(), do nothing
3. The ISR wakes the chip, samples the temperature, and calls a nifty LED glow routine based on temperature read, the returns chip to sleep.
4. Do nothing in the sleepHandler()

I'm still stitching together sketches from sleeping, timers and interrupt examples, so I don't have anything working yet.  It's kind of a FrankenSketch at the moment.

Thanks,
Tom

Sources read:
http://n0m1.com/2011/12/15/catching-some-zzzs-part-1-interrupted-sleep/
http://www.engblaze.com/we-interrupt-this-program-to-bring-you-a-tutorial-on-arduino-interrupts/
http://www.engblaze.com/microcontroller-tutorial-avr-and-arduino-timer-interrupts/

afremont

#12
May 04, 2013, 04:48 pm Last Edit: May 04, 2013, 04:55 pm by afremont Reason: 1
An Uno R3 with the CPU removed uses almost 42mA when powered by 12V on Vin.  With the RESET button held down, it uses almost 43mA.  The power LED and the LED connected to pin 13 are illuminated.

With the CPU installed, reset mode is 50mA and running at 16MHz it's burning 58mA.
Experience, it's what you get when you were expecting something else.

Coding Badly

Would a correct approach be:
1. In setup(), initiate a timer and define a one-second ISR requirement, then put the chip to sleep
2. In loop(), do nothing
3. The ISR wakes the chip, samples the temperature, and calls a nifty LED glow routine based on temperature read, the returns chip to sleep.
4. Do nothing in the sleepHandler()


There are at least two serious problems with putting the working code in the interrupt service routine.  Don't do it.  Madness lies down that path.  In my experience, empty interrupt service routines are a much better choice.

Build your application without sleeping and without interrupts.  When you are satisfied the application works the way you want, at the bottom of loop add code to wake the processor under the desired conditions then put the processor to sleep.  At the top of loop, disable wake conditions that will interfere with the work.

Quote
1. In setup(), initiate a timer and define a one-second ISR requirement, then put the chip to sleep


Watchdog timer.  That allows you to use Power Down sleep mode.

tlharv

Thanks, all, for the comments.  It runs!  The trick was structuring it as Coding Badly recommended.  Here's how it looks... I do have some questions about some of the statements in here, which I copied verbatim from the examples I read.  Perhaps I ought to move those questions to the programming room instead.  But for now, I seem to have my answer for getting the Uno to sleep for my project.  Next step will be interpreting it for the ATtiny85.  Any recommendations for making this less cluttered, feel free to provide.

Thanks,
Tom


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

// pin assignments are for Arduino Uno
const int redPin = 3;     // red lead of an RGB LED, common cathode
const int greenPin = 5;  // green lead of the RGB LED
const int bluePin = 6;   // blue lead of the RGB LED

const int LL = 63; // Lower Limit of acceptable temperature range; below this the light is blue
const int UL = 73; // Upper Limit of acceptable temperature range; above this the light is red

OneWire  ds(10);  // center lead of the Dallas one-wire temp sensor, plugged in to digital pin 10.


void setup(void) {
  pinMode(bluePin, OUTPUT);
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  wdtSetup();  // this sets up the watchdog timer
}

void loop(void) {
  byte i;
  byte present = 0;
  byte data[12];
  byte addr[8];
  int Temp;

  digitalWrite(13, HIGH);  // indicate that the chip is awake
  // Disable wake conditions that interfere with the main body of work
  // cli();

// GET THE TEMPERATURE FROM THE DALLAS ONE-WIRE TEMP SENSOR
  if ( !ds.search(addr)) {
      ds.reset_search();
      return;
  }

  ds.reset();
  ds.select(addr);
  ds.write(0x44,1); // start conversion, with parasite power on at the end
 
  delay(2000);     // Unsure what this does but it was included in the one-wire tutorial
 
  present = ds.reset();
  ds.select(addr);   
  ds.write(0xBE);         // Read Scratchpad
  for ( i = 0; i < 9; i++) // we need 9 bytes
  {           
    data[i] = ds.read();
  }
 
  //take the two bytes from the response relating to temperature
  Temp=(data[1]<<8)+data[0];
  Temp=Temp>>4; //divide by 16 to get pure Celsius readout
  Temp=Temp*1.8+32; // comment this line out to get Celsius 
 
// NOW LIGHT THE LED BASED ON THE TEMPERATURE READ

  if (Temp < LL) // then light the blue LED - it's cold!
  {
    analogWrite(greenPin, 0);
    analogWrite(redPin, 0);
    GlowLightOnce(bluePin);
  }
  else if (Temp >= LL && Temp <= UL) // then light the green LED
  {
    analogWrite(bluePin, 0);
    analogWrite(redPin, 0);
    GlowLightOnce(greenPin);
  }
  else // light the red LED
  {
    analogWrite(bluePin, 0);
    analogWrite(greenPin, 0);
    GlowLightOnce(redPin);
  }
 
  // DEFINE SLEEP MODE
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);  // choose your preferred sleep mode for the chip
  sleep_enable(); // this puts the chip into, sleep mode, but doesn't command it to sleep yet.
  // Define conditions by which chip should awake (watchdog timer for 1 second)

  // Go to sleep...
  digitalWrite(13, LOW); // turn LED off to indicate sleep
  sleep_mode();  // Last statement of loop() - this command actually puts the chip to sleep.
}

// Watchdog Timer Interrupt
ISR (WDT_vect) {
  // put whatever you want to have happen at regular WDT intervals in here.
}


void GlowLightOnce(int bulb)  // subroutine applies one fade in - fade out blink of an LED
{
  int brightness = 0;
  int fadeAmount = 5;
  int totalcount = 0;
    do
    {
      analogWrite(bulb, brightness);
      brightness = brightness + fadeAmount;
      totalcount++;
      if (brightness == 255)
      {
        fadeAmount = -fadeAmount;
      }
      delay(35);
    } while (totalcount < 103);
    delay(1000);  // pause for a second while the bulb is dark
}

void wdtSetup() // Set up watchdog timer
{
  cli(); // disable all interrupts
  MCUSR = 0;  // mystery statement, but is required
  // WDTCSR register gives you access to the Arduino WDT.
  // Bit 4 = Watchdog Change Enable.  Must be cleared to change or clear the WDE bit.
  // Bit 3 = WDT bit.  Must be cleared to set WDP3 through WDP0.
  WDTCSR |= B00011000; // clear WDTCSR register bits 3 & 4
  WDTCSR = B01000111;  // Set the WDP3 through WDP0 bits, to set the WDT prescale to two seconds.
  sei(); // enables all interrupts
}

void sleepHandler(void) {
}

Go Up