From bd6c25c9f8c28831d146f9077a0a2aa636c6e037 Mon Sep 17 00:00:00 2001 From: Kevin O'Connor Date: Mon, 25 Nov 2019 14:00:30 -0500 Subject: [PATCH] stm32: Allow external crystal speed to be customized in Kconfig Signed-off-by: Kevin O'Connor --- src/stm32/Kconfig | 14 +++++++--- src/stm32/stm32f0.c | 14 ++++++---- src/stm32/stm32f1.c | 20 +++++++------- src/stm32/stm32f4.c | 67 ++++++++++++++++++++++----------------------- 4 files changed, 60 insertions(+), 55 deletions(-) diff --git a/src/stm32/Kconfig b/src/stm32/Kconfig index d093c716..00ec72cd 100644 --- a/src/stm32/Kconfig +++ b/src/stm32/Kconfig @@ -112,13 +112,19 @@ choice prompt "Clock Reference" if LOW_LEVEL_OPTIONS config STM32_CLOCK_REF_8M bool "8Mhz crystal" + config STM32_CLOCK_REF_12M + bool "12Mhz crystal" + config STM32_CLOCK_REF_16M + bool "16Mhz crystal" config STM32_CLOCK_REF_INTERNAL bool "Internal clock" endchoice -config CLOCK_REF_8M - bool - default n if STM32_CLOCK_REF_INTERNAL - default y +config CLOCK_REF_FREQ + int + default 16000000 if STM32_CLOCK_REF_16M + default 12000000 if STM32_CLOCK_REF_12M + default 1 if STM32_CLOCK_REF_INTERNAL + default 8000000 config USBSERIAL bool "Use USB for communication (instead of serial)" diff --git a/src/stm32/stm32f0.c b/src/stm32/stm32f0.c index 11951920..6f9d994f 100644 --- a/src/stm32/stm32f0.c +++ b/src/stm32/stm32f0.c @@ -4,7 +4,7 @@ // // This file may be distributed under the terms of the GNU GPLv3 license. -#include "autoconf.h" // CONFIG_CLOCK_REF_8M +#include "autoconf.h" // CONFIG_CLOCK_REF_FREQ #include "board/armcm_boot.h" // armcm_main #include "board/irq.h" // irq_disable #include "command.h" // DECL_CONSTANT_STR @@ -99,7 +99,7 @@ usb_request_bootloader(void) NVIC_SystemReset(); } -#if CONFIG_CLOCK_REF_8M +#if !CONFIG_STM32_CLOCK_REF_INTERNAL DECL_CONSTANT_STR("RESERVE_PINS_crystal", "PF0,PF1"); #endif @@ -108,13 +108,15 @@ static void pll_setup(void) { uint32_t cfgr; - if (CONFIG_CLOCK_REF_8M) { - // Configure 48Mhz PLL from external 8Mhz crystal (HSE) + if (!CONFIG_STM32_CLOCK_REF_INTERNAL) { + // Configure 48Mhz PLL from external crystal (HSE) + uint32_t div = CONFIG_CLOCK_FREQ / CONFIG_CLOCK_REF_FREQ; RCC->CR |= RCC_CR_HSEON; - cfgr = RCC_CFGR_PLLSRC_HSE_PREDIV | ((6 - 2) << RCC_CFGR_PLLMUL_Pos); + cfgr = RCC_CFGR_PLLSRC_HSE_PREDIV | ((div - 2) << RCC_CFGR_PLLMUL_Pos); } else { // Configure 48Mhz PLL from internal 8Mhz oscillator (HSI) - cfgr = RCC_CFGR_PLLSRC_HSI_DIV2 | ((12 - 2) << RCC_CFGR_PLLMUL_Pos); + uint32_t div2 = (CONFIG_CLOCK_FREQ / 8000000) * 2; + cfgr = RCC_CFGR_PLLSRC_HSI_DIV2 | ((div2 - 2) << RCC_CFGR_PLLMUL_Pos); } RCC->CFGR = cfgr; RCC->CR |= RCC_CR_PLLON; diff --git a/src/stm32/stm32f1.c b/src/stm32/stm32f1.c index 33509ab7..66c4933b 100644 --- a/src/stm32/stm32f1.c +++ b/src/stm32/stm32f1.c @@ -4,7 +4,7 @@ // // This file may be distributed under the terms of the GNU GPLv3 license. -#include "autoconf.h" // CONFIG_CLOCK_REF_8M +#include "autoconf.h" // CONFIG_CLOCK_REF_FREQ #include "board/armcm_boot.h" // VectorTable #include "board/irq.h" // irq_disable #include "board/usb_cdc.h" // usb_request_bootloader @@ -129,19 +129,19 @@ clock_setup(void) { // Configure and enable PLL uint32_t cfgr; - if (CONFIG_CLOCK_REF_8M) { - // Configure 72Mhz PLL from external 8Mhz crystal (HSE) + if (!CONFIG_STM32_CLOCK_REF_INTERNAL) { + // Configure 72Mhz PLL from external crystal (HSE) + uint32_t div = CONFIG_CLOCK_FREQ / CONFIG_CLOCK_REF_FREQ; RCC->CR |= RCC_CR_HSEON; - cfgr = ((1 << RCC_CFGR_PLLSRC_Pos) | ((9 - 2) << RCC_CFGR_PLLMULL_Pos) - | RCC_CFGR_PPRE1_DIV2 | RCC_CFGR_PPRE2_DIV2 - | RCC_CFGR_ADCPRE_DIV4); + cfgr = (1 << RCC_CFGR_PLLSRC_Pos) | ((div - 2) << RCC_CFGR_PLLMULL_Pos); } else { // Configure 72Mhz PLL from internal 8Mhz oscillator (HSI) - cfgr = ((0 << RCC_CFGR_PLLSRC_Pos) | ((18 - 2) << RCC_CFGR_PLLMULL_Pos) - | RCC_CFGR_PPRE1_DIV2 | RCC_CFGR_PPRE2_DIV2 - | RCC_CFGR_ADCPRE_DIV4); + uint32_t div2 = (CONFIG_CLOCK_FREQ / 8000000) * 2; + cfgr = ((0 << RCC_CFGR_PLLSRC_Pos) + | ((div2 - 2) << RCC_CFGR_PLLMULL_Pos)); } - RCC->CFGR = cfgr; + RCC->CFGR = (cfgr | RCC_CFGR_PPRE1_DIV2 | RCC_CFGR_PPRE2_DIV2 + | RCC_CFGR_ADCPRE_DIV4); RCC->CR |= RCC_CR_PLLON; // Set flash latency diff --git a/src/stm32/stm32f4.c b/src/stm32/stm32f4.c index 0c87201a..f8b5ab2d 100644 --- a/src/stm32/stm32f4.c +++ b/src/stm32/stm32f4.c @@ -4,7 +4,7 @@ // // This file may be distributed under the terms of the GNU GPLv3 license. -#include "autoconf.h" // CONFIG_CLOCK_REF_8M +#include "autoconf.h" // CONFIG_CLOCK_REF_FREQ #include "board/armcm_boot.h" // VectorTable #include "board/irq.h" // irq_disable #include "board/usb_cdc.h" // usb_request_bootloader @@ -13,6 +13,7 @@ #include "sched.h" // sched_main #define FREQ_PERIPH (CONFIG_CLOCK_FREQ / 4) +#define FREQ_USB 48000000 // Enable a peripheral clock void @@ -101,7 +102,7 @@ usb_request_bootloader(void) NVIC_SystemReset(); } -#if CONFIG_CLOCK_REF_8M +#if !CONFIG_STM32_CLOCK_REF_INTERNAL DECL_CONSTANT_STR("RESERVE_PINS_crystal", "PH0,PH1"); #endif @@ -110,20 +111,20 @@ static void enable_clock_stm32f40x(void) { #if CONFIG_MACH_STM32F405 || CONFIG_MACH_STM32F407 - if (CONFIG_CLOCK_REF_8M) { - // Configure 168Mhz PLL from external 8Mhz crystal (HSE) + uint32_t pll_base = 2000000, pll_freq = CONFIG_CLOCK_FREQ * 2, pllcfgr; + if (!CONFIG_STM32_CLOCK_REF_INTERNAL) { + // Configure 168Mhz PLL from external crystal (HSE) + uint32_t div = CONFIG_CLOCK_REF_FREQ / pll_base; RCC->CR |= RCC_CR_HSEON; - RCC->PLLCFGR = ( - RCC_PLLCFGR_PLLSRC_HSE | (4 << RCC_PLLCFGR_PLLM_Pos) - | (168 << RCC_PLLCFGR_PLLN_Pos) | (0 << RCC_PLLCFGR_PLLP_Pos) - | (7 << RCC_PLLCFGR_PLLQ_Pos)); + pllcfgr = RCC_PLLCFGR_PLLSRC_HSE | (div << RCC_PLLCFGR_PLLM_Pos); } else { // Configure 168Mhz PLL from internal 16Mhz oscillator (HSI) - RCC->PLLCFGR = ( - RCC_PLLCFGR_PLLSRC_HSI | (8 << RCC_PLLCFGR_PLLM_Pos) - | (168 << RCC_PLLCFGR_PLLN_Pos) | (0 << RCC_PLLCFGR_PLLP_Pos) - | (7 << RCC_PLLCFGR_PLLQ_Pos)); + uint32_t div = 16000000 / pll_base; + pllcfgr = RCC_PLLCFGR_PLLSRC_HSI | (div << RCC_PLLCFGR_PLLM_Pos); } + RCC->PLLCFGR = (pllcfgr | ((pll_freq/pll_base) << RCC_PLLCFGR_PLLN_Pos) + | (0 << RCC_PLLCFGR_PLLP_Pos) + | ((pll_freq/FREQ_USB) << RCC_PLLCFGR_PLLQ_Pos)); RCC->CR |= RCC_CR_PLLON; #endif } @@ -132,20 +133,21 @@ static void enable_clock_stm32f446(void) { #if CONFIG_MACH_STM32F446 - if (CONFIG_CLOCK_REF_8M) { - // Configure 180Mhz PLL from external 8Mhz crystal (HSE) + uint32_t pll_base = 2000000, pll_freq = CONFIG_CLOCK_FREQ * 2, pllcfgr; + if (!CONFIG_STM32_CLOCK_REF_INTERNAL) { + // Configure 180Mhz PLL from external crystal (HSE) + uint32_t div = CONFIG_CLOCK_REF_FREQ / pll_base; RCC->CR |= RCC_CR_HSEON; - RCC->PLLCFGR = ( - RCC_PLLCFGR_PLLSRC_HSE | (4 << RCC_PLLCFGR_PLLM_Pos) - | (180 << RCC_PLLCFGR_PLLN_Pos) | (0 << RCC_PLLCFGR_PLLP_Pos) - | (7 << RCC_PLLCFGR_PLLQ_Pos) | (6 << RCC_PLLCFGR_PLLR_Pos)); + pllcfgr = RCC_PLLCFGR_PLLSRC_HSE | (div << RCC_PLLCFGR_PLLM_Pos); } else { // Configure 180Mhz PLL from internal 16Mhz oscillator (HSI) - RCC->PLLCFGR = ( - RCC_PLLCFGR_PLLSRC_HSI | (8 << RCC_PLLCFGR_PLLM_Pos) - | (180 << RCC_PLLCFGR_PLLN_Pos) | (0 << RCC_PLLCFGR_PLLP_Pos) - | (7 << RCC_PLLCFGR_PLLQ_Pos) | (6 << RCC_PLLCFGR_PLLR_Pos)); + uint32_t div = 16000000 / pll_base; + pllcfgr = RCC_PLLCFGR_PLLSRC_HSI | (div << RCC_PLLCFGR_PLLM_Pos); } + RCC->PLLCFGR = (pllcfgr | ((pll_freq/pll_base) << RCC_PLLCFGR_PLLN_Pos) + | (0 << RCC_PLLCFGR_PLLP_Pos) + | ((pll_freq/FREQ_USB) << RCC_PLLCFGR_PLLQ_Pos) + | (6 << RCC_PLLCFGR_PLLR_Pos)); RCC->CR |= RCC_CR_PLLON; // Enable "over drive" @@ -159,19 +161,14 @@ enable_clock_stm32f446(void) // Enable 48Mhz USB clock if (CONFIG_USBSERIAL) { - if (CONFIG_CLOCK_REF_8M) { - RCC->PLLSAICFGR = ( - (4 << RCC_PLLSAICFGR_PLLSAIM_Pos) - | (96 << RCC_PLLSAICFGR_PLLSAIN_Pos) - | (1 << RCC_PLLSAICFGR_PLLSAIP_Pos) - | (4 << RCC_PLLSAICFGR_PLLSAIQ_Pos)); - } else { - RCC->PLLSAICFGR = ( - (8 << RCC_PLLSAICFGR_PLLSAIM_Pos) - | (96 << RCC_PLLSAICFGR_PLLSAIN_Pos) - | (1 << RCC_PLLSAICFGR_PLLSAIP_Pos) - | (4 << RCC_PLLSAICFGR_PLLSAIQ_Pos)); - } + uint32_t ref = (CONFIG_STM32_CLOCK_REF_INTERNAL + ? 16000000 : CONFIG_CLOCK_REF_FREQ); + uint32_t plls_base = 2000000, plls_freq = FREQ_USB * 4; + RCC->PLLSAICFGR = ( + ((ref/plls_base) << RCC_PLLSAICFGR_PLLSAIM_Pos) + | ((plls_freq/plls_base) << RCC_PLLSAICFGR_PLLSAIN_Pos) + | (((plls_freq/FREQ_USB)/2 - 1) << RCC_PLLSAICFGR_PLLSAIP_Pos) + | ((plls_freq/FREQ_USB) << RCC_PLLSAICFGR_PLLSAIQ_Pos)); RCC->CR |= RCC_CR_PLLSAION; while (!(RCC->CR & RCC_CR_PLLSAIRDY)) ;