From 82a08a7678488b3944a8504187e847c37dbf09e7 Mon Sep 17 00:00:00 2001 From: Giancarlo Stasi Date: Fri, 12 Jun 2020 23:44:29 +0200 Subject: [PATCH] drivers: clock: stm32: fix Flash latency & clock settings for MSI & HSE According to RM, when increasing the CPU frequency, the new number of wait states to the Flash latency bits must be written and verified before modifying the CPU clock source and/or the CPU clock prescaler, to prevent NMI to occur; when decreasing the CPU frequency, after. Tested with STM32L462 SOC and MSI with several frequencies, both increasing and decreasing. HSE built, not tested. Signed-off-by: Giancarlo Stasi --- drivers/clock_control/clock_stm32_ll_common.c | 67 +++++++++++++++---- west.yml | 2 +- 2 files changed, 55 insertions(+), 14 deletions(-) diff --git a/drivers/clock_control/clock_stm32_ll_common.c b/drivers/clock_control/clock_stm32_ll_common.c index e92224ee2ae..8e956d41f4a 100644 --- a/drivers/clock_control/clock_stm32_ll_common.c +++ b/drivers/clock_control/clock_stm32_ll_common.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "clock_stm32_ll_common.h" @@ -286,6 +287,11 @@ static int stm32_clock_control_init(struct device *dev) { LL_UTILS_ClkInitTypeDef s_ClkInitStruct; uint32_t hclk_prescaler; +#if defined(CONFIG_CLOCK_STM32_SYSCLK_SRC_HSE) || \ + defined(CONFIG_CLOCK_STM32_SYSCLK_SRC_MSI) + uint32_t old_hclk_freq; + uint32_t new_hclk_freq; +#endif ARG_UNUSED(dev); @@ -381,6 +387,22 @@ static int stm32_clock_control_init(struct device *dev) #elif CONFIG_CLOCK_STM32_SYSCLK_SRC_HSE + old_hclk_freq = HAL_RCC_GetHCLKFreq(); + + /* Calculate new SystemCoreClock variable based on HSE freq */ + new_hclk_freq = __LL_RCC_CALC_HCLK_FREQ(CONFIG_CLOCK_STM32_HSE_CLOCK, + hclk_prescaler); +#if defined(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC) + __ASSERT(new_hclk_freq == CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC, + "Config mismatch HCLK frequency %u %u", + CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC, new_hclk_freq); +#endif + + /* If freq increases, set flash latency before any clock setting */ + if (new_hclk_freq > old_hclk_freq) { + LL_SetFlashLatency(new_hclk_freq); + } + /* Enable HSE if not enabled */ if (LL_RCC_HSE_IsReady() != 1) { /* Check if need to enable HSE bypass feature or not */ @@ -404,9 +426,7 @@ static int stm32_clock_control_init(struct device *dev) } /* Update SystemCoreClock variable */ - LL_SetSystemCoreClock(__LL_RCC_CALC_HCLK_FREQ( - CONFIG_CLOCK_STM32_HSE_CLOCK, - hclk_prescaler)); + LL_SetSystemCoreClock(new_hclk_freq); /* Set APB1 & APB2 prescaler*/ LL_RCC_SetAPB1Prescaler(s_ClkInitStruct.APB1CLKDivider); @@ -414,9 +434,10 @@ static int stm32_clock_control_init(struct device *dev) LL_RCC_SetAPB2Prescaler(s_ClkInitStruct.APB2CLKDivider); #endif /* CONFIG_SOC_SERIES_STM32F0X && CONFIG_SOC_SERIES_STM32G0X */ - /* Set flash latency */ - /* HSI used as SYSCLK, set latency to 0 */ - LL_FLASH_SetLatency(LL_FLASH_LATENCY_0); + /* If freq not increased, set flash latency after all clock setting */ + if (new_hclk_freq <= old_hclk_freq) { + LL_SetFlashLatency(new_hclk_freq); + } /* Disable other clocks */ LL_RCC_HSI_Disable(); @@ -425,6 +446,27 @@ static int stm32_clock_control_init(struct device *dev) #elif CONFIG_CLOCK_STM32_SYSCLK_SRC_MSI + old_hclk_freq = HAL_RCC_GetHCLKFreq(); + + /* Calculate new SystemCoreClock variable with MSI freq */ + /* MSI freq is defined from RUN range selection */ + new_hclk_freq = + __LL_RCC_CALC_HCLK_FREQ( + __LL_RCC_CALC_MSI_FREQ(LL_RCC_MSIRANGESEL_RUN, + CONFIG_CLOCK_STM32_MSI_RANGE << RCC_CR_MSIRANGE_Pos), + hclk_prescaler); + +#if defined(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC) + __ASSERT(new_hclk_freq == CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC, + "Config mismatch HCLK frequency %u %u", + CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC, new_hclk_freq); +#endif + + /* If freq increases, set flash latency before any clock setting */ + if (new_hclk_freq > old_hclk_freq) { + LL_SetFlashLatency(new_hclk_freq); + } + /* Set MSI Range */ LL_RCC_MSI_EnableRangeSelection(); LL_RCC_MSI_SetRange(CONFIG_CLOCK_STM32_MSI_RANGE << RCC_CR_MSIRANGE_Pos); @@ -448,10 +490,8 @@ static int stm32_clock_control_init(struct device *dev) while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_MSI) { } - /* Update SystemCoreClock variable with MSI freq */ - /* MSI freq is defined from RUN range selection */ - LL_SetSystemCoreClock(__LL_RCC_CALC_MSI_FREQ(LL_RCC_MSIRANGESEL_RUN, - LL_RCC_MSI_GetRange())); + /* Update SystemCoreClock variable */ + LL_SetSystemCoreClock(new_hclk_freq); /* Set APB1 & APB2 prescaler*/ LL_RCC_SetAPB1Prescaler(s_ClkInitStruct.APB1CLKDivider); @@ -462,9 +502,10 @@ static int stm32_clock_control_init(struct device *dev) LL_RCC_SetAHB4Prescaler(s_ClkInitStruct->AHB4CLKDivider); #endif /* CONFIG_SOC_SERIES_STM32WBX */ - /* Set flash latency */ - /* MSI used as SYSCLK (16MHz), set latency to 0 */ - LL_FLASH_SetLatency(LL_FLASH_LATENCY_0); + /* If freq not increased, set flash latency after all clock setting */ + if (new_hclk_freq <= old_hclk_freq) { + LL_SetFlashLatency(new_hclk_freq); + } /* Disable other clocks */ LL_RCC_HSE_Disable(); diff --git a/west.yml b/west.yml index eaf1e3157bd..5a12af98394 100644 --- a/west.yml +++ b/west.yml @@ -71,7 +71,7 @@ manifest: revision: 5b3ec3e182d4310e8943cc34c6c70ae57d9711da path: modules/hal/st - name: hal_stm32 - revision: 6812113dc58d134b74acdeebbffb4f80b8eeab75 + revision: pull/54/head path: modules/hal/stm32 - name: hal_ti revision: aabc6a04a8e871cbb01e02c22bb409f68001dc64