Mega2560 low power state / watchdog

Hi,

We have a project where we want to measure something for a few minutes per day and save as much power as possible. I'm trying to get the 'nightingale' code to work on my Mega2560 and I think it's supposed to execute the main code, then sleep for 7 seconds, then execute the main code, then sleep, etc. It isn't sleeping and some of the output on the console is gibberish. I'm using the default bootloader and I think that now supports the watchdog out of the box, but I've there are a lot of older forum posts and I'm not really sure. I'm very new to Arduino programming, and only kind of know what I'm doing. Here is the code and output.

Thanks!

//****************************************************************
/*
 * Watchdog Sleep Example 
 * Demonstrate the Watchdog and Sleep Functions
 * Photoresistor on analog0 Piezo Speaker on pin 10
 * 
 
 * KHM 2008 / Lab3/  Martin Nawrath nawrath@khm.de
 * Kunsthochschule fuer Medien Koeln
 * Academy of Media Arts Cologne
 
 */
//****************************************************************

#include <avr/sleep.h>
#include <avr/wdt.h>
#include <Time.h> 

#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

int nint;

volatile boolean f_wdt=1;

void setup(){

  Serial.begin(9600);
  setTime(16, 00, 0, 14, 2, 2012);
  Serial.println("nightingale");
  pinMode(13, OUTPUT); 



  // CPU Sleep Modes 
  // SM2 SM1 SM0 Sleep Mode
  // 0    0  0 Idle
  // 0    0  1 ADC Noise Reduction
  // 0    1  0 Power-down
  // 0    1  1 Power-save
  // 1    0  0 Reserved
  // 1    0  1 Reserved
  // 1    1  0 Standby(1)

  cbi( SMCR,SE );      // sleep enable, power down mode
  cbi( SMCR,SM0 );     // power down mode
  sbi( SMCR,SM1 );     // power down mode
  cbi( SMCR,SM2 );     // power down mode

  setup_watchdog(7);
}

byte del;
int cnt;
byte state=0;
int light=0;


//****************************************************************
//****************************************************************
//****************************************************************
void loop(){


  if (f_wdt==1) {  // wait for timed out watchdog / flag is set when a watchdog timeout occurs
    f_wdt=0;       // reset flag

    digitalWrite(13, HIGH);   // set the LED on
    delay(2);              // wait for a second
    digitalWrite(13, LOW);    // set the LED off
    nint++;

    Serial.print("Sleep " );
    Serial.println(nint);
    digitalClockDisplay();

    system_sleep();
  }

}

//****************************************************************  
// set system into the sleep state 
// system wakes up when wtchdog is timed out
void system_sleep() {

  cbi(ADCSRA,ADEN);                    // switch Analog to Digitalconverter OFF

  set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
  sleep_enable();

  sleep_mode();                        // System sleeps here

  sleep_disable();                     // System continues execution here when watchdog timed out 
  sbi(ADCSRA,ADEN);                    // switch Analog to Digitalconverter ON

}

//****************************************************************
// 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms
// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec
void setup_watchdog(int ii) {

  byte bb;
  int ww;
  if (ii > 9 ) ii=9;
  bb=ii & 7;
  if (ii > 7) bb|= (1<<5);
  bb|= (1<<WDCE);
  ww=bb;
  // Serial.println(ww);


  MCUSR &= ~(1<<WDRF);
  // start timed sequence
  WDTCSR |= (1<<WDCE) | (1<<WDE);
  // set new watchdog timeout value
  WDTCSR = bb;
  WDTCSR |= _BV(WDIE);


}
//****************************************************************  
// Watchdog Interrupt Service / is executed when  watchdog timed out
ISR(WDT_vect) {
  f_wdt=1;  // set global flag
}

void digitalClockDisplay() {
  // digital clock display of the time
  
    Serial.print(day() );
    Serial.print("/");
    Serial.print(month() );
    Serial.print("/");
    Serial.print(year() );
    Serial.print(" ");
    Serial.print(hour() );
    printDigits(minute() );
    printDigits(second() );
    Serial.print(" ");
  }

void printDigits(int digits) {
  // utility function for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

Here is the output:

14/2/2012 16:0

Hi,

The output was longer, but since there are weird characters in it, it won't post. It prints a line with the date and the hour, then about 10 chars of weird characters, then a number. The first line, the number is 284, then next line it is 285, etc...

thanks,

Eli

Eli...

I'm making a wild guess here, but if I had this problem I'd try changing

Serial.print('0');

to

Serial.print("0");

and see if that helped.

Hi,

Thank you for replying. I don't think that will fix the problem with the sleep function. The code that prints the date and time works fine, if I comment out the sleep function, so I think the reason it is printing gibberish is because the sleep function is doing something to memory that corrupts the output to the console as well as not putting the controller to sleep. Just to be sure that it did not change anything, I tried changing it to "0" and there wasn't any difference.

Thanks,
Eli

Hmm - then I think your analysis is likely correct. :frowning: I was hoping to be helpful, but have no experience with any of the power-saving modes yet. My apologies for making extra work for you.

 byte bb;

int ww;
  if (ii > 9 ) ii=9;
  bb=ii & 7;
  if (ii > 7) bb|= (1<<5);
  bb|= (1<<WDCE);
  ww=bb;
  // Serial.println(ww);

You could consider using meaningful variable names, and not just jab at the keyboard. A few comments wouldn't hurt either.

I did some posts about power saving here:

I think the reason it is printing gibberish is because the sleep function is doing something to memory that corrupts the output to the console as well as not putting the controller to sleep.

It's more likely the sleep function is putting it to sleep for a while, which shuts down things like the USART. As they wake up (it takes quite a few clock cycles for that to happen) it may place garbage on the serial port. It wouldn't surprise me too much. You could do something like disable the serial port, force it to high with a pull-up, sleep, then turn off the pull-up and re-enable the serial port. That should put more defined data on it.

In power down mode, IO clock to peripherals is being stopped. When awake, it takes few cycle to stabilize like what Nick said.

Hi Nick,

Thanks for the reference. I'll look into it.

You could consider using meaningful variable names, and not just jab at the keyboard. A few comments wouldn't hurt either.

Well, that code didn't come from me. It came from here: http://interface.khm.de/index.php/lab/experiments/sleep_watchdog_battery/

I was just trying to get it to work as it was the only example of power savings code I could find on the internet. I modified it as little as I could to run it without the speaker. I should have included that website reference in my original post, but for some reason, I thought people would be familiar with it.

I'll look into your write up, Nick.

Thanks,
Eli

elimorris:
Well, that code didn't come from me. It came from here: ...

Oh, sorry. Just shows how code can propagate. :slight_smile: