Watch Dog timer issue

kenhorner

Active member
I must be missing something, but a simple WD timer routine that will work on an Arduino fails to cooperate on the Teensy 3.2. Secret sauce please.

Test code is below. Just a quick and slow flashing LED pattern to show me it has reset.
//========================
#include <avr/wdt.h>

#define LED 16
bool flipflop=false;

void setup() {
pinMode(LED, OUTPUT);
digitalWrite(LED, HIGH);

wdt_disable(); // Should kill the timer if it was on before reset.

for(int i=0; i<20; i++){
digitalWrite(LED, LOW); // Pulse a pattern of quick flashes
delay(200);
digitalWrite(LED, HIGH);
delay(200);
}

wdt_enable(WDTO_4S); // Enable for a 4 sec timeout.
delay(1);
wdt_reset(); // Reset just in case.
}

void loop() {

if(flipflop) digitalWrite(LED, HIGH); // Flash slowly here until we reset.
else digitalWrite(LED, LOW);
flipflop=!flipflop;
delay(1000);
}
 
There was some discussion about watchdogs earlier today and some code was presented. See https://forum.pjrc.com/threads/69330-Odd-request-How-can-i-lock-up-a-teensy-3-2
I put that code together into some functions:-
Code:
/*Setup and use Watchdog in Teensy 3.2*/

//See: https://forum.pjrc.com/threads/69330-Odd-request-How-can-i-lock-up-a-teensy-3-2

/*Put in setup*/

void SetWatchdog(uint32_t duration) {  // duration in 1/7.2MHz units...1 second = 7,200,000
	// Setup WDT
	int16_t hiWord;
	int16_t loWord;

	hiWord = duration >> 16;
	loWord = duration & 0xFFFF;

	noInterrupts();                                         // don't allow interrupts while setting up WDOG
	WDOG_UNLOCK = WDOG_UNLOCK_SEQ1;                         // unlock access to WDOG registers
	WDOG_UNLOCK = WDOG_UNLOCK_SEQ2;
	delayMicroseconds(1);                                   // Need to wait a bit..

	// for this demo, we will use 1 second WDT timeout (e.g. you must reset it in < 1 sec or a boot occurs)
	//7.2mhz will require WDT reset < 1 second
	//WDOG_TOVALH = 0x006d;
	//WDOG_TOVALL = 0xdd00;

	// Kris I want make timer to reboot over 1 second, maybe this is the correct way to do this
//	WDOG_TOVALH = 0x0098;
//	WDOG_TOVALL = 0x9680;
	WDOG_TOVALH = hiWord;
	WDOG_TOVALL = loWord;

	// This sets prescale clock so that the watchdog timer ticks at 7.2MHz
	// Kris, no clue what this is but leaving it alone
	WDOG_PRESC = 0x400;

	// Set options to enable WDT. You must always do this as a SINGLE write to WDOG_CTRLH
	WDOG_STCTRLH |= WDOG_STCTRLH_ALLOWUPDATE |
		WDOG_STCTRLH_WDOGEN | WDOG_STCTRLH_WAITEN |
		WDOG_STCTRLH_STOPEN | WDOG_STCTRLH_CLKSRC;
	interrupts();
}
/*Put in loop*/
void ResetWatchdog() {
	noInterrupts();                                     //   No - reset WDT
// kris not sure what this does but it actually works just fine
	WDOG_REFRESH = 0xA602;
	WDOG_REFRESH = 0xB480;
	interrupts();
}

void setup() {
	SetWatchdog(7200000);
}
void loop() {
	ResetWatchdog();
}
 
Code:
#define wdt_reset()
#define wdt_enable(timeout)
#define wdt_disable()

Note, better would be
Code:
#define wdt_enable(timeout) do{}while(0)
etc... which at least does not lead to syntax errors (but still does nothing)
 
Well, hell, you are right. the file is just a stub in the Teensy3 fork of the AVR library. So there must be some issues with the Teensy 3 pin assignments or some such. I'll have to resort to the "no macro" approach. thanks.
 
I'd perhaps add a #warning "AVR Watchdog does not work"... or better delete that file... as it is, it is a) confusing, b) leads to the wrong assumption "hey,wdt is there and will work", and c) wrong.
 
Paul ported an Arduino watchdog library. The basic example works fine on a T3.2

Pete

Hm. 64 commits behind master, readme says "

Currently supports the following hardware:


  • Arduino Uno or compatible (ATmega328P)."
Last commit (2016) mentiones Teensy LC (partial support)

Code:
int WatchdogKinetisKseries::sleep(int maxPeriodMS)[TABLE="class: highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file"]
[TR]
[TD="class: blob-code blob-code-inner js-file-line"]{
[/TD]
         [/TR]
         [TR]
           [/TR]
[/TABLE]
[TABLE="class: highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file"]
[TR]
[TD="class: blob-code blob-code-inner js-file-line"]	if (maxPeriodMS <= 0) return 0;
[/TD]
         [/TR]
         [TR]
           [/TR]
[/TABLE]
[TABLE="class: highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file"]
[TR]
[TD="class: blob-code blob-code-inner js-file-line"]	// TODO....
[/TD]
         [/TR]
         [TR]
           [/TR]
[/TABLE]
[TABLE="class: highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file"]
[TR]
[TD="class: blob-code blob-code-inner js-file-line"]	return 0;
[/TD]
         [/TR]
         [TR]
           [/TR]
[/TABLE]
}[TABLE="class: highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file"]
[TR]
[TD="class: blob-code blob-code-inner js-file-line"][/TD]
         [/TR]
[TR]
           [/TR]
[/TABLE]

Thanks for the link, Pete :)
 
Last edited:
Well, some reading of the Freescale docs and testing proved out the code supplied by Bricomp above. Testing showed the WDT clock runs at 48mz on the T3.2 and is not dependent on the selected clock rate when compiling in the IDE. if you set the prescaler to max WDOG_PRESC =x0700, you can use a count of 6600000 and get a 1 sec trip. 2 sec needs 13200000, etc. Pretty simple, no libraries needed.

And after reset it stays off... so no need for a disable command to make sure it doesn't keep looping. Now I'm off to try it on a T3.5.

Thanks all.
 
In the true sense of a dog with a bone, I decided to work up a simple solution not dependent on device clock rates. The code below will work for any Teensy 3x (not having a model 4 around, I couldn't test it.) It should be self-explanatory enough
for general use. Thanks all.

//========================================================
//==================Teensy Watchdog Timer Routine==================
void Set_WatchDog_Timer(){ // A CPU Independent WD Timer
// This code sets a 5 second timeout
noInterrupts()
WDOG_UNLOCK = WDOG_UNLOCK_SEQ1;
WDOG_UNLOCK = WDOG_UNLOCK_SEQ2;
delayMicroseconds(1); // Need to wait a bit..
WDOG_STCTRLH = 0x0001; // Set Control Register... Enable WDG using the Low Power
// 1khz clock, and reset only no interrupt triggering,
// windowing disabled, allow updates, debug off, and
// WD disabled in CPU Stop mode
WDOG_TOVALL = 1000; // The next 2 lines set the time-out value. Low and High 16 bit values
WDOG_TOVALH = 0; // This is the value that the watchdog timer compare itself to-- 1000 ticks.
// Now set the clock prescaler.
// WDOG_PRESC = 0x0000; // After reset, the default prescaler setting is 0x0400. The hardware adds
// 1 to get a divisor of 5. This gives the default tick rate of
// 1khz/5 = 200 hz. If we wanted another rate, we could set the value here.
// Uncommenting the above line would produce a 1khz clock rate.
interrupts();
}

void Reset_Watchdog_Timer(){ // Set for a delay;
// Timer cycles at 200 hz. "count" value of 1000 = 5 secs
noInterrupts();
WDOG_REFRESH = 0xA602;
WDOG_REFRESH = 0xB480;
interrupts();
}
//===============================================================
 
I just got a watch dog timer working using the above code. You will need to call Reset_Watchdog_timer() before your time out. Meaning if you have a while statement that gets input, measures etc. you will need to have the reset call in there--otherwise the MCU will consider no activity and...reset.

I tested my implementation, which was posted above in this thread and used some code to intentionally lock up a teensy 3.2--and after the set timeout, the MCU restarted. Which is what I was after.
 
In the true sense of a dog with a bone, I decided to work up a simple solution not dependent on device clock rates. The code below will work for any Teensy 3x (not having a model 4 around, I couldn't test it.) It should be self-explanatory enough
for general use. Thanks all.

//========================================================
//==================Teensy Watchdog Timer Routine==================
void Set_WatchDog_Timer(){ // A CPU Independent WD Timer
// This code sets a 5 second timeout
noInterrupts()
WDOG_UNLOCK = WDOG_UNLOCK_SEQ1;
WDOG_UNLOCK = WDOG_UNLOCK_SEQ2;
delayMicroseconds(1); // Need to wait a bit..
WDOG_STCTRLH = 0x0001; // Set Control Register... Enable WDG using the Low Power
// 1khz clock, and reset only no interrupt triggering,
// windowing disabled, allow updates, debug off, and
// WD disabled in CPU Stop mode
WDOG_TOVALL = 1000;// The next 2 lines set the time-out value. Low and High 16 bit values
WDOG_TOVALH = 0; // This is the value that the watchdog timer compare itself to-- 1000 ticks.
// Now set the clock prescaler.
// WDOG_PRESC = 0x0000; // After reset, the default prescaler setting is 0x0400. The hardware adds
// 1 to get a divisor of 5. This gives the default tick rate of
// 1khz/5 = 200 hz. If we wanted another rate, we could set the value here.
// Uncommenting the above line would produce a 1khz clock rate.
interrupts();
}

void Reset_Watchdog_Timer(){ // Set for a delay;
// Timer cycles at 200 hz. "count" value of 1000 = 5 secs
noInterrupts();
WDOG_REFRESH = 0xA602;
WDOG_REFRESH = 0xB480;
interrupts();
}
//===============================================================

Code:
//================================================== ======
//==================Teensy Watchdog Timer Routine==================
void Set_WatchDog_Timer() { // A CPU Independent WD Timer
// This code sets a 5 second timeout
	noInterrupts()
	WDOG_UNLOCK = WDOG_UNLOCK_SEQ1;
	WDOG_UNLOCK = WDOG_UNLOCK_SEQ2;
	delayMicroseconds(1);	// Need to wait a bit..
	WDOG_STCTRLH = 0x0001;	// Set Control Register... Enable WDG using the Low Power
							// 1khz clock, and reset only no interrupt triggering,
							// windowing disabled, allow updates, debug off, and
							// WD disabled in CPU Stop mode
	WDOG_TOVALL = 1000;		// The next 2 lines set the time-out value. Low and High 16 bit values
	WDOG_TOVALH = 0;		// This is the value that the watchdog timer compare itself to-- 1000 ticks.
							// Now set the clock prescaler.
							// WDOG_PRESC = 0x0000; // After reset, the default prescaler setting is 0x0400. The hardware adds
							// 1 to get a divisor of 5. This gives the default tick rate of
							// 1khz/5 = 200 hz. If we wanted another rate, we could set the value here.
							// Uncommenting the above line would produce a 1khz clock rate.
	interrupts();
}

void Reset_Watchdog_Timer() { // Set for a delay;
// Timer cycles at 200 hz. "count" value of 1000 = 5 secs
	noInterrupts();
	WDOG_REFRESH = 0xA602;
	WDOG_REFRESH = 0xB480;
	interrupts();
}
//================================================== =============
Do you think in future you could enclose your code between code tags.
You can do this using the # button. I think you will agree it makes the code much more readable, and therefore more understandable.
 
Back
Top