Teensy 3.6 watchdog Timer ISR not firing

Status
Not open for further replies.

Rotario

Member
Hi,

I've set up the watchdog using startup_early_hook and enabled the ISR with NVIC_ENABLE)_IRQ but the isr still isn't firing, I'm using a teensy 3.6.

There's another thread here https://forum.pjrc.com/threads/41339-Different-Watchdog-timer-ISRs
but the isr problem isn't solved.

Can anyone try this on theirs to replicate the problem?
Find the program below

Code:
//taken from https://forum.pjrc.com/threads/25370-Teensy-3-0-Watchdog-Timer
#include <EEPROM.h>

#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

void kickDog() {
  Serial.println("Kicking the dog");
  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");
}

void watchdog_isr(){
 EEPROM.update(1024, 156);
}

#ifdef __cplusplus
extern "C" {
#endif
  void startup_early_hook() {
    uint16_t toval = 1000;
    WDOG_TOVALL = 1000; //Abt a minute
    WDOG_TOVALH = 0;
    WDOG_STCTRLH = (WDOG_STCTRLH_ALLOWUPDATE | WDOG_STCTRLH_WDOGEN | WDOG_STCTRLH_WAITEN | WDOG_STCTRLH_STOPEN | WDOG_STCTRLH_IRQRSTEN); // Enable WDG
    NVIC_ENABLE_IRQ(IRQ_WDOG);
    //WDOG_PRESC = 0; // prescaler
  }
#ifdef __cplusplus
}
#endif



void setup() {
  
  Serial.begin(9600);
  while (!Serial);
  while (Serial.available());

  Serial.printf("EEPROM 1024 = %u\n", EEPROM.read(1024));

  printResetType();

}

uint32_t dogTimer = 0;

void loop() {

  if (millis() - dogTimer > 1000){
    dogTimer = millis();
    kickDog();
  }
  
  if (Serial.available()){
    int c = Serial.parseInt();
    switch(c){
      case 150:
        Serial.printf("Hang at %lu\n", millis());
        kickDog();
        while(1);
    }
  }

}

Thanks,
Rowan
 
Hey Rotario,

I never got to the bottom of this one sadly. I ended up spoofing the behaviour using another hardware timer to check a boolean value, and if it hadn't been reset it performed my ISR and then reset the board. It's a Pseudo WDT in effect.
While not a true WDT, it seemed to behave the same way.
Hopefully someone else can chime in with something more helpful!

Ed
 
On a project that does not use the Teensyduino code, I have been successful in using the watchdog interrupt to great effect, using the ISR to store some state before the reset happens.

I had code that unlocked the watchdog, then set the interrupt bit. Subsequent checking of the watchdog registers showed that the interrupt was not enabled, as if my setup code had never executed. It took a ton of digging but I learned that the embedded OS that we use left the watchdog in a way that prevented it from being unlocked. The RTOS did not set the WDOG_STCTRLH_ALLOWUPDATE bit during its watchdog setup, so my code had no effect. Fixing the RTOS code to set the WDOG_STCTRLH_ALLOWUPDATE bit did the trick for me.

Separate but maybe important:

In your early hook code I do not see the watchdog unlock sequence. That is necessary for operating on the watchdog registers. The unlock code and subsequent register manipulation code should not be interrupted since the unlock sequence is time sensitive.
 
On a project that does not use the Teensyduino code, I have been successful in using the watchdog interrupt to great effect, using the ISR to store some state before the reset happens.

I had code that unlocked the watchdog, then set the interrupt bit. Subsequent checking of the watchdog registers showed that the interrupt was not enabled, as if my setup code had never executed. It took a ton of digging but I learned that the embedded OS that we use left the watchdog in a way that prevented it from being unlocked. The RTOS did not set the WDOG_STCTRLH_ALLOWUPDATE bit during its watchdog setup, so my code had no effect. Fixing the RTOS code to set the WDOG_STCTRLH_ALLOWUPDATE bit did the trick for me.

Separate but maybe important:

In your early hook code I do not see the watchdog unlock sequence. That is necessary for operating on the watchdog registers. The unlock code and subsequent register manipulation code should not be interrupted since the unlock sequence is time sensitive.

Hi Len,
There's no need to put the unlock sequence, as the startup early hook runs inside the WCT (Watchdog config time) at startup, I've added it anyway, and no change! I think your solution would work if I wasn't able to change any watchdog parameters but I'm changing the timeout value fine. It could possibly be a priority issue?

I hope someone can maybe chip in, because it's easily reproducible on any 3.6 without hardware

Thanks,
Rowan
 
Hi Rowan,

It turns out that my project at work is just finishing a design using an MK66 part, so I am interested in starting to use an MK66... I was a Kickstarter backer for the Teensy 3.6, and have two of them in my toolbox.

I grabbed the original code from your first post, and modified it to use a convenient set of registers, VBAT_REGS, which predictably survive resets and probably are not used by Teensy library code (...not defined in Teensy header files...). My intent for making the change is to ensure that the ISR executes in less than 256 clocks.

The good news is that your original setup is just fine, even without the unlock sequence, as you described in your most recent post. The possibly disappointing news is that storing anything in EEPROM in the ISR takes too long, and almost certainly won't be recorded.

The Kinetis parts have a rule that there are only 256 clock cycles (I think I remember it's bus cycles, not sure...) between firing the interrupt and the reset. It appears that your original code tries to write a value to an EEPROM, and I expect that to take way more than 256 bus cycles. I have attached a capture of an interaction between a minicom session and the T3.6 directly below, and included the code that produced that session further down.

The way I got around the limitation for our firmware project was to reserve a block of memory in the linker control file. During the watchdog ISR, store a few carefully considered bits of state, along with validation information in that reserved area. On waking up after the reset, firmware validates the reserved block and if valid, copies it to a comfortable place in normal working memory for subsequent reporting. Clearing the exception block to prepare it for subsequent use is probably a good idea.

Here is the recorded sequence of events is from my little demo:

  • Start
  • (at 7 seconds) enter "H" to force watchdog reset
  • Reset occurs
  • At 3 seconds after restart, query the VBAT register showing "7"
  • At 11 seconds, query the reset reason, which is the watchdog reset


Code:
Kicking the dog 0
Kicking the dog 1
Kicking the dog 2
Kicking the dog 3
Kicking the dog 4
Kicking the dog 5
Kicking the dog 6
Hang at 7
Kicking the dog 0
Kicking the dog 1
Kicking the dog 2
Kicking the dog 3
Query VB[0] = 7
Kicking the dog 4
Kicking the dog 5
Kicking the dog 6
Kicking the dog 7
Kicking the dog 8
Kicking the dog 9
Kicking the dog 10
Kicking the dog 11
[RCM_SRS0] - Watchdog(COP) Reset
Kicking the dog 12

Feel free to use whatever you learn from this code block, it's officially "public domain".

Code:
//taken from https://forum.pjrc.com/threads/25370-Teensy-3-0-Watchdog-Timer

#if !defined(RCM_SRS0_WAKEUP)
#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
#endif

volatile uint32_t* VBAT_REGS = (uint32_t*)0x4003e000;

uint32_t kickCounter = 0;

void kickDog() {
  Serial.printf("Kicking the dog %lu\r\n", kickCounter);
  noInterrupts();
  WDOG_REFRESH = 0xA602;
  WDOG_REFRESH = 0xB480;
  interrupts();
  kickCounter += 1;
}

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");
}

void watchdog_isr(){
 VBAT_REGS[0] = kickCounter;
}

#ifdef __cplusplus
extern "C" {
#endif
  void startup_early_hook() {
    uint16_t toval = 1000;
    WDOG_TOVALL = 1000; //Abt a minute
    WDOG_TOVALH = 0;
    WDOG_STCTRLH = (WDOG_STCTRLH_ALLOWUPDATE | WDOG_STCTRLH_WDOGEN | WDOG_STCTRLH_WAITEN | WDOG_STCTRLH_STOPEN | WDOG_STCTRLH_IRQRSTEN); // Enable WDG
    NVIC_ENABLE_IRQ(IRQ_WDOG);
    //WDOG_PRESC = 0; // prescaler
  }
#ifdef __cplusplus
}
#endif



void setup() {
  
  Serial.begin(9600);
  while (!Serial);
  while (Serial.available());
}

uint32_t dogTimer = 0;

void loop() {

  if (millis() - dogTimer > 1000){
    dogTimer = millis();
    kickDog();
  }
  
  if (Serial.available()){
    int c = Serial.read();
    switch(c){
      case 'H':
        kickDog();
        Serial.printf("Hang at %lu\r\n", kickCounter);
        while(1);
        break;
      case 'R':
        printResetType();
        break;
      case 'S':
        Serial.printf("Saving kickCounter at %lu\r\n", kickCounter);
        VBAT_REGS[0] = kickCounter;
        break;
      case 'Q':
        Serial.printf("Query VB[0] = %lu\r\n", VBAT_REGS[0]);
        break;
    }
  }

}
 
Status
Not open for further replies.
Back
Top