Teensy 3.0 Watchdog Timer

Status
Not open for further replies.
Hi Martinayotte - do you mind sharing your watchdog code? What Froeber describes in post #24 is exactly what I'm trying to achieve.

A very simple working code example would be extremely helpful that illustrates how to use the watchdog feature in this manner.
 
Hi RBrockman,
I've simply added the following startup_early_hook() and then call WatchdogReset() function periodically to avoid watchdog restarts.

#ifdef __cplusplus
extern "C" {
#endif
void startup_early_hook() {
WDOG_TOVALL = 1000; // The next 2 lines sets the time-out value. This is the value that the watchdog timer compa
WDOG_TOVALH = 1;
WDOG_PRESC = 0; // prescaler
WDOG_STCTRLH = (WDOG_STCTRLH_ALLOWUPDATE | WDOG_STCTRLH_WDOGEN); // Enable WDG
}
#ifdef __cplusplus
}
#endif

void WatchdogReset()
{
// use the following 4 lines to kick the dog
noInterrupts();
WDOG_REFRESH = 0xA602;
WDOG_REFRESH = 0xB480;
interrupts();
// if you don't refresh the watchdog timer before it runs out, the system will be rebooted
delay(1); // the smallest delay needed between each refresh is 1ms. anything faster and it will also reboot.
}
 
Would watchdog make more sense like this?

I really dislike delay() and it's pretty easy on a Teensy3 to set up a millisecond clock so you know when it's time to kick the dog. I've set it so it resets the watchdog every 3 milliseconds. You need to make it at least 2 as even set to 2 it can be called in 1.001 milliseconds or so if everything adds up wrong.

And even if you don't use this for a watchdog, Timer1 and Timer3 are really useful for keeping track of time if you need that.

Code:
unsigned char _watchTheDog  // how many milliseconds since we last reset the watchdog
void Setup()
{
    Timer3.initialize(1000000 / 1000); // set to fire every millisecond. initialize takes microseconds as an argument.
    Timer3.attachInterrupt(WatchTheDog  ); // call WatchTheDog  every millisecond
}

void WatchTheDog ()
{
   _watchTheDog+= 1
}
void WatchdogReset()
{
  if (_watchTheDog> 2){
    // use the following 4 lines to kick the dog
     noInterrupts();
     WDOG_REFRESH = 0xA602;
     WDOG_REFRESH = 0xB480;
     interrupts();
     _watchTheDog = 0
    }
 }
 
What are the units of these two values and how do they translate into time?

WDOG_TOVALL = 1000; // The next 2 lines sets the time-out value.
WDOG_TOVALH = 1;

I've implemented this and it is resetting about every 60 seconds with these values above. I want to set this to a value less than 1 second - actually in microseconds if possible.

Is there a minimum amount of elapsed time required between calls to kick the dog?
 
Last edited:
Thanks Martinayotte!

How do you start/enable the watchdog after a period of time in your code? Like after completing setup()
 
Please provide input on the code below. There are still a few watchdog items here I do not have an understanding of as of yet, but the code seems to be more or less working.

Goal: Start a watchdog when the Teensy first runs with a long timeout value, then after setup() change the timeout to a much smaller timeout period. Kick the dog more often than the timeout period.



Code:
#ifdef __cplusplus
extern "C" {
#endif
void startup_early_hook() {
WDOG_TOVALL = 2000; // The next 2 lines sets the time-out value. This is the value that the watchdog timer compares itself to
WDOG_TOVALH = 0;
WDOG_PRESC = 0; // prescaler
WDOG_STCTRLH = (WDOG_STCTRLH_ALLOWUPDATE | WDOG_STCTRLH_WDOGEN); // Enable WDG
}
#ifdef __cplusplus
}
#endif

void setup(){
  WDOG_UNLOCK = WDOG_UNLOCK_SEQ1;
  WDOG_UNLOCK = WDOG_UNLOCK_SEQ2;
  WDOG_TOVALL = 10; // The next 2 lines sets the time-out value. This is the value that the watchdog timer compares itself to
  WDOG_TOVALH = 0;
  WDOG_PRESC = 0; // prescaler
  WDOG_STCTRLH = (WDOG_STCTRLH_ALLOWUPDATE | WDOG_STCTRLH_WDOGEN); // Enable WDG
}


void loop(){
  WatchdogReset();
}


void WatchdogReset(){
  static elapsedMillis watchdogTimer;	
 
  if (watchdogTimer > 5){
    watchdogTimer = 0;
		
    noInterrupts();
    WDOG_REFRESH = 0xA602;
    WDOG_REFRESH = 0xB480;
    interrupts();
  }
}
 
Hello forum,
as far as I see, you use different approaches to simulate a watchdog behavior.
I am not to sure about the work of an interrupt watchdog.
Does it only work if the teensy hangs due to infinite (or to long) loops
or does it also works, if the teensy hangs for no obvios reason.

I use a teensy3.1 with an MFRC522 door reader and there are no "bad loops" inside.
The program works fine for days, sometimes weeks, sometimes months, but
somtimes it just stops working (and I have to go to that place an open the door with a key...)
When switching the teensy off and on again, everything is fine and it starts working for the next
unsure period of time.

A watchdog would be great, but would an interrupt watchdog prevent the teensy from these
types of chrashes?

If yes, which is the best approach for this?
I would love to keep the .c file unchanged...

If no, what would you reccomend? An oldfashioned 555 circuit?

Thanks for your help
Roland
 
Hello duff
Great and working code, but where in Your code is definition of 6 second delay ?
Max
 
The idea of a watchdog is that your app will "and" together several conditions and states to know whether to reset the watchdog timer.
 
There are a number of external watchdog ICs, with programmable or fixed reset windows. I personally have used the ADM706SANZ with Teensy, which gives you a 1.6s reset window. You could also use a STM6321S or TPS3828-33DBVT.

I've also made a simple external watchdog with programmable delay by using a NE556 timer IC. I can share the schematic and workings if you like.
 
Hello duff
Great and working code, but where in Your code is definition of 6 second delay ?
Max
I haven't actually used the watchdog since posting that so I'll have to look at it again and get back to you.
 
What are the units of these two values and how do they translate into time?

WDOG_TOVALL = 1000; // The next 2 lines sets the time-out value.
WDOG_TOVALH = 1;

I've implemented this and it is resetting about every 60 seconds with these values above. I want to set this to a value less than 1 second - actually in microseconds if possible.

Is there a minimum amount of elapsed time required between calls to kick the dog?

WDOG_TOVALH and WDOG_TOVALL are the high and low, respectively, registers for the 32-bit timeout value of the watchdog timer. This must be at least 4 cycles. WDOG_PRESC is the 3 bit, at bit 8-10 for some reason, prescaler which divides the watchdog clock by 1 + the three bit prescale value. The watchdog clock is running at 1kHz as far as I can tell. So, to get a WDT of 3 seconds you'd use WDOG_TOVALH = 0, WDOG_TOVALL = 3000 and WDOG_PRESC = 0.

With your values there of VALH = 1 and VALL = 1000 you should get a WDT of about 1<<16+1000 = 66536 ms which from what you say sounds reasonable.

To sum up, the final WDT in milliseconds will be (VALH<<16 + VALL) * (1 + PRESC >> 8).
 
Watchdog stopped working with Teensy V1.27 - solved

Thanks to everyone that contributed to this topic. I had a strange experience with the watchdog today, and am posting in the hope that it helps someone else. I've had the watchdog working well for quite some time with Arduino 1.6.5-r2 and Teensyduino V1.24, but when I transitioned to Arduino 1.6.5-r5 and Teensyduino V1.27, the sketches with watchdog would just hang. I found out that the watchdog was what was causing the problem - commenting out startup_early_hook() would get it working again. I then found that I had to make the watchdog period longer in order to get the sketch working again. My guess is that the new Teensyduino code takes longer to get to setup() than the old one. I have the watchdog reset as the first statement in setup(), and I found that I had to increase WDOG_TOVALL to 259 in order to get it to work OK. 258 causes it to hang. I'm guessing from the post above, that this is 259ms watchdog. I was trying to minimize this, so that if the program does ever hang, the watchdog would reset it as quickly as possible. I'm using "72MHz Optimized" as the CPU speed selection in the Arduino IDE.

#ifdef __cplusplus
extern "C" {
#endif
void startup_early_hook() {
WDOG_TOVALL = 259; // The next 2 lines sets the time-out value. This is the value that the watchdog timer compa
WDOG_TOVALH = 0;
WDOG_PRESC = 0; // prescaler
WDOG_STCTRLH = (WDOG_STCTRLH_ALLOWUPDATE | WDOG_STCTRLH_WDOGEN); // Enable WDG
}
#ifdef __cplusplus
}
#endif
 
No problem. I am a bit of a noob in programming so ppeas can you tell me what code to use? Post #31?
Thank you
 
tried the watchdog today... It works :) but like someone else said i can't figure out the time interval.. i used this code for testing
Code:
#ifdef __cplusplus
extern "C" {
#endif
void startup_early_hook() {
WDOG_TOVALL = 3000;
WDOG_TOVALH = 0;
WDOG_PRESC = 0;
WDOG_STCTRLH = (WDOG_STCTRLH_ALLOWUPDATE | WDOG_STCTRLH_WDOGEN); 
}
#ifdef __cplusplus
}
#endif
 
int led = 13;

void setup() {
  Serial.begin(9600);                
  pinMode(led, OUTPUT);
  Serial.println("Setup");     
}

void loop() {
  WatchdogReset();
  Serial.println("Begin");
  delay(2608);
}
void WatchdogReset(){
  static elapsedMillis watchdogTimer;  
 
  if (watchdogTimer > 5){
    watchdogTimer = 0;
    
    noInterrupts();
    WDOG_REFRESH = 0xA602;
    WDOG_REFRESH = 0xB480;
    interrupts();
  }
}

when the delay(2608); the sketch runs but when i use delay(2609); the watchdog kicks in. I expected a 3 sec reset time... But all and all this works for me .. I don't need accurate timing, just a reset if the code hangs :)
Thank you!
 
when the delay(2608); the sketch runs but when i use delay(2609); the watchdog kicks in. I expected a 3 sec reset time... But all and all this works for me .. I don't need accurate timing, just a reset if the code hangs :)
Thank you!
If your teensy 3* watchdog timer is configured to use the LPO, that internal oscillator is spec'd only at 10% accuracy (100,000 ppm). Using the LPTMR, i've measured the accuracy of LPO on various teensy's (anecdotal results at https://github.com/manitou48/crystals/blob/master/crystals.txt). I tested my T3.2 with LPO accuracy of 18934 ppm with the watchdog timer. I modified the BasicUsage example from https://github.com/adafruit/Adafruit_SleepyDog to adjust the delay before "kicking the watchdog" in loop().
Code:
  if (micros() -t > 3927000) {
    Watchdog.reset();
    t=micros();
    Serial.println("running");
  }
If i wait longer the 3.927 seconds, the teensy resets. if i wait less than 3.926 secs to kick the dog, then reset is avoided. That timing roughly agrees with measured LPO accuracy for that T3.2. The LPO accuaracy will vary from chip to chip and with temperature.

2nd test: T3.6 (LPO drift of -3232 ppm). If wait less than 4.011 secs, then reset is avoided.
 
Last edited:
Here is more portable version of your watchdog code, no need to edit any core files but instead use the startup_early_hook. It also uses the interval timer to kick the dog.

Code:
#define RCM_SRS0_WAKEUP                     0x01
#define RCM_SRS0_LVD                        0x02
#define RCM_SRS0_LOC                        0x04
#define RCM_SRS0_LOL                        0x08
#define RCM_SRS0_WDOG                       0x20
#define RCM_SRS0_PIN                        0x40
#define RCM_SRS0_POR                        0x80

#define RCM_SRS1_LOCKUP                     0x02
#define RCM_SRS1_SW                         0x04
#define RCM_SRS1_MDM_AP                     0x08
#define RCM_SRS1_SACKERR                    0x20

IntervalTimer wdTimer;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);
  delay(100);
  digitalWrite(LED_BUILTIN, LOW);
  // You have about 6 secs to open the serial monitor before a watchdog reset
  while(!Serial);
  delay(100);
  printResetType();
  wdTimer.begin(KickDog, 500000); // kick the dog every 500msec
}

void loop() {
  Serial.println("doing loop things...");
  delay(100);
}

void KickDog() {
  Serial.println("Kicking the dog!");
  digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
  noInterrupts();
  WDOG_REFRESH = 0xA602;
  WDOG_REFRESH = 0xB480;
  interrupts();
}

void printResetType() {
    if (RCM_SRS1 & RCM_SRS1_SACKERR)   Serial.println("[RCM_SRS1] - Stop Mode Acknowledge Error Reset");
    if (RCM_SRS1 & RCM_SRS1_MDM_AP)    Serial.println("[RCM_SRS1] - MDM-AP Reset");
    if (RCM_SRS1 & RCM_SRS1_SW)        Serial.println("[RCM_SRS1] - Software Reset");
    if (RCM_SRS1 & RCM_SRS1_LOCKUP)    Serial.println("[RCM_SRS1] - Core Lockup Event Reset");
    if (RCM_SRS0 & RCM_SRS0_POR)       Serial.println("[RCM_SRS0] - Power-on Reset");
    if (RCM_SRS0 & RCM_SRS0_PIN)       Serial.println("[RCM_SRS0] - External Pin Reset");
    if (RCM_SRS0 & RCM_SRS0_WDOG)      Serial.println("[RCM_SRS0] - Watchdog(COP) Reset");
    if (RCM_SRS0 & RCM_SRS0_LOC)       Serial.println("[RCM_SRS0] - Loss of External Clock Reset");
    if (RCM_SRS0 & RCM_SRS0_LOL)       Serial.println("[RCM_SRS0] - Loss of Lock in PLL Reset");
    if (RCM_SRS0 & RCM_SRS0_LVD)       Serial.println("[RCM_SRS0] - Low-voltage Detect Reset");
}

#ifdef __cplusplus
extern "C" {
#endif
  void startup_early_hook() {
    WDOG_TOVALL = (1000); // The next 2 lines sets the time-out value. This is the value that the watchdog timer compare itself to.
    WDOG_TOVALH = 0;
    WDOG_STCTRLH = (WDOG_STCTRLH_ALLOWUPDATE | WDOG_STCTRLH_WDOGEN | WDOG_STCTRLH_WAITEN | WDOG_STCTRLH_STOPEN); // Enable WDG
    //WDOG_PRESC = 0; // prescaler 
  }
#ifdef __cplusplus
}
#endif

Re: startup_early_hook()
i get a compile error if i try to compile Duff's watchdog sketch in post #21 ?? what is proper way to override weak startup_early hook?
Code:
sketch_apr09a: In function 'void startup_early_hook()':
sketch_apr09a:58: error: previous declaration of 'void startup_early_hook()' with 'C++' linkage
   void startup_early_hook() {
      ^
sketch_apr09a:58: error: conflicts with new declaration with 'C' linkage
   void startup_early_hook() {
                           ^
previous declaration of 'void startup_early_hook()' with 'C++' linkage
i'm using 1.8.1 with 1.35
 
Re: startup_early_hook()
i get a compile error if i try to compile Duff's watchdog sketch in post #21 ?? what is proper way to override weak startup_early hook?
Code:
sketch_apr09a: In function 'void startup_early_hook()':
sketch_apr09a:58: error: previous declaration of 'void startup_early_hook()' with 'C++' linkage
   void startup_early_hook() {
      ^
sketch_apr09a:58: error: conflicts with new declaration with 'C' linkage
   void startup_early_hook() {
                           ^
previous declaration of 'void startup_early_hook()' with 'C++' linkage
i'm using 1.8.1 with 1.35
The Arduino preprocessor is a buggy piece of <CENSORED>. You need an explicit forward declaration:

Code:
#ifdef __cplusplus
extern "C" { void startup_early_hook(); }
extern "C" {
#endif
  void startup_early_hook() {
    WDOG_TOVALL = (1000); // The next 2 lines sets the time-out value. This is the value that the watchdog timer compare itself to.
    WDOG_TOVALH = 0;
    WDOG_STCTRLH = (WDOG_STCTRLH_ALLOWUPDATE | WDOG_STCTRLH_WDOGEN | WDOG_STCTRLH_WAITEN | WDOG_STCTRLH_STOPEN); // Enable WDG
    //WDOG_PRESC = 0; // prescaler 
  }
#ifdef __cplusplus
}
 
Hello, I have followed this thread and it is confusing. Is there a final answer on how to implement a watchdog on teensy 3.2 ?
 
Status
Not open for further replies.
Back
Top