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.
@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.
After 4-sec delay, the WDT (interrupt mode) wakes up the MCU
MCU blinks L (at DPin-13) for 5 times at 200 ms interval
MCU is permanently blocked by while-do loop.
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.
@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.
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.
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.
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.
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