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 <giancarlo.stasi@nexxiot.com>
This commit is contained in:
parent
db9dca059e
commit
82a08a7678
2 changed files with 55 additions and 14 deletions
|
@ -9,6 +9,7 @@
|
||||||
#include <soc.h>
|
#include <soc.h>
|
||||||
#include <drivers/clock_control.h>
|
#include <drivers/clock_control.h>
|
||||||
#include <sys/util.h>
|
#include <sys/util.h>
|
||||||
|
#include <sys/__assert.h>
|
||||||
#include <drivers/clock_control/stm32_clock_control.h>
|
#include <drivers/clock_control/stm32_clock_control.h>
|
||||||
#include "clock_stm32_ll_common.h"
|
#include "clock_stm32_ll_common.h"
|
||||||
|
|
||||||
|
@ -286,6 +287,11 @@ static int stm32_clock_control_init(struct device *dev)
|
||||||
{
|
{
|
||||||
LL_UTILS_ClkInitTypeDef s_ClkInitStruct;
|
LL_UTILS_ClkInitTypeDef s_ClkInitStruct;
|
||||||
uint32_t hclk_prescaler;
|
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);
|
ARG_UNUSED(dev);
|
||||||
|
|
||||||
|
@ -381,6 +387,22 @@ static int stm32_clock_control_init(struct device *dev)
|
||||||
|
|
||||||
#elif CONFIG_CLOCK_STM32_SYSCLK_SRC_HSE
|
#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 */
|
/* Enable HSE if not enabled */
|
||||||
if (LL_RCC_HSE_IsReady() != 1) {
|
if (LL_RCC_HSE_IsReady() != 1) {
|
||||||
/* Check if need to enable HSE bypass feature or not */
|
/* 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 */
|
/* Update SystemCoreClock variable */
|
||||||
LL_SetSystemCoreClock(__LL_RCC_CALC_HCLK_FREQ(
|
LL_SetSystemCoreClock(new_hclk_freq);
|
||||||
CONFIG_CLOCK_STM32_HSE_CLOCK,
|
|
||||||
hclk_prescaler));
|
|
||||||
|
|
||||||
/* Set APB1 & APB2 prescaler*/
|
/* Set APB1 & APB2 prescaler*/
|
||||||
LL_RCC_SetAPB1Prescaler(s_ClkInitStruct.APB1CLKDivider);
|
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);
|
LL_RCC_SetAPB2Prescaler(s_ClkInitStruct.APB2CLKDivider);
|
||||||
#endif /* CONFIG_SOC_SERIES_STM32F0X && CONFIG_SOC_SERIES_STM32G0X */
|
#endif /* CONFIG_SOC_SERIES_STM32F0X && CONFIG_SOC_SERIES_STM32G0X */
|
||||||
|
|
||||||
/* Set flash latency */
|
/* If freq not increased, set flash latency after all clock setting */
|
||||||
/* HSI used as SYSCLK, set latency to 0 */
|
if (new_hclk_freq <= old_hclk_freq) {
|
||||||
LL_FLASH_SetLatency(LL_FLASH_LATENCY_0);
|
LL_SetFlashLatency(new_hclk_freq);
|
||||||
|
}
|
||||||
|
|
||||||
/* Disable other clocks */
|
/* Disable other clocks */
|
||||||
LL_RCC_HSI_Disable();
|
LL_RCC_HSI_Disable();
|
||||||
|
@ -425,6 +446,27 @@ static int stm32_clock_control_init(struct device *dev)
|
||||||
|
|
||||||
#elif CONFIG_CLOCK_STM32_SYSCLK_SRC_MSI
|
#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 */
|
/* Set MSI Range */
|
||||||
LL_RCC_MSI_EnableRangeSelection();
|
LL_RCC_MSI_EnableRangeSelection();
|
||||||
LL_RCC_MSI_SetRange(CONFIG_CLOCK_STM32_MSI_RANGE << RCC_CR_MSIRANGE_Pos);
|
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) {
|
while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_MSI) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update SystemCoreClock variable with MSI freq */
|
/* Update SystemCoreClock variable */
|
||||||
/* MSI freq is defined from RUN range selection */
|
LL_SetSystemCoreClock(new_hclk_freq);
|
||||||
LL_SetSystemCoreClock(__LL_RCC_CALC_MSI_FREQ(LL_RCC_MSIRANGESEL_RUN,
|
|
||||||
LL_RCC_MSI_GetRange()));
|
|
||||||
|
|
||||||
/* Set APB1 & APB2 prescaler*/
|
/* Set APB1 & APB2 prescaler*/
|
||||||
LL_RCC_SetAPB1Prescaler(s_ClkInitStruct.APB1CLKDivider);
|
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);
|
LL_RCC_SetAHB4Prescaler(s_ClkInitStruct->AHB4CLKDivider);
|
||||||
#endif /* CONFIG_SOC_SERIES_STM32WBX */
|
#endif /* CONFIG_SOC_SERIES_STM32WBX */
|
||||||
|
|
||||||
/* Set flash latency */
|
/* If freq not increased, set flash latency after all clock setting */
|
||||||
/* MSI used as SYSCLK (16MHz), set latency to 0 */
|
if (new_hclk_freq <= old_hclk_freq) {
|
||||||
LL_FLASH_SetLatency(LL_FLASH_LATENCY_0);
|
LL_SetFlashLatency(new_hclk_freq);
|
||||||
|
}
|
||||||
|
|
||||||
/* Disable other clocks */
|
/* Disable other clocks */
|
||||||
LL_RCC_HSE_Disable();
|
LL_RCC_HSE_Disable();
|
||||||
|
|
2
west.yml
2
west.yml
|
@ -71,7 +71,7 @@ manifest:
|
||||||
revision: 5b3ec3e182d4310e8943cc34c6c70ae57d9711da
|
revision: 5b3ec3e182d4310e8943cc34c6c70ae57d9711da
|
||||||
path: modules/hal/st
|
path: modules/hal/st
|
||||||
- name: hal_stm32
|
- name: hal_stm32
|
||||||
revision: 6812113dc58d134b74acdeebbffb4f80b8eeab75
|
revision: pull/54/head
|
||||||
path: modules/hal/stm32
|
path: modules/hal/stm32
|
||||||
- name: hal_ti
|
- name: hal_ti
|
||||||
revision: aabc6a04a8e871cbb01e02c22bb409f68001dc64
|
revision: aabc6a04a8e871cbb01e02c22bb409f68001dc64
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue