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.

TM4C1294KCPDT: SysCtlClockFreqSet changing OSCCLK

Part Number: TM4C1294KCPDT

I have a question about SysCtlClockFreqSet when configuring to use the PLL with the MOSC as its source. I see that the function does the following in that case:

  1. Power up the MOSC
  2. Set OSCSRC to PIOSC
  3. A quick calculation
  4. Set both OSCSRC and PLLSRC to MOSC
  5. Configure PLL and wait for PLL lock. On timeout return error.
  6. Change SYSCLK from OSCCLK to PLL.
  7. Set OSCSRC to PIOSC (added later to address errata SYSCTL#23)

I'm wondering why OSCSRC is changed to MOSC in #4 and if it's really necessary. I don't see any obvious purpose. It also seems strange to change to PIOSC and then almost immediately change to MOSC. Perhaps the second change was only intended to change PLLSRC? The errata seems to support this: "It sets the OSCCLK as MOSC which is not required".

This probably wouldn't matter in a typical system with a crystal, but I have a clock source that may take some time to come up. I do have something in place to delay calling SysCtlClockFreqSet until after the clock is ready, but I suspect that that may be failing on occasion.

I had originally expected a dead clock input to result in a timeout waiting for PLL lock in #5, but it seems that I missed the second change to OSCSRC in #4 which kills the CPU first. There is some opportunity to recover from that with a watchdog timer, but a timeout error would be more flexible. Also, a watchdog reset at that point is pretty much indistinguishable from a watchdog reset later on in application code and that makes debugging more difficult.

At the moment I'm trying to track down a rare WDT reset shortly after startup. If I can ever reproduce it, I'd like to know if it was during the clock switchover. To that end I've modified SysCtlClockFreqSet to stay on PIOSC until switching to the PLL. It seems to work fine, and I now get a specific error instead of a WDT reset if SysCtlClockFreqSet is called while the clock input is dead. I am a bit worried about possible unintended consequences. Are there any known issues this change could trigger?

int main(void)
{
    WaitForFpgaToSignalThat25MHzClockIsReady();
    EnableWatchdog(1000 /*ms*/); // reset occurs after 2 timeouts

    uint32_t clockFreq = SysCtlClockFreqSet(
        SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480,
        CPU_CLOCK_HZ // 120 MHz
    );
    if (clockFreq != CPU_CLOCK_HZ)
    {
        // This is supposed to handle PLL lock failures.
        // With stock SysCtlClockFreqSet, it's not triggered if the clock
        // input is dead (and the wait is bypassed). In that case a watchdog
        // reset occurs.
        LogError(CLOCK_FAIL);
        SystemReset();
    }

    if (ResetCauseIsWatchdog())
        LogError(WATCHDOG);
    ClearResetCause();

    DisplayLoggedErrors();
    RunApplication();
}

  • BB_ said:
    To that end I've modified SysCtlClockFreqSet to stay on PIOSC until switching to the PLL.

    Hello BB_,

    My opinion is PIOSC should never be the main clock source when external XTAL exists or MOSC has been previously powered up. It seems we have similar issue and was wondering what version of driver lib you are running? I'm using 21171 versus newer 214178 that rudely changes previous Tivaware version PYSDIV bit and PLL frequency divisor register settings.

     

    BB_ said:
    At the moment I'm trying to track down a rare WDT reset shortly after startup. I

    Have you by chance enabled the project Hold watchdog under ARM linker settings?

  • I understand what you are doing and why, but your fears are justified. A lot of effort went into crafting the SysCtlClockFreqSet() function as there are rare intermittent issues when setting the clock dividers for the different clock domains. The switching between MOSC and PIOSC is not arbitrary. While your modified routine will likely work most of the time, on rare instances one of the clock settings may not write properly and the device could lock up.
    As an alternative, consider dedicating a static variable that is set as a flag to indicate your are setting the PLL. If a watchdog reset occurs, check that flag to see if you were in the critical portion of code setting the PLL frequency.

  • Wonderfully detailed - both by poster & vendor!

    Vendor's alternative - although inspired & resourceful - (appears) to be vulnerable to, 'Watchdog Reset potentially being 'in process' (minutely prior) to that 'flag-set!'    (thus (maybe) invalidating that safety mechanism - is that not true?) 

    Clearly anticipating - and overcoming - SO MANY 'Exacting Clock Domain DEMANDS' - proves an 'extreme (often on-going) challenge.'

  • Hi CB1,

    Let me expand on that just a bit. What I suggest is setting a "flag" before calling SysCtlClockFreqSet() and clearing that flag after that function completes. If you get a watchdog reset and that flag is "set", then you are reasonably assured that the watchdog reset occurred during that function call. It is true that it is possible the watchdog reset occurs before setting the flag, but then the root cause would be different than the SysCtlClockFreqSet() function.

  • Hi Bob,

    Thank you - much appreciated.

    Now it is well noted - by several here - that the 'SysCtlClockFreqSet()' has, 'Set Near Records for'

    • number of times vendor has updated, modified, extended, corrected
    • size - the extent of the code is vast
    • potential for mayhem

    I accept your, 'in depth description' especially as you have 'allowed for a 'race or near-race' condition (hedge alert) - earlier noted.

    Staff/I 'assume' that 'internal debate waged' over the, 'Depth & Breadth' - demanded by the use of a, 'SINGLE, MCU Clock-Set Function!'

  • BP101 said:
    It seems we have similar issue and was wondering what version of driver lib you are running? I'm using 21171 versus newer 214178 that rudely changes previous Tivaware version PYSDIV bit and PLL frequency divisor register settings.

    2.1.4.178 - the latest one

    BP101 said:
    Have you by chance enabled the project Hold watchdog under ARM linker settings?

    It doesn't seen like something you can accidentally enable for ARM targets since apparently you need to define WDTCTL_SYM for it to work, but no, it's unspecified (off). I don't enable the watchdog until after reaching main. 

  • Bob Crosby said:
    As an alternative, consider dedicating a static variable that is set as a flag to indicate your are setting the PLL. If a watchdog reset occurs, check that flag to see if you were in the critical portion of code setting the PLL frequency.

    That does seem like a safer alternative. Thanks.