WDT and sleep coexistance problems

Hello,
I tried to find the solution to this problem but I haven't made any progress. So, if someone could give me a hand that would be great. Here, for energy-saving purposes (device on batteries) I have to put my assembly in deep_sleep. The wake-up is done with an RTC alert. Everything works great. The problem is that when the Arduino is working, I would like to use the watchdog in case there is a blockage somewhere. So, the watchdog also works very well when I don't use the deep_sleep function. I specify that I don't use the watchdog during deep_sleep (so I disable it) but just after waking up (the sleep function is disabled then). When the watchdog is triggered, it often (but not always) hangs the Arduino... I made this little program that shows it. I work with the MEGA 2560 pro. The RTC is connected via an I2C multiplexer.

#include <RTClib.h>
#include <Wire.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/wdt.h>
#include <avr/power.h>

RTC_DS3231 rtc;

// the pin that is connected to SQW
#define CLOCK_INTERRUPT_PIN 2

void setup() {
  wdt_disable();
  sleep_disable();
  delay(100);
  Serial.begin(38400);
  Serial1.begin(38400);
  Serial2.begin(9600);
  Serial3.begin(9600);
  pinMode(13, OUTPUT);// led "L"
  digitalWrite(13, LOW);
  digitalWrite(31, HIGH);//Resert i2c
  pinMode(31, OUTPUT);
  Wire.begin();
  //I21C multiplexer to RTC
  Wire.beginTransmission(0x70);
  Wire.write(1 << 0);  // send byte to selected bus
  Wire.endTransmission();
  delay(100);
  // initializing the rtc
  if(!rtc.begin()) {
    Serial.println("Couldn't find RTC!");
    Serial.flush();
    while (1) delay(10);
  }
  Serial.println("RTC OK");
  rtc.disable32K();
  rtc.clearAlarm(1);
  rtc.clearAlarm(2);
  rtc.writeSqwPinMode(DS3231_OFF);
  rtc.disableAlarm(2);
  pinMode(CLOCK_INTERRUPT_PIN, INPUT_PULLUP);
  wdt_reset();
}

void loop() {
  if(SetNextWakeup()){   
    delay(100);
    wdt_disable();
    deepSleep();
    // after wakeup
    WakeUp();
  }
  else {
    Wire.beginTransmission(0x70);
    Wire.write(1 << 0);  // send byte to selected bus
    Wire.endTransmission();
    delay(1000);
  }
  wdt_reset();
}

void onAlarm() {
  attachInterrupt(digitalPinToInterrupt(CLOCK_INTERRUPT_PIN), onAlarm, FALLING);
  detachInterrupt(CLOCK_INTERRUPT_PIN);
  Serial.begin(38400);
  Serial1.begin(38400);
  Serial2.begin(9600);
  Serial3.begin(9600);
  delay(1000);
  Serial.println("Alarm occured!");
}

bool SetNextWakeup() {
  DateTime now = rtc.now();
  rtc.clearAlarm(1);
  Serial.println("Alarm cleared");
  if(!rtc.setAlarm1(now.unixtime() + 10,DS3231_A1_Date)) {
    Serial.println("Error, alarm wasn't set!");
    return false;
  }
  else {
    Serial.println("Next Alarm will happen in 10 sec!");
    attachInterrupt(digitalPinToInterrupt(CLOCK_INTERRUPT_PIN), onAlarm, LOW);
    return true;
  }
}

void deepSleep(){
  char date[] = {"DD-MM-YYYY hh:mm:ss"};
  rtc.now().toString(date);
  Serial.println(date);

  // the stored alarm value
  DateTime alarm1 = rtc.getAlarm1();
  Ds3231Alarm1Mode alarm1mode = rtc.getAlarm1Mode();
  char alarm1Date[] = {"DD hh:mm:ss"};
  alarm1.toString(alarm1Date);
  Serial.print("Alarm1: ");
  Serial.println(alarm1Date);
    
  Serial.println("setting Arduino's params for the sleep mode");
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();
  delay(100);

  Serial.println("next line will put Arduino in sleep mode");
  digitalWrite(13, LOW);//LED "L"
  Serial.end();
  Serial1.end();
  Serial2.end();
  Serial3.end();
  delay(100);
  sleep_mode();
}

void WakeUp(){ 
  sleep_disable();
  detachInterrupt(CLOCK_INTERRUPT_PIN);
  delay(100);
  //power_all_enable();
  wdt_reset(); 
  MCUSR &= ~(1<<WDRF);
  wdt_enable(WDTO_4S);
  digitalWrite(31, LOW);//Reset multiplexer i2c
  delay(500);
  digitalWrite(31, HIGH);//Enadle multiplexer i2c
  Wire.beginTransmission(0x70);
  Wire.write(1 << 0);  // send byte to selected bus
  Wire.endTransmission();
  delay(100);
  digitalWrite(13, HIGH);//LED "L"
  Serial.println("Wake Up");
  Serial.println("sleep disabled for 5s");
  delay(5000);
}

Serial output:

"RTC OK

Alarm cleared

Next Alarm will happen in 10 sec!

11-04-2025 14:53:14

Alarm1: 11 14:53:24

setting Arduino's params for the sleep mode

next line will put Arduino in sleep mode

Alarm occured!

Wake Up

sleep disabled for 5s" And the Arduino hangs not restarting....

Any suggestions?

sets the timeout to 4 seconds

then you do

I woud replace the blocking delay with a non-blocking waiting to narrow down where the arduino really hangs

why do you attach and imidiately detach the interrupt-pin??

I guess it is a bad idea to do much more than setting a flag inside an interrupt-service routine

Here is a demo-code that combines IO-pin wakeup with wdt

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

const int wakePin = 2;          // Pin for RTC interrupt (e.g., INT0)
const int statusLed = 13;       // Status LED pin

volatile bool sleepFlag = true; // Controls sleep state

void setup() {
  pinMode(statusLed, OUTPUT);
  pinMode(wakePin, INPUT_PULLUP);
  
  // Configure interrupt for wakeup signal (FALLING/RISING depending on RTC signal)
  attachInterrupt(digitalPinToInterrupt(wakePin), wakeISR, FALLING);

  Serial.begin(9600);
  Serial.println("System starting");
}

// Interrupt Service Routine for RTC wakeup
void wakeISR() {
  sleepFlag = false; // Exit sleep mode
}

void enterSleep() {
  Serial.println("Entering sleep mode");
  delay(50); // Short delay to ensure Serial output completes

  // Disable watchdog before sleeping
  wdt_disable();

  // Configure sleep mode
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  power_all_disable();
  sleep_enable();
  
  // Activate sleep mode
  sleep_cpu();

  // Code continues here after wakeup
  sleep_disable();
  power_all_enable();
}

void loop() {
  if(!sleepFlag) {
    // ENABLE WATCHDOG FOR ACTIVE STATE
    wdt_enable(WDTO_4S); // 4-second timeout for safety reset
    
    // --- NORMAL OPERATION ---
    digitalWrite(statusLed, HIGH);
    Serial.println("Active state - Starting tasks...");
    
    // Insert your main logic here
    // e.g., read sensors, transmit data, etc.
    // IMPORTANT: Call wdt_reset() regularly!
    
    simulateWork(); // Example function (see below)
    // -------------------------
    
    digitalWrite(statusLed, LOW);
    
    // DISABLE WATCHDOG FOR SLEEP
    wdt_disable();
    
    sleepFlag = true;
  }
  
  enterSleep();
}

// Example function simulating work tasks
void simulateWork() {
  for(int i = 0; i < 5; i++) {
    Serial.print("Working... Step ");
    Serial.println(i+1);
    delay(800);
    wdt_reset(); // Reset watchdog timer regularly
  }
}

Hello, Thank you for your answer, and sorry for the late answer. I was warned about it in my spam.
I am provoking the watchdog trigger by delay(5000) just to see if it will work, and it does not work. Instead of restarting the Arduino, it stops the program but never restarts. I mean, sometimes, yes, it works, and sometimes it doesn't and hangs. I tried without detach interrupts (no success) and then with detach interrupts (no success). I'll try your code.

OK, I checked your sketch on my mega. FALLING does not wake Mega (it has to be LOW) inside the attachInterrupt. I also added a for loop to gradually increase a delay before calling wtd_reset. This is to trigger the watchdog to see if it works. Once changed, on a regular Mega2560, it works fine, but on a Mega Pro Mini, it's the same problem. Sometimes it works, sometimes it does not. :frowning: I guess it is a problem with the bootloader of that clone. The problem is that it is not so easy to burn a bootloader on the Maga. I ordered an ISP programmer to see if bootloader burn from another Arduino does not work for my Mega Pro Mini.

It is absolutely impossible to burn a new "bootloader" into a "MAGA" :wink:
They switched all fuses to total protection of the flashed content.

Agrrrrrr. But it is a clone. I uploaded a sketch to one of the Mega Pro Minis via ISP and there is no more bootloader. But without a bootloader, my Mega Pro Mini does not execute any sketch that includes watchdog or sleep.... BTW, what is the difference between "sleep_cpu();" and "sleep_mode();"?

A small update. I bought a new Mega Pro Mini with USB-C socket, and this one is working fine with deep sleep AND watchdog. Tried it something like 20 times (including several manual resets and power cuts), and I have 100% success :slight_smile:

Solved! I managed to upload new bootloaders on my Mega Pro with the ATMEL STK00v2 programmer. The bootloader that allows me to use both sleep and watchdog functions comes from MegaCore. It is now called Urboot (formerly Optiboot, then Optiboot-flash). But I have to burn the correct bootloader using avrdude under the command line, not using Arduino IDE... It works; it is essential. Thank you for your help :wink: