This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C1294NCPDT: Watchdog WDTLOAD fails in down counts

Guru 55913 points
Part Number: TM4C1294NCPDT
Other Parts Discussed in Thread: TM4C1294KCPDT

Hello,

I had the watchdog timer 0 enabled from migrated Stellaris code but TM4C1294 watchdog timer 0 has issues. For one writing WDTLOAD values lower than the current down count are just ignored. Tivaware uses = to write the value to WDTLOAD register value so values > the current WDLOAD are just ignored in the unlocked condition. Change Tiva function WDTLOAD write |= allows a greater timeout value to update watchdog 0 in the down counts. However, writes of lower WDTLOAD values will still be ignored. That is the errata condition as no shadow update ability and clearing WDTLOAD 0x0 triggers immediate interrupt.

Unless you use CCS debug to check the WDTLOAD register has changed after the unlocked register write event you would never know it did not and your hardware would Not be protected Flushed

Example: Changing WDTLOAD value from microseconds timeout to several seconds it can never be changed back to a lower value unless you run code snip below. This post informs TM4C1294 watchdog timer 0 has other undocumented errata. The code below can handle 2 defined WDTLOAD times to switch between or reduce the timeout once WDTLOAD has been set to greater value by Tivaware update writes WDTLOAD register via |= syntax.

      /* Unlock the Watchdodgs registers for write access */
      HWREG(WATCHDOG0_BASE + WDT_O_LOCK) = WDT_LOCK_UNLOCK;
      /* Time writes to WDTLOAD occurs below current down count value */ 
      while(HWREG(WATCHDOG0_BASE + WDT_O_VALUE) >= WATCHDOG0_HI_RELOAD_VALUE)
      {
          /* Reset Watchdog-0 for lower WDTLOAD write values */
          HWREG(WATCHDOG0_BASE + WDT_O_LOAD) = WATCHDOG0_MED_RELOAD_VALUE;
          /* Check ok to lock the WDog0 registers */
          if(HWREG(WATCHDOG0_BASE + WDT_O_LOAD) <= WATCHDOG0_MED_RELOAD_VALUE)
          {
              /* Lock the Watchdodg registers blocking write access. */
              HWREG(WATCHDOG0_BASE + WDT_O_LOCK) = WDT_LOCK_LOCKED;

              break;
          }
       }

  • Hello Gl,

    Tivaware uses = to write the value to WDTLOAD register value so values > the current WDLOAD are just ignored in the unlocked condition.

    I think you are confusing |= and = syntax for C code.

    Setting a register with an = syntax overwrites the entire register contents without care for what is inside of it at the time.

    Setting a register with |= as you are suggesting would preserve the current bits set as a '1' while writing any new '1' bits to the register. This would result in the new load value being a bitwise mix of the new value and the current value which the user would not be able to predict. I don't see why you would even bring that idea up.

    This post informs TM4C1294 watchdog timer 0 has other undocumented errata. The code below can handle 2 defined WDTLOAD times to switch between or reduce the timeout once WDTLOAD has been set to greater value by Tivaware update writes WDTLOAD register via |= syntax.

    Can you share your entire Watchdog update process? I have not been able to re-create this issue. I set the watchdog to be 5 seconds long, waited until the watchdog value was at 4 seconds and then just used WatchdogReloadSet to set it to 1 second and it updated and enters the Watchdog ISR at a 1 second interval without issue.

    Best Regards,

    Ralph Jacobi

  • Hi Ralph,

    Setting a register with an = syntax overwrites the entire register contents without care for what is inside of it at the time.

    Point still is C code has to poll the VDLOAD value to know when it is ok to load a lower WDLOAD value. Tivaware call to set watchdog WDLOAD register does not work if the WDLOAD value is set lower than the current down count, the = write is ignored. Seemingly WDLOAD register is intended to be reloaded at any time by SW calls, no mentions of load value down count time restrictions. Undocumented behavior leads engineers to believe the WDLOAD register can be changed at any time without regard of the current WDVALUE count. 

    Hence the |= is the only way to add more (binary) time to any WDLOAD count without polling the WDVALUE register is actually lower than the requested new or reduced count. That = only works if the initial WDLOAD value on POR (0x0) or has not changed. Since the timer never reloads a changed value on count zero or it would interrupt drive a reset on MCU. The WDLOAD register once the value is set, it cannot easily be reduced by call to Tivaware in SW functions. CCS debug indicated a much lower = value (333µs) was being ignored by the timer once increased to 6 seconds. The code snip times the new lower WDLOAD value to the current down count WDVALUE and pushes it into the current down count.   

    It's not a great idea to use code snip while loop in a function that is time sensitive. The code snip should only be used prior to exit of a non ISR reentrant function or in a call to reset WDLOAD register, as it is unpredictable may lock up the timer otherwise. Adding more time to WDLOAD binary value via |= works in ISR loops, the = does not!

    /* Unlock the Watchdogs registers for write access */
    HWREG(WATCHDOG0_BASE + WDT_O_LOCK) = WDT_LOCK_UNLOCK;

    // Set 200ms timeout, once set cannot easily be reduced
    HWREG(WATCHDOG0_BASE + WDT_O_LOAD) = WATCHDOG0_MED_RELOAD_VALUE;   

    /* Lock the Watchdog registers blocking write access. */
    HWREG(WATCHDOG0_BASE + WDT_O_LOCK) = WDT_LOCK_LOCKED;

  • Hello Gl,

    Point still is C code has to poll the VDLOAD value to know when it is ok to load a lower WDLOAD value. Tivaware call to set watchdog WDLOAD register does not work if the WDLOAD value is set lower than the current down count, the = write is ignored.

    As I said in my prior post, I cannot recreate this observation. I created an example designed around lowering the WDLOAD value and it worked properly.

    Provide your full watchdog implementation and I can try and re-create it with your specific code or identify what you are doing which is causing the issue and provide a resolution.

    There is no 'undocumented errata' at play here.

    Best Regards,

    Ralph Jacobi

  • As I said in my prior post, I cannot recreate this observation

    I can only say the debug simulator registers did not refresh with an update 6 second timeout reduced down to 333us by using = syntax on writes to WDLOAD register.

    It even failed to reload 6 second timeout down to 500ms. Once timeout was set to 6 seconds the timer refused to read the WDLAOD register for 333us or even 200ms without the while code snip. The timer while loops are in static functions able to switch between 2 load values on command watching the WDLOAD debug register.

    Why would the timer configuration have anything to do with loading the WDLOAD register?

    The only other thing setup changes is SYSCTRL reset behavior register and configures watch dog timer 1, disables the INT.

    Can I PM you the setup code?   

  • Hello Gl,

    I can only say the debug simulator registers did not refresh with an update 6 second timeout reduced down to 333us by using = syntax on writes to WDLOAD register.

    I wasn't looking at debug registers but rather observing board behavior with LED blink frequencies based on what reload value was used. I can try and see if I can recreate the refresh issue in debug but that wouldn't be an MCU issue then but an IDE issue. The MCU is clearly getting the new value and the timer is running accordingly.

    Why would the timer configuration have anything to do with loading the WDLOAD register?

    The example I put together is not using any lock / unlock features, seeing how you are using the WDT with those features could give me further elements to test and validate.

    Can I PM you the setup code?   

    Sure.

    Best Regards,

    Ralph Jacobi

  •  I'm rechecking what you mention though this issue was also occurring on TM4C1294KCPDT with B2B writes to WD1 and ISR disabled. Though the ISR function handles both dogs will be added to PM.

  • Hello Gl,

    So my initial question after reviewing what you sent is what is the Watchdog 0 initially set at and what are you trying to update it to be?

    I saw a commented out WatchdogReloadSet for Watchdog 0, but that was for WATCHDOG0_MED_RELOAD_VALUE. I was expecting to see one for WATCHDOG0_HI_RELOAD_VALUE?

    Best Regards,

    Ralph Jacobi

  • So my initial question after reviewing what you sent is what is the Watchdog 0 initially set

    Set in another function below 125m and downshifts the WDLOAD value via while loop, by GUI selection in this case. The high value is 1 second (snip) also set in another function that has while loop to reset back to 125ms. I retested calls in debug, Note I modified the while loop below >= to <=. You may be onto something about the locks or similar issue as B2B writes in second clock domain must poll the WD1 bit to know when it is safe to write WD1 registers.

    //*****************************************************************************
    //
    //! The watchdog timer reload value. 120Mhz/3k:333us,
    //! 120/10:100ms 120/8:125ms /5:200ms, "/2:500ms
    //! SYSCLK/1164=859us
    //
    //*****************************************************************************
    #define WATCHDOG0_LOW_RELOAD_VALUE            (g_ui32SysClock / 8) //125ms
    
    #define WATCHDOG0_MED_RELOAD_VALUE            (g_ui32SysClock / 5) //200ms
    
    #define WATCHDOG0_HI_RELOAD_VALUE             (g_ui32SysClock * 1) //1sec
    
    //*****************************************************************************
    
            /* Set the WDOG0 registers for write access */
            HWREG(WATCHDOG0_BASE + WDT_O_LOCK) = WDT_LOCK_UNLOCK;
            /* Time WDLOAD occurs below current value of the down count */
            while(HWREG(WATCHDOG0_BASE + WDT_O_VALUE) >= WATCHDOG0_LOW_RELOAD_VALUE)//125ms
            {
                /* Reset the Watchdog 125ms for precharge PWM ISR events */
                HWREG(WATCHDOG0_BASE + WDT_O_LOAD) = WATCHDOG0_LOW_RELOAD_VALUE;
                /* Check ok to lock the WDog0 registers */
                if(HWREG(WATCHDOG0_BASE + WDT_O_LOAD) <= WATCHDOG0_LOW_RELOAD_VALUE)
                {
                  /* Lock the Watchdog registers blocking write access. */
                  HWREG(WATCHDOG0_BASE + WDT_O_LOCK) = WDT_LOCK_LOCKED;
    
                  break;
                }
             }
             
         
             /* Unlock the Watchdodgs registers for write access */
             HWREG(WATCHDOG0_BASE + WDT_O_LOCK) = WDT_LOCK_UNLOCK;
            // Set watchdog 1 second for a slower motor startup sequence
            HWREG(WATCHDOG0_BASE + WDT_O_LOAD) = WATCHDOG0_HI_RELOAD_VALUE;
            /* Lock the Watchdodg registers blocking write access. */
            HWREG(WATCHDOG0_BASE + WDT_O_LOCK) = WDT_LOCK_LOCKED;
    .

  • Hello Gl,

    Using your entire Watchdog configuration, I was able to successfully write lower load values into the Watchdog timer as long as the timer was unlocked first. I used MAP_WatchdogUnlock and then immediately did a MAP_WatchdogReloadSet without any issues. Maybe at a certain level of optimization you need a few more cycles of delay but using those two sequentially for me worked to set a higher load value to a lower one. In my case I was going from a 5 second Watchdog to a 1 second watchdog.

    So your setup seems to be fine and I think you'll need to debug exactly how and when you are trying to change the load values and make sure those changes are being properly applied in your system.

    Best Regards,

    Ralph Jacobi

  • Hi Ralph,

    Using your entire Watchdog configuration, I was able to successfully write lower load values into the Watchdog timer as long as the timer was unlocked first.

    Yet my application reloads the timer 125ms during 333us ADC ISR function and in another GPTM timer ISR again writes WDLOAD register. Doing B2B writes WDLOAD register during two ISR events even at very low register 0 and speed 1 optimization had issues flip flopping load values on the fly.

    After posting this I made a tradeoff and stopped flipflopping time values, on the fly. Yet even the static calls WDLOAD would not write the lower 125ms after it was set for 1 second. That is because the ADC ISR is still running during idle mode, punching the dog 333us intervals. Again B2B writes to WDLOAD during ISR event seems to stop application from writing a lower value without my while loop patches being applied during idle mode.