From 7c923da0c8b507cab6b11928b0ab38a52e553ecd Mon Sep 17 00:00:00 2001 From: Alexandre Abadie Date: Sun, 30 Aug 2020 16:48:58 +0200 Subject: [PATCH 1/4] cpu/stm32: split f0 clock initialization in separate file --- cpu/stm32/stmclk/Makefile | 4 +- cpu/stm32/stmclk/stmclk_f0.c | 121 +++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 cpu/stm32/stmclk/stmclk_f0.c diff --git a/cpu/stm32/stmclk/Makefile b/cpu/stm32/stmclk/Makefile index 5491a666c3..ea3f263e5f 100644 --- a/cpu/stm32/stmclk/Makefile +++ b/cpu/stm32/stmclk/Makefile @@ -2,8 +2,10 @@ MODULE = stm32_clk SRC = stmclk_common.c -ifneq (,$(filter f%,$(CPU_FAM))) +ifneq (,$(filter-out f0,$(filter f%,$(CPU_FAM)))) SRC += stmclk_fx.c +else ifneq (,$(filter $(CPU_FAM),f0)) + SRC += stmclk_f0.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_f0.c new file mode 100644 index 0000000000..e187ebfe5d --- /dev/null +++ b/cpu/stm32/stmclk/stmclk_f0.c @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2017 Freie Universität Berlin + * 2017 OTA keys S.A. + * 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 cpu_stm32 + * @{ + * + * @file + * @brief Implementation of STM32 clock configuration for STM32 F0 + * + * @author Hauke Petersen + * @author Vincent Dupont + * @author Alexandre Abadie + * @} + */ + +#include "cpu.h" +#include "stmclk.h" +#include "periph_conf.h" + +/* PLL configuration */ +#if IS_ACTIVE(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) +#define PLL_PREDIV (CONFIG_CLOCK_PLL_PREDIV - 1) + +#define CLOCK_AHB_DIV (RCC_CFGR_HPRE_DIV1) + +#if CONFIG_CLOCK_APB1_DIV == 1 +#define CLOCK_APB1_DIV (RCC_CFGR_PPRE_DIV1) +#elif CONFIG_CLOCK_APB1_DIV == 2 +#define CLOCK_APB1_DIV (RCC_CFGR_PPRE_DIV2) +#elif CONFIG_CLOCK_APB1_DIV == 4 +#define CLOCK_APB1_DIV (RCC_CFGR_PPRE_DIV4) +#elif CONFIG_CLOCK_APB1_DIV == 8 +#define CLOCK_APB1_DIV (RCC_CFGR_PPRE_DIV8) +#elif CONFIG_CLOCK_APB1_DIV == 16 +#define CLOCK_APB1_DIV (RCC_CFGR_PPRE_DIV16) +#else +#error "Invalid APB prescaler value (only 1, 2, 4, 8 and 16 allowed)" +#endif + + +/* Deduct the needed flash wait states from the core clock frequency */ +#define FLASH_WAITSTATES ((CLOCK_CORECLOCK - 1) / MHZ(24)) +/* we enable I+D cashes, pre-fetch, and we set the actual number of + * needed flash wait states */ +#define FLASH_ACR_CONFIG (FLASH_ACR_PRFTBE | FLASH_WAITSTATES) +/** @} */ + +void stmclk_init_sysclk(void) +{ + /* disable any interrupts. Global interrupts could be enabled if this is + * called from some kind of bootloader... */ + unsigned is = irq_disable(); + RCC->CIR = 0; + + /* enable HSI clock for the duration of initialization */ + stmclk_enable_hsi(); + + /* use HSI as system clock while we do any further configuration and + * configure the AHB and APB clock dividers as configure by the board */ + RCC->CFGR = (RCC_CFGR_SW_HSI | CLOCK_AHB_DIV | CLOCK_APB1_DIV); + while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI) {} + + /* Flash config */ + FLASH->ACR = FLASH_ACR_CONFIG; + + /* 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)) { + 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 */ + 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 */ + } + else if (CONFIG_CLOCK_PLL_PREDIV > 2) { + RCC->CFGR2 = PLL_PREDIV; /* PREDIV > 2 */ + } + RCC->CR |= (RCC_CR_PLLON); + while (!(RCC->CR & RCC_CR_PLLRDY)) {} + + /* now that the PLL is running, use it as system clock */ + 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))) { + /* Disable HSI only if not used */ + stmclk_disable_hsi(); + } + + irq_restore(is); +} From 6d76e61ff0978933526360ee3c0d490ba9015cfb Mon Sep 17 00:00:00 2001 From: Alexandre Abadie Date: Sun, 30 Aug 2020 16:49:39 +0200 Subject: [PATCH 2/4] boards/stm32f0: adapt default clock configuration --- .../stm32/include/f0/cfg_clock_default.h | 117 ++++++++++++++---- 1 file changed, 94 insertions(+), 23 deletions(-) diff --git a/boards/common/stm32/include/f0/cfg_clock_default.h b/boards/common/stm32/include/f0/cfg_clock_default.h index cb46d5b782..50038d220a 100644 --- a/boards/common/stm32/include/f0/cfg_clock_default.h +++ b/boards/common/stm32/include/f0/cfg_clock_default.h @@ -31,33 +31,104 @@ extern "C" { * @name Clock settings * @{ */ -/* give the target core clock (HCLK) frequency [in Hz], - * maximum: 48MHz */ -#define CLOCK_CORECLOCK MHZ(48) -/* 0: no external high speed crystal available - * else: actual crystal frequency [in Hz] */ -#ifndef CLOCK_HSE -#define CLOCK_HSE MHZ(8) +/* 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 CONFIG_USE_CLOCK_PLL 1 /* Use PLL by default */ #endif -/* 0: no external low speed crystal available, - * 1: external crystal available (always 32.768kHz) */ -#ifndef CLOCK_LSE -#define CLOCK_LSE (0) -#endif -/* peripheral clock setup */ -#define CLOCK_AHB_DIV RCC_CFGR_HPRE_DIV1 -#define CLOCK_AHB (CLOCK_CORECLOCK / 1) -#define CLOCK_APB1_DIV RCC_CFGR_PPRE_DIV1 /* max 48MHz */ -#define CLOCK_APB1 (CLOCK_CORECLOCK / 1) -#define CLOCK_APB2 (CLOCK_APB1) +#endif /* CONFIG_USE_CLOCK_PLL */ -/* PLL factors */ -#ifndef CLOCK_PLL_PREDIV -#define CLOCK_PLL_PREDIV (1) +#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 -#ifndef CLOCK_PLL_MUL -#define CLOCK_PLL_MUL (6) + +#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 + +#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 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 48MHz system clock with HSI (or default HSE) as input clock */ +#ifndef CONFIG_CLOCK_PLL_PREDIV +#define CONFIG_CLOCK_PLL_PREDIV (1) +#endif +#ifndef CONFIG_CLOCK_PLL_MUL +#define CONFIG_CLOCK_PLL_MUL (6) +#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 -> 48MHz MAX! + */ +#define CLOCK_CORECLOCK ((CLOCK_PLL_SRC / CONFIG_CLOCK_PLL_PREDIV) * CONFIG_CLOCK_PLL_MUL) +#if CLOCK_CORECLOCK > MHZ(48) +#error "SYSCLK cannot exceed 48MHz" +#endif +#endif /* CONFIG_USE_CLOCK_PLL */ + +#define CLOCK_AHB CLOCK_CORECLOCK /* max: 48MHz */ + +#ifndef CONFIG_CLOCK_APB1_DIV +#define CONFIG_CLOCK_APB1_DIV (1) +#endif +#define CLOCK_APB1 (CLOCK_CORECLOCK / CONFIG_CLOCK_APB1_DIV) /* max: 48MHz */ /** @} */ #ifdef __cplusplus From 665426fefcc315f61bf9c5717e33dee700b9e84e Mon Sep 17 00:00:00 2001 From: Alexandre Abadie Date: Sun, 30 Aug 2020 16:50:03 +0200 Subject: [PATCH 3/4] boards/stm32f0: adapt to refactored clock configuration --- boards/nucleo-f030r8/include/periph_conf.h | 9 ++++++++- boards/nucleo-f031k6/include/periph_conf.h | 13 +++++++------ boards/nucleo-f042k6/include/periph_conf.h | 13 +++++++------ boards/nucleo-f070rb/include/periph_conf.h | 9 ++++++++- boards/nucleo-f072rb/include/periph_conf.h | 9 ++++++++- boards/nucleo-f091rc/include/periph_conf.h | 9 ++++++++- boards/stm32f030f4-demo/include/periph_conf.h | 5 +++++ boards/stm32f0discovery/include/periph_conf.h | 5 +++++ 8 files changed, 56 insertions(+), 16 deletions(-) diff --git a/boards/nucleo-f030r8/include/periph_conf.h b/boards/nucleo-f030r8/include/periph_conf.h index bdaec4460a..c3acb24fb2 100644 --- a/boards/nucleo-f030r8/include/periph_conf.h +++ b/boards/nucleo-f030r8/include/periph_conf.h @@ -22,7 +22,14 @@ #define PERIPH_CONF_H /* This board provides an LSE */ -#define CLOCK_LSE (1) +#ifndef CONFIG_BOARD_HAS_LSE +#define CONFIG_BOARD_HAS_LSE 1 +#endif + +/* This board provides an HSE */ +#ifndef CONFIG_BOARD_HAS_HSE +#define CONFIG_BOARD_HAS_HSE 1 +#endif #include "periph_cpu.h" #include "f0/cfg_clock_default.h" diff --git a/boards/nucleo-f031k6/include/periph_conf.h b/boards/nucleo-f031k6/include/periph_conf.h index ec8a57b986..e7f5da4bcb 100644 --- a/boards/nucleo-f031k6/include/periph_conf.h +++ b/boards/nucleo-f031k6/include/periph_conf.h @@ -20,12 +20,13 @@ #ifndef PERIPH_CONF_H #define PERIPH_CONF_H -/* No HSE available on this board */ -#define CLOCK_HSE (0U) - -/* Adjust PLL factors when PLL is clocked by HSI */ -#define CLOCK_PLL_PREDIV (2) -#define CLOCK_PLL_MUL (12) +/* Adjust PLL factors: + - On nucleo-f031k6, there's no HSE and PREDIV is hard-wired to 2 + - to reach 48MHz set PLL_MUL to 12 so core clock = (HSI8 / 2) * 12 = 48MHz */ +#define CONFIG_CLOCK_PLL_PREDIV (2) +#ifndef CONFIG_CLOCK_PLL_MUL +#define CONFIG_CLOCK_PLL_MUL (12) +#endif #include "periph_cpu.h" #include "f0/cfg_clock_default.h" diff --git a/boards/nucleo-f042k6/include/periph_conf.h b/boards/nucleo-f042k6/include/periph_conf.h index e2c8a47af3..e409716013 100644 --- a/boards/nucleo-f042k6/include/periph_conf.h +++ b/boards/nucleo-f042k6/include/periph_conf.h @@ -19,12 +19,13 @@ #ifndef PERIPH_CONF_H #define PERIPH_CONF_H -/* No HSE available on this board */ -#define CLOCK_HSE (0U) - -/* Adjust PLL factors when PLL is clocked by HSI */ -#define CLOCK_PLL_PREDIV (2) -#define CLOCK_PLL_MUL (12) +/* Adjust PLL factors: + - On nucleo-f042k6, there's no HSE and PREDIV is hard-wired to 2 + - to reach 48MHz set PLL_MUL to 12 so core clock = (HSI8 / 2) * 12 = 48MHz */ +#define CONFIG_CLOCK_PLL_PREDIV (2) +#ifndef CONFIG_CLOCK_PLL_MUL +#define CONFIG_CLOCK_PLL_MUL (12) +#endif #include "periph_cpu.h" #include "f0/cfg_clock_default.h" diff --git a/boards/nucleo-f070rb/include/periph_conf.h b/boards/nucleo-f070rb/include/periph_conf.h index 46a226bde1..deecb2c539 100644 --- a/boards/nucleo-f070rb/include/periph_conf.h +++ b/boards/nucleo-f070rb/include/periph_conf.h @@ -21,8 +21,15 @@ #ifndef PERIPH_CONF_H #define PERIPH_CONF_H +/* HSE available on this board */ +#ifndef CONFIG_BOARD_HAS_HSE +#define CONFIG_BOARD_HAS_HSE 1 +#endif + /* This board provides an LSE */ -#define CLOCK_LSE (1) +#ifndef CONFIG_BOARD_HAS_LSE +#define CONFIG_BOARD_HAS_LSE 1 +#endif #include "periph_cpu.h" #include "f0/cfg_clock_default.h" diff --git a/boards/nucleo-f072rb/include/periph_conf.h b/boards/nucleo-f072rb/include/periph_conf.h index eb4c6cac0a..b128a9f180 100644 --- a/boards/nucleo-f072rb/include/periph_conf.h +++ b/boards/nucleo-f072rb/include/periph_conf.h @@ -20,8 +20,15 @@ #ifndef PERIPH_CONF_H #define PERIPH_CONF_H +/* HSE available on this board */ +#ifndef CONFIG_BOARD_HAS_HSE +#define CONFIG_BOARD_HAS_HSE 1 +#endif + /* This board provides an LSE */ -#define CLOCK_LSE (1) +#ifndef CONFIG_BOARD_HAS_LSE +#define CONFIG_BOARD_HAS_LSE 1 +#endif #include "periph_cpu.h" #include "f0/cfg_clock_default.h" diff --git a/boards/nucleo-f091rc/include/periph_conf.h b/boards/nucleo-f091rc/include/periph_conf.h index 4819fd29f0..96f6681a77 100644 --- a/boards/nucleo-f091rc/include/periph_conf.h +++ b/boards/nucleo-f091rc/include/periph_conf.h @@ -19,8 +19,15 @@ #ifndef PERIPH_CONF_H #define PERIPH_CONF_H +/* HSE available on this board */ +#ifndef CONFIG_BOARD_HAS_HSE +#define CONFIG_BOARD_HAS_HSE 1 +#endif + /* This board provides an LSE */ -#define CLOCK_LSE (1) +#ifndef CONFIG_BOARD_HAS_LSE +#define CONFIG_BOARD_HAS_LSE 1 +#endif #include "periph_cpu.h" #include "f0/cfg_clock_default.h" diff --git a/boards/stm32f030f4-demo/include/periph_conf.h b/boards/stm32f030f4-demo/include/periph_conf.h index eb12644e4d..a7e80d6586 100644 --- a/boards/stm32f030f4-demo/include/periph_conf.h +++ b/boards/stm32f030f4-demo/include/periph_conf.h @@ -22,6 +22,11 @@ #ifndef PERIPH_CONF_H #define PERIPH_CONF_H +/* This board provides an HSE */ +#ifndef CONFIG_BOARD_HAS_HSE +#define CONFIG_BOARD_HAS_HSE 1 +#endif + #include "periph_cpu.h" #include "f0/cfg_clock_default.h" diff --git a/boards/stm32f0discovery/include/periph_conf.h b/boards/stm32f0discovery/include/periph_conf.h index 4a84bc62d1..520b672e82 100644 --- a/boards/stm32f0discovery/include/periph_conf.h +++ b/boards/stm32f0discovery/include/periph_conf.h @@ -19,6 +19,11 @@ #ifndef PERIPH_CONF_H #define PERIPH_CONF_H +/* This board provides an HSE */ +#ifndef CONFIG_BOARD_HAS_HSE +#define CONFIG_BOARD_HAS_HSE 1 +#endif + #include "periph_cpu.h" #include "f0/cfg_clock_default.h" From 8f1c5ab91968b15efdf7645bf8a50b578db1e514 Mon Sep 17 00:00:00 2001 From: Alexandre Abadie Date: Tue, 8 Sep 2020 15:54:32 +0200 Subject: [PATCH 4/4] Update boards/common/stm32/include/f0/cfg_clock_default.h --- boards/common/stm32/include/f0/cfg_clock_default.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/common/stm32/include/f0/cfg_clock_default.h b/boards/common/stm32/include/f0/cfg_clock_default.h index 50038d220a..dd49a049d6 100644 --- a/boards/common/stm32/include/f0/cfg_clock_default.h +++ b/boards/common/stm32/include/f0/cfg_clock_default.h @@ -128,7 +128,7 @@ extern "C" { #ifndef CONFIG_CLOCK_APB1_DIV #define CONFIG_CLOCK_APB1_DIV (1) #endif -#define CLOCK_APB1 (CLOCK_CORECLOCK / CONFIG_CLOCK_APB1_DIV) /* max: 48MHz */ +#define CLOCK_APB1 (CLOCK_AHB / CONFIG_CLOCK_APB1_DIV) /* max: 48MHz */ /** @} */ #ifdef __cplusplus