2

I have a custom board that is switching an inductive load through a 10A@230V ac relay. Due to a poor design, voltage spikes are causing the board to reboot from time to time (brown-out, watchdog and "unknown reason")

The problem here is that from time to time, the microcontroller freezes and no longer executes code (or at least, it seems so), even if the watchdog should be running. I programmed the WDTON and BROWN-OUT fuses, so the watchdog should be always on.

Once the microcontroller is frozen, an external reset makes it work again.

My questions:

Is there any SOFTWARE fix to guarantee that the device never freezes. Am I using the watchdog incorrectly?

I read in the Atmega 328P datasheet about the 4 cycle restriction between the WDE writing and the prescaler bits writing (page 44), but It ́s not clear to me if this restriction applies when WDON fuse is programmed. Also, I couldn ́t find what the "wdt_enable (WDTO_2S);" instruction is doing under the hood.

Is it possible that the watchdog oscillator stops due to a voltage spike?

This is my code (the part to illustrate the watchdog problem)

Hardware: Custom board

microcontroller: ATmega 328P

Brown-out fuse: programmed

WDTON fuse: programmed


#include <avr/wdt.h>
#define R0 3 // Relay output 16A @ 230Vac (10A @ 230Vac)
#define R1 4 // Relay output 10A @ 230Vac (10A @ 230Vac)
#define R2 5 // Relay output 10A @ 230Vac (10A @ 230Vac)
byte outputs;
//-------------------------------------------------------------------------
void test() {
#define TEST_SWITCHING_INTERVAL 500
 static unsigned long previousMillisTest;
 static int count;
 unsigned long actualTemp = millis();
 if ((actualTemp - previousMillisTest) >= TEST_SWITCHING_INTERVAL) {
 bitWrite (outputs, 0, !bitRead (outputs, 0)); Serial.print ("R0 = "); Serial.print (bitRead (outputs, 0));
 bitWrite (outputs, 1, !bitRead (outputs, 1)); Serial.print (" R1 = "); Serial.print (bitRead (outputs, 1));
 bitWrite (outputs, 2, !bitRead (outputs, 2)); Serial.print (" R2 = "); Serial.print (bitRead (outputs, 2));
 Serial.print (" count: "); Serial.print (count++);
 Serial.print (" millis: "); Serial.println (previousMillisTest);
 previousMillisTest = actualTemp;
 }
 digitalWrite (R0, bitRead (outputs, 0));
 digitalWrite (R1, bitRead (outputs, 1));
 digitalWrite (R2, bitRead (outputs, 2));
}
//-----------------------------------------------------------------------
void setup() {
 uint8_t MCUSR_save;
 MCUSR_save = MCUSR;
 MCUSR = 0;
 wdt_enable (WDTO_2S);
 Serial.begin (9600);
 if (MCUSR_save & 0x01) Serial.println ("*********Restarting . Power-on Reset*********");
 else if (MCUSR_save & 0x02) Serial.println ("*********Restarting . External Reset*********");
 else if (MCUSR_save & 0x04) Serial.println ("*********Restarting . Brown-out Reset*********");
 else if (MCUSR_save & 0x08) Serial.println ("*********Restarting . Watchdog Reset*********");
 else if (MCUSR_save & 0x10) Serial.println ("*********Restarting . JTAG Reset*********");
 else Serial.println ("*********Restarting . Unknown reason*********");
 Serial.print ("MCUSR = 0x"); Serial.println (MCUSR_save, HEX);
 initPins();
 initDevice();
 if (DEBUG) showConfig();
 // prevents flooding the RS485 bus if the device is continuously restarting
 delay (100);
 sendFrame (RESTARTED, 0); // sends the "restarted" event through the RS485 port
}
//---------------------------------------------------------------------------
void loop() {
 wdt_reset();
 test();
}
jsotola
1,5342 gold badges12 silver badges20 bronze badges
asked Jan 10, 2022 at 19:07

1 Answer 1

3

You can choose to either reset the processor or execute an interrupt routine. Example code:

#include <avr/wdt.h>
// watchdog intervals
// sleep bit patterns for WDTCSR
enum
{
 WDT_16_MS = 0b000000,
 WDT_32_MS = 0b000001,
 WDT_64_MS = 0b000010,
 WDT_128_MS = 0b000011,
 WDT_256_MS = 0b000100,
 WDT_512_MS = 0b000101,
 WDT_1_SEC = 0b000110,
 WDT_2_SEC = 0b000111,
 WDT_4_SEC = 0b100000,
 WDT_8_SEC = 0b100001,
 }; // end of WDT intervals enum
 
void setup()
 {
 wdt_disable ();
 Serial.begin(115200);
 Serial.println ();
 Serial.println("After reset");
 watchdogSetup(WDT_4_SEC);
 }
volatile bool watchdogFired = false;
ISR(WDT_vect) // Watchdog timer interrupt.
 {
 watchdogFired = true;
 }
 
void watchdogSetup(byte interval)
 {
 cli(); // disable all interrupts
 // Enter Watchdog Configuration mode:
 WDTCSR = bit (WDCE) | bit (WDE);
 // Set Watchdog settings:
 // WDTCSR = bit (WDIE) | interval; // set WDIE, and requested delay - for an INTERRUPT
 WDTCSR = bit (WDE) | interval; // set WDIE, and requested delay - for a RESET
 wdt_reset(); // reset the WDT timer
 sei(); // enable interrupts again
 }
 
void loop()
 {
 if (watchdogFired)
 {
 watchdogFired = false;
 Serial.println ("Watchdog fired.");
 } 
 // wdt_reset(); // if you want to reset the watchdog
 
 } // end of loop

This example resets the processor, however if you uncomment the line WDTCSR = bit (WDIE) | interval; and comment the one below WDTCSR = bit (WDE) | interval; then it interrupts instead. You can see that in the example output.

If you want an interrupt then you have to supply an interrupt routine (ISR).


Responding to comments:

But there ́s little documentation about how to adequately recover from a reset when the fuse is programmed.

The processor resets, which is what you want, right? You don't need to "recover" from a reset. It's like saying how do you recover from powering it on.

Do I still need to re-enable the watchdog, even if it should be enabled by the fuse?.

I doubt it. In my code the watchdog keeps firing, even after you get the message the first time (the interrupt one).

However you might want to change the interval to the one you want. And you might want to reset the watchdog (wdt_reset ()) if things are going OK.

Also, with the WDTON fuse enabled, the ISR mode is not valid (only the reset mode).

Well, there is not necessarily an ISR for the ISR mode (yet, if ever). The datasheet specifically says that you get the reset mode and not the ISR mode.

It is unclear from the datasheet what the time interval is, with the WDTON fuse programmed.

answered Jan 10, 2022 at 21:51
6
  • 1
    Thank you for your answer. I try to ensure that the watchdog is ALWAYS running to prevent freezing. In your example, the watchdog is disabled in the setup function. This is the reason why I chose to program the WDTON fuse. But there´s little documentation about how to adequately recover from a reset when the fuse is programmed. Do I still need to re-enable the watchdog, even if it should be enabled by the fuse?. Also, with the WDTON fuse enabled, the ISR mode is not valid (only the reset mode). Commented Jan 11, 2022 at 10:38
  • See my amended answer which answers your questions. Commented Jan 12, 2022 at 5:43
  • "The processor resets, which is what you want, right?" -> The point is that the processor DOES NOT reset sometimes. It gets freezed even with the WDTON programmed. 99,9 % of the time it works fine, but still I have some freezing cases. My previous version was very much alike as your code but my guess was: voltage spike -> uC resets -> setup function executes -> disable watchdog -> program counter jumps elsewhere in the code because of EMI -> program freezed because watchdog is disabled. I know maybe this is too much guessing, but I changed to WDTON and it improved Commented Jan 12, 2022 at 10:36
  • Now I am thinking that maybe one voltage spike stops the watchdog oscillator and also the uC oscillator. Do you know if this would be possible?. The fact is that only with a external restart the uC comes to live again Commented Jan 12, 2022 at 10:43
  • A voltage spike might conceivably set the thing into high-voltage programming mode. If you can reach the thing enough to press Reset, can't you wire in a spike protection? Like, a zener diode which redirects high voltages to earth. Commented Jan 13, 2022 at 4:45

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.