cancel
Showing results for 
Search instead for 
Did you mean: 

Setting up clocks on STM32U5 (Nucleo board) in startup assembler

Rob Meades
Senior

We have code which performs quite a lot of operations in C constructors.  This means that, with the standard STM32U5 startup code, execution of __libc_init_array takes around 10 seconds, which is undesirable, hence we would like to set up all of the system clocks, so that the chip is running at full speed, before we get there.

We have tried calling SystemCoreClockUpdate from the startup code before __libc_init_array (see code below) however that makes no difference.  What might we do to bring the core up to full speed before libc is initialised?

Reset_Handler:
  ldr   sp, =_estack    /* set stack pointer */
/* Call the clock system initialization function.*/
  bl  SystemInit

/* Copy the data segment initializers from flash to SRAM */
  movs r1, #0
  b LoopCopyDataInit

CopyDataInit:
ldr r3, =_sidata
ldr r3, [r3, r1]
str r3, [r0, r1]
adds r1, r1, #4

LoopCopyDataInit:
ldr r0, =_sdata
ldr r3, =_edata
adds r2, r0, r1
cmp r2, r3
bcc CopyDataInit
ldr r2, =_sbss
b LoopFillZerobss
/* Zero fill the bss segment. */
FillZerobss:
movs r3, #0
str r3, [r2], #4

LoopFillZerobss:
ldr r3, = _ebss
cmp r2, r3
bcc FillZerobss
/* Added in an attempt to bring chip up to full speed */
bl SystemCoreClockUpdate

/* Call static constructors */
    bl __libc_init_array
/* Call the application's entry point.*/
bl main

LoopForever:
    b LoopForever

These are our system clock settings (in a non-secure system):

#if !defined (HSE_VALUE)
#define HSE_VALUE 16000000U /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */

#if !defined (MSI_VALUE)
#define MSI_VALUE 4000000U /*!< Value of the Internal oscillator in Hz*/
#endif /* MSI_VALUE */

#if !defined (HSI_VALUE)
#define HSI_VALUE 16000000U /*!< Value of the Internal oscillator in Hz*/
#endif /* HSI_VALUE */
 

 

uint32_t SystemCoreClock = 4000000U;

const uint8_t AHBPrescTable[16] = {0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 1U, 2U, 3U, 4U, 6U, 7U, 8U, 9U};
const uint8_t APBPrescTable[8] = {0U, 0U, 0U, 0U, 1U, 2U, 3U, 4U};
const uint32_t MSIRangeTable[16] = {48000000U,24000000U,16000000U,12000000U, 4000000U, 2000000U, 1330000U,\
1000000U, 3072000U, 1536000U,1024000U, 768000U, 400000U, 200000U, 133000U, 100000U};


 

1 ACCEPTED SOLUTION

Accepted Solutions
Andrew Neil
Evangelist III

@Rob Meades wrote:

We have tried calling SystemCoreClockUpdate from the startup code before __libc_init_array (see code below) however that makes no difference.   


It wouldn't: it doesn't do anything to configure the clocks - it just updates the SystemCoreClock variable to reflect the current settings:

 

/**
  * @brief  Update SystemCoreClock variable according to Clock Register Values.
  *         The SystemCoreClock variable contains the core clock (HCLK), it can
  *         be used by the user application to setup the SysTick timer or configure
  *         other parameters.
  *
  * @note   Each time the core clock (HCLK) changes, this function must be called
  *         to update SystemCoreClock variable value. Otherwise, any configuration
  *         based on this variable will be incorrect.
  *
  * @note   - The system frequency computed by this function is not the real
  *           frequency in the chip. It is calculated based on the predefined
  *           constant and the selected clock source:
  *
  *           - If SYSCLK source is MSI, SystemCoreClock will contain the MSI
  *             value as defined by the MSI range.
  *
  *           - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*)
  *
  *           - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**)
  *
  *           - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**)
  *             or HSI_VALUE(*) multiplied/divided by the PLL factors.
  *
  *         (*) HSI_VALUE is a constant defined in stm32l0xx_hal.h file (default value
  *             16 MHz) but the real value may vary depending on the variations
  *             in voltage and temperature.
  *
  *         (**) HSE_VALUE is a constant defined in stm32l0xx_hal.h file (default value
  *              8 MHz), user has to ensure that HSE_VALUE is same as the real
  *              frequency of the crystal used. Otherwise, this function may
  *              have wrong result.
  *
  *         - The result of this function could be not correct when using fractional
  *           value for HSE crystal.
  * @PAram  None
  * @retval None
  */
void SystemCoreClockUpdate (void)

 

 

You need to call SystemClock_Config() - or replicate it.

 

 

 

View solution in original post

4 REPLIES 4
Andrew Neil
Evangelist III

@Rob Meades wrote:

We have tried calling SystemCoreClockUpdate from the startup code before __libc_init_array (see code below) however that makes no difference.   


It wouldn't: it doesn't do anything to configure the clocks - it just updates the SystemCoreClock variable to reflect the current settings:

 

/**
  * @brief  Update SystemCoreClock variable according to Clock Register Values.
  *         The SystemCoreClock variable contains the core clock (HCLK), it can
  *         be used by the user application to setup the SysTick timer or configure
  *         other parameters.
  *
  * @note   Each time the core clock (HCLK) changes, this function must be called
  *         to update SystemCoreClock variable value. Otherwise, any configuration
  *         based on this variable will be incorrect.
  *
  * @note   - The system frequency computed by this function is not the real
  *           frequency in the chip. It is calculated based on the predefined
  *           constant and the selected clock source:
  *
  *           - If SYSCLK source is MSI, SystemCoreClock will contain the MSI
  *             value as defined by the MSI range.
  *
  *           - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*)
  *
  *           - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**)
  *
  *           - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**)
  *             or HSI_VALUE(*) multiplied/divided by the PLL factors.
  *
  *         (*) HSI_VALUE is a constant defined in stm32l0xx_hal.h file (default value
  *             16 MHz) but the real value may vary depending on the variations
  *             in voltage and temperature.
  *
  *         (**) HSE_VALUE is a constant defined in stm32l0xx_hal.h file (default value
  *              8 MHz), user has to ensure that HSE_VALUE is same as the real
  *              frequency of the crystal used. Otherwise, this function may
  *              have wrong result.
  *
  *         - The result of this function could be not correct when using fractional
  *           value for HSE crystal.
  * @PAram  None
  * @retval None
  */
void SystemCoreClockUpdate (void)

 

 

You need to call SystemClock_Config() - or replicate it.

 

 

 

Rob Meades
Senior

Gah, sorry, yes, thanks for pointing that out, I always get confused with these System/Clock function names.  Calling the right function does indeed speed things up :-).

Model typically is to initialize clocks, external memories, etc in SystemInit(), but remember system is in a pre-init state, the C runtime hasn't moved/cleared the statics yet.

ST broke the CMSIS model by waiting to get to main() to get the system reasonably initialized. The older SPL did this properly. Can find code examples there, not for U5, but F1,F2,F3,F4,L1 for sure.

You can also peek/poke the RCC registers in Reset_Handler(), orders of magnitude more funner, but still.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..