diff --git a/cpu/stm32_common/stmclk.c b/cpu/stm32_common/stmclk.c new file mode 100644 index 0000000000..96f7e75a18 --- /dev/null +++ b/cpu/stm32_common/stmclk.c @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2017 Freie Universität Berlin + * 2017 OTA keys S.A. + * + * 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 Implementation of STM32 clock configuration + * + * @author Hauke Petersen + * @author Vincent Dupont + * @} + */ + +#if defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) || defined(CPU_FAM_STM32F7) + +#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 + +/** + * @name PLL configuration + * @{ + */ +/* figure out which input to use */ +#if (CLOCK_HSE) +#define PLL_SRC RCC_PLLCFGR_PLLSRC_HSE +#else +#define PLL_SRC RCC_PLLCFGR_PLLSRC_HSI +#endif + +#if (CLOCK_ENABLE_PLL_I2S) +#ifdef RCC_PLLI2SCFGR_PLLI2SM_Pos +#define PLLI2S_M (CLOCK_PLL_I2S_M << RCC_PLLI2SCFGR_PLLI2SM_Pos) +#else +#define PLLI2S_M (0) +#endif +#define PLLI2S_N (CLOCK_PLL_I2S_N << RCC_PLLI2SCFGR_PLLI2SN_Pos) +#ifdef RCC_PLLI2SCFGR_PLLI2SP_Pos +#define PLLI2S_P (((CLOCK_PLL_I2S_P / 2) - 1) << RCC_PLLI2SCFGR_PLLI2SP_Pos) +#else +#define PLLI2S_P (0) +#endif +#define PLLI2S_Q (CLOCK_PLL_I2S_Q << RCC_PLLI2SCFGR_PLLI2SQ_Pos) +#endif /* CLOCK_ENABLE_PLLI_2S */ + +#if (CLOCK_ENABLE_PLL_SAI) +#ifdef RCC_PLLSAICFGR_PLLSAIN_Pos +#define PLLSAI_M (CLOCK_PLL_SAI_M << RCC_PLLSAICFGR_PLLSAIN_Pos) +#else +#define PLLSAI_M (0) +#endif +#define PLLSAI_N (CLOCK_PLL_SAI_N << RCC_PLLSAICFGR_PLLSAIN_Pos) +#ifdef RCC_PLLSAICFGR_PLLSAIP_Pos +#define PLLSAI_P (((CLOCK_PLL_SAI_P / 2) - 1) << RCC_PLLSAICFGR_PLLSAIP_Pos) +#else +#define PLLSAI_P (0) +#endif +#define PLLSAI_Q (CLOCK_PLL_SAI_Q << RCC_PLLSAICFGR_PLLSAIQ_Pos) +#endif /* CLOCK_ENABLE_PLL_SAI */ + +#if defined(CPU_FAM_STM32F2) +#define RCC_PLLCFGR_PLLP_Pos (16U) +#define RCC_PLLCFGR_PLLM_Pos (0U) +#define RCC_PLLCFGR_PLLN_Pos (6U) +#define RCC_PLLCFGR_PLLQ_Pos (24U) +#endif + +/* now we get the actual bitfields */ +#define PLL_P (((CLOCK_PLL_P / 2) - 1) << RCC_PLLCFGR_PLLP_Pos) +#define PLL_M (CLOCK_PLL_M << RCC_PLLCFGR_PLLM_Pos) +#define PLL_N (CLOCK_PLL_N << RCC_PLLCFGR_PLLN_Pos) +#define PLL_Q (CLOCK_PLL_Q << RCC_PLLCFGR_PLLQ_Pos) +/** @} */ + +/** + * @name Deduct the needed flash wait states from the core clock frequency + * @{ + */ +#define FLASH_WAITSTATES (CLOCK_CORECLOCK / 30000000U) +/* we enable I+D cashes, pre-fetch, and we set the actual number of + * needed flash wait states */ +#if defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) +#define FLASH_ACR_CONFIG (FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_PRFTEN | FLASH_WAITSTATES) +#elif defined(CPU_FAM_STM32F7) +#define FLASH_ACR_CONFIG (FLASH_ACR_ARTEN | FLASH_ACR_PRFTEN | FLASH_WAITSTATES) +#endif +/** @} */ + +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 | CLOCK_APB2_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); + +#if (CLOCK_MCO1_SRC) +#ifndef RCC_CFGR_MCO1 +#error "stmclk: no MCO1 on this device" +#endif + RCC->CFGR |= CLOCK_MCO1_SRC | CLOCK_MCO1_PRE; +#endif +#if (CLOCK_MCO2_SRC) +#ifndef RCC_CFGR_MCO2 +#error "stmclk: no MCO2 on this device" +#endif + RCC->CFGR |= CLOCK_MCO2_SRC | CLOCK_MCO2_PRE; +#endif + + /* if configured, we need to enable the HSE clock now */ +#if (CLOCK_HSE) + RCC->CR |= (RCC_CR_HSEON); + while (!(RCC->CR & RCC_CR_HSERDY)) {} +#endif + +#if CLOCK_USE_ALT_48MHZ + RCC->DCKCFGR2 |= RCC_DCKCFGR2_CK48MSEL; +#endif + /* now we can safely configure and start the PLL */ + RCC->PLLCFGR = (PLL_SRC | PLL_M | PLL_N | PLL_P | PLL_Q); + RCC->CR |= (RCC_CR_PLLON); + while (!(RCC->CR & RCC_CR_PLLRDY)) {} + + /* now that the PLL is running, we use it as system clock */ + RCC->CFGR |= (RCC_CFGR_SW_PLL); + while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) {} + + stmclk_disable_hsi(); + +#if (CLOCK_ENABLE_PLLI2S) + RCC->PLLI2SCFGR = (PLLI2S_SRC | PLLI2S_M | PLLI2S_N | PLLI2s_P | PLLI2S_Q); + RCC->CR |= (RCC_CR_PLLI2SON); + while (!(RCC->CR & RCC_CR_PLLI2SRDY)) {} +#endif /* CLOCK_ENABLE_PLLI2S */ + +#if (CLOCK_ENABLE_PLLSAI) + RCC->PLLSAICFGR = (PLLSAI_M | PLLSAI_N | PLLSAI_P | PLLSAI_Q); + RCC->CR |= (RCC_CR_PLLSAION); + while (!(RCC->CR & RCC_CR_PLLSAIRDY)) {} +#endif + + irq_restore(is); +} +#else +typedef int dont_be_pedantic; +#endif /* defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) || defined(CPU_FAM_STM32F7) */ diff --git a/cpu/stm32f2/stmclk.c b/cpu/stm32f2/stmclk.c deleted file mode 100644 index a32ca10e14..0000000000 --- a/cpu/stm32f2/stmclk.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (C) 2017 Freie Universität Berlin - * 2017 OTA keys S.A. - * - * 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_stm32f2 - * @{ - * - * @file - * @brief Implementation of STM32 clock configuration - * - * @author Hauke Petersen - * @author Vincent Dupont - * @} - */ - -#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 - -/** - * @name PLL configuration - * @{ - */ -/* figure out which input to use */ -#if (CLOCK_HSE) -#define PLL_IN CLOCK_HSE -#define PLL_SRC RCC_PLLCFGR_PLLSRC_HSE -#else -#define PLL_IN (16000000U) /* HSI fixed @ 16MHz */ -#define PLL_SRC RCC_PLLCFGR_PLLSRC_HSI -#endif - -#ifndef P -/* we fix P to 2 (so the PLL output equals 2 * CLOCK_CORECLOCK) */ -#define P (2U) -#if ((P != 2) && (P != 4) && (P != 6) && (P != 8)) -#error "PLL configuration: PLL P value is invalid" -#endif -#endif /* P */ -/* the recommended input clock for the PLL should be 2MHz */ -#define M (PLL_IN / 2000000U) -#if ((M < 2) || (M > 63)) -#error "PLL configuration: PLL M value is out of range" -#endif -/* next we multiply the input freq to 2 * CORECLOCK */ -#define N (P * CLOCK_CORECLOCK / 2000000U) -#if ((N < 50) || (N > 432)) -#error "PLL configuration: PLL N value is out of range" -#endif -/* finally we need to set Q, so that the USB clock is 48MHz */ -#define Q ((P * CLOCK_CORECLOCK) / 48000000U) -#if ((Q * 48000000U) != (P * CLOCK_CORECLOCK)) -#error "PLL configuration: USB frequency is not 48MHz" -#endif - -#define RCC_PLLCFGR_PLLP_Pos (16U) -#define RCC_PLLCFGR_PLLM_Pos (0U) -#define RCC_PLLCFGR_PLLN_Pos (6U) -#define RCC_PLLCFGR_PLLQ_Pos (24U) -/* now we get the actual bitfields */ -#define PLL_P (((P / 2) - 1) << RCC_PLLCFGR_PLLP_Pos) -#define PLL_M (M << RCC_PLLCFGR_PLLM_Pos) -#define PLL_N (N << RCC_PLLCFGR_PLLN_Pos) -#define PLL_Q (Q << RCC_PLLCFGR_PLLQ_Pos) -/** @} */ - -/** - * @name Deduct the needed flash wait states from the core clock frequency - * @{ - */ -#define FLASH_WAITSTATES (CLOCK_CORECLOCK / 30000000U) -/** @} */ - -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 | CLOCK_APB2_DIV); - while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI) {} - - /* we enable I+D cashes, pre-fetch, and we set the actual number of - * needed flash wait states */ - FLASH->ACR = (FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_PRFTEN | FLASH_WAITSTATES); - - /* disable all active clocks except HSI -> resets the clk configuration */ - RCC->CR = (RCC_CR_HSION | RCC_CR_HSITRIM_4); - - /* if configured, we need to enable the HSE clock now */ -#if (CLOCK_HSE) - RCC->CR |= (RCC_CR_HSEON); - while (!(RCC->CR & RCC_CR_HSERDY)) {} -#endif - -#ifdef ENABLE_PLLI2S_MCO2 - /* reset PLL I2S config register */ - RCC->PLLI2SCFGR = 0x00000000U; - /* set PLL I2S division factor */ - RCC->PLLI2SCFGR |= (CLOCK_PLL_I2S_R & 0x07) << 28; - /* set PLL I2S multiplication factor */ - RCC->PLLI2SCFGR |= (CLOCK_PLL_I2S_N & 0x1FF) << 6; - - /* MCO2 output is PLLI2S */ - RCC->CFGR |= (uint32_t) RCC_CFGR_MCO2_0; - RCC->CFGR &= ~(uint32_t) RCC_CFGR_MCO2_1; - /* MCO2 prescaler div by 5 */ - RCC->CFGR |= (uint32_t) ((CLOCK_MC02_PRE + 4 - 2) & 0x7) << 27; - /* enable PLL I2S clock */ - RCC->CR |= RCC_CR_PLLI2SON; - /* wait till PLL I2S clock is ready */ - while ((RCC->CR & RCC_CR_PLLI2SRDY) == 0) {} -#endif - - /* now we can safely configure and start the PLL */ - RCC->PLLCFGR = (PLL_SRC | PLL_M | PLL_N | PLL_P | PLL_Q); - RCC->CR |= (RCC_CR_PLLON); - while (!(RCC->CR & RCC_CR_PLLRDY)) {} - - /* now that the PLL is running, we use it as system clock */ - RCC->CFGR |= (RCC_CFGR_SW_PLL); - while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) {} - - stmclk_disable_hsi(); - irq_restore(is); -} diff --git a/cpu/stm32f4/stmclk.c b/cpu/stm32f4/stmclk.c deleted file mode 100644 index ea2281f445..0000000000 --- a/cpu/stm32f4/stmclk.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2017 Freie Universität Berlin - * 2017 OTA keys S.A. - * - * 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_stm32f4 - * @{ - * - * @file - * @brief Implementation of STM32 clock configuration - * - * @author Hauke Petersen - * @author Vincent Dupont - * @} - */ - -#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 - -/** - * @name PLL configuration - * @{ - */ -/* figure out which input to use */ -#if (CLOCK_HSE) -#define PLL_IN CLOCK_HSE -#define PLL_SRC RCC_PLLCFGR_PLLSRC_HSE -#else -#define PLL_IN (16000000U) /* HSI fixed @ 16MHz */ -#define PLL_SRC RCC_PLLCFGR_PLLSRC_HSI -#endif - -#ifndef P -/* we fix P to 2 (so the PLL output equals 2 * CLOCK_CORECLOCK) */ -#define P (2U) -#if ((P != 2) && (P != 4) && (P != 6) && (P != 8)) -#error "PLL configuration: PLL P value is invalid" -#endif -#endif /* P */ -/* the recommended input clock for the PLL should be 2MHz */ -#define M (PLL_IN / 2000000U) -#if ((M < 2) || (M > 63)) -#error "PLL configuration: PLL M value is out of range" -#endif -/* next we multiply the input freq to 2 * CORECLOCK */ -#define N (P * CLOCK_CORECLOCK / 2000000U) -#if ((N < 50) || (N > 432)) -#error "PLL configuration: PLL N value is out of range" -#endif -/* finally we need to set Q, so that the USB clock is 48MHz */ -#define Q ((P * CLOCK_CORECLOCK) / 48000000U) -#if ((Q * 48000000U) != (P * CLOCK_CORECLOCK)) -#error "PLL configuration: USB frequency is not 48MHz" -#endif - -/* now we get the actual bitfields */ -#define PLL_P (((P / 2) - 1) << RCC_PLLCFGR_PLLP_Pos) -#define PLL_M (M << RCC_PLLCFGR_PLLM_Pos) -#define PLL_N (N << RCC_PLLCFGR_PLLN_Pos) -#define PLL_Q (Q << RCC_PLLCFGR_PLLQ_Pos) -/** @} */ - -/** - * @name Deduct the needed flash wait states from the core clock frequency - * @{ - */ -#define FLASH_WAITSTATES (CLOCK_CORECLOCK / 30000000U) -/** @} */ - -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 | CLOCK_APB2_DIV); - while ((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_HSI) {} - - /* we enable I+D cashes, pre-fetch, and we set the actual number of - * needed flash wait states */ - FLASH->ACR = (FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_PRFTEN | FLASH_WAITSTATES); - - /* disable all active clocks except HSI -> resets the clk configuration */ - RCC->CR = (RCC_CR_HSION | RCC_CR_HSITRIM_4); - - /* if configured, we need to enable the HSE clock now */ -#if (CLOCK_HSE) - RCC->CR |= (RCC_CR_HSEON); - while (!(RCC->CR & RCC_CR_HSERDY)) {} -#endif - - /* now we can safely configure and start the PLL */ - RCC->PLLCFGR = (PLL_SRC | PLL_M | PLL_N | PLL_P | PLL_Q); - RCC->CR |= (RCC_CR_PLLON); - while (!(RCC->CR & RCC_CR_PLLRDY)) {} - - /* now that the PLL is running, we use it as system clock */ - RCC->CFGR |= (RCC_CFGR_SW_PLL); - while ((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_PLL) {} - - stmclk_disable_hsi(); - irq_restore(is); -} diff --git a/cpu/stm32f7/stmclk.c b/cpu/stm32f7/stmclk.c deleted file mode 100644 index 4d00169390..0000000000 --- a/cpu/stm32f7/stmclk.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * 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_stm32f7 - * @{ - * - * @file - * @brief Implementation of STM32 clock configuration - * - * @author Hauke Petersen - * @} - */ - -#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 - -/** - * @name PLL configuration - * @{ - */ -/* figure out which input to use */ -#if (CLOCK_HSE) -#define PLL_IN CLOCK_HSE -#define PLL_SRC RCC_PLLCFGR_PLLSRC_HSE -#else -#define PLL_IN (16000000U) /* HSI fixed @ 16MHz */ -#define PLL_SRC RCC_PLLCFGR_PLLSRC_HSI -#endif - -/* we fix P to 2 (so the PLL output equals 2 * CLOCK_CORECLOCK) */ -#define P (2U) -/* the recommended input clock for the PLL should be 2MHz > ref. man. p. 143 */ -#define M (PLL_IN / 2000000U) -#if ((M < 2) || (M > 63)) -#error "PLL configuration: PLL M value is out of range" -#endif -/* next we multiply the input freq to 2 * CORECLOCK */ -#define N (P * CLOCK_CORECLOCK / 2000000U) -#if ((N < 50) || (N > 432)) -#error "PLL configuration: PLL N value is out of range" -#endif -/* finally we need to set Q, so that the USB clock is 48MHz */ -#define Q ((P * CLOCK_CORECLOCK) / 48000000U) -#if ((Q * 48000000U) != (P * CLOCK_CORECLOCK)) -#error "PLL configuration: USB frequency is not 48MHz" -#endif - -/* now we get the actual bitfields */ -#define PLL_P (0) -#define PLL_M (M << RCC_PLLCFGR_PLLM_Pos) -#define PLL_N (N << RCC_PLLCFGR_PLLN_Pos) -#define PLL_Q (Q << RCC_PLLCFGR_PLLQ_Pos) -/** @} */ - -/** - * @name Deduct the needed flash wait states from the core clock frequency - * @{ - */ -#define FLASH_WAITSTATES (CLOCK_CORECLOCK / 30000000U) -/** @} */ - -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 | CLOCK_APB2_DIV); - while ((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_HSI) {} - - /* we enable I+D cashes, pre-fetch, and we set the actual number of - * needed flash wait states */ - FLASH->ACR = (FLASH_ACR_ARTEN | FLASH_ACR_PRFTEN | FLASH_WAITSTATES); - - /* disable all active clocks except HSI -> resets the clk configuration */ - RCC->CR = (RCC_CR_HSION | RCC_CR_HSITRIM_4); - - /* if configured, we need to enable the HSE clock now */ -#if (CLOCK_HSE) - RCC->CR |= (RCC_CR_HSEON); - while (!(RCC->CR & RCC_CR_HSERDY)) {} -#endif - - /* now we can safely configure and start the PLL */ - RCC->PLLCFGR = (PLL_SRC | PLL_M | PLL_N | PLL_P | PLL_Q); - RCC->CR |= (RCC_CR_PLLON); - while (!(RCC->CR & RCC_CR_PLLRDY)) {} - - /* now that the PLL is running, we use it as system clock */ - RCC->CFGR |= (RCC_CFGR_SW_PLL); - while ((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_PLL) {} - - stmclk_disable_hsi(); - irq_restore(is); -}