After complaining publicly about this a couple of folk stepped up and fixed it so that this problem has been solved. You have to burn a new boot loader, but that's not too hard. The file I used is available here. It's a hex file, so copy, paste and save it as a .hex file using notepad.
However, they didn't address the problem of the watchdog timer. I've been using timer three to work around the problem, but I didn't like that solution much. Timer three is a nice general purpose timer and messing with it can affect PWM operations, so I've been thinking about how to solve it. I got a clue today on the Arduino forum and put together some code that solves this problem for me with a side benefit. I can have watchdog timers that exceed the 8 second limit in the hardware as well.
Here is the code, have fun with it.
#include <avr/wdt.h>
unsigned long resetTime = 0;
#define TIMEOUTPERIOD 5000 // You can make this time as long as you want,
// it's not limited to 8 seconds like the normal
// watchdog
#define doggieTickle() resetTime = millis(); // This macro will reset the timer
void(* resetFunc) (void) = 0; //declare reset function @ address 0
void watchdogSetup()
{
cli(); // disable all interrupts
wdt_reset(); // reset the WDT timer
MCUSR &= ~(1<<WDRF); // because the data sheet said to
/*
WDTCSR configuration:
WDIE = 1 :Interrupt Enable
WDE = 1 :Reset Enable - I won't be using this on the 2560
WDP3 = 0 :For 1000ms Time-out
WDP2 = 1 :bit pattern is
WDP1 = 1 :0110 change this for a different
WDP0 = 0 :timeout period.
*/
// Enter Watchdog Configuration mode:
WDTCSR = (1<<WDCE) | (1<<WDE);
// Set Watchdog settings: interrupte enable, 0110 for timer
WDTCSR = (1<<WDIE) | (0<<WDP3) | (1<<WDP2) | (1<<WDP1) | (0<<WDP0);
sei();
Serial.println("finished watchdog setup"); // just here for testing
}
ISR(WDT_vect) // Watchdog timer interrupt.
{
if(millis() - resetTime > TIMEOUTPERIOD){
Serial.println("This is where it would have rebooted"); // just here for testing
doggieTickle(); // take these lines out
// resetFunc(); // This will call location zero and cause a reboot.
}
else // these lines should
Serial.println("Howdy"); // be removed also
}
void setup(){
watchdogSetup();
Serial.begin(57600);
Serial.println("Hello, in setup");
}
int firstTime = true;
void loop() {
if (firstTime){
firstTime = false;
Serial.println("In loop waiting for Watchdog");
}
if(millis() - resetTime > 2000){
//doggieTickle(); // if you uncomment this line, it will keep resetting the timer.
}
}
And yes, I know about the millisecond timer rolling over. That is left as an exercise for the student.
Update Feb 2, 2012: I've gotten comments both here and in email that the routine above isn't truly a watchdog timer. OK, facts are that it is as good a simulation as one can get in software. Sure, the code could get overwritten and fail if one has a bad enough bug, but that's unlikely. When it fires, it goes to location zero which is in ROM and can't be over written which will reload the RAM code and start all over. I've been using it for months now without a problem. Just put it at the beginning of your code and it should be fine. Eventually, someone will correct the bootloader and all will be well.
Update May 30, 2012: The bootloader problems have been solved and there is a new loader that can be put on the board to avoid these problems. I post about the solution here.
No comments:
Post a Comment