sleep_cpu() of <avr/sleep.h> resets program

Hello,
I want to make a power saving watering system with a deep_sleep_mode.
The problem is, that the sleep_cpu() method of the <avr/sleep.h> library somehow resets my whole program each time the watchdogTimer wakes it up.

Thanks in advance for your advice!

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

int led;
int motor;   //TODO! Testing value

long timePointer1;
long n;
bool awake;
bool menuOn;

void setup() {
  wdt_disable();
  
  attachInterrupt(0, interruptFunction, RISING);  //Digital Pin 2 //Not used for testing //always LOW
  pinMode(led,OUTPUT);
  led=13;   //I also tried to assign the values on top of setup() as normal. The program always starts 
                //from the beginning
  motor=12; 
  timePointer1=1;
  n=0;
  awake=0;
  menuOn=0;
  Serial.begin(9600);
  Serial.print("Setup ");
  Serial.println();
  Serial.end();
}

void loop() {
  
  if((digitalRead(2)==HIGH || menuOn==1)&&awake==0){   //Menu  // not turned on for testing
    menuOn=0;
    
    
  }
  if(digitalRead(2)==LOW && awake==1 ){   //Time controlled event
    
    watering();
    
  }

  if(awake==0 && digitalRead(2)==LOW){
    
    longDelayWDT(40);
  }
  
}

void interruptFunction(){   //Not used for testing purpose
  
  //sleep_disable();
  //detachInterrupt(0);   //turns Interrupts off
  
}

ISR(WDT_vect){
  wdt_disable();
  //MCUSR=0; //clear WDT flag (optional)
}

void delayWDT(byte timer){
  sleep_enable();
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  ADCSRA &= ~(1<<ADEN);
  wdt_enable(timer);

  wdt_reset();
  sleep_cpu();                         //Here is the Problem!
  sleep_disable();
  ADCSRA |= (1<<ADEN);
}

void longDelayWDT(long t){
  //t in seconds
  
  //n=(long)(t/8);    //To be added later

  n=3;  //Testing value. To be removed
  
  if(timePointer1>=n-1){
    Serial.begin(9600);
    Serial.print("TimePointer>=n-1 ");
    Serial.println(timePointer1);
    Serial.end();
    
    timePointer1=0;
    awake=1;
  }
  if(timePointer1<n && awake==0){
    

    Serial.begin(9600);
    Serial.print("TimePointer: ");
    Serial.println(timePointer1);
    Serial.end();
    
    timePointer1++; 
    Serial.begin(9600);
    Serial.print("TimePointer: ");
    Serial.println(timePointer1);
    Serial.end();
      
    delayWDT(WDTO_1S);  //Testing Value: TODO Change to 8s
  }
  
}

void watering(){
  long t;
  
  noInterrupts();
  
  digitalWrite(motor,HIGH);
  delay(t*1000);
  digitalWrite(motor,LOW);
  
  interrupts();
  awake=0;
}
noInterrupts();
 
  digitalWrite(motor,HIGH);
  delay(t*1000);
  digitalWrite(motor,LOW);
 
  interrupts();

delay() doesn’t work with interrupts disabled. It needs for the clock to tick, which means that an interrupt needs to happen.

PaulS:
delay() doesn't work with interrupts disabled. It needs for the clock to tick, which means that an interrupt needs to happen.

Thank you for the reply. I changed it in my code.
Do you have any idea, why the program resets itself when i run sleep_cpu()?
It is strange because normally it should just wake up at the same point if you interrupt it.

I changed it in my code.
Do you have any idea, why the program resets itself when i run sleep_cpu()?

So, the code you have now has a problem, but you don't want to share it. Hmmm, I'll have to think about that for a while.

You’re configuring the WDT to act as a reset source rather than an interrupt source. I don’t know that the wdt library provides a wrapper around configuring it for interrupts - I know that construction just turns it on as a reset source.

PaulS:
So, the code you have now has a problem, but you don't want to share it. Hmmm, I'll have to think about that for a while.

I just removed the noInterrupt part of the code which was related to an other problem than the requested one.

  //noInterrupts();
 
  digitalWrite(motor,HIGH);
  delay(t*1000);
  digitalWrite(motor,LOW);
 
  //interrupts();

DrAzzy:
You’re configuring the WDT to act as a reset source rather than an interrupt source. I don’t know that the wdt library provides a wrapper around configuring it for interrupts - I know that construction just turns it on as a reset source.

Thank you DrAzzy! After your reply I researched for the workaround and found out that the WDT is normally set to reset mode. I changed the WDIE and WDE bits in the WDTCSR – Watchdog Timer Control Register of the ATMEGE328P Microcontroller to enable the interrupt mode and disable the reset mode for the Watchdog timer. I changed it in my code and now it is running as I want it to :slight_smile:

Small part of the code, which is relevant to change the register:

void delayWDT(byte timer){
  sleep_enable();
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  ADCSRA &= ~(1<<ADEN);
  wdt_enable(timer);

  WDTCSR = (1 <<WDIE) | (0<<WDE);   //Interrupt Enable, Reset Disable, This is the solution for my problem

  wdt_reset();
  sleep_cpu();
  sleep_disable();
  ADCSRA |= (1<<ADEN);
}

Complete code with some minor debugging changes: (Don’t mind that I always turn on and off the Serial communication. It can eventuelly interfer with the interrupts otherwise.)

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

int led;
int motor;   //TODO! Testing value

long timePointer1;
long n;
bool awake;
bool menuOn;

void setup() {
  wdt_disable();
  
  attachInterrupt(0, interruptFunction, RISING);  //Digital Pin 2
  pinMode(led,OUTPUT);
  led=13;
  motor=12; 
  timePointer1=0;
  n=0;
  awake=0;
  menuOn=1;
  Serial.begin(9600);
  Serial.print("Setup ");
  Serial.println();
  Serial.end();
}

void loop() {
  
  if((digitalRead(2)==HIGH || menuOn==1)&&awake==0){   //Menu
    menuOn=0;
    Serial.begin(9600);
    Serial.println("Menu ");
    Serial.end();
    delay(500);
    
  }
  if(digitalRead(2)==LOW && awake==1 ){   //Time controlled event
    
    watering();
    
  }
  if(digitalRead(2)==LOW){  //Test State
    Serial.begin(9600);
    Serial.println("Power LOW");
    Serial.end();
  }
  if(digitalRead(2)==HIGH){  //Test State
    Serial.begin(9600);
    Serial.println("Power HIGH");
    Serial.end();
    attachInterrupt(0, interruptFunction, RISING);
  }
  if(awake==1){   //Test Blink
    Serial.begin(9600);
    Serial.println("Awake");
    Serial.end();
  }

  if(awake==0 && digitalRead(2)==LOW){
    longDelayWDT(40);
  }
  
}

void interruptFunction(){
  
  sleep_disable();
  detachInterrupt(0);   //turns Interrupts off
  Serial.begin(9600);
    Serial.println("Interrupt");
    Serial.end();
}

ISR(WDT_vect){
  wdt_disable();    //TODO: should it be in the code?
  //MCUSR=0; //clear WDT flag (optional)
}

void delayWDT(byte timer){
  sleep_enable();
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  ADCSRA &= ~(1<<ADEN);
  wdt_enable(timer);
  WDTCSR = (1 <<WDIE) | (0<<WDE);   //Interrupt Enable, Reset Disable

  wdt_reset();
  sleep_cpu();
  sleep_disable();
  ADCSRA |= (1<<ADEN);
}

void longDelayWDT(long t){
  //t in seconds
  
  n=(long)(t/8);    //To be added later

  //n=5;  //Testing value. To be removed
  
  if(timePointer1>=n){
    Serial.begin(9600);
    Serial.println("Restarting queue");
    //Serial.println(timePointer1);
    Serial.end();
    
    timePointer1=0;
    awake=1;
  }
  if(timePointer1<n && awake==0){
    

    Serial.begin(9600);
    Serial.print("TimePointer: ");
    Serial.println(timePointer1);
    Serial.end();
    
    timePointer1++; 
    
    delayWDT(WDTO_8S);  //Testing Value: TODO Change to 8s
  }
  
}

void watering(){
  long t;
  
 
  
  digitalWrite(motor,HIGH);
  delay(t*1000);
  digitalWrite(motor,LOW);

  Serial.begin(9600);
  Serial.print("Watering");
  Serial.println();
  Serial.end();
  awake=0;
}

From my side the topic is now closed and solved. Thank you all for your effort and help! If you have any more questions don’t hestiate to ask.