[PATCH] bsp:stm32f4XXXX system clock configuration

tomasz.gregorek at gmail.com tomasz.gregorek at gmail.com
Sat Sep 20 18:23:26 UTC 2014


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;
+  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;
+  }
+
+  /* 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;
+  }
+
+  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




More information about the devel mailing list