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.

TM4C129DNCPDT: hard fault in SysCtlClockFreqSet() in application

Part Number: TM4C129DNCPDT
Hi.
Currently, I meet one hard fault in SysCtlClockFreqSet() and I need to figure out the cause.
I have some information about this issue.
1. this issue can be reproduced by jumping to bootloader and hard fault occurred in SysCtlClockFreqSet() in application on our platform.
2. I try to narrow down the possible coding and stress it, so my main() is like this
void main(void)
{
//
// Set the clocking to run at 80 MHz from the PLL.
//
SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
SYSCTL_OSC_MAIN |
SYSCTL_USE_PLL |
SYSCTL_CFG_VCO_480), SYSTEM_CLOCK);
SysCtlDelay(10*SYSTEM_DELAY_MS); // delay 10ms 
//jump to bootloader
(*((void (*)(void))(*(unsigned long *)0x2c)))();
while (1)
{
}
}
3. I capture the trace32 screen of hard fault as below:
   
   
4. I try to perform the same application on 129 EVM and it's also failed.
I use 2.1.4.178 of the Tiva Peripheral Driver Library.
Does anyone have idea about the issue?
thanks
Gavin
  • Hi Gavin,

      This is the first time I have seen a hard fault reported when calling SysCtlClockFreqSet. Perhaps I need to understand the problem better. 

      There are many TivaWare examples for TM4C129. Can you try any one of them (i.e. blinky example) and see you will get the hard fault when calling the SysCtlClockFreqSet. Every example will call SysCtlClockFreqSet to set up the System clock. 

      Does the hard fault come when you call the SysCtlClockFreqSet while you are still in the application or after it has already jumped to the bootloader?

      What is the reason that you need to setup the system clock again before you jump back to the bootloader. Normally, the bootloader will setup its own clock, isn't?

      You tried to setup for 80MHz. Does it make a difference if you choose a different frequent such as 120MHz or the frequency that is matching what the bootloader itself has?

  • Hi Charles

    Thanks for your replied, please refer to my comment as below:

    1. There are many TivaWare examples for TM4C129. Can you try any one of them (i.e. blinky example) and see you will get the hard fault when calling the SysCtlClockFreqSet. Every example will call SysCtlClockFreqSet to set up the System clock. 

    [Gavin] Yes, I can try the sample.

    2. Does the hard fault come when you call the SysCtlClockFreqSet while you are still in the application or after it has already jumped to the bootloader?

    [Gavin] I had checked this question before and the hard fault made CPU stick in SysCtlClockFreqSet in the application.

     3. What is the reason that you need to setup the system clock again before you jump back to the bootloader. Normally, the bootloader will setup its own clock, isn't?

    [Gavin] No, I didn't setup clock again before jumping to bootloader. Actually, the sequence is that I setup clock in bootloader and setup clock in the application again. 

                 I setup clock twice to fix clock setting issue.

    4. You tried to setup for 80MHz. Does it make a difference if you choose a different frequent such as 120MHz or the frequency that is matching what the bootloader itself has?

    [Gavin] No, I didn't try the different frequency. But I had set the same clock (80 Mhz) in bootloader and application.

    On the other hand, because I checked the hard fault in SysCtlClockFreqSet, so I simplify the stress code as post.

    Could you please comment the stress code properly to test or not?

    I also scoped the status of external crystal when hard fault occurred, the external crystal works normally.

    If you have any idea for this issue, please share with me.

    thanks

    Gavin

  • Hi Gavin,

      Can you please single step through the SysCtlClockFreqSet function and let me know exactly which line inside the function that caused the hard fault?

      Can you try with different compiler optimization level and does it make a difference?

      Could you also send me a test program (the shorter the better) that I can reproduce your problem on my launchPad?

  • Hi Charles

    I found that the hard fault occurred at the similar line in SysCtlClockFreqSet (), please refer to the attached screen

    I also attach the test program for your test and you can flash it into launchpad directly.

    In my test, I load bootloader(address: 0x0000) and application(0x8000),  the one CAN message sent from bootloader as record and the jump operation keep run until hard fault hit.

    TM4C129_hard_fault_reproduce.7z

    thanks

    Gavin

     

  • Hi Gavin,

      I cannot seem to reproduce your problem. As you can see I put a breakpoint at UIUpgrade() and it just runs to it. This means it runs through the SysCtlClockFreqSet() fine. Please see below. 

    One thing I notice is that I see your program image that your SysCtlClockFreqSet() is different from mine. Are you sure you are using the latest TivaWare library. Can you please download the latest TivaWare library and compare with your current one. 

     Look at the first yellow highlighted line of your sysctl.c file and compare with the first yellow highlighted line of my sysctl.c you will find that I have a divide by 2 while you are dividing by a variable. 

    Your file below:

    My sysctl.c file below:

    Here is the source of the SysCtlClockFreqSet() in the latest TivaWare library.

    //*****************************************************************************
    //
    //! 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 ui32Delay;
        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;
            
            //
            // Timeout using the legacy delay value.
            //
            ui32Delay = 524288;
    
            while((HWREG(SYSCTL_RIS) & SYSCTL_RIS_MOSCPUPRIS) == 0)
            {
                ui32Delay--;
    
                if(ui32Delay == 0)
                {
                    break;
                }
            }
    
            //
            // If the main oscillator failed to start up then do not switch to
            // it and return.
            //
            if(ui32Delay == 0)
            {
                return(0);
            }
    
            
        }
        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);
    }

    One last thing is that if you can just run a simple hello or blinky or any TivaWare examples. Do you see the problem?

  • Hi Charles

    First, this issue was not occurred at SysCtlClockFreqSet() every time, it needed to run a while.

    If possible, could you please try to make it run a while until issue occurred?

    Second, the different content of SysCtlClockFreqSet() was the workaround, that worked with your team for clock divisor setting issue.

    Third, I will run the simple hello sample, but I think that my stress code is simpler that hello. If I got the result, I will update to you.

    If you had more concern need to clarify, please tell me, I can try to get it from my side.

    thanks

    Gavin

  • Hi Gavin,

      I have several questions.

      1. I did a diff between the sysctl.c in the current TivaWare release vs. yours in the local directory and found quite some differences. Can you please  comment if you made the change on your own or you got the change from TI.

      2. If you got the workaround change from TI, did you make any modification on top of what was sent to you?

      3. When did you get the change?

      4.  Can you run your project with the driverlib.lib linked to the <TivaWare Installation>driverlib/ccs/Debug/driverlib.lib. instead of your local directory? Will you see a difference?

      5. As asked before, can you run a simple TivaWare example such as blinky or hello that has the driverlib linked to either the TivaWare_Installation or your local rebuilt directory? Will both cases fail or only only one of them fails or both of them will pass?

      6. I ran your project on the launchPad. I do not have the CAN message. However, I see the project going to the application. Therefore, I assume the CAN message is not necessary for this project to work, correct? I just flash both the bootloader and the application via JTAG. Is this OK?

      7. Your application is written to while(1) at the end. Once I pass the SysCtlClockFreqSet I'm just spinning. I cannot just run a while for the hardfault to happen unless I do a reset. 

      

     

  • Hi Charles

    Please refer to my response:

     1./ 2./3.

    [Gavin] Yes, the difference came from TI team around 2 years ago. The modification fixed the abnormal system clock setting in reset case and usb clock (under system clock 80Mhz) issue.

                We tried to push TI to make the modification as the official release (document and SDK), but it's still not updated so far.

     4. /5. 

    [Gavin] I can update to you, once I got the result.

     6. /7. 

    [Gavin] The CAN message is just a record and let me know the test is still running, that is not the necessary. The test should be running once you flashed bootloader and application.

                I guess that you erased bootloader when you flashed application. You may dump the flash to confirm.

    I also have some update:

    1. I try to disable the compiler optimization, but the hard fault is still occurred.

    2. when hard fault was occurred, I check the LR in exception frame dump, it seems failed at 

    //
    // Set the Flash and EEPROM timing values.
    //
    HWREG(SYSCTL_MEMTIM0) = _SysCtlMemTimingGet(ui32SysClock);

    But I don't have idea why it made the hard fault so far, and I try to figure out  the possible cause.

    If you got some suggestion, could you please share with me?

    thanks

    Gavin

     

     

  • Hi Gavin,

      Since you have had the workaround for more than a year, didn't you have similar issue during this time? I'm just wondering why suddenly the hard fault came up. Did you have any products that implemented the workaround and was working? If this is the case, do you know what is the difference between the products that were once working with the workaround vs. the current project? 

      I'm wondering if the frequency becomes out of spec that caused the hard fault? Can you try an experiment by setting the frequency to something that is lower? For example try 40MHz. Does that make a difference? 

      

  • Hello Gavin,

    I reviewed the SysCtl file you sent and it is from 2.1.0. We have had multiple updates since then including a key update due to errata that can cause hard faults that is not reflected in your software. Please use the latest file from 2.1.4. You likely will find the changes you required are also baked into it but in a cleaner and more compact manner.

    See Errata items SYSCTL#22 and SYSCTL#23 that were addressed in 2.1.3 and newer: http://www.ti.com/lit/er/spmz850g/spmz850g.pdf