STM32F4xx Clock Sources (HSI, HSE, PLL)
Clock is the heart beat of every Processor Core and subsequently the system built around it. Microprocessors require clock source to execute instructions. If the clock stops, the processor stops. In Embedded Systems usually multiple clock sources input facility is provided. The provision of multiple clock sources options provide the flexibility to connect and switch to any one as per application requirements.
Before we can start our journey with STM32F4-Discovery, lets briefly discuss the most fundamental part of Embedded Systems in general and STM32F407VG (Microcontroller on STM32F4-Discovery board) in particular.
The main clock controlling entity on STM32F4 devices is RCC (Reset and Clock Control). This is the main junction/hub which is responsible for selection one of the multiple input clock sources and subsequently distributing clock to core (ARM Cortex-M) and various onchip peripherals like GPIO, UART, I2C etc. The RCC subsystem is also responsible for turning ON/OFF clock to various onchip peripherals to reduce power consumption.
Another responsibility of RCC is controlling and managing various System Reset Options which we won’t discuss in this tutorial.
With programmers point of view, RCC is nothing more than just a bunch of few registers used to:
- Select one of various Input Clock Sources
- Multiply/Divide clock to get a desired clock (via PLL)
- Distribute clock to onchip peripherals
- Turn ON/OFF clock to individual hardware peripheral units
- Handle System Reset
As can be seen from Figure-1, various Switches (Registers settings) can be used to route clock (HSI, HSE – discussed later) to Clock Distribution block, which subsequently distribute clock to various buses (AHB, APB etc.) on bus matrix. Similarly another set of Switches (registers)-SWx can be used to enable/disabled bus clock to any specific desired peripheral (P1, P2 etc.) like GPIO, UART, Timers etc. For more details on how to enable disable individual peripheral clock, refer to peripheral related tutorial. For example for GPIOs, refer to “GPIO as an output” tutorial in GPIOs tutorials section.
1. STM32F4 input Clock Options:
STM32F4 SoCs consist of two set of onchip peripherals i.e. the ones operating at high frequency e.g. UART, SPI, etc. and the others that require relatively lower clock e.g. WatchDog, RTC. The High frequency peripherals are clocked from one of primary clock sources like HSI/HSE/PLL while the other low frequency peripherals are clocked from LSI/LSE.
Let’s discuss them one by one.
STM32F4 provides various clock input options listed bellow.
- High Speed Internal (HSI)
- High Speed External (HSE)
- Phase Lockup Loop (PLL)
- Low Speed Internal (LSI)
- Low Speed External (LSE)
1.1 High Speed Internal (HSI):
This is low accuracy (about 1%) onchip RC-Oscillator of 16Mhz (in case of STm32F4xx devices) which is selected as default system clock on Reset. Although this clock source meets most of the application requirements yet its low accuracy and less stable makes it unsuitable for applications requiring high accuracy clocks like SPI, I2C, CAN, USB etc. Another flaw of using this oscillator is that RC-Oscillators are very much temperature dependent which pretty much limits limits its usability. Also as the oscillator is built onchip so its fixed and can’t be adjusted as per application requirements.
1.2 High Speed External (HSE):
This option lets you connect any desirable (and inexpensive) external clock source or crystal oscillator (usually in range of 4-8Mhz). Usually quarts crystals or crystal oscillators are connected to OSC1, OSC2 pins of STM32F4 chips. Crystal oscillator are very stable and highly tolerant to temperature variations.
1.3 Phase Lockup Loop (PLL):
This is not actually a clock source. PLL is an onchip electronic circuit which takes an input clock and within certain range output adjustable clock. PLL is used to MULTIPLY any input clock to output higher frequency. For example, STM32F407VG is capable of operating at 168Mhz. Similarly STM32F429 clock can go upto 180Mhz. In order to operate these devices at maximum capacity, a crystal of that frequency need to be connected to clock input pins. Crystal oscillators of that range are either rarely available or very expensive. The solution is to connect a relatively low frequency, inexpensive crystal like 8Mhz, route clock through PLL, adjust PLL settings to provide maximum clock as per SoC capability and finally drive main System clock from PLL. 🙂
1.4 Low Speed Internal (LSI):
Again this is onchip RC-Oscillator of around 32Khz. The LSI RC acts as an low-power clock source that can be kept running in Stop and Standby modes for the independent watchdog (IWDG) and Auto-wakeup unit (AWU) .
1.5 Low Speed External (LSE):
This clock is mainly required for the proper operation of Real Time Clock (RTC). RTCs usually require low speed but highly accurate clock. The purpose of HSE clock is to provide more accurate clock to Real Time Clock (RTC).
Overall the primary clock sources on STM32F4xx selection and distribution is shown in bellow figure.
2. System Clock Selection:
In this section we will explain how to select HSI, HSE, and PLL with configuring PLL for producing desirable output clock.
In STM32 any of three primary clock sources can be selected/deselected and switched via three RCC Registers i.e. RCC clock control register (RCC_CR) – Figure-4, RCC clock configuration register (RCC_CFGR) – Figure-5, and RCC PLL configuration register (RCC_PLLCFGR) – Figure-6.
2.1 HSI Clock Selection:
Following are the steps to select High Speed Internal (HSI) as System Clock.
- Turn ON HSI Oscillator (bit-0, RCC-CR)
- Wait until the clock get stable (bit-1, RCC-CR)
- Switch System clock to HSI (bit-0,1 in RCC_CFGR; see Figure-1 SW1,SW2)
/* Turn ON HSI Clock [Default selected] */ RCC->CR |= (1U << 0); /* wait until HSI gets stable */ while (!(RCC->CR & (1U << 1))); /* switch clock to HSI */ RCC->CFGR &= (~0x3U);
2.2 HSE Clock Selection:
Selection of HSE clock is similar to that of HSI except bits position in RCC_CR register.
uint32_t regVal = 0; /* Turn ON HSE Clock */ RCC->CR |= (1U << 16); /* wait until HSE gets stable */ while (!(RCC->CR & (1U << 17))); /* switch clock to HSE */ regVal = RCC->CFGR & (~(0x3U)); regVal |= 0x1U; RCC->CFGR = regVal;
2.3 PLL Clock Selection:
The STM32F4xx devices feature three PLLs.
- The main PLL which is used to feed clock to onchip Core and other peripherals on AHB and APB bus. A special output of this PLL (PLL48CLK) is also used for USB OTG FS (48 MHz), the random analog generator (≤48 MHz) and the SDIO (≤48 MHz).
- The other two PLLs are used dedicatedly for high quality audio performance on the I2S and SAI1 interfaces.
In this tutorial we will focus on the main PLL. A simplified diagram of STM32F4xx PLL is given bellow.
Configuring PLL on STM32F4xx devices requires the following three steps.
1. PLL input Clock Source: As mentioned earlier, PLL is not a clock source itself, it takes input clock from a clock source, adjust/multiply it, and emit it on output pin. It acts like an amplifier that amplifies input frequency. So before we can use PLL, we must feed it from some clock source – Figure-7.
2. Configuring PLL: The next step is to configure PLL main Logic as shown in Figure-7. The PLL output frequency is calculated as:
While configuring PLL, following conditions need to meet otherwise PLL may not lock.
- Reserved bits must be kept at their default values in PLL registers.
- PLL bits can be written only when PLL is disabled.
- VCO input frequency ranges from 1 to 2 MHz. It is recommended to select a frequency of 2 MHz to limit PLL jitter.
- VCO output frequency must be in range 192 to 432 MHz.
3. Switching to PLL: The last step is to switch system to PLL clock.
For the purpose of demonstration we will feed STM32F4-Discovery PLL from internal HSI oscillator and will operate it on maximum capabilities of STM32F4-Discovery Microcontroller i.e. Core Frequency: 168Mhz, APB1: 42Mhz, APB2: 84Mhz.
uint32_t regVal = 0; /* disable PLL */ RCC->CR &= ~(1U << 24); #define PLLN 168U #define PLLM 8U #define PLLP 0U /* 00: PLLP = 2 */ #define PLLQ 7U /* configure PLL PLLN = 168 PLLM = 8 PLLP = 2 f(vco) = f(input) * PLLN / PLLM f(vco) = 16Mhz * 168 / 8 = 2Mhz * 168 f(pll out) = f(vco) / PLLP f(pll out) = 2Mhz * 168 / 2 = 168Mhz f(USB OTG FS, SDIO, RNG clock output) = f(VCO clock) / PLLQ f(USB OTG FS, SDIO, RNG clock output) = 2Mhz * 168 / 7 = 48Mhz */ regVal = (PLLQ << 24)| (PLLP << 16) | (PLLN << 6) | (PLLM); RCC->PLLCFGR = regVal; /* turn on PLL */ RCC->CR |= (1U << 24); /* wait until PLL get stable */ while (!(RCC->PLLCFGR & (1U << 24))); /* PLL can now feed SYSCLK of 168Mhz Let's keep AHB/ARM Cortex-M core at maximum capacity i.e. 168Mhz (for STM32F407VG) APB1 = 42Mhz (its max capacity for STM32F407VG) APB2 = 84Mhz (its max capacity for STM32F407VG) */ #define AHB_PRESCALER 0U /* 0xxx: system clock not divided (HCLK = SYSCLK) */ #define APB1_PRESCALER 5U /* 101: AHB clock divided by 4 (PCLK1 = HCLK / 4 = 42Mhz) */ #define APB2_PRESCALER 4U /* 100: AHB clock divided by 2 (PCLK2 = HCLK / 2 = 84Mhz) */ regVal = 0; regVal = (AHB_PRESCALER << 4) | (APB2_PRESCALER << 13) | (APB1_PRESCALER << 10); /* switch to PLL as main system clock */ regVal |= 0x2; RCC->CFGR = regVal;
For complete source code refer to the link given at the start of this tutorial.
 – Reference manual-RM0090
 – Clock: STM32F407