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.

For SYSCTL#22 and #23 in TM4C129x Silicon Errata

Hello,

For SYSCTL#22 and #23 in TM4C129x Silicon Errata(SPMZ850E),
I understand need to update the SysCtlClockFreqSet API as shown in Appendix 3.

But if PLLFREQ1 is set to Q=0, we must apply the Appendix 3?

Appendix 3  add code:
1. #define PLL_Q_TO_REG(q)                                                    \
        ((uint32_t)(q - 1) << SYSCTL_PLLFREQ1_Q_S)

2. HWREG(SYSCTL_PLLFREQ1) |=
  g_pppui32XTALtoVCO[i32VCOIdx][i32XtalIdx][2];

3. //
 // Finally change the OSCSRC back to PIOSC
 //
 HWREG(SYSCTL_RSCLKCFG) &= ~(SYSCTL_RSCLKCFG_OSCSRC_M);

Appendix 3  Change code:
1.static const uint32_t g_pppui32XTALtoVCO[MAX_VCO_ENTRIES][MAX_XTAL_ENTRIES][3]
{ VCO 320MHz, VCO 480MHz }

2.static const uint32_t g_pui32VCOFrequencies[MAX_VCO_ENTRIES] =
{
    160000000,                              // VCO 320
    240000000,                              // VCO 480
};

Best Regards,
sopatopa

  • Hello Sopatopa

    Yes, that is correct. However some additional changes are coming as well.

    Regards
    Amit
  • Hello Amit

    Thanks for your reply.
    Even PLLFREQ1=0, I has understood that there is a need to apply the Appendix 3.

    Please teach me the procedure to avoid the errata(SYSCTL#22 and #23) with unuse Appendix 3.
    The reason is because my customers are register set without using the tivaware.

    Best Regards,
    sopatopa

  • Hello Sopatopam

    Not using TivaWare puts more debug effort (another customer migrated due to the same issue and got their system working). They can make an explicit call to the updated SysCtlClockFreqSet thus having minimal code update.

    The long way is more difficult as I would need to look/update/debug a code. You may post the base code, and I can check what recommendations can be made.

    Regards
    Amit
  • Hello Amit

    Thanks for your reply.
    It is difficult to post a customer code.

    In SYSCTL # 22, it is written in the following.
    -----------------------------------------------------
    When generating system clock from the PLL, the user programs the system control
    register bits RSCLKCFG.PSYSDIV to divide the PLL output. This register value may not
    be loaded into the physical divider causing the system clock to be divided by 2. This
    condition will cause the system clock to be out of specification.
    -----------------------------------------------------

    In SysClk = fVCO / (PSYSDIV + 1),if PSYDIV + 1 is not a 2,
    If PSYDIV + 1 is not a 2, I understanding that it will not meet
    the conditions of errata.

    Simply, if to set a value that is not a PSYDIV + 1 to 2,
    do not be able to avoid the errata?

    In SYSCTL # 23, this workaround is not use MOSC as the OSCCLK source.

    If there is another problem, please teach me the reason and necessity.

    Best Regards,
    sopatopa

  • Hello Amit

    Sorry, for SYSCTL # 22,my understanding was incorrect.
    My understanding is, this register divider setting of
    the system clock be set to any value is that it becomes 2.

    In uint32_t g_pppui32XTALtoVCO[MAX_VCO_ENTRIES][MAX_XTAL_ENTRIES][3],
    Why put PLL_Q_TO_REG and (2) an additional?

    As a workaround for this errata, please tell me
    how to register settings and reason.

    Best Regards,
    sopatopa
  • Hello Sopatopa,

    Using the Q reg ensures that if the PSYSDIV fails, the device is still within 120MHz (480 % Q of 2, divided by failed PSYSDIV of 2). There are some more changes that we would make to the final release.

    Regards
    Amit
  • Hi Amit,

    Sorry for jumping in.

    I understood the workaround is dividing the PLL output frequency(=fVCO) by 2 using Q reg, before PSYSDIV divider.
    Then use PSYSDIV divider 2, so that it works fine regardless it fails or not.
    Correct ?

    Thanks and regards,
    Koichiro

  • Hello Koichiro

    Yes, that is correct. The PSYSDIV of 2 is the default setting. So the divide is performed by the Q-reg.

    Regards
    Amit
  • Amit,

    Thanks !

    Thanks and regards,
    Koichiro

  • Hello Koichiro,

    There is some restriction that may not be evident which is what we are addressing. E.g. 96MHz is not possible as 240/2 = 120 and 240/3 = 80MHz.

    Regards
    Amit
  • Hi Amit,
    Excuse me for jump in.

    I have two question for SYSCTL#22 errata and workaround.

    1. I think this problem has two issues.
    (A). System Clock may be set to out of specification. (over 120MHz)
    (B). We may not set system clock to required frequency.
    For example : We want to set system clock to 30MHz.
    However, system clock might be set another frequency by PSYSDIV problem.

    Does workaround of SYSCLK#22 fix issue A ? or both issue A and B?

    2. Does this workaround modify PLL VCO frequency to 240MHz ?
    Should we modify other clock settings that are based on PLL VCO clock (USBCLK..) ?

    Regards.
  • Hello Tomohiko

    1. When there is a failure the system clock shall get set as VCO divided by 2. So the workaround applies to both A and B
    2. No the VCO is still 480MHz. It is the post divider of Q that is applied to get it down to a value where a failure or successful update makes the clock as 120MHz and in spec.

    Regards
    Amit
  • Amit,

    Regarding Sysctl 23, would a reset due to hibernation trigger Sysctl 23, or does it have to be a system reset [i.e. using SysCtlReset() method]?  

    When the Bus fault occurs, is it possible to trap the bus fault in an ISR?

    When the Bus fault occurs, would another soft reset recover the situation, or is a power on reset required?

  • When the Bus fault occurs, is it possible to trap the bus fault in an ISR?

    The M4 has a separate exception handler vector for the bus error. However, it is not enabled by default (like MemManage and UsageFault errors), and gets escalated to a hardfault. You can enable busfaults in your application (and provide a handler, of course).

    When the Bus fault occurs, would another soft reset recover the situation, or is a power on reset required?

    Not sure. Beside (usually) a few flags, both are effectively the same.

    Except you actually mean power cycling, which would also "kill" all unbuffered RAM content.

  • Hello Aaron,

    It is only on a soft reset like SysCtlReset or a watchdog/bor/pin configured as a System Reset that would cause the issue. If it is configured as a Power On reset the issue does not occur.

    A second soft reset will recover it. However the WA for the errata, prevents the second soft reset requirement.

    Regards
    Amit
  • Is this correct?

    fvco = fxtal ÷ N * MDIV

    SysClk = fvco ÷ Q ÷ PSYSDIV (or fvco ÷ Q in the failure case)

  • Amit,

    Thank you for your response.

    We use the following code to set the brown out control register:
    HWREG(SYSCTL_PTBOCTL) |= (SYSCTL_PTBOCTL_VDDA_UBOR_RST | SYSCTL_PTBOCTL_VDD_UBOR_NONE);

    Question 1: We do not change the "RESBEHAVCTL" register, so if a brown out occurs, it will be a POR, and is thus not affected by this errata, correct?

    Question 2: Are there working theories as to why the SYSCTL22 or SYSCTl23 issues occur? For example, why does the PSYSDIV fail to get loaded? Why does a bus fault occur if the OSCCLK is sourced from MOSC (even if the PLL is used)?

    Question 3: I am trying to replicate SYSCTL 23 errata on my device. I set up my code to toggle a GPIO pin, then call "SysCtlReset()". It basically performs this loop forever. I can hook this up to a scope, and for my device I am able to achieve ~ 60 resets per second. The GPIO pin stop toggling anywhere from 10 seconds, to 22 minutes when running this code. I then tried to implement the workaround. When I implemented the workaround, I saw the same behavior--the GPIO pin stops toggling within the same timeframe. Is there some example code that could be used to prove that I've implemented the workaround properly?

    Thanks
  • Hello BB_

    Adding the brackets.

    fvco = (fxtal % N) * MDIV

    Regards
    Amit
  • Hello Aaron,

    Answer-1: Yes that is correct
    Answer-2: We do understand why the PSYSDIV fails to get loaded and why the OSCCLK sourced from the MOSC fails
    Answer-3: It was the same code which we used as well. When you load the code on the device, set a Breakpoint on the function SysCtlReset, and run the code till breakpoint: what is the value of RSCLKCFG and PLLFREQ1 registers?

    Regards
    Amit
  • Follow up to Answer 2--can you share the information why they occur?

    Follow up to Answer 3:

    When using old TivaWare:
    PLLFREQ0 = 0x00800014
    PLLFREQ1 = 0x00000000
    PLLSTAT = 0x00000001
    RSCLKCFG = 0x13300009

    When using old Workaround:
    PLLFREQ0 = 0x00800014
    PLLFREQ1 = 0x00000100
    PLLSTAT = 0x00000001
    RSCLKCFG = 0x13000004
  • Amit,

    I've attached a zip file of my project which causes the issue.  Note, I'm running on a custom board; however, this project is stripped down and doesn't use any of the custom portions of the board.  I'm just toggling a GPIO.  After anywhere from 10 seconds to 22 minutes (at least on my board) the GPIO stops toggling.

    I am using TivaWare_C_Series-2.1.0.12573, CCS Version: 6.1.0.00104, TI ARM Compiler Version 5.1.7 [note I am in a regulated industry so the tool chain is older than the latest]

    ErrataTest.zip

  • Hello Aaron,

    A2: The information cannot be disclosed on the public forum as it is TI Confidential and pertains to the design.
    A3: What is the system frequency you are attempting to run the device at?

    Regards
    Amit
  • 32MHz is the target frequency. Just to note, in the previous post, I uploaded a zip file of a stripped down version of the project that is an issue for me with and without the workaround.
  • Hello Aaron

    Are you trying to get 32MHz from 320MHz VCO? If yes, the first test I will ask you to run is for 80MHz System Clock

    Regards
    Amit
  • Amit,

    When running at 80MHz (320MHz VCO) I have run for 35 minutes thus far with no issues with the workaround in place (which is the longest it's run).

    When the issue occurred on 32MHz, the GPIO pin was left in a high state, which means something went wrong in the call to "SysCtlClockFreqSet()".

    Why would this not work with 32MHz?

    Thanks

  • Hello Aaron,

    I think I know what the issue is with 32MHz. And I fear it is an issue in the WA itself, which was not correctly thought for cases other than 120MHz for 480MHz VCO and 80MHz for 320MHz VCO. It is a software issue and I hope I should be able to provide a first cut by tomorrow for testing.

    In the meantime please let the 80MHz test running for getting confidence in the WA on your side

    Regards
    Amit
  • Hello Amit.
    Thank you for your response. I understand system clock issues.

    However,
    ---------------------------------------------------------
    2. No the VCO is still 480MHz. It is the post divider of Q that is applied to get it down to a value where a failure or successful update makes the clock as 120MHz and in spec.
    ---------------------------------------------------------
    I think this explanation disagrees with description on TM4C129x datasheet.

    Section 5.2.5.5 on TM4C1290 datasheet :
    ---------------------------------------------------------
    The PLL VCO frequency (fVCO) is determined through the following calculation:
    fVCO = fIN* MDIV
    where
    fIN = fXTAL / (Q+1)(N+1) or fPIOSC/ (Q+1)(N+1)
    ---------------------------------------------------------
  • Hello Tomohiko,

    The description in the data sheet is incorrect. This has already been clarified in another thread on the forum. The Q divider is not in the control loop for deriving the fVCO.

    Regards
    Amit
  • Amit,

    I ran for 15 hours overnight at 80MHz with no issues.

    This morning I switched back to the old TivaWare without the WA in place, but with 80MHz instead of 32MHz, and I trapped the fault ISR pretty quickly (I have a while(1) in the faultISR).

    What's interesting is that when running at the 32MHz, I encounter an issue; however, I don't trap the fault ISR... When you break on the debugger it appears to be in some random memory location, presumably from the call to SysCtlClockFreqSet() since the GPIO line is active...

    It seems something different is occurring when running at 32MHz, or at least the effect is different when you hit the breakpoint.

  • Hello Aaron,

    I believe the issue is that when using 32MHz, the PSYSDIV is being used again instead of the Q divider.

    Regards
    Amit
  • Amit,

    If that is the cause, why do I not end up in a FaultISR when running the 32MHz code? When running 80MHz code without the WA in place, I end up in the FaultISR when I hit break on the debugger. When I hit break on the debugger in the 32MHz code without the WA in place, I do not end up in the FaultISR. I inspected the NVIC_FAULT_STAT register, it indicated an "Instruction Bus Error" with an "Instruction Access Violation". The PC register seems to be way out in the middle of nowhere (it points to 0x6841 E01A).
  • Hello Aaron,

    On your board before calling the SysCtlClockFreqSet configure a Timer in PWM mode with divide by 1000 of the system clock. Monitor the corresponding Timer output on a scope. You should see 160KHz when the failure occurs. Under normal conditions the same pin will be 32KHz.

    Regards
    Amit
  • Amit,

    I configured my PWM to be 32KHz, (however I enable this before setting the clock, so it's actually at 16KHz since it's using the 16MHz internal clock instead of the 32MHz external clock). When the failure occurs, the PWM does indeed get bumped to 160KHz as you indicated, which must mean it's running at 320MHz.

    I'm assuming I then get a bus fault or something similar because the Tiva is not rated to run at that speed and bad things happen, correct?
  • Hello Aaron

    Yes, that is correct.

    Regards
    Amit
  • Amit,

    Thank you for your assistance thus far.

    1) Is there a way to configure the registers to achieve a 32MHz clock speed using the Q register instead of PSYSDIV?

    2) I know you can't provide certain information about the errata since it's related to the chip design; however, is it possible that certain Tiva chips would be more susceptible to this errata than others? Could the ambient temperature make the errata more susceptible than other temperatures?

    Thanks
  • Hello Aaron,

    I am working on the updated sysctl.c which will fix the issue for any system frequency being derived.

    No, to the second question. The probability of failure may change with device to device, but IMHO, it is a failure.

    Regards
    Amit
  • Thanks Amit.

    Please let me know when something is available for the 32MHz frequency.

    Regarding your answer to the second question--the reason I ask is because we have a board where we are thinking SYSCTL 22 is an issue we've observed. We've observed it three times on this board (very intermittently) and haven't observed it on any other boards. If the probability of failure can change with device to device, that may explain why this particular board has exhibited it three times.
  • Hello Aaron,

    I agree with your observations and statements. In the past we have seen a failure that has not been seen on some devices and creating a probability model was almost next to impossible. Rather a bullet proof workaround shall ensure no device fails.

    Regards
    Amit
  • Hello Aaron

    Attached is a patch file. I have done some basic testing and it seems to be configuring the device correctly and should work for your use case of 32MHz. Replace the existing SysCtlClockFreqSet with the function in the file, recompile the driverlib and "REBUILD" your project.

    //*****************************************************************************
    //
    //! Configures the system clock.
    //!
    //! \param ui32Config is the required configuration of the device clocking.
    //! \param ui32SysClock is the requested processor frequency.
    //!
    //! This function configures the main system clocking for the device.  The
    //! input frequency, oscillator source, whether or not to enable the PLL, and
    //! the system clock divider are all configured with this function.  This
    //! function configures the system frequency to the closest available divisor
    //! of one of the fixed PLL VCO settings provided in the \e ui32Config
    //! parameter.  The caller sets the \e ui32SysClock parameter to request the
    //! system clock frequency, and this function then attempts to match this using
    //! the values provided in the \e ui32Config parameter.  If this function
    //! cannot exactly match the requested frequency, it picks the closest
    //! frequency that is lower than the requested frequency.  The \e ui32Config
    //! parameter provides the remaining configuration options using a set of
    //! defines that are a logical OR of several different values, many of which
    //! are grouped into sets where only one of the set can be chosen.  This
    //! function returns the current system frequency which may not match the
    //! requested frequency.
    //!
    //! If the application is using an external crystal then the frequency is
    //! set by using one of the following values:
    //! \b SYSCTL_XTAL_5MHZ, \b SYSCTL_XTAL_6MHZ, \b SYSCTL_XTAL_8MHZ,
    //! \b SYSCTL_XTAL_10MHZ, \b SYSCTL_XTAL_12MHZ, \b SYSCTL_XTAL_16MHZ,
    //! \b SYSCTL_XTAL_18MHZ, \b SYSCTL_XTAL_20MHZ, \b SYSCTL_XTAL_24MHZ, or
    //! \b SYSCTL_XTAL_25MHz.
    //!
    //! The oscillator source is chosen with one of the following values:
    //!
    //! - \b SYSCTL_OSC_MAIN to use an external crystal or oscillator.
    //! - \b SYSCTL_OSC_INT to use the 16-MHz precision internal oscillator.
    //! - \b SYSCTL_OSC_INT30 to use the internal low frequency oscillator.
    //! - \b SYSCTL_OSC_EXT32 to use the hibernate modules 32.786-kHz oscillator.
    //! This option is only available on devices that include the hibernation
    //! module.
    //!
    //! The system clock source is chosen with one of the following values:
    //!
    //! - \b SYSCTL_USE_PLL is used to select the PLL output as the system clock.
    //! - \b SYSCTL_USE_OSC is used to choose one of the oscillators as the
    //! system clock.
    //!
    //! The PLL VCO frequency is chosen with one of the the following values:
    //!
    //! - \b SYSCTL_CFG_VCO_480 to set the PLL VCO output to 480-MHz
    //! - \b SYSCTL_CFG_VCO_320 to set the PLL VCO output to 320-MHz
    //!
    //! Example: Configure the system clocking to be 40 MHz with a 320-MHz PLL
    //! setting using the 16-MHz internal oscillator.
    //!
    //! \verbatim
    //! SysCtlClockFreqSet(SYSCTL_OSC_INT | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_320,
    //!                    40000000);
    //! \endverbatim
    //!
    //! \note This function cannot be used with TM4C123 devices.  For TM4C123
    //! devices use the SysCtlClockSet() function.
    //!
    //! \return The actual configured system clock frequency in Hz or zero if the
    //! value could not be changed due to a parameter error or PLL lock failure.
    //
    //*****************************************************************************
    uint32_t
    SysCtlClockFreqSet(uint32_t ui32Config, uint32_t ui32SysClock)
    {
        int32_t i32Timeout, i32VCOIdx, i32XtalIdx;
        uint32_t ui32MOSCCTL;
        uint32_t ui32SysDiv, ui32Osc, ui32OscSelect, ui32RSClkConfig;
    
        //
        // TM4C123 devices should not use this function.
        //
        if(CLASS_IS_TM4C123)
        {
            return(0);
        }
    
        //
        // Get the index of the crystal from the ui32Config parameter.
        //
        i32XtalIdx = SysCtlXtalCfgToIndex(ui32Config);
    
        //
        // Determine which non-PLL source was selected.
        //
        if((ui32Config & 0x38) == SYSCTL_OSC_INT)
        {
            //
            // Use the nominal frequency for the PIOSC oscillator and set the
            // crystal select.
            //
            ui32Osc = 16000000;
            ui32OscSelect = SYSCTL_RSCLKCFG_OSCSRC_PIOSC;
            ui32OscSelect |= SYSCTL_RSCLKCFG_PLLSRC_PIOSC;
    
            //
            // Force the crystal index to the value for 16-MHz.
            //
            i32XtalIdx = SysCtlXtalCfgToIndex(SYSCTL_XTAL_16MHZ);
        }
        else if((ui32Config & 0x38) == SYSCTL_OSC_INT30)
        {
            //
            // Use the nominal frequency for the low frequency oscillator.
            //
            ui32Osc = 30000;
            ui32OscSelect = SYSCTL_RSCLKCFG_OSCSRC_LFIOSC;
        }
        else if((ui32Config & 0x38) == (SYSCTL_OSC_EXT32 & 0x38))
        {
            //
            // Use the RTC frequency.
            //
            ui32Osc = 32768;
            ui32OscSelect = SYSCTL_RSCLKCFG_OSCSRC_RTC;
        }
        else if((ui32Config & 0x38) == SYSCTL_OSC_MAIN)
        {
            //
            // Bounds check the source frequency for the main oscillator.  The is
            // because the PLL tables in the g_pppui32XTALtoVCO structure range
            // from 5MHz to 25MHz.
            //
            if((i32XtalIdx > (SysCtlXtalCfgToIndex(SYSCTL_XTAL_25MHZ))) ||
               (i32XtalIdx < (SysCtlXtalCfgToIndex(SYSCTL_XTAL_5MHZ))))
            {
                return(0);
            }
    
            ui32Osc = g_pui32Xtals[i32XtalIdx];
    
            //
            // Set the PLL source select to MOSC.
            //
            ui32OscSelect = SYSCTL_RSCLKCFG_OSCSRC_MOSC;
            ui32OscSelect |= SYSCTL_RSCLKCFG_PLLSRC_MOSC;
    
            //
            // Clear MOSC power down, high oscillator range setting, and no crystal
            // present setting.
            //
            ui32MOSCCTL = HWREG(SYSCTL_MOSCCTL) &
                          ~(SYSCTL_MOSCCTL_OSCRNG | SYSCTL_MOSCCTL_PWRDN |
                            SYSCTL_MOSCCTL_NOXTAL);
    
            //
            // Increase the drive strength for MOSC of 10 MHz and above.
            //
            if(i32XtalIdx >= (SysCtlXtalCfgToIndex(SYSCTL_XTAL_10MHZ) -
                              (SysCtlXtalCfgToIndex(SYSCTL_XTAL_5MHZ))))
            {
                ui32MOSCCTL |= SYSCTL_MOSCCTL_OSCRNG;
            }
    
            HWREG(SYSCTL_MOSCCTL) = ui32MOSCCTL;
        }
        else
        {
            //
            // This was an invalid request because no oscillator source was
            // indicated.
            //
            ui32Osc = 0;
            ui32OscSelect = SYSCTL_RSCLKCFG_OSCSRC_PIOSC;
        }
    
        //
        // Check if the running with the PLL enabled was requested.
        //
        if((ui32Config & SYSCTL_USE_OSC) == SYSCTL_USE_PLL)
        {
            //
            // ui32Config must be SYSCTL_OSC_MAIN or SYSCTL_OSC_INT.
            //
            if(((ui32Config & 0x38) != SYSCTL_OSC_MAIN) &&
               ((ui32Config & 0x38) != SYSCTL_OSC_INT))
            {
                return(0);
            }
    
            //
            // Get the VCO index out of the ui32Config parameter.
            //
            i32VCOIdx = (ui32Config >> 24) & 7;
    
            //
            // Check that the VCO index is not out of bounds.
            //
            ASSERT(i32VCOIdx < MAX_VCO_ENTRIES);
    
            //
            // Set the memory timings for the maximum external frequency since
            // this could be a switch to PIOSC or possibly to MOSC which can be
            // up to 25MHz.
            //
            HWREG(SYSCTL_MEMTIM0) = _SysCtlMemTimingGet(25000000);
    
            //
            // Clear the old PLL divider and source in case it was set.
            //
            ui32RSClkConfig = HWREG(SYSCTL_RSCLKCFG) &
                              ~(SYSCTL_RSCLKCFG_PSYSDIV_M |
                                SYSCTL_RSCLKCFG_OSCSRC_M |
                                SYSCTL_RSCLKCFG_PLLSRC_M | SYSCTL_RSCLKCFG_USEPLL);
    
            //
            // Update the memory timings to match running from PIOSC.
            //
            ui32RSClkConfig |= SYSCTL_RSCLKCFG_MEMTIMU;
    
            //
            // Update clock configuration to switch back to PIOSC.
            //
            HWREG(SYSCTL_RSCLKCFG) = ui32RSClkConfig;
    
            //
            // The table starts at 5 MHz so modify the index to match this.
            //
            i32XtalIdx -= SysCtlXtalCfgToIndex(SYSCTL_XTAL_5MHZ);
    
            //
            // Calculate the System divider such that we get a frequency that is
            // the closest to the requested frequency without going over.
            //
            ui32SysDiv = (g_pui32VCOFrequencies[i32VCOIdx] + ui32SysClock - 1) /
                         ui32SysClock;
    
            //
            // Set the oscillator source.
            //
            HWREG(SYSCTL_RSCLKCFG) |= ui32OscSelect;
    
            //
            // Set the M, N and Q values provided from the table and preserve
            // the power state of the main PLL.
            //
            HWREG(SYSCTL_PLLFREQ1) =
                g_pppui32XTALtoVCO[i32VCOIdx][i32XtalIdx][1];
            HWREG(SYSCTL_PLLFREQ1) |= PLL_Q_TO_REG(ui32SysDiv);
            HWREG(SYSCTL_PLLFREQ0) =
                (g_pppui32XTALtoVCO[i32VCOIdx][i32XtalIdx][0] |
                 (HWREG(SYSCTL_PLLFREQ0) & SYSCTL_PLLFREQ0_PLLPWR));
    
            //
            // Calculate the actual system clock as PSYSDIV is always div-by 2.
            //
            ui32SysClock = _SysCtlFrequencyGet(ui32Osc) / 2;
    
            //
            // Set the Flash and EEPROM timing values.
            //
            HWREG(SYSCTL_MEMTIM0) = _SysCtlMemTimingGet(ui32SysClock);
    
            //
            // Check if the PLL is already powered up.
            //
            if(HWREG(SYSCTL_PLLFREQ0) & SYSCTL_PLLFREQ0_PLLPWR)
            {
                //
                // Trigger the PLL to lock to the new frequency.
                //
                HWREG(SYSCTL_RSCLKCFG) |= SYSCTL_RSCLKCFG_NEWFREQ;
            }
            else
            {
                //
                // Power up the PLL.
                //
                HWREG(SYSCTL_PLLFREQ0) |= SYSCTL_PLLFREQ0_PLLPWR;
            }
    
            //
            // Wait until the PLL has locked.
            //
            for(i32Timeout = 32768; i32Timeout > 0; i32Timeout--)
            {
                if((HWREG(SYSCTL_PLLSTAT) & SYSCTL_PLLSTAT_LOCK))
                {
                    break;
                }
            }
    
            //
            // If the loop above did not timeout then switch over to the PLL
            //
            if(i32Timeout)
            {
                ui32RSClkConfig = HWREG(SYSCTL_RSCLKCFG);
                ui32RSClkConfig |= (1 << SYSCTL_RSCLKCFG_PSYSDIV_S) |
                                    ui32OscSelect | SYSCTL_RSCLKCFG_USEPLL;
                ui32RSClkConfig |= SYSCTL_RSCLKCFG_MEMTIMU;
    
                //
                // Set the new clock configuration.
                //
                HWREG(SYSCTL_RSCLKCFG) = ui32RSClkConfig;
            }
            else
            {
                ui32SysClock = 0;
            }
        }
        else
        {
            //
            // Set the Flash and EEPROM timing values for PIOSC.
            //
            HWREG(SYSCTL_MEMTIM0) = _SysCtlMemTimingGet(16000000);
    
            //
            // Make sure that the PLL is powered down since it is not being used.
            //
            HWREG(SYSCTL_PLLFREQ0) &= ~SYSCTL_PLLFREQ0_PLLPWR;
    
            //
            // Clear the old PLL divider and source in case it was set.
            //
            ui32RSClkConfig = HWREG(SYSCTL_RSCLKCFG);
            ui32RSClkConfig &= ~(SYSCTL_RSCLKCFG_OSYSDIV_M |
                                 SYSCTL_RSCLKCFG_OSCSRC_M |
                                 SYSCTL_RSCLKCFG_USEPLL);
    
            //
            // Update the memory timings.
            //
            ui32RSClkConfig |= SYSCTL_RSCLKCFG_MEMTIMU;
    
            //
            // Set the new clock configuration.
            //
            HWREG(SYSCTL_RSCLKCFG) = ui32RSClkConfig;
    
            //
            // If zero given as the system clock then default to divide by 1.
            //
            if(ui32SysClock == 0)
            {
                ui32SysDiv = 0;
            }
            else
            {
                //
                // Calculate the System divider based on the requested
                // frequency.
                //
                ui32SysDiv = ui32Osc / ui32SysClock;
    
                //
                // If the system divisor is not already zero, subtract one to
                // set the value in the register which requires the value to
                // be n-1.
                //
                if(ui32SysDiv != 0)
                {
                    ui32SysDiv -= 1;
                }
    
                //
                // Calculate the system clock.
                //
                ui32SysClock = ui32Osc / (ui32SysDiv + 1);
            }
    
            //
            // Set the memory timing values for the new system clock.
            //
            HWREG(SYSCTL_MEMTIM0) = _SysCtlMemTimingGet(ui32SysClock);
    
            //
            // Set the new system clock values.
            //
            ui32RSClkConfig = HWREG(SYSCTL_RSCLKCFG);
            ui32RSClkConfig |= (ui32SysDiv << SYSCTL_RSCLKCFG_OSYSDIV_S) |
                               ui32OscSelect;
    
            //
            // Update the memory timings.
            //
            ui32RSClkConfig |= SYSCTL_RSCLKCFG_MEMTIMU;
    
            //
            // Set the new clock configuration.
            //
            HWREG(SYSCTL_RSCLKCFG) = ui32RSClkConfig;
        }
    
        //
        // Finally change the OSCSRC back to PIOSC
        //
        HWREG(SYSCTL_RSCLKCFG) &= ~(SYSCTL_RSCLKCFG_OSCSRC_M);
    
        return(ui32SysClock);
    }
    
    

    Regards

    Amit

  • Amit,

    Do I still use the same tables for g_pui32VCOFrequencies and g_pppui32XTALtoVCO as indicated in the WA?

  • Hello Aaron

    The tables are unmodified, only the code logic has changed.

    Regards
    Amit
  • If the following is true:

    fvco = fxtal ÷ N * MDIV
    MDIV = MINT + (MFRAC / 1024)
    SysClk = fvco ÷ Q ÷ PSYSDIV (or fvco ÷ Q in the failure case)

    Then with an unmodified table for 320MHz PLL and 16MHz crystal with the patch we will get

    FVCO = 16,000,000 / 1 * 20 = 320,000,000
    SysClk = 320,000,000 / 10 / 2 = 16,000,000

    Because Q calculates to 10 with the following code "ui32SysDiv = (g_pui32VCOFrequencies[i32VCOIdx] + ui32SysClock - 1) / ui32SysClock;" and PSYSDIV is always 2.

    It seems like I must be missing something in my calculations as to what is/should be happening with the Q register.

    Could you please help my misunderstanding?
  • Perhaps I'm misunderstanding that PSYSDIV is not always 2, is it always 1 with the new patch?
  • Hello Aaron,

    When the PSYSDIV is written with a value of 1, it implements a +1 divider, giving a div-by 2.

    Regards
    Amit
  • Okay, so with the patch, the Q value is set to 10. And if I'm doing the math correctly, shouldn't that provide a system clock of 16MHz, not 32MHz? Since Q is calculated as "ui32SysDiv = (g_pui32VCOFrequencies[i32VCOIdx] + ui32SysClock - 1) / ui32SysClock;"
  • Hello Aaron

    If you look at the value of g_pui32VCOFrequencies table it is already 160 and 240 MHz for computation. So the resulting Q is already tuned for a PSYSDIV of 2.

    Regards
    Amit
  • Okay, so the original "g_pui32VCOFrequencies "table in the version of TivaWare I'm using (2.1.0.12573) the frequencies values are 320,000,000 and 480,000,000. So with the patch, I will need to update that table to be 160,000,000 and 240,000,000, but I don't need to make an update to the "g_pppui32XTALtoVCO" table.

    Is that correct?
  • Hello Aaron

    The Appendix 3 code already does that.

    Regards
    Amit
  • Okay, that all makes sense now.

    Follow up question: The patch created will work for 32MHz using 320MHz PLL. If a 480MHz PLL were to be used, and a 32MHz clock specified, the actual clock speed would be less than 32MHz because Q would want to be 7.5, but would get set to 8 in the division, and the effective clock speed would be 30MHz instead of 32MHz. It wouldn't be possible to achieve 32MHz without using MFRACT [and the datasheet recommends that MFRACT be set to 0 to reduce jitter].

    Is my understanding of that correct?
  • Hello Aaron

    Yes. You can use the MFRACT but the jitter would be too high on the clock.

    Regards
    Amit