Unstable deep sleep wake up

Hi everyone !

I’m Alex, and first time posting on arduino wish I do well :slight_smile:

I’m actually building an atmega328P as a timer to close a transistor gate to power a sensor.

The target is to wake up few seconds (measure + send data via 2.4 GHz arduino module ) each 6 hours (around ) and then go back to sleep.

So Here is the set up I’ve made :

I’ve tried those 2 codes but ended with the same problem :

Code 1 :
Reference : Low Power Arduino! Deep Sleep Tutorial - YouTube

/*
Clock to send data
*/
int porte = 13;

void setup() {
  
  pinMode(porte, OUTPUT);
  for(int i=0; i<20 ;i++){
    pinMode(i,OUTPUT);
  }
  
// WATCHDOG TIMER
WDTCSR = (24);
WDTCSR = (33); // 6 = 1 sec , unit for counting  , 33 for 8 sec conting cf WDTCSR dans atmega328P datasheet 
WDTCSR |= (1<<6);


//DISABLE ADC
ADCSRA &= ~(1<<7);

//ENABLE SLEEP
SMCR |= (1<<2);
SMCR |= 1;

}

// ******************** CONTROLE DE L'HORLOGE ******************************
void loop() {
  
  digitalWrite(porte, HIGH);   // High to the door
  delay(10e3);             // Laisse la pin 13 allumé pendant x ms
  digitalWrite(porte, 0);    // Low to the pin 13 door


for(int i=0; i<2700;i++){  // Unité choisie fois le nombre d'itération de i; exemple WDTCSR = 6 => 1 sec et si i <5 => 5 sec || Si WDTCSR = 33 = 8 sec et i < 2 => 2x8 = 16 sec , ici 60*1 = 60 sec
//BOD DISABLE
MCUCR |= (3<<5);
MCUCR = (MCUCR & ~(1 <<5)) | (1 << 6);
__asm__  __volatile__("sleep");
}
}

ISR(WDT_vect){
  //DON'T FORGET THIS!  Needed for the watch dog timer.  This is called after a watch dog timer timeout - this is the interrupt function called after waking up
}// watchdog interrupt

Code 2 :

Reference : Forum : https://www.gammon.com.au/power

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

const byte LED = 13;

void flash ()
  {
  pinMode (LED, OUTPUT);
//  for (byte i = 0; i < 10; i++)
//    {
    digitalWrite (LED, HIGH);
    delay (8000);
    digitalWrite (LED, LOW);
    delay (50);
//   }
    
  //pinMode (LED, INPUT);
    
  }  // end of flash
  
// watchdog interrupt
ISR (WDT_vect) 
{
   wdt_disable();  // disable watchdog
}  // end of WDT_vect
 
void setup () { }

void loop () 
{
 
  flash ();

  for (int j = 0; j < 1800; j++){
  // disable ADC
  ADCSRA = 0;  

  // clear various "reset" flags
  MCUSR = 0;     
  // allow changes, disable reset
  WDTCSR = bit (WDCE) | bit (WDE);
  // set interrupt mode and an interval 
  WDTCSR = bit (WDIE) | bit (WDP3) | bit (WDP0);    // set WDIE, and 8 seconds delay
    wdt_reset();  // pat the dog
  
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
  noInterrupts ();           // timed sequence follows
  sleep_enable();
 
  // turn off brown-out enable in software
  MCUCR = bit (BODS) | bit (BODSE);
  MCUCR = bit (BODS); 
  interrupts ();             // guarantees next instruction executed
  sleep_cpu ();  
  
  // cancel sleep as a precaution
  sleep_disable();
  }
  } // end of loop

The problem is: once in a while the atmega 328p stays on, and then drags the batteries.

I tried several times to figure out but couldn’t find out from where the problem comes.

I’ve tried

  • Put capacitor in parallel of the transistor to absorb the shoot of amperage of sending the data : didn’t change

What I’ll try :

  • Put capacitor in parallel of the batteries
  • Separate the power source from the Atmega328P and the one for the sensor + arduino stuffs

Have you ever had to face that ? Or any track I should try ?

Also if you know any chip or solution able to wake up few seconds and sleep for 4 hours or more I’m more than ok to listen to it. :slight_smile:

I really thank you for your help and wish it would help all other people trying to save consumption on their project.

Alex

Your code has some flaws: 1) You never reset the watchdog with "wdt_reset()" and 2) You never disable either sleep or watchdog when waking up. You should study the code from Gammon a bit closer :-)

Another thing: Most alkaline batteries deliver >= 1.5V per cell. 4 cells deliver >= 6V and the MCU has an upper limit of 5.5V per spec sheet. You may damage the chip in your setup.

Hi Danois90 !

Thank you !

1) You never reset the watchdog with "wdt_reset()"

I don't realy catch it. It seemed to me that "wdt_reset()" was known So what you say is that I have to write a new fonction as wdt_reset() { xxxxx } ? Because what I understand is that the wdt_reset is used here isn't it ?

 // clear various "reset" flags
  MCUSR = 0;     
  // allow changes, disable reset
  WDTCSR = bit (WDCE) | bit (WDE);
  // set interrupt mode and an interval
  WDTCSR = bit (WDIE) | bit (WDP3) | bit (WDP0);    // set WDIE, and 8 seconds delay
    wdt_reset();  // pat the dog

This function seems used as " sleep_cpu (); " or "sleep_disable ()" then I don't catch it I'm sorry, too rookie maybe.... :(

2) You never disable either sleep or watchdog when waking up. You should study the code from Gammon a bit closer :-)

Ok, I'll check this out, so when waking up , I have to add this part IN the loop if I understand what you say, isn't it ? :

// watchdog interrupt
ISR (WDT_vect) 
{
   wdt_disable();  // disable watchdog
}  // end of WDT_vect

Another thing: Most alkaline batteries deliver >= 1.5V per cell. 4 cells deliver >= 6V and the MCU has an upper limit of 5.5V per spec sheet. You may damage the chip in your setup.

Thank you very much,you're right, I'll add a diode or a resistor to drop few volts and preserve the MCU.

"wdt_reset()" is a library function, you do not need to create it your self. The watchdog is a counter/timer and by calling "wdt_reset()" you set that counter to 0. If you do not reset the counter, you will get weird behaviour and erratic sleep cycles.

Gammon's code calls "wdt_reset()" as it should be done and as said, you should study the code (and info) from Gammon's site a bit closer. Just blindly copying parts of a code and expecting it to work is a bad idea.

Instead of adding components, you should remove one battery to lower the voltage to ~4.5V.

So you are saying the second code, which looks like a straight port of the Nick Gammon well proven code ‘sometimes’ keeps flashing the LED, when presumably the intention is for it to flash once and then go off for (8 x 1800) seconds ?

Odd, that code looks OK, although the first one has errors as mentioned.

An alternative to the watchdog approach which can cut sleep current from maybe an average of 10uA or more to less than 1uA is to use a PCF8563 RTC. An 8pin IC, watch crystal and a capacitor is all you need. use the alarm function to wake the Arduino up from deep sleep.

You do need to sort out the power supply, 4 fresh AA Alkalines would give you around 6.2V which exceeds tha maximum voltage of a lot of 5V devices.

With 3 Alkalines then 50% through the life of the batteries you will have a supply of 3.6v or maybe less, which is OK if your using a 8Mhz ATMega328 and all the sensors are happy with the lower voltage.

Danois90: "wdt_reset()" is a library function, you do not need to create it your self. The watchdog is a counter/timer and by calling "wdt_reset()" you set that counter to 0. If you do not reset the counter, you will get weird behaviour and erratic sleep cycles.

Gammon's code calls "wdt_reset()" as it should be done and as said, you should study the code (and info) from Gammon's site a bit closer. Just blindly copying parts of a code and expecting it to work is a bad idea.

Instead of adding components, you should remove one battery to lower the voltage to ~4.5V.

You're right , I'll check deeper the Gammon's code. step by step.

About the input Voltage, it's a good trick , I'll try and see if the arduino + 2.4 GHz can follow at 4.5V, but might be ok.

Thanks !

srnet: So you are saying the second code, which looks like a straight port of the Nick Gammon well proven code 'sometimes' keeps flashing the LED, when presumably the intention is for it to flash once and then go off for (8 x 1800) seconds ?

Exactly, which seemed weird to me too, reading the clear strictness of the guy.

I usually keep the arduino the "easy" way not playing with the bits of the MCU, this is why I'm re-learing electronic now and have troubles to get everything.

( I've followed the Kevin Darra's tutorial, and couldn't neither understand where the problem could come from.)

Odd, that code looks OK, although the first one has errors as mentioned.

What do you mean ? the "not reseting" the Watchdog timer ?

use a PCF8563 RTC. An 8pin IC, watch crystal and a capacitor is all you need. use the alarm function to wake the Arduino up from deep sleep.

Ok, this seems very interesting, the PCF8563 RTC is able to communicate the time to the arduino. (read and write) The thing is that is it possible to use it then as an alarm by itself ? Or I might not understand what you mean by using it to wake up the Arduino from deep sleep ? Using it at an external output you mean ?

With 3 Alkalines then 50% through the life of the batteries you will have a supply of 3.6v or maybe less, which is OK if your using a 8Mhz ATMega328 and all the sensors are happy with the lower voltage.

All right, as said to Danois90 , I was pretty afraid of the power of the 2.4 GHz but finally you're right, I'm a bit dumb keeping 5V+ and have to drop it down after if 4.5V (~3.6 V) could work very well.

Thank you very much, so I'll keep this is mind, try it and be back to you for the hardware.

For the soft, I have to dig and learn ! If you have any other advice feel free !

Alexpop: Ok, this seems very interesting, the PCF8563 RTC is able to communicate the time to the arduino. (read and write) The thing is that is it possible to use it then as an alarm by itself ? Or I might not understand what you mean by using it to wake up the Arduino from deep sleep ? Using it at an external output you mean ?

PCF8563 is an I2C device, it has an Alarm output. No need to program it with the real time, just clear it down and set the Alarm for +4hours say.

When the Alarm goes, from seconds to a month, you can use the Alarm output as an interrupt to wake the Arduino from deep sleep. You can buy modules with all the parts on for about £1.20 delivered, or the seperate parts for around the same.

Danois90: Your code has some flaws: 1) You never reset the watchdog with "wdt_reset()"

2) You never disable either sleep or watchdog when waking up. You should study the code from Gammon a bit closer :-)

So you mean that

wdt_reset();

and

sleep_disable();

should be outside of the "for j" loop (even directly in the flash() function) to avoid the unstability for instance ?

I'll try it, and check if I've well understood how to manage the watchdog timer.

The thing is that it seemed a random error, is there a way to be sure it doesn't work ? so that I'll know how to also know when it works.

Thanks again so much.

srnet: PCF8563 is an I2C device, it has an Alarm output. No need to program it with the real time, just clear it down and set the Alarm for +4hours say.

When the Alarm goes, from seconds to a month, you can use the Alarm output as an interrupt to wake the Arduino from deep sleep. You can buy modules with all the parts on for about £1.20 delivered, or the seperate parts for around the same.

All right, so it would be an external interrupt for the nano you mean ? or the atmega328 P ?

Use pins 2 or 3 on the Nano or bare bones Atmega328p as the external wakeup interrupt.

You can use other pins for the wakeup interrupt, but that can cause problems with some liberaries, so its easier if pin 2 or 3 are free.

Okay, I see, yes it’s also a good way to go.

I will definitely use it once I would have understood what’s wrong with the actual code.

As Danois90 said, I’ve well put the watchdog and sleep disable in my loop but still facing the same “stay awake” phenomenon.

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

const byte LED = 13;

void flash ()
  {
  pinMode (LED, OUTPUT);
//  for (byte i = 0; i < 10; i++)
//    {
    digitalWrite (LED, HIGH);
    delay (1000);
    digitalWrite (LED, LOW);
    delay (1000);
//   }
    
  //pinMode (LED, INPUT);
    
  }  // end of flash
  
// watchdog interrupt
ISR (WDT_vect) 
{
   wdt_disable();  // disable watchdog
}  // end of WDT_vect
 
void setup () { }

void loop () 
{
 
  flash ();
  
  wdt_disable();
  sleep_disable();

  
  // disable ADC
  ADCSRA = 0;  

  // clear various "reset" flags
  MCUSR = 0;     
  // allow changes, disable reset
  WDTCSR = bit (WDCE) | bit (WDE);
  // set interrupt mode and an interval 
  WDTCSR = bit (WDIE) | bit (WDP2) | bit (WDP1);    // set WDIE, and 8 seconds delay
    wdt_reset();  // pat the dog
  
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
  noInterrupts ();           // timed sequence follows
  sleep_enable();
 
  // turn off brown-out enable in software
  MCUCR = bit (BODS) | bit (BODSE);
  MCUCR = bit (BODS); 
  interrupts ();             // guarantees next instruction executed
  sleep_cpu ();  
  delay(10000);
  // cancel sleep as a precaution
  sleep_disable();
  
  } // end of loop

I’ll keep reading, learning and digging in the meanders of the bits. :slight_smile: