====== RCC Setup System Clocks ======
To setup the system clocks you have to:
* Select a [[#clock_source|clock source]].
* Set up the [[#setup_pll|PLL]] (optional).
* Configure the [[#clock_ratios|clock ratios]].
\\
==== Available Oscillators ====
|< 100% 5em 5em >|
^ ^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|
==== Available Clocks ====
|< 100% 5em 5em >|
^ ^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|
===== Clock Source =====
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).
\\ {{clock_clocksource.svg}} \\ \\
* Set xxxON bit of desired oscillator.
* Wait until xxxRDY flag is set.
\\
#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);
}
\\
===== Setup PLL =====
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.
\\ {{clock_pllconfig.svg}} \\ \\
* Choose input clock for PLL.
* Choose PLLM value, so that the resulting frequency is between 1..2 MHz (2 MHz for less jitter).
* Choose PLLN and PLLP values, so that you reach the desired system clock frequency.
* If USB is used, choose PLLQ value, so that fPLL48CLK is 48 MHz.
\\
#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);
}
\\
===== Clock Ratios =====
If the SYSCLK is set up correctly, the AHB and APB clocks have to be adjusted.
\\ {{clock_clockconfig.svg}} \\ \\
* Choose HPRE, maximum allowed clock on AHB is 168 MHz.
* Choose PPRE1, maximum allowed clock on APB1 is 42 MHz.
* Choose PPRE2, maximum allowed clock on APB2 is 84 MHz.
* Select input source.
\\
#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);
}
\\
===== Configuration Registers =====
==== CR - Control register ====
\\ {{clock_reg_cr.svg}} \\ \\
|< 100% 5em 5em >|
|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|
==== CSR - Control and status register ====
\\ {{clock_reg_csr.svg}} \\ \\
|< 100% 5em 5em >|
|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)|
==== PLLCFGR - PLL configuration register ====
\\ {{clock_reg_pllcfgr.svg}} \\ \\
|< 100% 5em 5em 15em 5em>|
|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. \\ \\
==== CFGR - Configuration register ====
\\ {{clock_reg_cfgr.svg}} \\ \\
|< 100% 5em 5em 15em 5em >|
|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 \\ \\