diff --git a/boards/fox/include/periph_conf.h b/boards/fox/include/periph_conf.h index b2893ac7ea..ee8127cb3f 100644 --- a/boards/fox/include/periph_conf.h +++ b/boards/fox/include/periph_conf.h @@ -29,19 +29,34 @@ extern "C" { * @name Clock system configuration * @{ **/ -#define CLOCK_HSE (16000000U) /* frequency of external oscillator */ -#define CLOCK_CORECLOCK (72000000U) /* targeted core clock frequency */ -/* configuration of PLL prescaler and multiply values */ -/* CORECLOCK := CLOCK_SOURCE / PLL_DIV * PLL_MUL */ +/* high speed clock configuration: + * 0 := use internal HSI oscillator (always 8MHz) + * HSE frequency value := use external HSE oscillator with given freq [in Hz] + * must be 4000000 <= value <= 16000000 */ +#define CLOCK_HSE (16000000U) +/* low speed clock configuration: + * 0 := use internal LSI oscillator (~40kHz) + * 1 := use extern LSE oscillator, always 32.768kHz */ +#define CLOCK_LSE (1) +/* targeted system clock speed [in Hz], must be <= 72MHz */ +#define CLOCK_CORECLOCK (72000000U) +/* PLL configuration, set both values to zero to disable PLL usage. The values + * must be set to satisfy the following equation: + * CORECLOCK := CLOCK_SOURCE / PLL_DIV * PLL_MUL + * with + * 1 <= CLOCK_PLL_DIV <= 2 + * 2 <= CLOCK_PLL_MUL <= 17 */ #define CLOCK_PLL_DIV (2) #define CLOCK_PLL_MUL (9) -/* configuration of peripheral bus clock prescalers */ -#define CLOCK_AHB_DIV RCC_CFGR_HPRE_DIV1 /* AHB clock -> 72MHz */ -#define CLOCK_APB2_DIV RCC_CFGR_PPRE2_DIV1 /* APB2 clock -> 72MHz */ -#define CLOCK_APB1_DIV RCC_CFGR_PPRE1_DIV2 /* APB1 clock -> 36MHz */ -/* resulting bus clocks */ +/* AHB and APBx bus clock configuration, keep in mind the following constraints: + * ABP1 <= 36MHz + */ +#define CLOCK_AHB_DIV RCC_CFGR_HPRE_DIV1 +#define CLOCK_AHB (CLOCK_CORECLOCK / 1) +#define CLOCK_APB2_DIV RCC_CFGR_PPRE2_DIV1 +#define CLOCK_APB2 (CLOCK_CORECLOCK / 1) +#define CLOCK_APB1_DIV RCC_CFGR_PPRE1_DIV2 #define CLOCK_APB1 (CLOCK_CORECLOCK / 2) -#define CLOCK_APB2 (CLOCK_CORECLOCK) /** @} */ /** diff --git a/boards/iotlab-common/include/periph_conf_common.h b/boards/iotlab-common/include/periph_conf_common.h index 6c39347d25..9283ef57bc 100644 --- a/boards/iotlab-common/include/periph_conf_common.h +++ b/boards/iotlab-common/include/periph_conf_common.h @@ -30,20 +30,33 @@ extern "C" { * @name Clock system configuration * @{ **/ -#define CLOCK_HSE (16000000U) /* frequency of external oscillator */ -#define CLOCK_CORECLOCK (72000000U) /* targeted core clock frequency */ -/* configuration of PLL prescaler and multiply values */ -/* CORECLOCK := CLOCK_SOURCE / PLL_DIV * PLL_MUL */ +/* high speed clock configuration: + * 0 := use internal HSI oscillator (always 8MHz) + * HSE frequency value := use external HSE oscillator with given freq [in Hz] + * must be 4000000 <= value <= 16000000 */ +#define CLOCK_HSE (16000000U) +/* low speed clock configuration: + * 0 := use internal LSI oscillator (~40kHz) + * 1 := use extern LSE oscillator, always 32.768kHz */ +#define CLOCK_LSE (1) +/* targeted system clock speed [in Hz], must be <= 72MHz */ +#define CLOCK_CORECLOCK (72000000U) +/* PLL configuration, set both values to zero to disable PLL usage. The values + * must be set to satisfy the following equation: + * CORECLOCK := CLOCK_SOURCE / PLL_DIV * PLL_MUL + * with + * 1 <= CLOCK_PLL_DIV <= 2 + * 2 <= CLOCK_PLL_MUL <= 17 */ #define CLOCK_PLL_DIV (2) #define CLOCK_PLL_MUL (9) -/* configuration of peripheral bus clock prescalers */ -#define CLOCK_AHB_DIV RCC_CFGR_HPRE_DIV1 /* AHB clock -> 72MHz */ -#define CLOCK_APB2_DIV RCC_CFGR_PPRE2_DIV1 /* APB2 clock -> 72MHz */ -#define CLOCK_APB1_DIV RCC_CFGR_PPRE1_DIV2 /* APB1 clock -> 36MHz */ - -/* bus clocks for simplified peripheral initialization, UPDATE MANUALLY! */ +/* AHB and APBx bus clock configuration, keep in mind the following constraints: + * ABP1 <= 36MHz + */ +#define CLOCK_AHB_DIV RCC_CFGR_HPRE_DIV1 #define CLOCK_AHB (CLOCK_CORECLOCK / 1) +#define CLOCK_APB2_DIV RCC_CFGR_PPRE2_DIV1 #define CLOCK_APB2 (CLOCK_CORECLOCK / 1) +#define CLOCK_APB1_DIV RCC_CFGR_PPRE1_DIV2 #define CLOCK_APB1 (CLOCK_CORECLOCK / 2) /** @} */ diff --git a/boards/maple-mini/include/periph_conf.h b/boards/maple-mini/include/periph_conf.h index 9cd4ecd764..81f92d458f 100644 --- a/boards/maple-mini/include/periph_conf.h +++ b/boards/maple-mini/include/periph_conf.h @@ -26,27 +26,37 @@ extern "C" { #endif /** - * @name Clock system configuration + * @name Clock system configuration * @{ - */ -#define CLOCK_HSE (8000000U) /* external oscillator */ -#define CLOCK_CORECLOCK (72000000U) /* desired core clock frequency */ - -/* the actual PLL values are automatically generated */ + **/ +/* high speed clock configuration: + * 0 := use internal HSI oscillator (always 8MHz) + * HSE frequency value := use external HSE oscillator with given freq [in Hz] + * must be 4000000 <= value <= 16000000 */ +#define CLOCK_HSE (8000000U) +/* low speed clock configuration: + * 0 := use internal LSI oscillator (~40kHz) + * 1 := use extern LSE oscillator, always 32.768kHz */ +#define CLOCK_LSE (0) +/* targeted system clock speed [in Hz], must be <= 72MHz */ +#define CLOCK_CORECLOCK (72000000U) +/* PLL configuration, set both values to zero to disable PLL usage. The values + * must be set to satisfy the following equation: + * CORECLOCK := CLOCK_SOURCE / PLL_DIV * PLL_MUL + * with + * 1 <= CLOCK_PLL_DIV <= 2 + * 2 <= CLOCK_PLL_MUL <= 17 */ #define CLOCK_PLL_DIV (1) -#define CLOCK_PLL_MUL CLOCK_CORECLOCK / CLOCK_HSE - -/* AHB, APB1, APB2 dividers */ +#define CLOCK_PLL_MUL (9) +/* AHB and APBx bus clock configuration, keep in mind the following constraints: + * ABP1 <= 36MHz + */ #define CLOCK_AHB_DIV RCC_CFGR_HPRE_DIV1 +#define CLOCK_AHB (CLOCK_CORECLOCK / 1) #define CLOCK_APB2_DIV RCC_CFGR_PPRE2_DIV1 +#define CLOCK_APB2 (CLOCK_CORECLOCK / 1) #define CLOCK_APB1_DIV RCC_CFGR_PPRE1_DIV2 - -/* Bus clocks */ #define CLOCK_APB1 (CLOCK_CORECLOCK / 2) -#define CLOCK_APB2 (CLOCK_CORECLOCK) - -/* Flash latency */ -#define CLOCK_FLASH_LATENCY FLASH_ACR_LATENCY_2 /* for >= 72 MHz */ /** @} */ /** diff --git a/boards/nucleo-f103/include/periph_conf.h b/boards/nucleo-f103/include/periph_conf.h index a8b9ad5b1d..ba9e54ffca 100644 --- a/boards/nucleo-f103/include/periph_conf.h +++ b/boards/nucleo-f103/include/periph_conf.h @@ -26,22 +26,36 @@ extern "C" { #endif /** - * @name Clock system configuration + * @name Clock system configuration * @{ - */ -#define CLOCK_HSE (8000000U) /* external oscillator */ -#define CLOCK_CORECLOCK (72000000U) /* desired core clock frequency */ -/* the actual PLL values are automatically generated */ + **/ +/* high speed clock configuration: + * 0 := use internal HSI oscillator (always 8MHz) + * HSE frequency value := use external HSE oscillator with given freq [in Hz] + * must be 4000000 <= value <= 16000000 */ +#define CLOCK_HSE (8000000U) +/* low speed clock configuration: + * 0 := use internal LSI oscillator (~40kHz) + * 1 := use extern LSE oscillator, always 32.768kHz */ +#define CLOCK_LSE (1) +/* targeted system clock speed [in Hz], must be <= 72MHz */ +#define CLOCK_CORECLOCK (72000000U) +/* PLL configuration, set both values to zero to disable PLL usage. The values + * must be set to satisfy the following equation: + * CORECLOCK := CLOCK_SOURCE / PLL_DIV * PLL_MUL + * with + * 1 <= CLOCK_PLL_DIV <= 2 + * 2 <= CLOCK_PLL_MUL <= 17 */ #define CLOCK_PLL_DIV (1) #define CLOCK_PLL_MUL (9) -/* AHB, APB1, APB2 dividers */ +/* AHB and APBx bus clock configuration, keep in mind the following constraints: + * ABP1 <= 36MHz + */ #define CLOCK_AHB_DIV RCC_CFGR_HPRE_DIV1 -#define CLOCK_APB2_DIV RCC_CFGR_PPRE2_DIV1 -#define CLOCK_APB1_DIV RCC_CFGR_PPRE1_DIV2 /* max 36 MHz (!) */ - -/* bus clocks for simplified peripheral initialization, UPDATE MANUALLY! */ #define CLOCK_AHB (CLOCK_CORECLOCK / 1) +#define CLOCK_APB2_DIV RCC_CFGR_PPRE2_DIV1 #define CLOCK_APB2 (CLOCK_CORECLOCK / 1) +#define CLOCK_APB1_DIV RCC_CFGR_PPRE1_DIV2 #define CLOCK_APB1 (CLOCK_CORECLOCK / 2) /** @} */ diff --git a/boards/opencm904/include/periph_conf.h b/boards/opencm904/include/periph_conf.h index 321b477d34..324f535968 100644 --- a/boards/opencm904/include/periph_conf.h +++ b/boards/opencm904/include/periph_conf.h @@ -26,27 +26,37 @@ extern "C" { #endif /** - * @name Clock system configuration + * @name Clock system configuration * @{ - */ -#define CLOCK_HSE (8000000U) /* external oscillator */ -#define CLOCK_CORECLOCK (72000000U) /* desired core clock frequency */ - -/* the actual PLL values are automatically generated */ + **/ +/* high speed clock configuration: + * 0 := use internal HSI oscillator (always 8MHz) + * HSE frequency value := use external HSE oscillator with given freq [in Hz] + * must be 4000000 <= value <= 16000000 */ +#define CLOCK_HSE (8000000U) +/* low speed clock configuration: + * 0 := use internal LSI oscillator (~40kHz) + * 1 := use extern LSE oscillator, always 32.768kHz */ +#define CLOCK_LSE (0) +/* targeted system clock speed [in Hz], must be <= 72MHz */ +#define CLOCK_CORECLOCK (72000000U) +/* PLL configuration, set both values to zero to disable PLL usage. The values + * must be set to satisfy the following equation: + * CORECLOCK := CLOCK_SOURCE / PLL_DIV * PLL_MUL + * with + * 1 <= CLOCK_PLL_DIV <= 2 + * 2 <= CLOCK_PLL_MUL <= 17 */ #define CLOCK_PLL_DIV (1) -#define CLOCK_PLL_MUL CLOCK_CORECLOCK / CLOCK_HSE - -/* AHB, APB1, APB2 dividers */ +#define CLOCK_PLL_MUL (9) +/* AHB and APBx bus clock configuration, keep in mind the following constraints: + * ABP1 <= 36MHz + */ #define CLOCK_AHB_DIV RCC_CFGR_HPRE_DIV1 +#define CLOCK_AHB (CLOCK_CORECLOCK / 1) #define CLOCK_APB2_DIV RCC_CFGR_PPRE2_DIV1 +#define CLOCK_APB2 (CLOCK_CORECLOCK / 1) #define CLOCK_APB1_DIV RCC_CFGR_PPRE1_DIV2 - -/* Bus clocks */ #define CLOCK_APB1 (CLOCK_CORECLOCK / 2) -#define CLOCK_APB2 (CLOCK_CORECLOCK) - -/* Flash latency */ -#define CLOCK_FLASH_LATENCY FLASH_ACR_LATENCY_2 /* for >= 72 MHz */ /** @} */ /** diff --git a/boards/spark-core/include/periph_conf.h b/boards/spark-core/include/periph_conf.h index afa0348989..25f671f026 100644 --- a/boards/spark-core/include/periph_conf.h +++ b/boards/spark-core/include/periph_conf.h @@ -26,22 +26,37 @@ #endif /** - * @name Clock system configuration + * @name Clock system configuration * @{ **/ -#define CLOCK_HSE (8000000U) /* frequency of external oscillator */ -#define CLOCK_CORECLOCK (72000000U) /* targeted core clock frequency */ -/* configuration of PLL prescaler and multiply values */ -/* CORECLOCK := HSE / PLL_HSE_DIV * PLL_HSE_MUL */ +/* high speed clock configuration: + * 0 := use internal HSI oscillator (always 8MHz) + * HSE frequency value := use external HSE oscillator with given freq [in Hz] + * must be 4000000 <= value <= 16000000 */ +#define CLOCK_HSE (8000000U) +/* low speed clock configuration: + * 0 := use internal LSI oscillator (~40kHz) + * 1 := use extern LSE oscillator, always 32.768kHz */ +#define CLOCK_LSE (0) +/* targeted system clock speed [in Hz], must be <= 72MHz */ +#define CLOCK_CORECLOCK (72000000U) +/* PLL configuration, set both values to zero to disable PLL usage. The values + * must be set to satisfy the following equation: + * CORECLOCK := CLOCK_SOURCE / PLL_DIV * PLL_MUL + * with + * 1 <= CLOCK_PLL_DIV <= 2 + * 2 <= CLOCK_PLL_MUL <= 17 */ #define CLOCK_PLL_DIV (1) #define CLOCK_PLL_MUL (9) -/* configuration of peripheral bus clock prescalers */ -#define CLOCK_AHB_DIV RCC_CFGR_HPRE_DIV1 /* AHB clock -> 72MHz */ -#define CLOCK_APB2_DIV RCC_CFGR_PPRE2_DIV1 /* APB2 clock -> 72MHz */ -#define CLOCK_APB1_DIV RCC_CFGR_PPRE1_DIV2 /* APB1 clock -> 36MHz */ -/* resulting bus clocks */ +/* AHB and APBx bus clock configuration, keep in mind the following constraints: + * ABP1 <= 36MHz + */ +#define CLOCK_AHB_DIV RCC_CFGR_HPRE_DIV1 +#define CLOCK_AHB (CLOCK_CORECLOCK / 1) +#define CLOCK_APB2_DIV RCC_CFGR_PPRE2_DIV1 +#define CLOCK_APB2 (CLOCK_CORECLOCK / 1) +#define CLOCK_APB1_DIV RCC_CFGR_PPRE1_DIV2 #define CLOCK_APB1 (CLOCK_CORECLOCK / 2) -#define CLOCK_APB2 (CLOCK_CORECLOCK) /** @} */ /** diff --git a/cpu/stm32_common/include/stmclk.h b/cpu/stm32_common/include/stmclk.h new file mode 100644 index 0000000000..bc07d83a22 --- /dev/null +++ b/cpu/stm32_common/include/stmclk.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2017 Freie Universität Berlin + * + * 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_common + * @{ + * + * @file + * @brief Interface for configuring the clock tree of STM32 CPUs + * + * @todo This interface should probably be moved and implemented for + * every STM32 CPU + * + * @author Hauke Petersen +*/ + +#ifndef STMCLK_H +#define STMCLK_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Configure the high speed clock domain (main system clock) + * + * This function initializes and configures the main systems clock(s). For this, + * the following actions are carried out: + * - enable the HSI + * - use the HSI as system clock (so now we are always in a defined state) + * - configure flash wait states and AHB/APB bus dividers + * - [opt] enable the HSE / MSI + * - configure the PLL + * - use PLL as system clock + * - turn off the HSI if unused + * + * All of these options are configurable through the board's periph_conf.h + */ +void stmclk_init_sysclk(void); + +/** + * @brief Enable the internal high speed clock (HSI) + */ +void stmclk_enable_hsi(void); + +/** + * @brief Disable the internal high speed clock (HSI) + * + * @note The HSI is only disabled, if it is at that point not used to drive + * the system clock or the PLL + */ +void stmclk_disable_hsi(void); + +/** + * @brief Configure and enable the low speed clock domain + * + * The actual clock used as input for the low frequency clock can be either the + * external low speed clock (LSE) or the internal low speed clock (LSI). This + * is configured in the board's periph_conf.h file. + */ +void stmclk_enable_lfclk(void); + +/** + * @brief Disable the low frequency clock domain + * + * @note When calling this function, better know what you do: be sure that + * the clock is not needed by any peripheral before calling this + * function. + */ +void stmclk_disable_lfclk(void); + +/** + * @brief Unlock write access to the backup domain control + */ +void stmclk_bdp_unlock(void); + +/** + * @brief Lock write access to backup control domain + */ +void stmclk_bdp_lock(void); + +#ifdef __cplusplus +} +#endif + +#endif /* STMCLK_H */ +/** @} */ diff --git a/cpu/stm32f1/cpu.c b/cpu/stm32f1/cpu.c index c2d465a640..d2cbf07dd2 100644 --- a/cpu/stm32f1/cpu.c +++ b/cpu/stm32f1/cpu.c @@ -26,139 +26,15 @@ */ #include "cpu.h" -#include "periph_conf.h" +#include "stmclk.h" #include "periph/init.h" -/* Configuration of flash access cycles */ -#if CLOCK_CORECLOCK <= 24000000 -#define FLASH_LATENCY (0) /* Zero wait state, if 0 < SYSCLK≤ 24 MHz */ -#elif CLOCK_CORECLOCK <= 48000000 -#define FLASH_LATENCY (1) /* One wait states, if 24 MHz < SYSCLK ≤ 48 MHz */ -#elif CLOCK_CORECLOCK <= 72000000 -#define FLASH_LATENCY (2) /* Two wait states, if 48 MHz < SYSCLK ≤ 72 MHz */ -#endif - -/* See if we want to use the PLL */ -#if defined(CLOCK_PLL_DIV) || defined(CLOCK_PLL_MUL) -#define CLOCK_USE_PLL 1 -#else -#define CLOCK_USE_PLL 0 -#endif - -/* Check the source to be used and parameters */ -#if defined(CLOCK_HSI) && defined(CLOCK_HSE) -#error "Only provide one of two CLOCK_HSI/CLOCK_HSE" -#elif (CLOCK_USE_PLL == 1) && (!defined(CLOCK_PLL_MUL) || !defined(CLOCK_PLL_DIV)) -#error "When using PLL both CLOCK_PLL_DIV and CLOCK_PLL_MUL must be provided" - -#elif CLOCK_HSI -#define CLOCK_CR_SOURCE RCC_CR_HSION -#define CLOCK_CR_SOURCE_RDY RCC_CR_HSIRDY -#define CLOCK_PLL_DIVMSK 0 -#define CLOCK_PLL_SOURCE 0 -#define CLOCK_DISABLE_HSI 0 - -#if (CLOCK_USE_PLL == 0) -#define CLOCK_CFGR_SW RCC_CFGR_SW_HSI -#define CLOCK_CFGR_SW_RDY RCC_CFGR_SWS_HSI -#elif (CLOCK_PLL_DIV != 2) -#error "CLOCK_PLL_DIV can only be 2 for the HSI" -#endif - -#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 -#define CLOCK_DISABLE_HSI 1 - -#if (CLOCK_USE_PLL == 0) -#define CLOCK_CFGR_SW RCC_CFGR_SW_HSE -#define CLOCK_CFGR_SW_RDY RCC_CFGR_SWS_HSE -#elif (CLOCK_PLL_DIV == 2) -#define CLOCK_PLL_DIVMSK RCC_CFGR_PLLXTPRE -#elif (CLOCK_PLL_DIV == 1) -#define CLOCK_PLL_DIVMSK 0 -#elif defined(CLOCK_PLL_DIV) -#error "HSE divider must be 1 or 2" -#endif - -#else -#error "Please provide CLOCK_HSI or CLOCK_HSE in boards/NAME/includes/perhip_cpu.h" -#endif - -#if (CLOCK_USE_PLL == 1) -#define CLOCK_CFGR_SW RCC_CFGR_SW_PLL -#define CLOCK_CFGR_SW_RDY RCC_CFGR_SWS_PLL -#if CLOCK_PLL_MUL > 16 -#error "PLL multiplier cannot exceed 16 times" -#elif CLOCK_PLL_MUL < 2 -#error "PLL multiplier cannot be set to 1 or lower" -#endif -#endif - -static void clk_init(void); - void cpu_init(void) { /* initialize the Cortex-M core */ cortexm_init(); - /* initialize system clocks */ - clk_init(); + /* initialize the system clock as configured in the periph_conf.h */ + stmclk_init_sysclk(); /* trigger static peripheral initialization */ periph_init(); } - -/** - * @brief Configure the clock system of the stm32f1 - */ -static void clk_init(void) -{ - /* Reset the RCC clock configuration to the default reset state(for debug purpose) */ - /* Set HSION bit */ - RCC->CR |= (uint32_t)0x00000001; - /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */ - RCC->CFGR &= (uint32_t)0xF0FF0000; - /* Reset HSEON, CSSON and PLLON bits */ - RCC->CR &= (uint32_t)0xFEF6FFFF; - /* Reset HSEBYP bit */ - RCC->CR &= (uint32_t)0xFFFBFFFF; - /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */ - RCC->CFGR &= (uint32_t)0xFF80FFFF; - /* Disable all interrupts and clear pending bits */ - RCC->CIR = (uint32_t)0x009F0000; - - /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration */ - /* Enable high speed clock source */ - RCC->CR |= ((uint32_t)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) == 0) {} - /* Enable prefetch buffer and set flash wait state */ - FLASH->ACR = (uint32_t)(FLASH_ACR_PRFTBE | FLASH_LATENCY); - /* 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; - -#if (CLOCK_USE_PLL == 1) - /* PLL configuration: PLLCLK = CLOCK_SOURCE / PLL_DIV * PLL_MUL */ - RCC->CFGR |= (uint32_t)(CLOCK_PLL_SOURCE | CLOCK_PLL_DIVMSK | ((CLOCK_PLL_MUL - 2) << 18)); - /* Enable PLL */ - RCC->CR |= RCC_CR_PLLON; - /* Wait till PLL is ready */ - while ((RCC->CR & RCC_CR_PLLRDY) == 0) {} -#endif - - /* Select the system clock source */ - RCC->CFGR &= ~((uint32_t)(RCC_CFGR_SW)); - RCC->CFGR |= (uint32_t)CLOCK_CFGR_SW; - /* Wait till selected system clock source is ready */ - while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != CLOCK_CFGR_SW_RDY) {} - -#if CLOCK_DISABLE_HSI - RCC->CR &= ~(RCC_CR_HSION); - while ((RCC->CR & RCC_CR_HSIRDY) != 0) {} -#endif -} diff --git a/cpu/stm32f1/stmclk.c b/cpu/stm32f1/stmclk.c new file mode 100644 index 0000000000..95f7052dd0 --- /dev/null +++ b/cpu/stm32f1/stmclk.c @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2017 Freie Universität Berlin + * + * 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_stm32f1 + * @{ + * + * @file + * @brief Implementation of STM32F1 clock configuration + * + * @author Stefan Pfeiffer + * @author Alaeddine Weslati + * @author Thomas Eichinger + * @author Hauke Petersen + * @author Nick van IJzendoorn + * @author Víctor Ariño + * + * @} + */ + +#include "irq.h" +#include "cpu.h" +#include "stmclk.h" +#include "periph_conf.h" + +/* make sure we have all needed information about the clock configuration */ +#ifndef CLOCK_HSE +#error "Please provide CLOCK_HSE in your board's perhip_conf.h" +#endif +#ifndef CLOCK_LSE +#error "Please provide CLOCK_LSE in your board's periph_conf.h" +#endif +#ifndef CLOCK_CORECLOCK +#error "Please provide CLOCK_CORECLOCK in your board's periph_conf.h" +#endif +#if !defined(CLOCK_PLL_MUL) || !defined(CLOCK_PLL_DIV) +#error "Please provide a valid PLL configuration in your board's periph_conf.h" +#endif +#if !defined(CLOCK_AHB_DIV) || !defined(CLOCK_AHB) || \ + !defined(CLOCK_APB1_DIV) || !defined(CLOCK_APB1) || \ + !defined(CLOCK_APB2_DIV) || !defined(CLOCK_APB2) +#error "Please provide a AHB and APBx configuration in your board configuration" +#endif + +/* make sure the selected system clock is valid */ +#if (CLOCK_CORECLOCK > 72000000) +#error "clock config: the selected system clock exceeds 72MHz" +#endif + +/* figure out which base block to use */ +#if CLOCK_HSE +#if (CLOCK_HSE < 4000000) || (CLOCK_HSE > 16000000) +#error "clock config: HSE value is out of valid range" +#endif +#define BASECLK (CLOCK_HSE) +#else +#define BASECLK (8000000) /* HSI is alway 8MHz */ +#endif + +/* if PLL is configured, verify its parameters */ +#if (CLOCK_PLL_DIV && CLOCK_PLL_MUL) +#define USEPLL +/* check clock config */ +#if (CLOCK_CORECLOCK != ((BASECLK / CLOCK_PLL_DIV) * CLOCK_PLL_MUL)) +#error "clock config: PLL configuration does not yield expected system clock" +#endif +/* make sure PLL_MUL is in range */ +#if (CLOCK_PLL_MUL < 2) || (CLOCK_PLL_MUL > 17) +#error "clock config: CLOCK_PLL_MUL is out of range" +#endif +/* make sure PLL_DIV is 2 when using HSI as input */ +#if (!CLOCK_HSE) && (CLOCK_PLL_DIV != 2) +#error "clock config: CLOCK_PLL_DIV must be 2 when using HSI oscillator" +#endif +/* and produce the actual PLL configuration */ +#if CLOCK_HSE +#define PLLSRC (RCC_CFGR_PLLSRC) +#if (CLOCK_PLL_DIV == 2) +#define PLLDIV (RCC_CFGR_PLLXTPRE) +#else +#define PLLDIV (0) +#endif +#else +#define PLLSRC (0) +#define PLLDIV (0) +#endif +#define PLLMUL ((CLOCK_PLL_MUL - 2) << 18) +/* and join it for writing the the CFGR register */ +#define PLLCFG (PLLMUL | PLLDIV | PLLSRC) +#else +#define PLLCFG (0) +#endif + +/* now we need to select the system clock source configuration */ +#ifdef USEPLL +#define SYSCLK_SRC RCC_CFGR_SW_PLL +#define SYSCLK_BSY RCC_CFGR_SWS_PLL +#elif CLK_HSE +#define SYSCLK_SRC RCC_CFGR_SW_HSE +#define SYSCLK_BSY RCC_CFGR_SWS_HSE +#elif +#define SYSCLK_SRC RCC_CFGR_SW_HSI +#define SYSCLK_BSY RCC_CFGR_SWS_HSI +#endif + +/* Configuration of flash access cycles */ +#define FLASH_WAITSTATES ((CLOCK_CORECLOCK - 1) / 24000000U) + +/* define some bitfields */ +#define HSITRIM (1 << 7) +#define SWSHSI (0) + + +void stmclk_init_sysclk(void) +{ + /* disable any IRQs */ + unsigned is = irq_disable(); + RCC->CIR = 0; + + /* enable HSI and use it as system clock */ + stmclk_enable_hsi(); + RCC->CFGR &= ~(RCC_CFGR_SW); + while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI) {} + + /* its safe now to program the flash wait states */ + FLASH->ACR = (FLASH_ACR_PRFTBE | FLASH_WAITSTATES); + /* now we are in a defined state and can stop all other clocks */ + RCC->CR = (HSITRIM | RCC_CR_HSION); + /* next we put in the desired PLL and peripheral bus configuration */ + RCC->CFGR = (CLOCK_AHB_DIV | CLOCK_APB1_DIV | CLOCK_APB2_DIV | PLLCFG); + + /* now we need to (re-)enable the used clocks */ +#if CLOCK_HSE + RCC->CR |= RCC_CR_HSEON; + while (!(RCC->CR & RCC_CR_HSERDY)) {} +#endif +#ifdef USEPLL + RCC->CR |= RCC_CR_PLLON; + while (!(RCC->CR & RCC_CR_PLLRDY)) {} +#endif + + /* leaves switching the system clock */ + RCC->CFGR |= SYSCLK_SRC; + while ((RCC->CFGR & RCC_CFGR_SWS) != SYSCLK_BSY) {} + + /* disable HSI (if not used) */ + stmclk_disable_hsi(); + + /* re-enable IRQs */ + irq_restore(is); +} + +void stmclk_enable_hsi(void) +{ + RCC->CR |= RCC_CR_HSION; + while (!(RCC->CR & RCC_CR_HSIRDY)) {} +} + +void stmclk_disable_hsi(void) +{ + /* we only disable the HSI clock if not used as input for the PLL and if + * not used directly as system clock */ +#ifdef CLOCK_HSE + if ((RCC->CFGR & RCC_CFGR_SWS) != SWSHSI) { + RCC->CR &= ~(RCC_CR_HSION); + } +#endif +} + +void stmclk_enable_lfclk(void) +{ +#if CLOCK_LSE + stmclk_bdp_unlock(); + RCC->BDCR |= RCC_BDCR_LSEON; + while (!(RCC->BDCR & RCC_BDCR_LSERDY)) {} + stmclk_bdp_lock(); +#else + RCC->CSR |= RCC_CSR_LSION; + while (!(RCC->CSR & RCC_CSR_LSIRDY)) {} +#endif +} + +void stmclk_disable_lfclk(void) +{ +#if CLOCK_LSE + stmclk_bdp_unlock(); + RCC->BDCR &= ~(RCC_BDCR_LSEON); + stmclk_bdp_lock(); +#else + RCC->CSR &= ~(RCC_CSR_LSION); +#endif +} + +void stmclk_bdp_unlock(void) +{ + periph_clk_en(APB1, RCC_APB1ENR_PWREN); + PWR->CR |= PWR_CR_DBP; +} + +void stmclk_bdp_lock(void) +{ + PWR->CR &= ~(PWR_CR_DBP); + periph_clk_dis(APB1, RCC_APB1ENR_PWREN); +}