Arduino Wdt Restart, with Power down mode

Good morning all.
Recently I am working on a project with atmega 328 Arduino UNO boot load, where I have to use a power down mode (5uA current consumption in power down) to keep device sleep for for few minutes and then again communicate. But communication was on I2C and few cases due to sensor failure found out to go into infinite loop.
To avoid infinite loop I tried to use a Wdt function to restart the MCU but was unable to do so.
When we use a Power down mode, we are using wdt for waking up. (We can use Power save mode keeping timer to wake up sstem but it takes 5mA which wont suit my application.)
Due to use of wdt Vect hen i try to use the same to reset MCU, MCU is going n different hang loop.
Please check a representation code below for reference.

#include<avr/wdt.h>
#include <avr/sleep.h>
#include <avr/power.h>
#define LED_PIN       A1
// the setup function runs once when you press reset or power the board
volatile boolean ResetFlag = 0;
ISR (WDT_vect)
{
  if (ResetFlag == 0)
  {
    wdt_disable();  // disable watchdog
  }
 else 
  {
 // sleep_disable();
  digitalWrite(LED_PIN, HIGH);
  while(1);
 /* WDTCSR = bit (WDCE) | bit (WDE);
   WDTCSR = WDTCSR & B10111111;
   WDTCSR = WDTCSR | B10000000;
  // MCUSR |= (1<<WDRF);*/
  }
}
void MCU_sleep_1s() {
  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 1 seconds delay
  // WDTCSR = WDTCSR & B11111110;
  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 ();              // Sleep within 3 clock cycles of above
  //sleep_disable();
}


void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  wdt_disable();  // disable watchdog
  
  pinMode(LED_PIN, OUTPUT);
  
  //MCU_sleep_1s();
  for (int i = 0; i < 3; i++) {
    digitalWrite(LED_PIN, HIGH);   // turn the LED on (HIGH is the voltage level)
    delay(200);// wait for a second
    digitalWrite(LED_PIN, LOW);
    delay(200);// wait for a second
  }
  ResetFlag=0;
}

// the loop function runs over and over again forever
void loop() {
  for (int i = 0; i < 3; i++) {

    digitalWrite(LED_PIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  MCU_sleep_1s();                       // wait for a second
  digitalWrite(LED_PIN, LOW);    // turn the LED off by making the voltage LOW
  MCU_sleep_1s(); // wait for a second
  ResetFlag=0;
}
ResetFlag=1;
wdt_enable(WDTO_2S);
//digitalWrite(LED_PIN, HIGH); 
while(1);
}

In this code I am expecting the system should reset and again give 3 fast and 3 slow blinks, but Arduino is giving continuous fast blinks, making me think either it is resetting in void setup itself or it is going in different state.

Low-power and sleep with peripherals is a deep subject. I've written deep sleep and WDT wakeup, but not with SPI/I2C/serial comms.

Quick list of resources:
Arduino Uno + "I2C" sleep mode "low-power" at DuckDuckGo

With luck, maybe a forum member will have a decent answer, but they will need more info about I2C and what is hanging off that line: be very specific.

@mrburnette completely agree its a deep subject, so to reduce my area of problem,
I have attached a simple code where I am not using any peripheral interrupts like I2C etc.
I am just using basic pin high low using wdt wakeup with sleep for 1 sec. and then I am intentionally stuck MCU with while (1) and trying to make reset through watch dog, but I am unable to do it.
Where as I can do it if I don't use power down mode( don't call wdt ISR) , it works.
so how to handle wdt reset based on condition like if it is in sleep just wake up, but if it is not in sleep and wdt ISR calls reset MCU.

The following sketch --

  1. Puts MCU into sleep (Power Down Mode) for 4-sec
  2. After 4-sec delay, the WDT (interrupt mode) wakes up the MCU
  3. MCU blinks L (at DPin-13) for 5 times at 200 ms interval
  4. MCU is permanently blocked by while-do loop.
  5. WDT's interrupt continues to happen after each 4-sec timeout period.
#include<avr/sleep.h>
#include<avr/wdt.h>

void setup()
{
  Serial.begin(115200);
  pinMode(13, OUTPUT);

  SMCR |= (1 << SM1);  //power down mode
  //-------------------------------
  noInterrupts(); //ensure no interruptwhile initializing WDTCSR Reg
  wdt_reset();
  WDTCSR |= (1 << WDCE) | (1 << WDE);//both bits must be HIGH
  //above bits will assume LOW with next 4-cycles
  //so keep new value for WDTCSR by the following line in uffer
  //after 4 cycles, the new value is loaded from Buffer to WDTCSR
  WDTCSR = (1 << WDIE) | (0 << WDE)
           | (1 << WDP3); //WDT inerrupt Mode time-out 4 sec
  interrupts();
  //------------------------------------
  Serial.println("Reset/Boot");
}

void loop()
{
  bitSet(SMCR, SE);  //Sleep enable
  sleep_cpu();  //asm: sleep; the MCU sleeps for 4-sec
  Serial.println("MCU is Wake up.");
  for (int i = 0; i < 5; i++)
  {
    digitalWrite(13, HIGH);
    delay(100);
    digitalWrite(13, LOW);
    delay(100);
  }
  while (1)
  {
      ;
  }
}

ISR(WDT_vect)
{
  Serial.println("WDT interrupt has occured.");
}

If you need a sleep current of circa 5uA, dont use a UNO, it will never go that low.

The processor on the UNO can be put into a sleep current of 5uA or less, but the USB to Serial converter will still be powered and the regulator takes a bit too. A few mA is probably the lowest it will go.

Yes that's true but I am not using Arduino board I am just using battery operated s/m with bare atmega 328 mcu.

@GolamMostafa Yes the code you have shared is doing its job to wake up MCU by wdt timer.
But my problem that I wanted to ask through a representing code is if I am using Wdt to wake my MCU how can I use same when it is not in sleep mode to reset if MCU stuck some where in code or if your I2C save stops responding to MCU and you want to restart the MCU.

1. If your processing codes/subroutine taking more execution time than the expected, then you can operate WDT in "System Reset Mode"; where, the MCU will re-start from boot location after the expiry of timeout period. The following sketch demonstrate the concept.

#include<avr/sleep.h>
#include<avr/wdt.h>
int i = 0;

void setup()
{
  Serial.begin(9600);
  pinMode(13, OUTPUT);
  Serial.println("Sytem Reset");
  noInterrupts();
  WDTCSR |= (1 << WDCE) | (1 << WDE);
  WDTCSR = (0 << WDIE) | (1 << WDE) | (1 << WDP3); //WDT system reset 4-sec time out
  interrupts();
}

void loop()
{
  blinkLed();
}

void blinkLed()  //taking 5-sec time Vs 4-sec timeout
{
  for (i = 0; i < 5; i++)
  {
    digitalWrite(13, HIGH);
    delay(500);
    digitalWrite(13, LOW);
    delay(500);
  }
}

2. For unresponsive I2C slave, you may use WDT concept or millis() function to bring out the MCU from the infinite loop of waiting.

Yes we can use wdt for reset mode when we want to use it.
But to achieve power down mode for higher duration like 2 mins / 10 mins etc I used looped 8s wdt, to wake mcu on specific time and do the function.
but when I use wdt for waking up, how can we use with some 'if' or 'case' or using some other way around to reset mcu too if its not in a sleep loop.

If your I2C Slave does not respond for 4-sec (for example), do you want to cancel the session and proceed to trouble shooting?

That can also work or complete restart of mcu will also work

Then what kind of codes do you want to present?

Yes I am not attaching full code just want to check how we can restart MCU.
I searched on non blocking I2C library a bit but couldnt found anything so trying to complete restart of MCU.

The reason of I2C hangs is few times my sensor dies. nd it stps entire process so want to restart it.

Restart is fine when you are sure that the trouble is with the software and NOT the hardware.

Wire.beginTrasmission(slaveAddress);
Wire.wrire(0x23);
do
{
     byte busStatus = Wire.endTransmission();
     if(busStatus == 0)  //transaction complete
     {
         break;
     }
}
while(millis() - presntMillis <= 2000);   //2-sec time out
if(busStatus != 0)
{
      Serial.println("Incomplete I2C Bus Transaction.");
      while(1);    // 
}   

I have checked this but it also fails and MCU stucks when my I2C sensor fails on field.
It will be best if I can restart my MCU in that case. I am able to put timer and other interrupt in the hang state but couldn't able to break the stuck state.

Can any one guide how to use wdt in interrupt as well as reset mode

You may upload the following sketch, observe the result, read the text of the attached file and then try to understand the working principle of WDT Timer in "Interrupt" and "Reset" Modes.

The following sketch configures WDT for 4 sec timeout period in "Interrupt and Reset" Mode. After 4-sec timeout period, the control goes to ISR(WDT_vect){} routine, displays a status message, WDT is automatically reset and gets prepared for the next 4-sec timeout period. After the expiry of another 4 sec timeout period, the control goes to boot/reset location, displays a status message and the process repeats.

#include<avr/wdt.h>

void setup()
{
  Serial.begin(9600);
  Serial.println("Sytem Reset");

  noInterrupts();
  wdt_reset();
  WDTCSR |= (1 << WDCE) | (1 << WDE);
  WDTCSR = (1 << WDIE) | (1 << WDE) | (1 << WDP3); //4-sec time out
  interrupts();
}

void loop()
{

}

ISR(WDT_vect)
{
  Serial.println("Interrupt has happened");
}

Output:

20:48:35.337 -> System Reset
20:48:39.724 -> Interrupt has happened
20:48:44.189 -> System Reset

WDTPost.pdf (145.5 KB)

To make your life easier search for Lowpower.h library in arduino library manager or in github, that way you can easily fe=igure out what is wrong with your code.

it is always good to use libraries that are usefull

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.