When sleeping helps

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

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.

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

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.

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.

[quote author=Jack Christensen link=topic=164146.msg1225718#msg1225718 date=1367514109]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.[/quote]

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!)

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

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

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

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

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

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.

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

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.

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

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

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

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.

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.

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/

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.

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

  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.

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

#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) {
}

tlharv: Any recommendations for making this less cluttered, feel free to provide.

There are no references to sleepHandler. You could remove it.

  delay(2000);     // Unsure what this does but it was included in the one-wire tutorial

I believe that's to allow time for the conversion. I also believe it's only necessary for parasitic power. How are you powering the 1-Wire device?

In either case, it should be replaced with a blink-without-delay pattern; a while-loop polling for 2 seconds to elapse. In the while-loop body put the processor to sleep (Idle mode).

750mS is the recommended minimum conversion time allowance, regardless of power mode. That's for a 12-bit conversion. The OP could cut that long delay in half at least. 12 bits is the default for a new part, but I believe it can be overridden by a flashable programming setting.

afremont:
750mS is the recommended minimum conversion time allowance, regardless of power mode.

I believe, when the device is fully powered, some devices can be polled for completion. I recall the temperature sensor I was using took considerably less than 750ms.

[quote author=Coding Badly link=topic=164146.msg1229076#msg1229076 date=1367744620]

afremont: 750mS is the recommended minimum conversion time allowance, regardless of power mode.

I believe, when the device is fully powered, some devices can be polled for completion. I recall the temperature sensor I was using took considerably less than 750ms.

[/quote]

That's absolutely correct, but I've never actually timed any to see how long they take. Do you recall how much less it was? I'm a big fan of the 1-wire stuff, have been for many years. I've also found that many times you can get away with doing a conversion using parasite power mode, but not supplying the so-called "strong pullup" on the bus. Only one device at a time though. Which reminds me of one other piece of probably useless trivia. You can do a SKIP ROM and then start a conversion on all the devices on the bus simultaneously. Conversions using less bits of precision take substantially less time to complete according to the datasheet.

EDIT: I've had good success using a PIC I/O pin to power the 1-wire bus when awake and then powering it down when sleeping, but I wrote it in assembler so it was relatively easy to insert the control code. Now that I've thought about it as long as it took me to type this, it probably wouldn't be that hard to wrap the library code with something to accomplish the same thing. Possibly just powering up after sleep and down just before, but you probably have to wait up to 60uS for the RESET pulse from the temp sensors after releasing the bus from reset mode. I don't know if you have to hold the bus in reset mode for an extra 480uS before releasing it after applying power. Experimentation would be in order on that.