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:
- Power up the MOSC
- Set OSCSRC to PIOSC
- A quick calculation
- Set both OSCSRC and PLLSRC to MOSC
- Configure PLL and wait for PLL lock. On timeout return error.
- Change SYSCLK from OSCCLK to PLL.
- 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(); }