diff --git a/boards/common/stm32/include/f1f3/cfg_clock_default.h b/boards/common/stm32/include/f1f3/cfg_clock_default.h index a18cbf72fb..53d0f507e9 100644 --- a/boards/common/stm32/include/f1f3/cfg_clock_default.h +++ b/boards/common/stm32/include/f1f3/cfg_clock_default.h @@ -36,40 +36,113 @@ extern "C" { * @name Clock settings * @{ */ -/* 0: no external high speed crystal available - * else: actual crystal frequency [in Hz] */ -#ifndef CLOCK_HSE -#define CLOCK_HSE MHZ(8) -#endif - -/* give the target core clock (HCLK) frequency [in Hz], - * maximum: 72MHz when input clock is HSE, 64MHz when input clock is HSI */ -#if CLOCK_HSE -#define CLOCK_CORECLOCK MHZ(72) +/* Select the desired system clock source between PLL, HSE or HSI */ +#ifndef CONFIG_USE_CLOCK_PLL +#if IS_ACTIVE(CONFIG_USE_CLOCK_HSE) || IS_ACTIVE(CONFIG_USE_CLOCK_HSI) +#define CONFIG_USE_CLOCK_PLL 0 #else -#define CLOCK_CORECLOCK MHZ(64) +#define CONFIG_USE_CLOCK_PLL 1 /* Use PLL by default */ +#endif +#endif /* CONFIG_USE_CLOCK_PLL */ + +#ifndef CONFIG_USE_CLOCK_HSE +#define CONFIG_USE_CLOCK_HSE 0 +#endif /* CONFIG_USE_CLOCK_HSE */ + +#ifndef CONFIG_USE_CLOCK_HSI +#define CONFIG_USE_CLOCK_HSI 0 +#endif /* CONFIG_USE_CLOCK_HSI */ + +#if IS_ACTIVE(CONFIG_USE_CLOCK_PLL) && \ + (IS_ACTIVE(CONFIG_USE_CLOCK_HSE) || IS_ACTIVE(CONFIG_USE_CLOCK_HSI)) +#error "Cannot use PLL as clock source with other clock configurations" #endif -/* 0: no external low speed crystal available, - * 1: external crystal available (always 32.768kHz) */ -#ifndef CLOCK_LSE -#define CLOCK_LSE (0) +#if IS_ACTIVE(CONFIG_USE_CLOCK_HSE) && \ + (IS_ACTIVE(CONFIG_USE_CLOCK_PLL) || IS_ACTIVE(CONFIG_USE_CLOCK_HSI)) +#error "Cannot use HSE as clock source with other clock configurations" #endif -/* peripheral clock setup */ -#define CLOCK_AHB_DIV RCC_CFGR_HPRE_DIV1 -#define CLOCK_AHB (CLOCK_CORECLOCK / 1) -#define CLOCK_APB1_DIV RCC_CFGR_PPRE1_DIV2 /* max 36MHz */ -#define CLOCK_APB1 (CLOCK_CORECLOCK / 2) -#define CLOCK_APB2_DIV RCC_CFGR_PPRE2_DIV1 /* max 72MHz */ -#define CLOCK_APB2 (CLOCK_CORECLOCK / 1) -/* PLL factors */ -#ifndef CLOCK_PLL_PREDIV -#define CLOCK_PLL_PREDIV (1) +#if IS_ACTIVE(CONFIG_USE_CLOCK_HSI) && \ + (IS_ACTIVE(CONFIG_USE_CLOCK_PLL) || IS_ACTIVE(CONFIG_USE_CLOCK_HSE)) +#error "Cannot use HSI as clock source with other clock configurations" #endif -#ifndef CLOCK_PLL_MUL -#define CLOCK_PLL_MUL (9) + +#ifndef CONFIG_BOARD_HAS_HSE +#define CONFIG_BOARD_HAS_HSE 0 #endif + +#ifndef CLOCK_HSE +#define CLOCK_HSE MHZ(8) +#endif +#if IS_ACTIVE(CONFIG_BOARD_HAS_HSE) && (CLOCK_HSE < MHZ(4) || CLOCK_HSE > MHZ(32)) +#error "HSE clock frequency must be between 4MHz and 32MHz" +#endif + +#ifndef CONFIG_BOARD_HAS_LSE +#define CONFIG_BOARD_HAS_LSE 0 +#endif +#if IS_ACTIVE(CONFIG_BOARD_HAS_LSE) +#define CLOCK_LSE (1) +#else +#define CLOCK_LSE (0) +#endif + +#define CLOCK_HSI MHZ(8) + +/* The following parameters configure a 72MHz system clock with HSE (8MHz or + 16MHz) and HSI (8MHz) as input clock */ +#ifndef CONFIG_CLOCK_PLL_PREDIV +#if IS_ACTIVE(CONFIG_BOARD_HAS_HSE) && (CLOCK_HSE == MHZ(16)) +#define CONFIG_CLOCK_PLL_PREDIV (2) +#else +#define CONFIG_CLOCK_PLL_PREDIV (1) +#endif +#endif +#ifndef CONFIG_CLOCK_PLL_MUL +#define CONFIG_CLOCK_PLL_MUL (9) +#endif + +#if IS_ACTIVE(CONFIG_USE_CLOCK_HSI) +#define CLOCK_CORECLOCK (CLOCK_HSI) + +#elif IS_ACTIVE(CONFIG_USE_CLOCK_HSE) +#if !IS_ACTIVE(CONFIG_BOARD_HAS_HSE) +#error "The board doesn't provide an HSE oscillator" +#endif +#define CLOCK_CORECLOCK (CLOCK_HSE) + +#elif IS_ACTIVE(CONFIG_USE_CLOCK_PLL) +#if IS_ACTIVE(CONFIG_BOARD_HAS_HSE) +#define CLOCK_PLL_SRC (CLOCK_HSE) +#else /* CLOCK_HSI */ +#define CLOCK_PLL_SRC (CLOCK_HSI) +#endif +/* PLL configuration: make sure your values are legit! + * + * compute by: CORECLOCK = ((PLL_IN / PLL_PREDIV) * PLL_MUL) + * with: + * PLL_IN: input clock is HSE if available or HSI otherwise + * PLL_PREDIV : pre-divider, allowed range: [1:16] + * PLL_MUL: multiplier, allowed range: [2:16] + * CORECLOCK -> 72MHz MAX! + */ +#define CLOCK_CORECLOCK ((CLOCK_PLL_SRC / CONFIG_CLOCK_PLL_PREDIV) * CONFIG_CLOCK_PLL_MUL) +#if CLOCK_CORECLOCK > MHZ(72) +#error "SYSCLK cannot exceed 72MHz" +#endif +#endif /* CONFIG_USE_CLOCK_PLL */ + +#define CLOCK_AHB CLOCK_CORECLOCK /* HCLK, max: 72MHz */ + +#ifndef CONFIG_CLOCK_APB1_DIV +#define CONFIG_CLOCK_APB1_DIV (2) +#endif +#define CLOCK_APB1 (CLOCK_AHB / CONFIG_CLOCK_APB1_DIV) /* PCLK1, max: 36MHz */ +#ifndef CONFIG_CLOCK_APB2_DIV +#define CONFIG_CLOCK_APB2_DIV (1) +#endif +#define CLOCK_APB2 (CLOCK_AHB / CONFIG_CLOCK_APB2_DIV) /* PCLK2, max: 72MHz */ /** @} */ #ifdef __cplusplus diff --git a/cpu/stm32/stmclk/Makefile b/cpu/stm32/stmclk/Makefile index ea3f263e5f..d3d0295d8d 100644 --- a/cpu/stm32/stmclk/Makefile +++ b/cpu/stm32/stmclk/Makefile @@ -2,10 +2,10 @@ MODULE = stm32_clk SRC = stmclk_common.c -ifneq (,$(filter-out f0,$(filter f%,$(CPU_FAM)))) +ifneq (,$(filter f2 f4 f7,$(CPU_FAM))) SRC += stmclk_fx.c -else ifneq (,$(filter $(CPU_FAM),f0)) - SRC += stmclk_f0.c +else ifneq (,$(filter $(CPU_FAM),f0 f1 f3)) + SRC += stmclk_f0f1f3.c else ifneq (,$(filter $(CPU_FAM),l0 l1)) SRC += stmclk_l0l1.c else ifneq (,$(filter $(CPU_FAM),l4 wb)) diff --git a/cpu/stm32/stmclk/stmclk_f0.c b/cpu/stm32/stmclk/stmclk_f0f1f3.c similarity index 53% rename from cpu/stm32/stmclk/stmclk_f0.c rename to cpu/stm32/stmclk/stmclk_f0f1f3.c index e187ebfe5d..a871f5fdec 100644 --- a/cpu/stm32/stmclk/stmclk_f0.c +++ b/cpu/stm32/stmclk/stmclk_f0f1f3.c @@ -13,7 +13,7 @@ * @{ * * @file - * @brief Implementation of STM32 clock configuration for STM32 F0 + * @brief Implementation of STM32 clock configuration for STM32 F0/F1/F3 * * @author Hauke Petersen * @author Vincent Dupont @@ -26,17 +26,32 @@ #include "periph_conf.h" /* PLL configuration */ +#if defined(CPU_FAM_STM32F1) #if IS_ACTIVE(CONFIG_BOARD_HAS_HSE) +#define PLL_SRC (RCC_CFGR_PLLSRC) /* HSE */ +#else +#define PLL_SRC (0) /* HSI / 2 */ +#endif + +/* RCC_CR_HSITRIM_4 is not defined on stm32f1 and corresponds to a value of 16. + Use the same definition used for stm32f0/stm32f3 */ +#define RCC_CR_HSITRIM_4 (0x10UL << RCC_CR_HSITRIM_Pos) +#define RCC_CFGR_PLLMUL RCC_CFGR_PLLMULL +#define PLL_MUL ((CONFIG_CLOCK_PLL_MUL - 2) << RCC_CFGR_PLLMULL_Pos) +#else /* CPU_FAM_STM32F0 && CPU_FAM_STM32F3 */ +#if CONFIG_BOARD_HAS_HSE #define PLL_SRC (RCC_CFGR_PLLSRC_HSE_PREDIV | RCC_CFGR_PLLXTPRE_HSE_PREDIV_DIV1) #else #define PLL_SRC (RCC_CFGR_PLLSRC_HSI_DIV2) #endif - #define PLL_MUL ((CONFIG_CLOCK_PLL_MUL - 2) << RCC_CFGR_PLLMUL_Pos) +#endif /* CPU_FAM_STM32F1 */ + #define PLL_PREDIV (CONFIG_CLOCK_PLL_PREDIV - 1) #define CLOCK_AHB_DIV (RCC_CFGR_HPRE_DIV1) +#if defined(CPU_FAM_STM32F0) #if CONFIG_CLOCK_APB1_DIV == 1 #define CLOCK_APB1_DIV (RCC_CFGR_PPRE_DIV1) #elif CONFIG_CLOCK_APB1_DIV == 2 @@ -50,7 +65,69 @@ #else #error "Invalid APB prescaler value (only 1, 2, 4, 8 and 16 allowed)" #endif +#else +#if CONFIG_CLOCK_APB1_DIV == 1 +#define CLOCK_APB1_DIV (RCC_CFGR_PPRE1_DIV1) +#elif CONFIG_CLOCK_APB1_DIV == 2 +#define CLOCK_APB1_DIV (RCC_CFGR_PPRE1_DIV2) +#elif CONFIG_CLOCK_APB1_DIV == 4 +#define CLOCK_APB1_DIV (RCC_CFGR_PPRE1_DIV4) +#elif CONFIG_CLOCK_APB1_DIV == 8 +#define CLOCK_APB1_DIV (RCC_CFGR_PPRE1_DIV8) +#elif CONFIG_CLOCK_APB1_DIV == 16 +#define CLOCK_APB1_DIV (RCC_CFGR_PPRE1_DIV16) +#else +#error "Invalid APB1 prescaler value (only 1, 2, 4, 8 and 16 allowed)" +#endif +#if CONFIG_CLOCK_APB2_DIV == 1 +#define CLOCK_APB2_DIV (RCC_CFGR_PPRE2_DIV1) +#elif CONFIG_CLOCK_APB2_DIV == 2 +#define CLOCK_APB2_DIV (RCC_CFGR_PPRE2_DIV2) +#elif CONFIG_CLOCK_APB2_DIV == 4 +#define CLOCK_APB2_DIV (RCC_CFGR_PPRE2_DIV4) +#elif CONFIG_CLOCK_APB2_DIV == 8 +#define CLOCK_APB2_DIV (RCC_CFGR_PPRE2_DIV8) +#elif CONFIG_CLOCK_APB2_DIV == 16 +#define CLOCK_APB2_DIV (RCC_CFGR_PPRE2_DIV16) +#else +#error "Invalid APB2 prescaler value (only 1, 2, 4, 8 and 16 allowed)" +#endif +#endif + +/* Check whether PLL is required */ +/* Check whether PLL must be enabled: + - When PLLCLK is used as SYSCLK +*/ +#if IS_ACTIVE(CONFIG_USE_CLOCK_PLL) +#define CLOCK_ENABLE_PLL 1 +#else +#define CLOCK_ENABLE_PLL 0 +#endif + +/* Check whether HSE is required: + - When HSE is used as SYSCLK + - When PLL is used as SYSCLK and the board provides HSE (since HSE will be + used as PLL input clock) +*/ +#if IS_ACTIVE(CONFIG_USE_CLOCK_HSE) || \ + (IS_ACTIVE(CONFIG_BOARD_HAS_HSE) && IS_ACTIVE(CONFIG_USE_CLOCK_PLL)) +#define CLOCK_ENABLE_HSE 1 +#else +#define CLOCK_ENABLE_HSE 0 +#endif + +/* Check whether HSI is required: + - When HSI is used as SYSCLK + - When PLL is used as SYSCLK and the board doesn't provide HSE (since HSI will be + used as PLL input clock) +*/ +#if IS_ACTIVE(CONFIG_USE_CLOCK_HSI) || \ + (!IS_ACTIVE(CONFIG_BOARD_HAS_HSE) && IS_ACTIVE(CONFIG_USE_CLOCK_PLL)) +#define CLOCK_ENABLE_HSI 1 +#else +#define CLOCK_ENABLE_HSI 0 +#endif /* Deduct the needed flash wait states from the core clock frequency */ #define FLASH_WAITSTATES ((CLOCK_CORECLOCK - 1) / MHZ(24)) @@ -71,7 +148,11 @@ void stmclk_init_sysclk(void) /* use HSI as system clock while we do any further configuration and * configure the AHB and APB clock dividers as configure by the board */ +#if defined(CPU_FAM_STM32F0) RCC->CFGR = (RCC_CFGR_SW_HSI | CLOCK_AHB_DIV | CLOCK_APB1_DIV); +#else /* CPU_FAM_STM32F1 && CPU_FAM_STM32F3 */ + RCC->CFGR = (RCC_CFGR_SW_HSI | CLOCK_AHB_DIV | CLOCK_APB1_DIV | CLOCK_APB2_DIV); +#endif /* CPU_FAM_STM32F0*/ while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI) {} /* Flash config */ @@ -80,39 +161,40 @@ void stmclk_init_sysclk(void) /* disable all active clocks except HSI -> resets the clk configuration */ RCC->CR = (RCC_CR_HSION | RCC_CR_HSITRIM_4); - /* HSE is only used if provided by board and core clock input is using HSE - or PLL */ - if (IS_ACTIVE(CONFIG_BOARD_HAS_HSE) && !IS_ACTIVE(CONFIG_USE_CLOCK_HSI)) { + /* Enable HSE if it's used */ + if (IS_ACTIVE(CLOCK_ENABLE_HSE)) { RCC->CR |= (RCC_CR_HSEON); while (!(RCC->CR & RCC_CR_HSERDY)) {} } - if (IS_ACTIVE(CONFIG_USE_CLOCK_HSE)) { - RCC->CFGR |= RCC_CFGR_SW_HSE; - while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSE) {} - } - else if (IS_ACTIVE(CONFIG_USE_CLOCK_PLL)) { - /* now the PLL can safely be configured and started */ - /* reset PLL configuration bits */ + /* Enable PLL if it's used */ + if (IS_ACTIVE(CLOCK_ENABLE_PLL)) { RCC->CFGR &= ~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMUL); /* set PLL configuration */ RCC->CFGR |= (PLL_SRC | PLL_MUL); if (CONFIG_CLOCK_PLL_PREDIV == 2) { RCC->CFGR |= RCC_CFGR_PLLXTPRE; /* PREDIV == 2 */ } +#if !defined(CPU_FAM_STM32F1) else if (CONFIG_CLOCK_PLL_PREDIV > 2) { RCC->CFGR2 = PLL_PREDIV; /* PREDIV > 2 */ } +#endif RCC->CR |= (RCC_CR_PLLON); while (!(RCC->CR & RCC_CR_PLLRDY)) {} + } - /* now that the PLL is running, use it as system clock */ + /* Configure SYSCLK */ + if (IS_ACTIVE(CONFIG_USE_CLOCK_HSE)) { + RCC->CFGR |= RCC_CFGR_SW_HSE; + while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSE) {} + } + else if (IS_ACTIVE(CONFIG_USE_CLOCK_PLL)) { RCC->CFGR |= RCC_CFGR_SW_PLL; while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) {} } - if (!IS_ACTIVE(CONFIG_USE_CLOCK_HSI) || - (IS_ACTIVE(CONFIG_USE_CLOCK_PLL) && IS_ACTIVE(CONFIG_BOARD_HAS_HSE))) { + if (!IS_ACTIVE(CLOCK_ENABLE_HSI)) { /* Disable HSI only if not used */ stmclk_disable_hsi(); }