clock_stm32.c

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