BeRTOS
clock_stm32.c
Go to the documentation of this file.
00001 
00038 #include "clock_stm32.h"
00039 
00040 #include <cfg/compiler.h>
00041 #include <cfg/debug.h>
00042 
00043 #include <io/stm32.h>
00044 
00045 struct RCC *RCC;
00046 
00047 INLINE int rcc_get_flag_status(uint32_t flag)
00048 {
00049     uint32_t id;
00050     reg32_t reg;
00051 
00052     /* Get the RCC register index */
00053     id = flag >> 5;
00054     /* The flag to check is in CR register */
00055     if (id == 1)
00056         reg = RCC->CR;
00057     /* The flag to check is in BDCR register */
00058     else if (id == 2)
00059         reg = RCC->BDCR;
00060     /* The flag to check is in CSR register */
00061     else
00062         reg = RCC->CSR;
00063     /* Get the flag position */
00064     id = flag & FLAG_MASK;
00065 
00066     return reg & (1 << id);
00067 }
00068 
00069 INLINE uint16_t pll_clock(void)
00070 {
00071     unsigned int div, mul;
00072 
00073     /* Hopefully this is evaluate at compile time... */
00074     for (div = 2; div; div--)
00075         for (mul = 2; mul <= 16; mul++)
00076             if (CPU_FREQ <= (PLL_VCO / div * mul))
00077                 break;
00078     return mul << 8 | div;
00079 }
00080 
00081 INLINE void rcc_pll_config(void)
00082 {
00083     reg32_t reg = RCC->CFGR & CFGR_PLL_MASK;
00084 
00085     /* Evaluate clock parameters */
00086     uint16_t clock = pll_clock();
00087     uint32_t pll_mul = ((clock >> 8) - 2) << 18;
00088     uint32_t pll_div = ((clock & 0xff) << 1 | 1) << 16;
00089 
00090     /* Set the PLL configuration bits */
00091     reg |= pll_div | pll_mul;
00092 
00093     /* Store the new value */
00094     RCC->CFGR = reg;
00095 
00096     /* Enable PLL */
00097     *CR_PLLON_BB = 1;
00098 }
00099 
00100 INLINE void rcc_set_clock_source(uint32_t source)
00101 {
00102     reg32_t reg;
00103 
00104     reg = RCC->CFGR & CFGR_SW_MASK;
00105     reg |= source;
00106     RCC->CFGR = reg;
00107 }
00108 
00109 void clock_init(void)
00110 {
00111     /* Initialize global RCC structure */
00112     RCC = (struct RCC *)RCC_BASE;
00113 
00114     /* Enable the internal oscillator */
00115     *CR_HSION_BB = 1;
00116     while (!rcc_get_flag_status(RCC_FLAG_HSIRDY));
00117 
00118     /* Clock the system from internal HSI RC (8 MHz) */
00119     rcc_set_clock_source(RCC_SYSCLK_HSI);
00120 
00121     /* Enable external oscillator */
00122     RCC->CR &= CR_HSEON_RESET;
00123     RCC->CR &= CR_HSEBYP_RESET;
00124     RCC->CR |= CR_HSEON_SET;
00125     while (!rcc_get_flag_status(RCC_FLAG_HSERDY));
00126 
00127     /* Initialize PLL according to CPU_FREQ */
00128     rcc_pll_config();
00129     while(!rcc_get_flag_status(RCC_FLAG_PLLRDY));
00130 
00131     /* Configure USB clock (48MHz) */
00132     *CFGR_USBPRE_BB = RCC_USBCLK_PLLCLK_1DIV5;
00133     /* Configure ADC clock: PCLK2 (9MHz) */
00134     RCC->CFGR &= CFGR_ADCPRE_RESET_MASK;
00135     RCC->CFGR |= RCC_PCLK2_DIV8;
00136     /* Configure system clock dividers: PCLK2 (72MHz) */
00137     RCC->CFGR &= CFGR_PPRE2_RESET_MASK;
00138     RCC->CFGR |= RCC_HCLK_DIV1 << 3;
00139     /* Configure system clock dividers: PCLK1 (36MHz) */
00140     RCC->CFGR &= CFGR_PPRE1_RESET_MASK;
00141     RCC->CFGR |= RCC_HCLK_DIV2;
00142     /* Configure system clock dividers: HCLK */
00143     RCC->CFGR &= CFGR_HPRE_RESET_MASK;
00144     RCC->CFGR |= RCC_SYSCLK_DIV1;
00145 
00146     /* Set 1 wait state for the flash memory */
00147     *(reg32_t *)FLASH_BASE = 0x12;
00148 
00149     /* Clock the system from the PLL */
00150     rcc_set_clock_source(RCC_SYSCLK_PLLCLK);
00151 }