WDT_T4 - Watchdog Library for Teensy 4

callback not firing?

Dear all,
it seems the callback does not fire in my test sketch.
The aim of the sketch is to be able to copy last function name into DMAMEM arrays to see in which function did the WDT fired.
The code is self explanatory i hope and i am using the DMAMEM area as i read somewhere that that memory is kept during code upload (or during wdt reset) while the teensy is powered.

Code:
#include "Watchdog_t4.h"
#include "elapsedMillis.h"
#include <Bounce.h>
WDT_T4<WDT3> wdt;

DMAMEM  char  lastFunc[32];
DMAMEM  char  lastLastFunc[32];
DMAMEM  uint32_t  wdfired;
uint32_t  bttn_1_pressed = 0;
uint32_t  bttn_2_pressed = 0;

#define debug_out1  3
#define debug_out2  4


void myCallback() {
  digitalWriteFast(LED_BUILTIN, HIGH);
  wdfired++;    //  indicate the fired wdt
}

elapsedMicros oneMillis;
elapsedMillis wdtRefresh;

#define millisecond         998
#define wdtRefreshInterval  40

const int button_clear = 2;
const int button_1 = 0;
const int button_2 = 1;
Bounce bttn_clear = Bounce(button_clear,10); 
Bounce bttn_1 = Bounce(button_1,10); 
Bounce bttn_2 = Bounce(button_2,10); 


void setup() {
  
  Serial.begin(1);
  pinMode(button_clear, INPUT_PULLUP);
  pinMode(button_1, INPUT_PULLUP);
  pinMode(button_2, INPUT_PULLUP);
  pinMode(debug_out1, OUTPUT);
  pinMode(debug_out2, OUTPUT);
  pinMode(LED_BUILTIN,  OUTPUT);


  while (!Serial);
  
  Serial.print("Begin wdt test / wdtfired: ");
  Serial.println(wdfired);  // at first run, display random data in DMAMEM array
  
  WDT_timings_t config;
  config.window = 30;
  config.timeout = 55;
  config.callback = myCallback;
  wdt.begin(config);
  wdtRefresh = 0;

}

void loop() {

  if (bttn_clear.update()) {
    if (bttn_clear.fallingEdge()) {
      Serial.print(F(" wdfired "));   // at first run, display random data in DMAMEM array
      Serial.print(wdfired);
      wdfired = 0;
      Serial.println(F(" cleared"));
      Serial.println(lastLastFunc);   //  print previous func array
      Serial.println(lastFunc);     //  print last func array
   
/*      for (uint8_t  q = 0;  q < sizeof(lastFunc); q++)  {
        Serial.print(lastFunc[q]);
      } */

      memset(lastFunc,  '.',  sizeof(lastFunc));      //  preset them
      memset(lastLastFunc,  '.',  sizeof(lastLastFunc));   
      
    }
  }

  if (bttn_1.update()) {        //  button debounce
    if (bttn_1.fallingEdge()) {
      Serial.println(F("Button 1 pressed"));  
      bttn_1_pressed++;         //  just increase the variable
    }
  }

    if (bttn_2.update()) {
    if (bttn_2.fallingEdge()) {
      Serial.println(F("Button 2 pressed"));  
      bttn_2_pressed++;
    }
  }
  
  if  (oneMillis > millisecond) {   //  1 ms interval
    oneMillis = 0;
//    digitalWriteFast(LED_BUILTIN, LOW);
    test1();
    test_kurna_snad_to_pojde();
    digitalWrite(debug_out2,  !digitalRead(debug_out2));
  }


  if  (wdtRefresh > wdtRefreshInterval) {   //  wdt feeder 41 ms
    wdtRefresh = 0;
    wdt.feed();
    digitalWrite(debug_out1,  !digitalRead(debug_out1));
  }

}

FASTRUN void  test1() {
  memcpy(lastLastFunc,  lastFunc, sizeof(lastFunc));    //  copy last to previous
  memcpy(lastFunc,  __func__, sizeof(__func__));      //  update last
  while (bttn_1_pressed)  {
    
  }
}

FASTRUN void  test_kurna_snad_to_pojde() {
  memcpy(lastLastFunc,  lastFunc, sizeof(lastFunc));
  memcpy(lastFunc,  __func__, sizeof(__func__));
  while (bttn_2_pressed)  {
    
  }  
}

I am running the code on Teensy 4.1.

Thank You a lot
 
Hello

In this configuration:
Code:
 WDT_timings_t configWatchdog;
  configWatchdog.callback = watchdogCallback;
  configWatchdog.trigger = 5; /* in seconds, 0->128 */
  configWatchdog.window = 100; /* window mode is disabled when ommitted */
  configWatchdog.timeout = 2000;
  configWatchdog.pin = WATCHDOG_LED;
  watchdog.begin(configWatchdog);

what do configWatchdog.trigger and configWatchdog.window do? I've kind of worked out what the others are for.

Thanks
Karl.
 
Am I reading this stream correctly.... in post 1 TonTon81 describes WDOG1 as driving GPIO pins 19, 20 low and needing a POR to reset them. Given #19 is the I2C SCL pin, does this mean that after the dog trips and reset() executes, the I2C channel will be inoperative unless I externally power cycle the whole board? Something seems wrong with my reading of this. Let me know.

Thanks
 
that's only if you define the pin in the wdt config, otherwise no.
it's purpose is to hold the line till the main processor resets if teensy is a sub processor, where after the main resets the power of the teensy then the pin state is restored.
 
watchdog cannot be disabled unless it is in debug mode, i will need to check the RF what that mode affects, if DBG mode hinders operational features then it wouldn't be good to add, however, maybe I can add the option for specific use case, but not default.
It would be very nice if there was a disable option. For example in my case, I have OTA on the Teensy using FlasherX, but when the move occurs, the watchdog will trigger and thus brick the device by restarting.
 
It would be very nice if there was a disable option. For example in my case, I have OTA on the Teensy using FlasherX, but when the move occurs, the watchdog will trigger and thus brick the device by restarting.
I'm pretty sure you could update the flash_move() function in FlasherX to periodically service the watchdog. I don't think I would try to call the feed() function directly, but if you had a few statements inline to write to WDT registers, it seems likely that would be okay.
 
I'm pretty sure you could update the flash_move() function in FlasherX to periodically service the watchdog. I don't think I would try to call the feed() function directly, but if you had a few statements inline to write to WDT registers, it seems likely that would be okay.
Calling directly feed() is ugly just as you say.
I'm gonna do my best to add code to the flash_move which feeds the dog.

I think it could actually be a good addition to the library. Adding a #define and #ifdef, so that if someone has a watchdog, no matter how many or whatever, all the dogs will be fed by flash_move to keep the moving safe.

Here's the feed() function code:
if ( _device == EWM ) {
EWM_SERV = 0xB4;
EWM_SERV = 0x2C;
return;
}
if ( _device == WDT1 || _device == WDT2 ) {
WDOGb_WSR(_device) = 0x5555;
WDOGb_WSR(_device) = 0xAAAA;
}
else {
if ( WDOGb_CS(_device) & WDOG_CS_CMD32EN ) WDOGb_CNT32(_device) = 0xB480A602;
else {
WDOGb_CNT(_device) = 0xA602;
WDOGb_CNT(_device) = 0xB480;
}
}
 
I think it could actually be a good addition to the library. Adding a #define and #ifdef, so that if someone has a watchdog, no matter how many or whatever, all the dogs will be fed by flash_move to keep the moving safe.

I think at most I would add a hook to allow an arbitrary function to be called from within flash_move(). The link below is to a thread on the NXP Community Forum that discusses the differences between the various watchdogs. I can't believe there are four of them!!

 
I think at most I would add a hook to allow an arbitrary function to be called from within flash_move(). The link below is to a thread on the NXP Community Forum that discusses the differences between the various watchdogs. I can't believe there are four of them!!

I solved it by doing this. I give the flash_move function the name of my watchdog feed function. It worked perfectly now that I tested it.
Question remains, is this considered safe(?). Because if flash_move fails for some reason, the dog will kill the device which essentially bricks it.

1700036576626.png
 
I solved it by doing this. I give the flash_move function the name of my watchdog feed function. It worked perfectly now that I tested it.
Question remains, is this considered safe(?). Because if flash_move fails for some reason, the dog will kill the device which essentially bricks it.
Nice. That's a pretty simple fix. Can you say which watchdog you are using, and what is the timeout period? For the watchdogs that only require a sequence of writes to registers, it's clear that this will work. I'm not 100% sure about the watchdog that has a more complex "feed" function.

Regarding safety, I don't think this addition reduces the safety of the firmware update. As long as you have a method to verify that the new code is complete and correct before calling flash_move(), the process can only fail if there is a power glitch during flash_move(), or there is a hardware issue such as a failed/failing flash or processor, or a bad connection to flash or PSRAM. As far as I know, there is no way to brick a T4 that has no hardware issues. The warnings in FlasherX about bricking the device go back to the original Flasher, which was for T3.x, and the risk was associated with writing incorrect values to critical locations in the on-board flash that control boot-up. If those were written with incorrect values, the T3 would never again be able to boot up. As far as I know, that can't happen with T4 because it uses external flash, and the worst that can happen is to end up with an invalid program in flash, requiring the 15-second recovery process.
 
Nice. That's a pretty simple fix. Can you say which watchdog you are using, and what is the timeout period? For the watchdogs that only require a sequence of writes to registers, it's clear that this will work. I'm not 100% sure about the watchdog that has a more complex "feed" function.

Regarding safety, I don't think this addition reduces the safety of the firmware update. As long as you have a method to verify that the new code is complete and correct before calling flash_move(), the process can only fail if there is a power glitch during flash_move(), or there is a hardware issue such as a failed/failing flash or processor, or a bad connection to flash or PSRAM. As far as I know, there is no way to brick a T4 that has no hardware issues. The warnings in FlasherX about bricking the device go back to the original Flasher, which was for T3.x, and the risk was associated with writing incorrect values to critical locations in the on-board flash that control boot-up. If those were written with incorrect values, the T3 would never again be able to boot up. As far as I know, that can't happen with T4 because it uses external flash, and the worst that can happen is to end up with an invalid program in flash, requiring the 15-second recovery process.
Sounds good Joe!

I use the standard simple example like this:

This code above and outside setup()
WDT_T4<WDT1> wdt;
WDT_timings_t config;

This code in the start of Setup to make sure it's always first. 2 seconds is good for me.
// WATCHDOG
config.timeout = 2;
wdt.begin(config);

Then obviously the feed function
In my loop, alltho it's not being called every loop, I have it set to every 50ms along with othere stuff.
I then have another function called "wdt_feed();" which I give to FlasherX as per my example above. wdt_feed() holds wdt.feed();
wdt.feed();
 
Hi

I try to understand this library. Most of the things are understandable. But I was not yet able to figure out, what this function does:
Code:
wdt.expired();
Is it usable in the loop function of my program, or is it just used by some other functions within the library itself?

Best regards
Simon
 
Hi

I try to understand this library. Most of the things are understandable. But I was not yet able to figure out, what this function does:
Code:
wdt.expired();
Is it usable in the loop function of my program, or is it just used by some other functions within the library itself?

Best regards
Simon
Simon,
Code:
wdt.expired();
This function returns a boolean value indicating if the LAST reset resulted from a watchdog timeout. If the last reset was due to power-on reset or software initiated reset (normal operations), this will return false. This could be useful in the setup or the loop function to perform additional diagnostics/repair to try to resolve the issue, potentially preventing a boot loop.
 
Back
Top