Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 5 of 5

Thread: Teensy 3.6 watchdog Timer ISR not firing

Hybrid View

  1. #1
    Junior Member
    Join Date
    Aug 2017
    Posts
    5

    Teensy 3.6 watchdog Timer ISR not firing

    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...dog-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

  2. #2
    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

  3. #3
    Member
    Join Date
    Aug 2013
    Location
    Ohio
    Posts
    88
    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.

  4. #4
    Junior Member
    Join Date
    Aug 2017
    Posts
    5
    Quote Originally Posted by LenSamuelson View Post
    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

  5. #5
    Member
    Join Date
    Aug 2013
    Location
    Ohio
    Posts
    88
    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;
        }
      }
    
    }

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •