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.

TM4C129ENCPDT: Clock Watchdog1 from RTCOSC via ALTCLK?

Part Number: TM4C129ENCPDT

I'm having trouble getting the Watchdog 1 peripheral to become Ready after Enable when clocked by the RTCOSC.

Watchdog 0 has a maximum timeout before Reset of about 72 seconds. Some of our functions take longer than that. Thus the desired for Watchdog 1.

Watchdog 1 is clocked from ALTCLK, which can select between the 16 MHz Precision Internal Oscillator, Hibernation Module 32.768 kHz Real-Time Clock Oscillator, or the Low-Frequency Internal Oscillator (also 33 kHz).

Testing with ALTCLK pointed to the PIOSC works fine, but the maximum timeout before Reset is 8.9 minutes, and that's a little shy of our 10-minute goal. It seems like the 32.768 kHz ALTCLK source would be best. However, enabling RTCOSC before starting Watchdog 1 results in that peripheral never starting! The code hangs on SysCtlPeripheralReady(SYSCTL_PERIPH_WDOG1).

I'm wondering what steps I might be missing to enable the RTC to drive WDOG1. I have confirmed that the Hibernate example runs, which seems to indicate that the crystal on my LaunchPad is working.

Here's the startup code:

    SysCtlPeripheralEnable(SYSCTL_PERIPH_HIBERNATE);
    while (!SysCtlPeripheralReady(SYSCTL_PERIPH_HIBERNATE))
        ;
    HibernateEnableExpClk(32768);   // parameter value is not used
    // allow time for the crystal to stabilize
    HibernateClockConfig(HIBERNATE_OSC_LOWDRIVE);
    HibernateRTCEnable();
    HibernateCounterMode(HIBERNATE_COUNTER_RTC);
    UARTprintf("Hibernation module is%s active\n", HibernateIsActive() ? "" : " not");
    SysCtlAltClkConfig(SYSCTL_ALTCLK_RTCOSC);
    SysCtlResetBehaviorSet(SYSCTL_ONRST_WDOG1_POR);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_WDOG1);
    while (!SysCtlPeripheralReady(SYSCTL_PERIPH_WDOG1))
        ;

  • I think the problem is in enabling the Watchdog peripheral after switching the alternate clock to 32KHz. Try doing the clock switch after enabling the peripheral.

        SysCtlPeripheralEnable(SYSCTL_PERIPH_HIBERNATE);
        while (!SysCtlPeripheralReady(SYSCTL_PERIPH_HIBERNATE));
        HibernateEnableExpClk(32768);   // parameter value is not used
        // allow time for the crystal to stabilize
        HibernateClockConfig(HIBERNATE_OSC_LOWDRIVE);
        HibernateRTCEnable();
        HibernateCounterMode(HIBERNATE_COUNTER_RTC);
        SysCtlResetBehaviorSet(SYSCTL_ONRST_WDOG1_POR);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_WDOG1);
        while (!SysCtlPeripheralReady(SYSCTL_PERIPH_WDOG1));
        SysCtlAltClkConfig(SYSCTL_ALTCLK_RTCOSC);
    

    Remember that writes to the Watchdog 1 register require polling the WRC bit of the WDTCTL register. This is not done automatically in the TivaWare functions.

  • Thank you for the suggestion. I had assumed that the clock should be selected first, but I can see how it might need to be the last step, rather than the first. I will give that a try and see if it helps.

    By the way, I did insert WRC bit polling before every Watchdog*() function call. Here, in the cited code, I assume that the SysCtl*() functions do not need to poll that bit. If that's not the case, let me know.

  • I tried the suggestion, but it did not work.

    I moved the ALTCLK select after waiting for WDOG1 to be Ready. There was a slight improvement, because now the WRC bit does go high, meaning that the peripheral is completing operations. However, the watchdog does not actually trigger a reset.

    In my firmware, I use compiler directives to select between LFIOSC and RTCOSC, since they're both at the same nominal rate. With LFIOSC and a count of 0x28000, I see a 10-second delay before reset. With RTCOSC and the same count, the watchdog never fires.

    Perhaps I need a way to confirm that the RTC has indeed started.

  • Hi Brian,

      Bob is out of office. I will try to help you here. 

      Can you monitor the WDTVALUE register and see if the counter is decrementing?

     Can you for experiment purpose generate interrupt instead of reset when timeout? Do you see the interrupt? I'm wondering if the issue is related only to the reset generation. 

     Can you take a screenshot of the WD1 registers dump?

  • Hi Brian,

      I have not heard back from you. Is your issue resolved? I will close this thread for now. If your issue is not resolved, you can just reply back to this post to reopen the thread. 

  • Hi Charles,

    With RTCOSC selected, the WDTVALUE, obtained via WatchdogValueGet(WATCHDOG1_BASE), is stuck at 0xFFFFFFFF.

    Enabling the interrupt changes nothing. I assume this is because the Watchdog peripheral never reaches the Write Complete state, so none of its functions are working.

    A screenshot of WD1 registers follows:

  • Hi Bob,

    I tried moving SysCtlAltClkConfig() to be called after SysCtlPeripheralReady(), as you suggested. No change in behavior.

    The symptom is that WRC (write complete) is never set after the ALTCLT_RTCOSC is selected. I have tested that code for correctness when using ALTCLK_LFIOSC, so I know there isn't any problem with the code. In fact, LFIOSC and RTCOSC should be running at approximately the same rate, so the code should be looping for the same number of cycles in each case.

  • See screenshot and other answers in my other post.

  • Hi Brian,

      I see your screenshot. Looks to me that it is not the watchdog module issue but rather the RTC clock is not starting or the RTC clock is somehow not fed to the watchdog module. The Watchdog takes whatever ALTCLK that is fed to it. It works with LFIOSC or PIOSC. This means the Watchdog is counting whenever the ALTCLK is available and ticking. This also means the mux as shown below is correctly steering the selected alternate clock source. 

      Can you use the scope to measure the 32.768kHz OSC on the LaunchPad? 

      One thing I forgot to ask is you are seeing the same problem on both the LaunchPad and your custom board?

  • Hi Charles,

    I had similar concerns, but I have run the hibernate example to prove that the RTC crystal is working. I also made a point of ensuring that all of the initialization and setup for the Hibernate peripheral exists in my watchdog firmware. My firmware doesn't call HibernateIsActive(), but that shouldn't matter. I am using HibernateCounterMode(HIBERNATE_COUNTER_RTC) instead of *_24HR; hopefully that should pose any issues.

    I assume that there are no GPIO ports that need to be enabled for the RTC to function. The pins for the 32.768 kHz crystal are dedicated pins, right? ... not GPIO that need to be selected for RTC function?

    Yes, the problem is the same on the LaunchPad and our custom TM4C boards.

  • Hi Brian,

      . To use the 32K clock as the alternate clock source you would need to enable Hibernate module and then start the clocking by setting HIBCTL.CLK32EN bit. Below is a piece of code to enable the RTC counter. It looks similar to yours. What is different is that you didn't enable the hibernate module. Can you call the SysCtlPeripheralEnable(SYSCTL_PERIPH_HIBERNATE) to see if that makes a difference?

      Since you said you have the RTC working in the hibernate example, could you for experimental purpose incorporate the watchdog code into the hibernate example to see if the watchdog counter is decrementing? 

        //
        // Enable the hibernate module.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_HIBERNATE);
    
        //
        // Enable the Hibernation module for operation.
        //
        HibernateEnableExpClk(0);
    
        //
        // Wait for 32.768kHz clock to stabilize.
        //
        while(!(HWREG(HIB_RIS) & HIB_RIS_WC));
    
        //
        // Configure the drive strength for the crystal.
        //
        HibernateClockConfig(HIBERNATE_OSC_LOWDRIVE);
    
        //
        // Enable the Hibernate module RTC mode.
        //
        HibernateRTCEnable();

  • Good suggestions.

    I already have the SysCtlPeripheralEnable(SYSCTL_PERIPH_HIBERNATE) call, as shown in the source quoted in my opening message.

    I had a comment about waiting for the clock to stabilize, but didn't have any code for that. Thanks for the example. I incorporated this, but it did not enable things to work.

    I will work on adding the watchdog to the working hibernate example. That should prove interesting.

  • Hi Brian,

      Do you have some update?

  • Hi Charles,

    I apologize for the delay. We have a national holiday here in the US.

    I added the same watchdog code to the hibernate example, but the code still times out waiting for the WRC bit to be set.

    Perhaps Texas Instruments could provide an example CCS project demonstrating the Watchdog 1 peripheral with the RTC source. Then, if your code works for you, I should be able to run the same code on the LaunchPad and compare the performance with my code.

    Brian

  • Hi Brian,

      Let me take a look and I will get back with you.

  • Hi Brian,

      I have spent quite some time trying to get the WDG1 to run off the RTC clock but I'm not successful. It seems to me the RTC is not propagated to the WDG1 module. I'm successful using either PIOSC or LFIOSC as the clock source for the WDG1. I even try to use RTC as the source for the Timer module but unfortunately I can't get it to work either. Actually I have locked out my board by doing do. Perhaps it is a hardware issue which I'm still looking into. I will have discussion with my colleagues as well. In the meantime, I will suggest you use the LFIOSC if that meets your requirement as an interim solution. 

  • Thank you, Charles. My results are identical. You'll even find another thread on the forum here where I sought help recovering my board after it was locked out! Thankfully, I was able to recover the board.

    We're currently using the LFIOSC, but there's a lot of variation since that oscillator specification ranges from 10 kHz to 75 kHz! The 32.768 kHz crystal would be superior, of course, but we can make do with the less accurate internal oscillator so long as we allow for a 7.5x variation between minimum and maximum.

    Brian

  • Hi Brian,

      Glad to hear that LFIOSC would meet your requirement although not ideal. I have found the below errata pertaining to the Timer module problem I'm facing. I'm guessing more or less the RTCOSC issue with the Timer module may manifest to others as well. Please let me know if you have an issue with me to close this thread for now. If I have additional findings I will update the thread again. 

  • Hi Brian,

      I have some update. What is missing in your code is that you did not output the hibernate clock to the system although you enable the hibernate clock. I happen to stumble on this too. This is why I don't see the RTC going to the watchdog module. Once I enable it, it is all good.  What you need is the HWREG(HIB_CC) = 0x1. 







    //*****************************************************************************
    //
    // watchdog_rtcosc.c - Watchdog timer example.
    //
    // Copyright (c) 2013-2017 Texas Instruments Incorporated.  All rights reserved.
    // Software License Agreement
    // 
    // Texas Instruments (TI) is supplying this software for use solely and
    // exclusively on TI's microcontroller products. The software is owned by
    // TI and/or its suppliers, and is protected under applicable copyright
    // laws. You may not combine this software with "viral" open-source
    // software in order to form a larger program.
    // 
    // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
    // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
    // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
    // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
    // DAMAGES, FOR ANY REASON WHATSOEVER.
    // 
    // This is part of revision 2.1.4.178 of the EK-TM4C1294XL Firmware Package.
    //
    //*****************************************************************************
    
    #include <stdint.h>
    #include <stdbool.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include <time.h>
    #include "inc/hw_hibernate.h"
    #include "driverlib/debug.h"
    #include "driverlib/fpu.h"
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/hibernate.h"
    #include "driverlib/watchdog.h"
    #include "driverlib/rom.h"
    #include "driverlib/rom_map.h"
    #include "drivers/buttons.h"
    #include "driverlib/hibernate.h"
    
    //*****************************************************************************
    //
    //! \addtogroup example_list
    //! <h1>Watchdog (watchdog)</h1>
    //!
    //! This example application demonstrates the use of the watchdog as a simple
    //! heartbeat for the system.  If the watchdog is not periodically fed, it will
    //! reset the system.  Each time the watchdog is fed, the LED is inverted so
    //! that it is easy to see that it is being fed, which occurs once every
    //! second.  To stop the watchdog being fed and, hence, cause a system reset,
    //! press the SW1 button.
    //
    //*****************************************************************************
    
    //****************************************************************************
    //
    // System clock rate in Hz.
    //
    //****************************************************************************
    uint32_t g_ui32SysClock;
    
    //*****************************************************************************
    //
    // Flag to tell the watchdog interrupt handler whether or not to clear the
    // interrupt (feed the watchdog).
    //
    //*****************************************************************************
    volatile bool g_bFeedWatchdog = true;
    
    //*****************************************************************************
    //
    // The error routine that is called if the driver library encounters an error.
    //
    //*****************************************************************************
    #ifdef DEBUG
    void
    __error__(char *pcFilename, uint32_t ui32Line)
    {
    }
    #endif
    
    //*****************************************************************************
    //
    // The interrupt handler for the watchdog.  This feeds the dog (so that the
    // processor does not get reset) and winks the LED connected to GPIO B3.
    //
    //*****************************************************************************
    void
    WatchdogIntHandler(void)
    {
        //
        // If we have been told to stop feeding the watchdog, return immediately
        // without clearing the interrupt.  This will cause the system to reset
        // next time the watchdog interrupt fires.
        //
        if(!g_bFeedWatchdog)
        {
            return;
        }
    
        //
        // Clear the watchdog interrupt.
        //
        ROM_WatchdogIntClear(WATCHDOG1_BASE);
    
        //
        // Invert the GPIO PN0 value.
        //
        ROM_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0,
                         (ROM_GPIOPinRead(GPIO_PORTN_BASE, GPIO_PIN_0) ^
                                         GPIO_PIN_0));
    }
    
    //*****************************************************************************
    //
    // This function is called when the SW1 button is pressed.
    //
    //*****************************************************************************
    static int32_t
    SW1ButtonPressed(void)
    {
        //
        // Set the flag that tells the interrupt handler not to clear the
        // watchdog interrupt.
        //
        g_bFeedWatchdog = false;
    
        return(0);
    }
    
    //*****************************************************************************
    //
    // This example demonstrates the use of the watchdog timer.
    //
    //*****************************************************************************
    int
    main(void)
    {
        //
        // Set the clocking to run directly from the crystal at 120MHz.
        //
        g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
                                                 SYSCTL_OSC_MAIN |
                                                 SYSCTL_USE_PLL |
                                                 SYSCTL_CFG_VCO_480), 120000000);
        //
        // Setup PD1 as input pin with internal pullup enabled. Only when PD1 is
        // connected to ground will allow the code to continue execution.
    
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
        while(!(SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOD)));
        GPIOPinTypeGPIOInput(GPIO_PORTD_BASE, GPIO_PIN_1);
        GPIOPadConfigSet(GPIO_PORTD_BASE, GPIO_PIN_1, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);
    
        // wait here while PD1 is high. Need to connect PD1 to GND to continue the rest of
        // code execution. This is to prevent the device from being locked out unable to connect.
        while (GPIOPinRead(GPIO_PORTD_BASE, GPIO_PIN_1));
    
        //
        // Initialize the buttons driver.
        //
        ButtonsInit();
    
        //
        // Enable the peripherals used by this example.
        //
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_WDOG1);
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);
    
        //
        // Enable processor interrupts.
        //
        ROM_IntMasterEnable();
    
        //
        // Set GPIO PN0 as an output.  This drives an LED on the board that will
        // toggle when a watchdog interrupt is processed.
        //
        ROM_GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_0);
        ROM_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0, 0);
    
        //
        // Enable the watchdog interrupt.
        //
        ROM_IntEnable(INT_WATCHDOG);
    
        //
        // Set the period of the watchdog timer to 1 second. The ALTCLK
        // is the RTCOSC which is 32.768kHz. Load 32668 to the watchdog
        // reload register for one second timeout
        //
        WatchdogReloadSet(WATCHDOG1_BASE, 32768);
        //
        // Enable reset generation from the watchdog timer.
        //
        ROM_WatchdogResetEnable(WATCHDOG1_BASE);
    
        // Enable stall during debug mode
        WatchdogStallEnable(WATCHDOG1_BASE);
    
        //
        // Enable the hibernate module.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_HIBERNATE);
    
        //
        // Enable the Hibernation module for operation.
        //
        HibernateEnableExpClk(0);
    
        //
        // Wait for 32.768kHz clock to stabilize.
        //
        while(!(HWREG(HIB_RIS) & HIB_RIS_WC));
    
        //
        // Configure the drive strength for the crystal.
        //
        HibernateClockConfig(HIBERNATE_OSC_LOWDRIVE);
    
        //
        // Enable Hibernate RTC clock (32.768kHz) to output to the
        // the system.
        //
        HWREG(HIB_CC) = 0x1;
    
        //
        // Enable the Hibernate module RTC mode.
        //
        HibernateRTCEnable();
    
        //
        // Load initial RTC value.
        //
        HibernateRTCSet(0);
    
        //
        // Configure RTCOSC as the alternate clock source
        //
        SysCtlAltClkConfig(SYSCTL_ALTCLK_RTCOSC);
    
        //
        // Enable the watchdog timer.
        //
        ROM_WatchdogEnable(WATCHDOG1_BASE);
    
        //
        // Loop forever while the LED winks as watchdog interrupts are handled.
        //
        while(1)
        {
            //
            // Poll for the select button pressed
            //
            uint8_t ui8Buttons = ButtonsPoll(0, 0);
            if(ui8Buttons & USR_SW1)
            {
                SW1ButtonPressed();
                while(1)
                {
                }
            }
        }
    }

  • Thanks, Charles, this worked!

  • Hi Brian,

      I just wanted to let you know that you could use the API to output the RTC clock to the system as follows instead of writing to the HIB_CC register manually. 

    HibernateClockConfig(HIBERNATE_OSC_LOWDRIVE | HIBERNATE_OUT_SYSCLK );