[HAL][RCC] Update HAL_RCC_ClockConfig() function to avoid issue with CPU clock being out of range versus the Flash latency
diff --git a/Src/stm32l4xx_hal_rcc.c b/Src/stm32l4xx_hal_rcc.c
index 71da794..d1d5e10 100644
--- a/Src/stm32l4xx_hal_rcc.c
+++ b/Src/stm32l4xx_hal_rcc.c
@@ -1144,6 +1144,18 @@
}
}
+ /*----------------- HCLK Configuration prior to SYSCLK----------------------*/
+ /* Apply higher HCLK prescaler request here to ensure CPU clock is not of of spec when SYSCLK is increased */
+ if(((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_HCLK) == RCC_CLOCKTYPE_HCLK)
+ {
+ assert_param(IS_RCC_HCLK(RCC_ClkInitStruct->AHBCLKDivider));
+
+ if(RCC_ClkInitStruct->AHBCLKDivider > READ_BIT(RCC->CFGR, RCC_CFGR_HPRE))
+ {
+ MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_ClkInitStruct->AHBCLKDivider);
+ }
+ }
+
/*------------------------- SYSCLK Configuration ---------------------------*/
if(((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_SYSCLK) == RCC_CLOCKTYPE_SYSCLK)
{
@@ -1163,22 +1175,12 @@
/* Compute target PLL output frequency */
if(RCC_GetSysClockFreqFromPLLSource() > 80000000U)
{
+ /* If lowest HCLK prescaler, apply intermediate step with HCLK prescaler 2 necessary before to go over 80Mhz */
if(READ_BIT(RCC->CFGR, RCC_CFGR_HPRE) == RCC_SYSCLK_DIV1)
{
- /* Intermediate step with HCLK prescaler 2 necessary before to go over 80Mhz */
MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_SYSCLK_DIV2);
hpre = RCC_SYSCLK_DIV2;
}
- else if((((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_HCLK) == RCC_CLOCKTYPE_HCLK) && (RCC_ClkInitStruct->AHBCLKDivider == RCC_SYSCLK_DIV1))
- {
- /* Intermediate step with HCLK prescaler 2 necessary before to go over 80Mhz */
- MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_SYSCLK_DIV2);
- hpre = RCC_SYSCLK_DIV2;
- }
- else
- {
- /* nothing to do */
- }
}
#endif
}
@@ -1216,9 +1218,12 @@
/* Overshoot management when going down from PLL as SYSCLK source and frequency above 80Mhz */
if(HAL_RCC_GetSysClockFreq() > 80000000U)
{
- /* Intermediate step with HCLK prescaler 2 necessary before to go under 80Mhz */
- MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_SYSCLK_DIV2);
- hpre = RCC_SYSCLK_DIV2;
+ /* If lowest HCLK prescaler, apply intermediate step with HCLK prescaler 2 necessary before to go under 80Mhz */
+ if(READ_BIT(RCC->CFGR, RCC_CFGR_HPRE) == RCC_SYSCLK_DIV1)
+ {
+ MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_SYSCLK_DIV2);
+ hpre = RCC_SYSCLK_DIV2;
+ }
}
#endif
@@ -1238,25 +1243,26 @@
}
}
- /*-------------------------- HCLK Configuration --------------------------*/
- if(((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_HCLK) == RCC_CLOCKTYPE_HCLK)
- {
- assert_param(IS_RCC_HCLK(RCC_ClkInitStruct->AHBCLKDivider));
- MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_ClkInitStruct->AHBCLKDivider);
- }
#if defined(STM32L4P5xx) || defined(STM32L4Q5xx) || \
defined(STM32L4R5xx) || defined(STM32L4R7xx) || defined(STM32L4R9xx) || defined(STM32L4S5xx) || defined(STM32L4S7xx) || defined(STM32L4S9xx)
- else
+ /* Is intermediate HCLK prescaler 2 applied internally, resume with HCLK prescaler 1 */
+ if(hpre == RCC_SYSCLK_DIV2)
{
- /* Is intermediate HCLK prescaler 2 applied internally, complete with HCLK prescaler 1 */
- if(hpre == RCC_SYSCLK_DIV2)
- {
- MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_SYSCLK_DIV1);
- }
+ MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_SYSCLK_DIV1);
}
#endif
- /* Decreasing the number of wait states because of lower CPU frequency */
+ /*----------------- HCLK Configuration after SYSCLK-------------------------*/
+ /* Apply lower HCLK prescaler request here to ensure CPU clock is not of of spec when SYSCLK is set */
+ if(((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_HCLK) == RCC_CLOCKTYPE_HCLK)
+ {
+ if(RCC_ClkInitStruct->AHBCLKDivider < READ_BIT(RCC->CFGR, RCC_CFGR_HPRE))
+ {
+ MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_ClkInitStruct->AHBCLKDivider);
+ }
+ }
+
+ /* Allow decreasing of the number of wait states (because of lower CPU frequency expected) */
if(FLatency < __HAL_FLASH_GET_LATENCY())
{
/* Program the new number of wait states to the LATENCY bits in the FLASH_ACR register */
@@ -1886,23 +1892,7 @@
*/
static uint32_t RCC_GetSysClockFreqFromPLLSource(void)
{
- uint32_t msirange = 0U;
- uint32_t pllvco, pllsource, pllr, pllm, sysclockfreq; /* no init needed */
-
- if(__HAL_RCC_GET_PLL_OSCSOURCE() == RCC_PLLSOURCE_MSI)
- {
- /* Get MSI range source */
- if(READ_BIT(RCC->CR, RCC_CR_MSIRGSEL) == 0U)
- { /* MSISRANGE from RCC_CSR applies */
- msirange = READ_BIT(RCC->CSR, RCC_CSR_MSISRANGE) >> RCC_CSR_MSISRANGE_Pos;
- }
- else
- { /* MSIRANGE from RCC_CR applies */
- msirange = READ_BIT(RCC->CR, RCC_CR_MSIRANGE) >> RCC_CR_MSIRANGE_Pos;
- }
- /*MSI frequency range in HZ*/
- msirange = MSIRangeTable[msirange];
- }
+ uint32_t msirange, pllvco, pllsource, pllr, pllm, sysclockfreq; /* no init needed */
/* PLL_VCO = (HSE_VALUE or HSI_VALUE or MSI_VALUE) * PLLN / PLLM
SYSCLK = PLL_VCO / PLLR
@@ -1920,8 +1910,21 @@
break;
case RCC_PLLSOURCE_MSI: /* MSI used as PLL clock source */
+ /* Get MSI range source */
+ if(READ_BIT(RCC->CR, RCC_CR_MSIRGSEL) == 0U)
+ { /* MSISRANGE from RCC_CSR applies */
+ msirange = READ_BIT(RCC->CSR, RCC_CSR_MSISRANGE) >> RCC_CSR_MSISRANGE_Pos;
+ }
+ else
+ { /* MSIRANGE from RCC_CR applies */
+ msirange = READ_BIT(RCC->CR, RCC_CR_MSIRANGE) >> RCC_CR_MSIRANGE_Pos;
+ }
+ /*MSI frequency range in HZ*/
+ pllvco = MSIRangeTable[msirange];
+ break;
default:
- pllvco = msirange;
+ /* unexpected */
+ pllvco = 0;
break;
}
pllm = (READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U ;