To setup the system clocks you have to:
ftypical | ||
---|---|---|
LSI | 32 kHz | Low speed internal oscillator |
LSE | 32 kHz | Low speed external oscillator |
HSI | 16 MHz | High speed internal oscillator |
HSE | 8 MHz | High speed external oscillator |
ftypical | ||
---|---|---|
PLLCLK | var. | PLL clock, used to generate all other clocks |
PLL48CLK | 48 MHz | PLL48 clock, used for USB or SDIO |
RTCCLK | var. | RTC clock, used by real time clock |
SYSCLK | 168 MHz | System clock, used by CPU |
HCLK | 84 MHz | AHB clock, used for AHB peripherals |
PCLK1 | 42 MHz | APB1 clock, used for APB1 peripherals |
PCLK2 | 84 MHz | APB2 clock, used for APB2 peripherals |
TCLK | 84 MHz | Timer clock, used for the timers |
By default the 16 MHz HSI is selected as clock source. For a more accurate clock you can use an external oscillator.
On the Discovery Board is a external 8 MHz oscillator mounted, which should be used (especially for USB applications).
#include "reg_stm32f4xx.h" uint32_t reg; RCC->CR |= (0x1 << 16u); /* Set HSEON bit. */ reg = RCC->CR & (0x1 << 17u); while (reg == 0u) { /* Wait for HSERDY flag. */ reg = RCC->CR & (0x1 << 17u); }
To get to a system clock of 168 MHz, the PLL has to be used. The PLL can be used either with HSE or HSI.
#include "reg_stm32f4xx.h" uint32_t reg; RCC->PLLCFGR |= (0x4 << 0u); /* PLLM: input => 8 MHz / 4 => 2 MHz */ RCC->PLLCFGR |= (168u << 6u); /* PLLN: VCO => 2 MHz • 168 => 336 MHz */ RCC->PLLCFGR |= (0x0 << 16u); /* PLLP: PLLCLK => 336 MHz / 2 => 168 MHz */ RCC->PLLCFGR |= (7u << 24u); /* PLLQ: PLL48CLK => 336 MHz / 7 => 48 MHz */ RCC->PLLCFGR |= (0x1 << 22u); /* Choose HSE as PLL input clock. */ RCC->CR |= (0x1 << 24u); /* Set PLLON bit. */ reg = RCC->CR & (0x1 << 25u); while (reg == 0u) { /* Wait for PLLRDY flag. */ reg = RCC->CR & (0x1 << 25u); }
If the SYSCLK is set up correctly, the AHB and APB clocks have to be adjusted.
#include "reg_stm32f4xx.h" uint32_t reg; RCC->CFGR |= (0x8 << 4u); /* HPRE: HCLK => 168 MHz / 2 => 84 MHz */ RCC->CFGR |= (0x4 << 10u); /* PPRE1: PCLK1 => 84 MHz / 2 => 42 MHz */ RCC->CFGR |= (0x0 << 13u); /* PPRE2: PCLK2 => 84 MHz / 2 => 42 MHz TCLK => 42 MHz • 2 => 84MHz */ RCC->CFGR |= (0x2 << 0u); /* Choose PLLCLK as input. */ reg = RCC->CFGR & (0x3 << 2u); while (reg == 0u) { /* Wait for SWS status. */ reg = RCC->CFGR & (0x3 << 2u); }
HSION | 0 | Internal high speed clock enabled |
1 | Internal high speed clock disabled (reset state) | |
HSIRDY | 0 | Internal high speed clock not ready |
1 | Internal high speed clock ready (reset state) | |
xON | 0 | X enabled (reset state) |
1 | X disabled | |
xRDY | 0 | X not ready (reset state) |
1 | X ready |
LSION | 0 | Internal low speed clock enabled |
1 | Internal low speed clock disabled (reset state) | |
LSIRDY | 0 | Internal low speed clock not ready |
1 | Internal low speed clock ready (reset state) |
PLLM | xxxxxx | Division factor for PLL, choose factor so resulting frequency is between 1..2 MHz. | ||
PLLN | xxxxxxxxx | Multiplication factor for VCO. | ||
PLLP | 00 | SYSCLK ⇒ fPLL / 2. | 10 | SYSCLK ⇒ fPLL / 6. |
01 | SYSCLK ⇒ fPLL / 4. | 11 | SYSCLK ⇒ fPLL / 8. | |
PLLQ | xxxx | Division factor PLL48CLK (for USB / SDIO clock), has to result in 48 MHz frequency. | ||
PLLSRC | 0 | Select HSI for PLL input clock. | ||
1 | Select HSE for PLL input clock. |
* Please refer to reference manual (p.162ff) for detailed explanation of register values.
SW | 00 | Enable HSI as SYSCLK (reset state) | ||
01 | Enable HSE as SYSCLK | |||
10 | Enable PLL as SYSCLK | |||
SWS | 00 | HSI used as SYSCLK | ||
01 | HSE used as SYSCLK | |||
10 | PLL used as SYSCLK | |||
HPRE | 0xxx | SYSCLK not divided (reset state) | ||
1000 | HCLK ⇒ fSYSCLK / 2 | 1100 | HCLK ⇒ fSYSCLK / 64 | |
1001 | HCLK ⇒ fSYSCLK / 4 | 1101 | HCLK ⇒ fSYSCLK / 128 | |
1010 | HCLK ⇒ fSYSCLK / 8 | 1110 | HCLK ⇒ fSYSCLK / 256 | |
1011 | HCLK ⇒ fSYSCLK / 16 | 1111 | HCLK ⇒ fSYSCLK / 512 | |
PPRE1 | 0xx | HCLK not divided (reset state) | ||
1000 | PCLK1 ⇒ fHCLK / 2 | 1100 | PCLK1 ⇒ fHCLK / 64 | |
1001 | PCLK1 ⇒ fHCLK / 4 | 1101 | PCLK1 ⇒ fHCLK / 128 | |
PPRE2* | 0xx | HCLK not divided (reset state) | ||
100 | PCLK2 ⇒ fHCLK / 2 | 110 | PCLK2 ⇒ fHCLK / 8 | |
101 | PCLK2 ⇒ fHCLK / 4 | 111 | PCLK2 ⇒ fHCLK / 16 |
* if PPRE2 not 0xx then TCLK ⇒ fPCLK2 • 2