diff --git a/boards/b-l072z-lrwan1/include/periph_conf.h b/boards/b-l072z-lrwan1/include/periph_conf.h index b596a664f6..3381fb6bd7 100644 --- a/boards/b-l072z-lrwan1/include/periph_conf.h +++ b/boards/b-l072z-lrwan1/include/periph_conf.h @@ -19,8 +19,13 @@ #ifndef PERIPH_CONF_H #define PERIPH_CONF_H +/* Add specific clock configuration (HSE, LSE) for this board here */ +#ifndef CONFIG_BOARD_HAS_LSE +#define CONFIG_BOARD_HAS_LSE 1 +#endif + #include "periph_cpu.h" -#include "l0/cfg_clock_32_16_1.h" +#include "l0l1/cfg_clock_default.h" #include "cfg_rtt_default.h" #include "cfg_i2c1_pb8_pb9.h" #include "cfg_timer_tim2.h" diff --git a/boards/common/stm32/include/l0/cfg_clock_32_16_1.h b/boards/common/stm32/include/l0/cfg_clock_32_16_1.h deleted file mode 100644 index 4274804229..0000000000 --- a/boards/common/stm32/include/l0/cfg_clock_32_16_1.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2018-2019 Inria - * - * This file is subject to the terms and conditions of the GNU Lesser - * General Public License v2.1. See the file LICENSE in the top level - * directory for more details. - */ - -/** - * @ingroup boards_common_stm32 - * @{ - * - * @file - * @brief Configure STM32L0 clock using 32MHz core clock and LSE (32.768kHz) - * - * @author Alexandre Abadie - */ - -#ifndef L0_CFG_CLOCK_32_16_1_H -#define L0_CFG_CLOCK_32_16_1_H - -#include "periph_cpu.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @name Clock system configuration - * @{ - */ -#define CLOCK_HSI (16000000U) /* internal oscillator */ -#define CLOCK_CORECLOCK (32000000U) /* desired core clock frequency */ -#define CLOCK_LSE (1) /* enable low speed external oscillator */ - -/* configuration of PLL prescaler and multiply values */ -/* CORECLOCK := HSI / CLOCK_PLL_DIV * CLOCK_PLL_MUL */ -#define CLOCK_PLL_DIV RCC_CFGR_PLLDIV2 -#define CLOCK_PLL_MUL RCC_CFGR_PLLMUL4 -/* configuration of peripheral bus clock prescalers */ -#define CLOCK_AHB_DIV RCC_CFGR_HPRE_DIV1 /* AHB clock -> 32MHz */ -#define CLOCK_APB2_DIV RCC_CFGR_PPRE2_DIV1 /* APB2 clock -> 32MHz */ -#define CLOCK_APB1_DIV RCC_CFGR_PPRE1_DIV1 /* APB1 clock -> 32MHz */ -/* configuration of flash access cycles */ -#define CLOCK_FLASH_LATENCY FLASH_ACR_LATENCY - -/* bus clocks for simplified peripheral initialization, UPDATE MANUALLY! */ -#define CLOCK_AHB (CLOCK_CORECLOCK / 1) -#define CLOCK_APB2 (CLOCK_CORECLOCK / 1) -#define CLOCK_APB1 (CLOCK_CORECLOCK / 1) -/** @} */ - -#ifdef __cplusplus -} -#endif - -#endif /* L0_CFG_CLOCK_32_16_1_H */ -/** @} */ diff --git a/boards/common/stm32/include/l0l1/cfg_clock_default.h b/boards/common/stm32/include/l0l1/cfg_clock_default.h new file mode 100644 index 0000000000..883a70e8f3 --- /dev/null +++ b/boards/common/stm32/include/l0l1/cfg_clock_default.h @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2018-2020 Inria + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup boards_common_stm32 + * @{ + * + * @file + * @brief Default STM32L0/STM32L1 clock configuration + * + * @author Alexandre Abadie + */ + +#ifndef L0L1_CFG_CLOCK_DEFAULT_H +#define L0L1_CFG_CLOCK_DEFAULT_H + +#include "periph_cpu.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Clock system configuration + * @{ + */ +/* 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) || \ + IS_ACTIVE(CONFIG_USE_CLOCK_MSI) +#define CONFIG_USE_CLOCK_PLL 0 +#else +#define CONFIG_USE_CLOCK_PLL 1 /* Use PLL by default */ +#endif +#endif /* CONFIG_USE_CLOCK_PLL */ + +#ifndef CONFIG_USE_CLOCK_MSI +#define CONFIG_USE_CLOCK_MSI 0 +#endif /* CONFIG_USE_CLOCK_MSI */ + +#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_MSI) || IS_ACTIVE(CONFIG_USE_CLOCK_HSE) || \ + IS_ACTIVE(CONFIG_USE_CLOCK_HSI)) +#error "Cannot use PLL as clock source with other clock configurations" +#endif + +#if IS_ACTIVE(CONFIG_USE_CLOCK_MSI) && \ + (IS_ACTIVE(CONFIG_USE_CLOCK_PLL) || IS_ACTIVE(CONFIG_USE_CLOCK_HSE) || \ + IS_ACTIVE(CONFIG_USE_CLOCK_HSI)) +#error "Cannot use MSI as clock source with other clock configurations" +#endif + +#if IS_ACTIVE(CONFIG_USE_CLOCK_HSE) && \ + (IS_ACTIVE(CONFIG_USE_CLOCK_PLL) || IS_ACTIVE(CONFIG_USE_CLOCK_MSI) || \ + IS_ACTIVE(CONFIG_USE_CLOCK_HSI)) +#error "Cannot use HSE as clock source with other clock configurations" +#endif + +#if IS_ACTIVE(CONFIG_USE_CLOCK_HSI) && \ + (IS_ACTIVE(CONFIG_USE_CLOCK_PLL) || IS_ACTIVE(CONFIG_USE_CLOCK_MSI) || \ + IS_ACTIVE(CONFIG_USE_CLOCK_HSE)) +#error "Cannot use HSI as clock source with other clock configurations" +#endif + +#ifndef CONFIG_BOARD_HAS_HSE +#define CONFIG_BOARD_HAS_HSE 0 +#endif + +#ifndef CLOCK_HSE +#define CLOCK_HSE MHZ(24) +#endif +#if IS_ACTIVE(CONFIG_BOARD_HAS_HSE) && (CLOCK_HSE < MHZ(1) || CLOCK_HSE > MHZ(24)) +#error "HSE clock frequency must be between 1MHz and 24MHz" +#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(16) + +#ifndef CONFIG_CLOCK_MSI +#define CONFIG_CLOCK_MSI KHZ(4194) +#endif + +/* The following parameters configure a 32MHz system clock with HSI as input clock */ +#ifndef CONFIG_CLOCK_PLL_DIV +#define CONFIG_CLOCK_PLL_DIV (2) +#endif +#ifndef CONFIG_CLOCK_PLL_MUL +#define CONFIG_CLOCK_PLL_MUL (4) +#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_MSI) +#define CLOCK_CORECLOCK (CONFIG_CLOCK_MSI) + +#elif IS_ACTIVE(CONFIG_USE_CLOCK_PLL) +#if IS_ACTIVE(CONFIG_BOARD_HAS_HSE) +#if CLOCK_HSE < MHZ(2) +#error "HSE must be greater than 2MHz when used as PLL input clock" +#endif +#define CLOCK_PLL_SRC (CLOCK_HSE) +#else /* CLOCK_HSI */ +#define CLOCK_PLL_SRC (CLOCK_HSI) +#endif /* CONFIG_BOARD_HAS_HSE */ +/* 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_DIV : divider, allowed values: 2, 3, 4. Default is 2. + * PLL_MUL: multiplier, allowed values: 3, 4, 6, 8, 12, 16, 24, 32, 48. Default is 4. + * CORECLOCK -> 32MHz MAX! + */ +#define CLOCK_CORECLOCK ((CLOCK_PLL_SRC / CONFIG_CLOCK_PLL_DIV) * CONFIG_CLOCK_PLL_MUL) +#if CLOCK_CORECLOCK > MHZ(32) +#error "SYSCLK cannot exceed 32MHz" +#endif +#endif /* CONFIG_USE_CLOCK_PLL */ + +#define CLOCK_AHB CLOCK_CORECLOCK /* max: 32MHz */ + +#ifndef CONFIG_CLOCK_APB1_DIV +#define CONFIG_CLOCK_APB1_DIV (1) +#endif +#define CLOCK_APB1 (CLOCK_CORECLOCK / CONFIG_CLOCK_APB1_DIV) /* max: 32MHz */ +#ifndef CONFIG_CLOCK_APB2_DIV +#define CONFIG_CLOCK_APB2_DIV (1) +#endif +#define CLOCK_APB2 (CLOCK_CORECLOCK / CONFIG_CLOCK_APB2_DIV) /* max: 32MHz */ +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* L0L1_CFG_CLOCK_DEFAULT_H */ +/** @} */ diff --git a/boards/common/stm32/include/l1/cfg_clock_default.h b/boards/common/stm32/include/l1/cfg_clock_default.h deleted file mode 100644 index 5623deb3ed..0000000000 --- a/boards/common/stm32/include/l1/cfg_clock_default.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2020 Inria - * - * This file is subject to the terms and conditions of the GNU Lesser - * General Public License v2.1. See the file LICENSE in the top level - * directory for more details. - */ - -/** - * @ingroup boards_common_stm32 - * @{ - * - * @file - * @brief Default clock configuration for the STM32L1 - * - * @author Alexandre Abadie - */ - -#ifndef L1_CFG_CLOCK_DEFAULT_H -#define L1_CFG_CLOCK_DEFAULT_H - -#include "periph_cpu.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @name Clock system configuration - * @{ - */ -#define CLOCK_HSI (16000000U) /* internal oscillator */ -#define CLOCK_CORECLOCK (32000000U) /* desired core clock frequency */ - -#ifndef CLOCK_LSE -#define CLOCK_LSE (0) /* disable low speed external oscillator */ -#endif - -/* configuration of PLL prescaler and multiply values */ -/* CORECLOCK := HSI / CLOCK_PLL_DIV * CLOCK_PLL_MUL */ -#define CLOCK_PLL_DIV RCC_CFGR_PLLDIV2 -#define CLOCK_PLL_MUL RCC_CFGR_PLLMUL4 -/* configuration of peripheral bus clock prescalers */ -#define CLOCK_AHB_DIV RCC_CFGR_HPRE_DIV1 /* AHB clock -> 32MHz */ -#define CLOCK_APB2_DIV RCC_CFGR_PPRE2_DIV1 /* APB2 clock -> 32MHz */ -#define CLOCK_APB1_DIV RCC_CFGR_PPRE1_DIV1 /* APB1 clock -> 32MHz */ -/* configuration of flash access cycles */ -#define CLOCK_FLASH_LATENCY FLASH_ACR_LATENCY - -/* bus clocks for simplified peripheral initialization, UPDATE MANUALLY! */ -#define CLOCK_AHB (CLOCK_CORECLOCK / 1) -#define CLOCK_APB2 (CLOCK_CORECLOCK / 1) -#define CLOCK_APB1 (CLOCK_CORECLOCK / 1) -/** @} */ - -#ifdef __cplusplus -} -#endif - -#endif /* L1_CFG_CLOCK_DEFAULT_H */ -/** @} */ diff --git a/boards/i-nucleo-lrwan1/include/periph_conf.h b/boards/i-nucleo-lrwan1/include/periph_conf.h index 4761e37000..f97514f0f7 100644 --- a/boards/i-nucleo-lrwan1/include/periph_conf.h +++ b/boards/i-nucleo-lrwan1/include/periph_conf.h @@ -19,8 +19,13 @@ #ifndef PERIPH_CONF_H #define PERIPH_CONF_H +/* Add specific clock configuration (HSE, LSE) for this board here */ +#ifndef CONFIG_BOARD_HAS_LSE +#define CONFIG_BOARD_HAS_LSE 1 +#endif + #include "periph_cpu.h" -#include "l0/cfg_clock_32_16_1.h" +#include "l0l1/cfg_clock_default.h" #include "cfg_rtt_default.h" #include "cfg_timer_tim2.h" diff --git a/boards/im880b/include/periph_conf.h b/boards/im880b/include/periph_conf.h index 2c330bf3f4..d4e2bfc464 100644 --- a/boards/im880b/include/periph_conf.h +++ b/boards/im880b/include/periph_conf.h @@ -22,12 +22,12 @@ /* * This board provides an LSE, so enable it before including the default clock config */ -#ifndef CLOCK_LSE -#define CLOCK_LSE (1) +#ifndef CONFIG_BOARD_HAS_LSE +#define CONFIG_BOARD_HAS_LSE 1 #endif #include "periph_cpu.h" -#include "l1/cfg_clock_default.h" +#include "l0l1/cfg_clock_default.h" #ifdef __cplusplus extern "C" { diff --git a/boards/limifrog-v1/include/periph_conf.h b/boards/limifrog-v1/include/periph_conf.h index 62d92ff8ca..e919e4efe6 100644 --- a/boards/limifrog-v1/include/periph_conf.h +++ b/boards/limifrog-v1/include/periph_conf.h @@ -20,7 +20,7 @@ #define PERIPH_CONF_H #include "periph_cpu.h" -#include "l1/cfg_clock_default.h" +#include "l0l1/cfg_clock_default.h" #ifdef __cplusplus extern "C" { diff --git a/boards/lobaro-lorabox/include/periph_conf.h b/boards/lobaro-lorabox/include/periph_conf.h index 64c8a47003..37aa291cc7 100644 --- a/boards/lobaro-lorabox/include/periph_conf.h +++ b/boards/lobaro-lorabox/include/periph_conf.h @@ -27,12 +27,12 @@ /* * This board provides an LSE, so enable it before including the default clock config */ -#ifndef CLOCK_LSE -#define CLOCK_LSE (1) +#ifndef CONFIG_BOARD_HAS_LSE +#define CONFIG_BOARD_HAS_LSE 1 #endif #include "periph_cpu.h" -#include "l1/cfg_clock_default.h" +#include "l0l1/cfg_clock_default.h" #include "cfg_timer_tim2.h" #ifdef __cplusplus diff --git a/boards/lsn50/include/periph_conf.h b/boards/lsn50/include/periph_conf.h index 8e3c2c09c2..8caf9b212c 100644 --- a/boards/lsn50/include/periph_conf.h +++ b/boards/lsn50/include/periph_conf.h @@ -19,8 +19,13 @@ #ifndef PERIPH_CONF_H #define PERIPH_CONF_H +/* Add specific clock configuration (HSE, LSE) for this board here */ +#ifndef CONFIG_BOARD_HAS_LSE +#define CONFIG_BOARD_HAS_LSE 1 +#endif + #include "periph_cpu.h" -#include "l0/cfg_clock_32_16_1.h" +#include "l0l1/cfg_clock_default.h" #include "cfg_rtt_default.h" #include "cfg_timer_tim2.h" diff --git a/boards/nucleo-l031k6/include/periph_conf.h b/boards/nucleo-l031k6/include/periph_conf.h index eb8e02035a..b1acd433c2 100644 --- a/boards/nucleo-l031k6/include/periph_conf.h +++ b/boards/nucleo-l031k6/include/periph_conf.h @@ -21,8 +21,13 @@ #ifndef PERIPH_CONF_H #define PERIPH_CONF_H +/* Add specific clock configuration (HSE, LSE) for this board here */ +#ifndef CONFIG_BOARD_HAS_LSE +#define CONFIG_BOARD_HAS_LSE 1 +#endif + #include "periph_cpu.h" -#include "l0/cfg_clock_32_16_1.h" +#include "l0l1/cfg_clock_default.h" #include "cfg_i2c1_pb6_pb7.h" #include "cfg_rtt_default.h" #include "cfg_timer_tim2.h" diff --git a/boards/nucleo-l053r8/include/periph_conf.h b/boards/nucleo-l053r8/include/periph_conf.h index bdbe21c66b..4960222fb9 100644 --- a/boards/nucleo-l053r8/include/periph_conf.h +++ b/boards/nucleo-l053r8/include/periph_conf.h @@ -21,8 +21,13 @@ #ifndef PERIPH_CONF_H #define PERIPH_CONF_H +/* Add specific clock configuration (HSE, LSE) for this board here */ +#ifndef CONFIG_BOARD_HAS_LSE +#define CONFIG_BOARD_HAS_LSE 1 +#endif + #include "periph_cpu.h" -#include "l0/cfg_clock_32_16_1.h" +#include "l0l1/cfg_clock_default.h" #include "cfg_rtt_default.h" #include "cfg_timer_tim2.h" diff --git a/boards/nucleo-l073rz/include/periph_conf.h b/boards/nucleo-l073rz/include/periph_conf.h index 6bcb2d79a2..9a7a0918b4 100644 --- a/boards/nucleo-l073rz/include/periph_conf.h +++ b/boards/nucleo-l073rz/include/periph_conf.h @@ -21,8 +21,13 @@ #ifndef PERIPH_CONF_H #define PERIPH_CONF_H +/* Add specific clock configuration (HSE, LSE) for this board here */ +#ifndef CONFIG_BOARD_HAS_LSE +#define CONFIG_BOARD_HAS_LSE 1 +#endif + #include "periph_cpu.h" -#include "l0/cfg_clock_32_16_1.h" +#include "l0l1/cfg_clock_default.h" #include "cfg_rtt_default.h" #include "cfg_timer_tim2.h" diff --git a/boards/nucleo-l152re/include/periph_conf.h b/boards/nucleo-l152re/include/periph_conf.h index 1ef9319431..384c1ae989 100644 --- a/boards/nucleo-l152re/include/periph_conf.h +++ b/boards/nucleo-l152re/include/periph_conf.h @@ -21,7 +21,7 @@ #define PERIPH_CONF_H #include "periph_cpu.h" -#include "l1/cfg_clock_default.h" +#include "l0l1/cfg_clock_default.h" #include "cfg_timer_tim5.h" #ifdef __cplusplus diff --git a/boards/nz32-sc151/include/periph_conf.h b/boards/nz32-sc151/include/periph_conf.h index d26307a3a6..26cc201308 100644 --- a/boards/nz32-sc151/include/periph_conf.h +++ b/boards/nz32-sc151/include/periph_conf.h @@ -20,7 +20,7 @@ #define PERIPH_CONF_H #include "periph_cpu.h" -#include "l1/cfg_clock_default.h" +#include "l0l1/cfg_clock_default.h" #include "cfg_timer_tim5.h" #ifdef __cplusplus diff --git a/boards/stm32l0538-disco/include/periph_conf.h b/boards/stm32l0538-disco/include/periph_conf.h index d74c1ee041..0ca3b44a64 100644 --- a/boards/stm32l0538-disco/include/periph_conf.h +++ b/boards/stm32l0538-disco/include/periph_conf.h @@ -20,36 +20,12 @@ #define PERIPH_CONF_H #include "periph_cpu.h" +#include "l0l1/cfg_clock_default.h" #ifdef __cplusplus extern "C" { #endif -/** - * @name Clock system configuration - * @{ - */ -#define CLOCK_HSI (16000000U) /* internal oscillator */ -#define CLOCK_CORECLOCK (32000000U) /* desired core clock frequency */ -#define CLOCK_LSE (0) /* enable low speed external oscillator */ - -/* configuration of PLL prescaler and multiply values */ -/* CORECLOCK := HSI / CLOCK_PLL_DIV * CLOCK_PLL_MUL */ -#define CLOCK_PLL_DIV RCC_CFGR_PLLDIV2 -#define CLOCK_PLL_MUL RCC_CFGR_PLLMUL4 -/* configuration of peripheral bus clock prescalers */ -#define CLOCK_AHB_DIV RCC_CFGR_HPRE_DIV1 /* AHB clock -> 32MHz */ -#define CLOCK_APB2_DIV RCC_CFGR_PPRE2_DIV1 /* APB2 clock -> 32MHz */ -#define CLOCK_APB1_DIV RCC_CFGR_PPRE1_DIV1 /* APB1 clock -> 32MHz */ -/* configuration of flash access cycles */ -#define CLOCK_FLASH_LATENCY FLASH_ACR_LATENCY - -/* bus clocks for simplified peripheral initialization, UPDATE MANUALLY! */ -#define CLOCK_AHB (CLOCK_CORECLOCK / 1) -#define CLOCK_APB2 (CLOCK_CORECLOCK / 1) -#define CLOCK_APB1 (CLOCK_CORECLOCK / 1) -/** @} */ - /** * @name Timer configuration * @{ diff --git a/cpu/stm32/stmclk/stmclk_l0l1.c b/cpu/stm32/stmclk/stmclk_l0l1.c index c353237111..52f8b8d936 100644 --- a/cpu/stm32/stmclk/stmclk_l0l1.c +++ b/cpu/stm32/stmclk/stmclk_l0l1.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 Freie Universität Berlin - * 2017 Inria + * 2017-2020 Inria * 2018 Kaspar Schleiser * * This file is subject to the terms and conditions of the GNU Lesser @@ -22,67 +22,170 @@ */ #include "cpu.h" -#include "board.h" +#include "stmclk.h" #include "periph_conf.h" -#include "periph/init.h" + +#if defined(CPU_FAM_STM32L1) +#define REG_CIR (RCC->CIR) +#else /* CPU_FAM_STM32L0 */ +#define REG_CIR (RCC->CICR) +#endif + +/* configuration of flash access cycles */ +#define CLOCK_FLASH_LATENCY (FLASH_ACR_LATENCY) + +/* Configure the prescalers */ +#define CLOCK_AHB_DIV (RCC_CFGR_HPRE_DIV1) /* HCLK = SYSCLK */ + +#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) +#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) +#endif /* Check the source to be used for the PLL */ -#if defined(CLOCK_HSI) && defined(CLOCK_HSE) -#error "Only provide one of two CLOCK_HSI/CLOCK_HSE" -#elif CLOCK_HSI -#define CLOCK_CR_SOURCE RCC_CR_HSION -#define CLOCK_CR_SOURCE_RDY RCC_CR_HSIRDY -#define CLOCK_PLL_SOURCE RCC_CFGR_PLLSRC_HSI -#elif CLOCK_HSE -#define CLOCK_CR_SOURCE RCC_CR_HSEON -#define CLOCK_CR_SOURCE_RDY RCC_CR_HSERDY -#define CLOCK_PLL_SOURCE RCC_CFGR_PLLSRC_HSE +#if IS_ACTIVE(CONFIG_BOARD_HAS_HSE) +#define CLOCK_PLL_SOURCE (RCC_CFGR_PLLSRC_HSE) +#else /* Use HSI as PLL input */ +#define CLOCK_PLL_SOURCE (RCC_CFGR_PLLSRC_HSI) +#endif + +#if CONFIG_CLOCK_PLL_DIV == 2 +#define CLOCK_PLL_DIV (RCC_CFGR_PLLDIV2) +#elif CONFIG_CLOCK_PLL_DIV == 3 +#define CLOCK_PLL_DIV (RCC_CFGR_PLLDIV3) +#elif CONFIG_CLOCK_PLL_DIV == 4 +#define CLOCK_PLL_DIV (RCC_CFGR_PLLDIV4) #else -#error "Please provide CLOCK_HSI or CLOCK_HSE in boards/NAME/includes/perhip_cpu.h" +#error "Invalid PLL DIV value, only 2, 3, and 4 values are allowed." +#endif + +#if CONFIG_CLOCK_PLL_MUL == 3 +#define CLOCK_PLL_MUL (RCC_CFGR_PLLMUL3) +#elif CONFIG_CLOCK_PLL_MUL == 4 +#define CLOCK_PLL_MUL (RCC_CFGR_PLLMUL4) +#elif CONFIG_CLOCK_PLL_MUL == 6 +#define CLOCK_PLL_MUL (RCC_CFGR_PLLMUL6) +#elif CONFIG_CLOCK_PLL_MUL == 8 +#define CLOCK_PLL_MUL (RCC_CFGR_PLLMUL8) +#elif CONFIG_CLOCK_PLL_MUL == 12 +#define CLOCK_PLL_MUL (RCC_CFGR_PLLMUL12) +#elif CONFIG_CLOCK_PLL_MUL == 16 +#define CLOCK_PLL_MUL (RCC_CFGR_PLLMUL16) +#elif CONFIG_CLOCK_PLL_MUL == 24 +#define CLOCK_PLL_MUL (RCC_CFGR_PLLMUL24) +#elif CONFIG_CLOCK_PLL_MUL == 32 +#define CLOCK_PLL_MUL (RCC_CFGR_PLLMUL32) +#elif CONFIG_CLOCK_PLL_MUL == 48 +#define CLOCK_PLL_MUL (RCC_CFGR_PLLMUL48) +#else +#error "Invalid PLL MUL value, only 3, 4, 6, 8, 12, 16, 24, 32 and 48 values are allowed." +#endif + +#if CONFIG_CLOCK_MSI == 65536UL +#define CLOCK_MSIRANGE (RCC_ICSCR_MSIRANGE_0) +#elif CONFIG_CLOCK_MSI == 131072UL +#define CLOCK_MSIRANGE (RCC_ICSCR_MSIRANGE_1) +#elif CONFIG_CLOCK_MSI == 262144UL +#define CLOCK_MSIRANGE (RCC_ICSCR_MSIRANGE_2) +#elif CONFIG_CLOCK_MSI == 524288UL +#define CLOCK_MSIRANGE (RCC_ICSCR_MSIRANGE_3) +#elif CONFIG_CLOCK_MSI == KHZ(1048) +#define CLOCK_MSIRANGE (RCC_ICSCR_MSIRANGE_4) +#elif CONFIG_CLOCK_MSI == KHZ(2097) +#define CLOCK_MSIRANGE (RCC_ICSCR_MSIRANGE_5) +#elif CONFIG_CLOCK_MSI == KHZ(4194) +#define CLOCK_MSIRANGE (RCC_ICSCR_MSIRANGE_6) +#else +#error "Invalid MSI clock value" +#endif + +/* Check whether PLL must be enabled: + - When PLLCLK is used as SYSCLK + - When HWRNG feature is used (for the 48MHz clock) +*/ +#if IS_ACTIVE(CONFIG_USE_CLOCK_PLL) || IS_USED(MODULE_PERIPH_HWRNG) +#define CLOCK_ENABLE_PLL 1 +#else +#define CLOCK_ENABLE_PLL 0 +#endif + +/* Check whether HSE must be enabled: + - 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 must be enabled: + - 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 + +/* Check whether MSI must be enabled: + - When MSI is used as SYSCLK +*/ +#if IS_ACTIVE(CONFIG_USE_CLOCK_MSI) +#define CLOCK_ENABLE_MSI 1 +#else +#define CLOCK_ENABLE_MSI 0 #endif /** * @brief Configure the controllers clock system * - * The clock initialization make the following assumptions: - * - the external HSE clock from an external oscillator is used as base clock - * - the internal PLL circuit is used for clock refinement - * - * Use the following formulas to calculate the needed values: - * - * SYSCLK = ((HSE_VALUE / CLOCK_PLL_M) * CLOCK_PLL_N) / CLOCK_PLL_P - * USB, SDIO and RNG Clock = ((HSE_VALUE / CLOCK_PLL_M) * CLOCK_PLL_N) / CLOCK_PLL_Q - * - * The actual used values are specified in the board's `periph_conf.h` file. - * - * NOTE: currently there is not timeout for initialization of PLL and other locks + * NOTE: currently there is no timeout for initialization of PLL and other locks * -> when wrong values are chosen, the initialization could stall */ void stmclk_init_sysclk(void) { - /* Reset the RCC clock configuration to the default reset state(for debug purpose) */ - /* Set MSION bit */ - RCC->CR |= RCC_CR_MSION; - /* Reset SW, HPRE, PPRE1, PPRE2, MCOSEL and MCOPRE bits */ - RCC->CFGR &= ~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLDIV | RCC_CFGR_PLLMUL); - /* Reset HSION, HSEON, CSSON and PLLON bits */ - RCC->CR &= ~(RCC_CR_HSION | RCC_CR_HSEON | RCC_CR_HSEBYP | RCC_CR_CSSON | RCC_CR_PLLON); + /* disable any interrupts. Global interrupts could be enabled if this is + * called from some kind of bootloader... */ + unsigned is = irq_disable(); /* Disable all interrupts */ + REG_CIR = 0x0; -#if defined(CPU_FAM_STM32L0) - RCC->CICR = 0x0; -#elif defined(CPU_FAM_STM32L1) - RCC->CIR = 0x0; -#else -#error unexpected MCU -#endif + /* enable HSI clock for the duration of initialization */ + stmclk_enable_hsi(); + + /* Reset the RCC clock configuration to the default reset state(for debug purpose) */ + /* Reset MSION, HSEON, CSSON and PLLON bits */ + RCC->CR &= ~(RCC_CR_MSION | RCC_CR_HSEON | RCC_CR_HSEBYP | RCC_CR_CSSON | RCC_CR_PLLON); + + /* use HSI as system clock while we do any further configuration and + * configure the AHB and APB clock dividers as configured by the board */ + RCC->CFGR = (RCC_CFGR_SW_HSI | CLOCK_AHB_DIV | CLOCK_APB1_DIV | CLOCK_APB2_DIV); - /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration */ - /* Enable high speed clock source */ - RCC->CR |= CLOCK_CR_SOURCE; - /* Wait till the high speed clock source is ready - * NOTE: the MCU will stay here forever if you use an external clock source and it's not connected */ - while (!(RCC->CR & CLOCK_CR_SOURCE_RDY)) {} #if defined(CPU_FAM_STM32L1) FLASH->ACR |= FLASH_ACR_ACC64; #endif @@ -94,22 +197,58 @@ void stmclk_init_sysclk(void) PWR->CR = PWR_CR_VOS_0; /* Wait Until the Voltage Regulator is ready */ while((PWR->CSR & PWR_CSR_VOSF) != 0) {} - /* HCLK = SYSCLK */ - RCC->CFGR |= (uint32_t)CLOCK_AHB_DIV; - /* PCLK2 = HCLK */ - RCC->CFGR |= (uint32_t)CLOCK_APB2_DIV; - /* PCLK1 = HCLK */ - RCC->CFGR |= (uint32_t)CLOCK_APB1_DIV; - /* PLL configuration: PLLCLK = CLOCK_SOURCE / PLL_DIV * PLL_MUL */ - RCC->CFGR &= ~((uint32_t)(RCC_CFGR_PLLSRC | RCC_CFGR_PLLDIV | RCC_CFGR_PLLMUL)); - RCC->CFGR |= (uint32_t)(CLOCK_PLL_SOURCE | CLOCK_PLL_DIV | CLOCK_PLL_MUL); - /* Enable PLL */ - RCC->CR |= RCC_CR_PLLON; - /* Wait till PLL is ready */ - while ((RCC->CR & RCC_CR_PLLRDY) == 0) {} - /* Select PLL as system clock source */ - RCC->CFGR &= ~((uint32_t)(RCC_CFGR_SW)); - RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; - /* Wait till PLL is used as system clock source */ - while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) {} + + /* Enable HSE if needed */ + if (IS_ACTIVE(CLOCK_ENABLE_HSE)) { + RCC->CR |= (RCC_CR_HSEON); + while (!(RCC->CR & RCC_CR_HSERDY)) {} + } + + /* Enable MSI if needed */ + if (IS_ACTIVE(CLOCK_ENABLE_MSI)) { + /* Configure MSI range and enable it */ + RCC->ICSCR |= CLOCK_MSIRANGE; + RCC->CR |= (RCC_CR_MSION); + while (!(RCC->CR & RCC_CR_MSIRDY)) {} + } + + /* Enable PLL if needed */ + if (IS_ACTIVE(CLOCK_ENABLE_PLL)) { + /* Configure PLL clock source and configure the different prescalers */ + RCC->CFGR &= ~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLDIV | RCC_CFGR_PLLMUL); + RCC->CFGR |= (CLOCK_PLL_SOURCE | CLOCK_PLL_DIV | CLOCK_PLL_MUL); + /* Enable PLL */ + RCC->CR |= RCC_CR_PLLON; + /* Wait till PLL is ready */ + while (!(RCC->CR & RCC_CR_PLLRDY)) {} + } + + /* Disable HSI if it's unused */ + if (!IS_ACTIVE(CLOCK_ENABLE_HSI)) { + RCC->CFGR &= ~(RCC_CFGR_SW); + } + + /* Configure SYSCLK input source */ + if (IS_ACTIVE(CONFIG_USE_CLOCK_HSE)) { + /* Select HSE as system clock and wait till it's used as system clock */ + RCC->CFGR |= RCC_CFGR_SW_HSE; + while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSE) {} + } + else if (IS_ACTIVE(CONFIG_USE_CLOCK_MSI)) { + /* Select MSI as system clock and wait till it's used as system clock */ + RCC->CFGR |= RCC_CFGR_SW_MSI; + while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_MSI) {} + } + else if (IS_ACTIVE(CONFIG_USE_CLOCK_PLL)) { + RCC->CFGR |= RCC_CFGR_SW_PLL; + /* Select PLL as system clock and wait till it's used as system clock */ + while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) {} + } + + if (!IS_ACTIVE(CLOCK_ENABLE_HSI)) { + /* Disable HSI only if not needed */ + stmclk_disable_hsi(); + } + + irq_restore(is); }