[PATCH] bsp:stm32f4XXXX system clock configuration
Joel Sherrill
joel.sherrill at oarcorp.com
Sat Sep 20 18:41:25 UTC 2014
Style comments from me. I will let those who know who the HW comment on that.
On September 20, 2014 1:23:26 PM CDT, "tomasz.gregorek at gmail.com" <tomasz.gregorek at gmail.com> wrote:
>From: Tomasz Gregorek <tomasz.gregorek at gmail.com>
>
>Added simple math to caclulate register values for the PLL
>and for the prescalers. It will try to keep 48MHz for the USB OTG FS.
>Also it will slow down Flash memory for the high speeds.
>---
> c/src/lib/libbsp/arm/stm32f4/include/stm32f4.h | 10 +
> .../libbsp/arm/stm32f4/include/stm32f4xxxx_flash.h | 41 ++++
> .../libbsp/arm/stm32f4/include/stm32f4xxxx_rcc.h | 94 +++++++++
>c/src/lib/libbsp/arm/stm32f4/startup/bspstart.c | 211
>+++++++++++++++++++++
> 4 files changed, 356 insertions(+)
>create mode 100644
>c/src/lib/libbsp/arm/stm32f4/include/stm32f4xxxx_flash.h
>
>diff --git a/c/src/lib/libbsp/arm/stm32f4/include/stm32f4.h
>b/c/src/lib/libbsp/arm/stm32f4/include/stm32f4.h
>index 59d13ef..d26f914 100644
>--- a/c/src/lib/libbsp/arm/stm32f4/include/stm32f4.h
>+++ b/c/src/lib/libbsp/arm/stm32f4/include/stm32f4.h
>@@ -55,6 +55,16 @@
>
> /** @} */
>
>+/**
>+ * @name STM32F4XXXX FLASH
>+ * @{
>+ */
>+
>+#include <bsp/stm32f4xxxx_flash.h>
>+#define STM32F4_FLASH ((volatile stm32f4_flash *) (STM32F4_BASE +
>0x40023C00))
>+
>+/** @} */
>+
> #include <bsp/stm32_i2c.h>
>
> /**
>diff --git a/c/src/lib/libbsp/arm/stm32f4/include/stm32f4xxxx_flash.h
>b/c/src/lib/libbsp/arm/stm32f4/include/stm32f4xxxx_flash.h
>new file mode 100644
>index 0000000..31b3992
>--- /dev/null
>+++ b/c/src/lib/libbsp/arm/stm32f4/include/stm32f4xxxx_flash.h
>@@ -0,0 +1,41 @@
>+/**
>+ * @file
>+ * @ingroup stm32f4_flash
>+ * @brief STM32F4XXXX FLASH support.
>+ */
>+
>+/*
>+ * Copyright (c) 2014 Tomasz Gregorek. All rights reserved.
>+ *
>+ * <tomasz.gregorek at gmial.com>
>+ *
>+ * The license and distribution terms for this file may be
>+ * found in the file LICENSE in this distribution or at
>+ * http://www.rtems.org/license/LICENSE.
>+ */
>+
>+#ifndef LIBBSP_ARM_STM32F4_STM32F4XXXX_FLASH_H
>+#define LIBBSP_ARM_STM32F4_STM32F4XXXX_FLASH_H
>+
>+#include <bsp/utility.h>
>+
>+/**
>+ * @defgroup stm32f10xxx_flash STM32F4XXXX FLASH Support
>+ * @ingroup stm32f4_flash
>+ * @brief STM32F4FXXX FLASH Support
>+ * @{
>+ */
>+
>+typedef struct {
>+ uint32_t acr;
>+ uint32_t keyr;
>+ uint32_t optkeyr;
>+ uint32_t sr;
>+ uint32_t cr;
>+ uint32_t optcr;
>+ uint32_t optcr1;
>+} stm32f4_flash;
>+
>+/** @} */
>+
>+#endif /* LIBBSP_ARM_STM32F4_STM32F4XXXX_FLASH_H */
>diff --git a/c/src/lib/libbsp/arm/stm32f4/include/stm32f4xxxx_rcc.h
>b/c/src/lib/libbsp/arm/stm32f4/include/stm32f4xxxx_rcc.h
>index 8126340..ce85b8e 100644
>--- a/c/src/lib/libbsp/arm/stm32f4/include/stm32f4xxxx_rcc.h
>+++ b/c/src/lib/libbsp/arm/stm32f4/include/stm32f4xxxx_rcc.h
>@@ -56,4 +56,98 @@ typedef struct {
>
> /** @} */
>
>+#define RCC_CR_HSION BSP_BIT32(0)
>+#define RCC_CR_HSIRDY BSP_BIT32(1)
>+#define RCC_CR_HSITRIM 3
>+#define RCC_CR_HSICAL 8
>+#define RCC_CR_HSEON BSP_BIT32(16)
>+#define RCC_CR_HSERDY BSP_BIT32(17)
>+#define RCC_CR_HSEBYP BSP_BIT32(18)
>+#define RCC_CR_CSSON BSP_BIT32(19)
>+#define RCC_CR_PLLON BSP_BIT32(24)
>+#define RCC_CR_PLLRDY BSP_BIT32(25)
>+#define RCC_CR_PLLI2SON BSP_BIT32(26)
>+#define RCC_CR_PLLI2SRDY BSP_BIT32(27)
>+
>+
>+#define RCC_PLLCFGR_PLLM 0
>+#define RCC_PLLCFGR_PLLN 6
>+#define RCC_PLLCFGR_PLLP 16
>+
>+#define RCC_PLLCFGR_PLLSRC_HSE BSP_BIT32(22)
>+#define RCC_PLLCFGR_PLLSRC_HSI 0
>+
>+#define RCC_PLLCFGR_PLLQ 24
>+
>+
>+#define RCC_CFGR_SW 0
>+#define RCC_CFGR_SW_MASK 3
>+#define RCC_CFGR_SW_HSI 0
>+#define RCC_CFGR_SW_HSE 1
>+#define RCC_CFGR_SW_PLL 2
>+
>+#define RCC_CFGR_SWS 2
>+#define RCC_CFGR_SWS_MASK (3 << RCC_CFGR_SWS)
>+
>+#define RCC_CFGR_SWS_HSI 0
>+#define RCC_CFGR_SWS_HSE (1 << RCC_CFGR_SWS)
>+#define RCC_CFGR_SWS_PLL (2 << RCC_CFGR_SWS)
>+
>+#define RCC_CFGR_HPRE 4
>+#define RCC_CFGR_HPRE_BY_1 0
>+#define RCC_CFGR_HPRE_BY_2 ( 8 << RCC_CFGR_HPRE)
>+#define RCC_CFGR_HPRE_BY_4 ( 9 << RCC_CFGR_HPRE)
>+#define RCC_CFGR_HPRE_BY_8 (10 << RCC_CFGR_HPRE)
>+#define RCC_CFGR_HPRE_BY_16 (11 << RCC_CFGR_HPRE)
>+#define RCC_CFGR_HPRE_BY_64 (12 << RCC_CFGR_HPRE)
>+#define RCC_CFGR_HPRE_BY_128 (13 << RCC_CFGR_HPRE)
>+#define RCC_CFGR_HPRE_BY_256 (14 << RCC_CFGR_HPRE)
>+#define RCC_CFGR_HPRE_BY_512 (15 << RCC_CFGR_HPRE)
>+
>+#define RCC_CFGR_PPRE1 10
>+#define RCC_CFGR_PPRE1_BY_1 0
>+#define RCC_CFGR_PPRE1_BY_2 (4 << RCC_CFGR_PPRE1)
>+#define RCC_CFGR_PPRE1_BY_4 (5 << RCC_CFGR_PPRE1)
>+#define RCC_CFGR_PPRE1_BY_8 (6 << RCC_CFGR_PPRE1)
>+#define RCC_CFGR_PPRE1_BY_16 (7 << RCC_CFGR_PPRE1)
>+
>+#define RCC_CFGR_PPRE2 13
>+#define RCC_CFGR_PPRE2_BY_1 0
>+#define RCC_CFGR_PPRE2_BY_2 (4 << RCC_CFGR_PPRE2)
>+#define RCC_CFGR_PPRE2_BY_4 (5 << RCC_CFGR_PPRE2)
>+#define RCC_CFGR_PPRE2_BY_8 (6 << RCC_CFGR_PPRE2)
>+#define RCC_CFGR_PPRE2_BY_16 (7 << RCC_CFGR_PPRE2)
>+
>+#define RCC_CFGR_RTCPRE 16
>+#define RCC_CFGR_RTCPRE_SET(a) (a << RCC_CFGR_RTCPRE)
>+
>+#define RCC_CFGR_MCO1 21
>+#define RCC_CFGR_MCO1_HSI 0
>+#define RCC_CFGR_MCO1_LSE (1 << RCC_CFGR_MCO1)
>+#define RCC_CFGR_MCO1_HSE (2 << RCC_CFGR_MCO1)
>+#define RCC_CFGR_MCO1_PLL (3 << RCC_CFGR_MCO1)
>+
>+#define RCC_CFGR_I2SSRC BSP_BIT32(23)
>+
>+#define RCC_CFGR_MCO1PRE 24
>+#define RCC_CFGR_MCO1PRE_BY_1 0
>+#define RCC_CFGR_MCO1PRE_BY_2 (4 << RCC_CFGR_MCO1PRE)
>+#define RCC_CFGR_MCO1PRE_BY_3 (5 << RCC_CFGR_MCO1PRE)
>+#define RCC_CFGR_MCO1PRE_BY_4 (6 << RCC_CFGR_MCO1PRE)
>+#define RCC_CFGR_MCO1PRE_BY_5 (7 << RCC_CFGR_MCO1PRE)
>+
>+#define RCC_CFGR_MCO2PRE 27
>+#define RCC_CFGR_MCO2PRE_BY_1 0
>+#define RCC_CFGR_MCO2PRE_BY_2 (4 << RCC_CFGR_MCO2PRE)
>+#define RCC_CFGR_MCO2PRE_BY_3 (5 << RCC_CFGR_MCO2PRE)
>+#define RCC_CFGR_MCO2PRE_BY_4 (6 << RCC_CFGR_MCO2PRE)
>+#define RCC_CFGR_MCO2PRE_BY_5 (7 << RCC_CFGR_MCO2PRE)
>+
>+#define RCC_CFGR_MCO2 30
>+#define RCC_CFGR_MCO2_SYSCLK 0
>+#define RCC_CFGR_MCO2_PLLI2S (1 << RCC_CFGR_MCO2)
>+#define RCC_CFGR_MCO2_HSE (2 << RCC_CFGR_MCO2)
>+#define RCC_CFGR_MCO2_PLL (3 << RCC_CFGR_MCO2)
>+
>+
> #endif /* LIBBSP_ARM_STM32F4_STM32F4XXXX_RCC_H */
>diff --git a/c/src/lib/libbsp/arm/stm32f4/startup/bspstart.c
>b/c/src/lib/libbsp/arm/stm32f4/startup/bspstart.c
>index d337d3a..31823d1 100644
>--- a/c/src/lib/libbsp/arm/stm32f4/startup/bspstart.c
>+++ b/c/src/lib/libbsp/arm/stm32f4/startup/bspstart.c
>@@ -17,9 +17,220 @@
> #include <bsp/irq.h>
> #include <bsp/bootcard.h>
> #include <bsp/irq-generic.h>
>+#include <bsp/stm32f4.h>
>+#include <bsp/stm32f4xxxx_rcc.h>
>+#include <bsp/stm32f4xxxx_flash.h>
>+
>+static rtems_status_code set_system_clk(uint32_t sysclk, uint32_t
>hseclk, uint32_t hseflag);
>+
>+static void init_main_osc(void)
>+{
>+ volatile stm32f4_rcc *rcc = STM32F4_RCC;
>+
>+ /* Revert to reset values */
>+ rcc->cr |= RCC_CR_HSION; /* turn on HSI */
>+ while (! (rcc->cr & RCC_CR_HSIRDY) );
>+
>+ rcc->cfgr &= 0x00000300; /* all prescalers to 0, clock source to HSI
>*/
>+
>+ rcc->cr &= 0xF0F0FFFD; /* turn off all clocks and PLL except HSI
>*/
>+
>+ set_system_clk(STM32F4_SYSCLK / 1000000L, STM32F4_HSE_OSCILLATOR /
>1000000L, 1);
>+}
>+
>+
>+/*
>+ * Sets up clocks configuration to achieve desired system clock
>+ * as close as possible with simple math
>+ */
>+static rtems_status_code set_system_clk(uint32_t sysclk, uint32_t
>hseclk, uint32_t hseflag)
>+{
>+ volatile stm32f4_rcc *rcc = STM32F4_RCC;
>+ volatile stm32f4_flash *flash = STM32F4_FLASH;
>+ rtems_interrupt_level level;
>+ long timeout = 0;
>+ const long timeoutset = 10000000L;
>+
>+ int srcclk = 0;
>+
>+ int pll_m = 0;
>+ int pll_n = 0;
>+ int pll_p = 0;
>+ int pll_q = 0;
>+ //int cr;
No C++ style comments and no commented out code without good reason.
>+ int ahbpre = 0;
>+ int apbpre1 = 0;
>+ int apbpre2 = 0;
>+
>+ if (sysclk == 16) {
>+ /* Revert to reset values */
>+ rcc->cr |= 0x00000001; /* turn on HSI */
>+ while (! (rcc->cr & (1 << RCC_CR_HSIRDY)) );
>+
>+ rcc->cfgr &= 0x00000300; /* all prescalers to 0, clock source to
>HSI */
>+
>+ rcc->cr &= 0xF0F0FFFD; /* turn off all clocks and PLL except HSI
>*/
>+
>+ flash->acr = 0; /* slow clock so no cache, no prefetch, no latency
>*/
>+
>+ return RTEMS_SUCCESSFUL;
>+ }
>+
>+ if (hseclk == 0 || hseflag == 0) {
>+ srcclk = 16;
>+ hseflag = 0;
>+ }
>+ else {
>+ srcclk = hseclk;
>+ }
>+
>+ if (sysclk > 180) {
>+ return RTEMS_INVALID_NUMBER;
>+ }
>+ else if (sysclk > 96) {
>+ pll_n = sysclk; /* multpily by the desired speed in MHz */
>+ pll_p = 0; /* divide by 2 */
>+ }
>+ else if (sysclk > 48) {
>+ pll_n = sysclk >> 1; /* multpily by 2x the desired speed in MHz */
>+ pll_p = 1; /* divide by 4 */
>+ }
>+ else if (sysclk > 24) {
>+ pll_n = sysclk >> 2; /* multpily by 4x the desired speed in MHz */
>+ pll_p = 3; /* divide by 8 */
>+ }
>+ else {
>+ return RTEMS_INVALID_NUMBER;
>+ }
>+
>+ /*
>+ * Lets use 1MHz input for PLL so we get higher VCO output
>+ * this way we get better value for the PLL_Q divader for the USB
>+ *
>+ * Though you might want to use 2MHz as per CPU specification:
>+ *
>+ * Caution:The software has to set these bits correctly to ensure
>+ * that the VCO input frequency ranges from 1 to 2 MHz.
>+ * It is recommended to select a frequency of 2 MHz to limit PLL
>jitter.
>+ */
>+ pll_m = srcclk; /* divide by the oscilator speed in MHz */
>+ pll_n <<= 1; /* multiply by requested clock x2 */
>+
>+ /* pll_q is a prescaler from VCO for the USB OTG FS, SDIO and RNG,
>+ * should result in the 48MHz for the USB
>+ */
>+ pll_q = ((long)(srcclk * pll_n + srcclk * pll_n / 2)) / pll_m / 48;
>+
>+ if (pll_q < 2)
>+ {
>+ pll_q = 2;
>+ }
>+
Pull the { up.
>+ /* APB1 prescaler, APB1 clock must be < 42MHz */
>+ apbpre1 = (sysclk * 100) / 42;
>+ if (apbpre1 <= 100) {
>+ apbpre1 = RCC_CFGR_PPRE1_BY_1;
>+ }
>+ else if (apbpre1 <= 200) {
>+ apbpre1 = RCC_CFGR_PPRE1_BY_2;
>+ }
>+ else if (apbpre1 <= 400) {
>+ apbpre1 = RCC_CFGR_PPRE1_BY_4;
>+ }
>+ else if (apbpre1 <= 800) {
>+ apbpre1 = RCC_CFGR_PPRE1_BY_8;
>+ }
>+ else if (apbpre1) {
>+ apbpre1 = RCC_CFGR_PPRE1_BY_16;
>+ }
>+
>+ /* APB2 prescaler, APB2 clock must be < 84MHz */
>+ apbpre2 = (sysclk * 100) / 84;
>+ if (apbpre2 <= 100) {
>+ apbpre2 = RCC_CFGR_PPRE2_BY_1;
>+ }
>+ else if (apbpre2 <= 200) {
>+ apbpre2 = RCC_CFGR_PPRE2_BY_2;
>+ }
>+ else if (apbpre2 <= 400) {
>+ apbpre2 = RCC_CFGR_PPRE2_BY_4;
>+ }
>+ else if (apbpre2 <= 800) {
>+ apbpre2 = RCC_CFGR_PPRE2_BY_8;
>+ }
>+ else {
>+ apbpre2 = RCC_CFGR_PPRE2_BY_16;
>+ }
>+
I thought RTEMS style had } else and } else if. Is that right?
If so adjust style.
>+ rtems_interrupt_disable(level);
>+
>+ rcc->cr |= RCC_CR_HSION; /* turn on HSI */
>+ timeout = timeoutset;
>+ while ((! (rcc->cr & RCC_CR_HSIRDY) ) && timeout--);
>+
>+ if (timeout == 0) while(1);
>+
>+ /* all prescalers to 0, clock source to HSI */
>+ rcc->cfgr &= 0x00000300;
>+ rcc->cfgr |= RCC_CFGR_SW_HSI;
>+
>+ timeout = timeoutset;
>+ while ( ( (rcc->cfgr & RCC_CFGR_SWS_MASK) != RCC_CFGR_SWS_HSI ) &&
>--timeout );
>+
>+ if (timeout == 0) while(1);
>+
>+ /* turn off PLL */
>+ rcc->cr &= ~ (RCC_CR_PLLON | RCC_CR_PLLRDY);
>+
>+ if (hseflag) {
>+ rcc->cr |= RCC_CR_HSEON;
>+ timeout = timeoutset;
>+ while ((! (rcc->cr & RCC_CR_HSERDY) ) && timeout--);
>+ }
>+
>+ rcc->pllcfgr &= 0xF0BC8000; /* clear PLL prescalers */
>+
>+ /* set pll parameters */
>+ rcc->pllcfgr |=(pll_m << RCC_PLLCFGR_PLLM) // input divider
>+ | (pll_n << RCC_PLLCFGR_PLLN) // multiplier
>+ | (pll_p << RCC_PLLCFGR_PLLP) // output divider from
>table
>+ // HSE v HSI
>+ | (hseflag ? RCC_PLLCFGR_PLLSRC_HSE :
>RCC_PLLCFGR_PLLSRC_HSI)
>+ | (pll_q << RCC_PLLCFGR_PLLQ); // PLLQ
>+
>+ /* set prescalers for the internal busses */
>+ rcc->cfgr |= apbpre1
>+ | apbpre2
>+ | ahbpre;
>+
>+ /* set flash parameters, hard coded for now for fast system clocks
>*/
>+ flash->acr |= 5 // latency
>+ | (1 << 9) // instruction cache
>+ | (1 << 10);// data cache
>+
>+ /* turn on PLL */
>+ rcc->cr |= RCC_CR_PLLON;
>+ timeout = timeoutset;
>+ while ( (! (rcc->cr & RCC_CR_PLLRDY) ) && --timeout );
>+
>+ if (timeout == 0) while(1);
>+
>+ /* clock source to PLL */
>+ rcc->cfgr = (rcc->cfgr & ~RCC_CFGR_SW_MASK) | RCC_CFGR_SW_PLL;
>+ timeout = timeoutset;
>+ while ( ((rcc->cfgr & RCC_CFGR_SWS_MASK) != RCC_CFGR_SWS_PLL) &&
>--timeout );
>+ //if (timeout == 0) while(1);
>+
>+ rtems_interrupt_enable(level);
>+
>+ return RTEMS_SUCCESSFUL;
>+}
>+
>
> void bsp_start(void)
> {
>+ init_main_osc();
>+
> stm32f4_gpio_set_config_array(&stm32f4_start_config_gpio [0]);
>
> bsp_interrupt_initialize();
>--
>2.1.0
>
>_______________________________________________
>devel mailing list
>devel at rtems.org
>http://lists.rtems.org/mailman/listinfo/devel
More information about the devel
mailing list