Problems with software reset using watchdog!

Hey, can anyone help me?

I've made an arduino sketch that does a software reset using the watchdog timer.

When I want to reset I call wdt_enable and enter an infinite loop. Everything works great.

The problem occurs when I try to run the same sketch on a standalone chip without bootloader. Once it resets, it just hangs there. My theory is that the bootloader must be disabling the watchdog and so since I'm running the chip standalone I need to disable it myself. Great, not a problem.

Unfortunately, running wdt_disable() in the Setup() function doesn't seem to do anything. After some google searching I've found some people saying the code for wdt_disable() is messed up. All the fixes I've tried don't do anything.

Has anyone had this problem or any ideas?

The watchdog functions are simple enough for you to go through them on the datasheet and use the appropriate registers to set and reset whatever you need. Have you tried that?

Thanks for your reply.

I’ve found a C code example in the datasheet for disabling the watchdog:

      __disable_interrupt();
      __watchdog_reset();
      /* Clear WDRF in MCUSR */
      MCUSR &= ~(1<<WDRF);
      /* Write logical one to WDCE and WDE */
      /* Keep old prescaler setting to prevent unintentional time-out */
      WDTCSR |= (1<<WDCE) | (1<<WDE);
      /* Turn off WDT */
      WDTCSR = 0x00;
      __enable_interrupt();

The functions in here disable_interrupt(), watchdog_reset(), and enable_interrupt() wouldn’t compile. I read a forum post elsewhere that suggested I change them to this:

      cli();
      wdt_reset();
      /* Clear WDRF in MCUSR */
      MCUSR &= ~(1<<WDRF);
      /* Write logical one to WDCE and WDE */
      /* Keep old prescaler setting to prevent unintentional time-out */
      WDTCSR |= (1<<WDCE) | (1<<WDE);
      /* Turn off WDT */
      WDTCSR = 0x00;
      sei();

Now it compiles, but I still have the same behavior as before :-(.

I wonder if it’s even resetting? I have it hooked up to a parallel 16x2 LCD and the display just hangs at whatever text was there before I initiate. Any code I put after the reset doesn’t get executed, so I know it’s doing something, but if I were in a reset loop wouldn’t the display get cleared at some point during reset?

Anyone else have any ideas? I'm stumped...

I’m using this code and its working perfectly in a RBBB (an arduino clone with Duemilanove bootloader).

/*
 Watchdog Sleepy Bones (the skeleton is the essential armature for any living thing)
 This is the basic structure that you need to Sleep_Mode_Pwr_Down/Watchdog interrupt wake
 Provided for general consumption by Rachel's Electronics http://www.rachelselectronics.com
 Under the CC licence here (http://creativecommons.org/licenses/by-sa/3.0/us/)
 Rachel's Electronics: Making the World Safe for Robots! -Joel Murphy joel@joelmurphy.net
 
 Built in part from code posted by:
 * KHM 2008 / Lab3/  Martin Nawrath nawrath@khm.de
 * Kunsthochschule fuer Medien Koeln
 * Academy of Media Arts Cologne
 http://interface.khm.de/index.php/lab/experiments/sleep_watchdog_battery/
 */


#include <avr/sleep.h>
#include <avr/wdt.h>
#define sleepTime  1                       //number of 8 second sleep cycles

volatile byte wdt=0;                       //used to cound number of sleep cycles

void setup(){

  setup_watchdog();                        // set prescaller and enable interrupt                  
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);     // sleep mode is set here Power Down uses the least current
  pinMode(13,OUTPUT);                                       // system clock is turned off, so millis won't be reliable!
  delay(10);
}


void loop(){

  // do what you want to before you sleep here

  system_sleep();
  // do what you want to after you sleep here
  digitalWrite(13, HIGH);
  delay(100);
  digitalWrite(13, LOW);
  delay(100);
  digitalWrite(13, HIGH);
  delay(100);
  digitalWrite(13, LOW);
  delay(100);
}


void system_sleep() {
  ADCSRA |= (0<<ADEN);                     // disable ADC
  sleep_enable();                          // enable sleeping
  while (wdt < sleepTime){                 // sleep for sleepTime * 8sec
    sleep_mode();                          // activate system sleep
    // sleeping ...
  }
  sleep_disable();                         // disable sleep  
  ADCSRA |= (1<<ADEN);                     // switch ADC on
  wdt = 0;                                 // reset wdt for next cycle
} 


void setup_watchdog() {
  cli(); //disable global interrupts
  MCUSR = 0x00;  //clear all reset flags
  //set WD_ChangeEnable and WD_resetEnable to alter the register
  WDTCSR |= (1<<WDCE) | (1<<WDE);   // this is a timed sequence to protect WDTCSR
  // set new watchdog timeout value to 1024K cycles (~8.0 sec)
  WDTCSR = (1<<WDP3) | (1<<WDP0);
  //enable watchdog interrupt
  WDTCSR |= (1<<WDIE);    
  sei(); //enable global interrupts
}

// Watchdog Interrupt Service Routine.
// Very first thing after sleep wakes with WDT Interrupt
ISR(WDT_vect) {
  wdt++;  // increment the watchdog timer
}

I have however a question that I couldn’t figure out reading the datasheet. This line:

WDTCSR |= (1<<WDCE) | (1<<WDE);

sets the Watchdog to both interrupt and reset. I wonder to which point does it reset and why it is necessary to set the watchdog to reset reset in order to obtain the expected functionality (a LED that blinks every 8 seconds).

If I just set it to Interrupt mode, it blinks all the time.

I do the same kind of thing on a different processor and I initially had trouble with it. Not the same problem you’re describing, but maybe it will help to set a time in the register. By clearing it to zero you’re going for the lowest possible time and that could be your problem. Try setting it to something longer like:

WDTCSR = (0<<WDIE) | (0<<WDP3) | (1<<WDP2) | (1<<WDP1) | (0<<WDP0); //no interrupts with a 1 second timeout.

If I remember correctly, this will set the timeout to a second.

The reason you do the watchdog reset at the beginning is to make it start counting down all over again. Otherwise it might fire while you’re changing it. I saw that somewhere in the datasheet, couldn’t find it when I looked again, but the idea stuck to some neuron.

tribble222:
When I want to reset I call wdt_enable and enter an infinite loop. Everything works great.

The problem occurs when I try to run the same sketch on a standalone chip without bootloader.

Can you post a sample sketch with code that reproduces this problem?

(edit) Also, which chip?