STM32 Baremetal EmbeddedC Programming

Clock Configuration in STM32

An in-depth guide to using the STM32 Arm Cortex M3 controller at its maximum speed

Rohit Nimkar
5 min readJan 9, 2023

By default, the clock on the STM32F1 series of micro-controllers is configured at speed of 8MHz. This is enough for many applications; however, you might want to run the controller at a higher speed to achieve your goals.

In this article, I will be explaining in detail the Clock configuration procedure for the STM32F103 microcontroller. This process is mostly the same for the majority of the STM32 micro-controllers and can be made to work with minor adjustments according to the clock circuitry.

Clocks

For the STM32F103 we have 3 different clock sources to drive the system clock (SYSCLK):

  1. HSI Oscillator clock
  2. HSE Oscillator clock
  3. PLL Clock
Clock Configuration in STM32F103
Fig 1: Clock configuration flow diagram

The device also has secondary clocks to drive the built-in RTC, but it is out of scope for this article. We will be focusing on HSE to get the max possible clock speed for SYSCLK.

HSI Oscillator Clock

The HSI clock signal is generated from an internal 8 MHz RC Oscillator and can be used directly as a system clock or divided by 2 to be used as PLL input.

The HSI RC oscillator has the advantage of providing a clock source at a low cost (no external components). It also has a faster startup time than the HSE crystal oscillator however, even with calibration the frequency is less accurate than an external crystal oscillator or ceramic resonator.

When HSI is used as a clock source, the maximum system clock frequency that can be achieved is 36MHz.

HSE Oscillator Clock

The high-speed external clock signal can be generated from two sources i.e. a ceramic oscillator or an external clock. For the scope of this article, we will look at the HSE external ceramic oscillator clock.

The 4 to 16 MHz external oscillator has the advantage of producing a very accurate rate on the main clock. The associated hardware configuration is shown in the figure below.

Fig 2: HSE hardware connections

The HSERDY flag in the Clock control register (RCC_CR) indicates if the high-speed external oscillator is stable or not. At startup, the clock is not released until this bit is set by the hardware. An interrupt can be generated if enabled in the Clock interrupt register (RCC_CIR).

The HSE Crystal can be switched on and off using the HSEON bit in the Clock control register (RCC_CR).

PLL Clock

The internal PLL can be used to multiply the HSI RC output or HSE crystal output clock frequency. Refer to Figure 8 and the Clock control register (RCC_CR).

The PLL configuration (selection of HSI oscillator divided by 2 or HSE oscillator for PLL input clock, and multiplication factor) must be done before enabling the PLL. Once the PLL is enabled, these parameters cannot be changed.

An interrupt can be generated when the PLL is ready if enabled in the Clock interrupt register (RCC_CIR).

Application Code

The clock configuration code is explained as follows

Set Flash Latency

The FLASH_ACR register is used to enable/disable prefetch and half-cycle access, and to control the Flash memory access time according to the CPU frequency. The tables below provide the bit map and bit descriptions for this register.

These bits represent the ratio of the SYSCLK (system clock) period to the Flash access time.
000 Zero wait state, if 0 < SYSCLK 24 MHz
001 One wait state, if 24 MHz < SYSCLK  48 MHz
010 Two wait states, if 48 MHz < SYSCLK  72 MHz
As we are configuring our controller to run at 72MHz, setting 2 wait states as follows:

APB divisor and HSE divisor

In the first line below snippet, we are setting the APB clock to be obtained after dividing the HCLK by 2. In the next line we are setting the division factor of the HSE clock to 0 i.e. HSE clock is not to be divided before applying to PLL.

Maximum allowable clock speed on APB1 peripherals is 36MHz

Turn on HSE

After configuring the division factor we switch on the HSE oscillator and wait for it to reach a stable state. The stable (ready) state is indicated by HSERDY bit. This bit needs 6 cycles of the HSE oscillator clock to fall down after the HSEON reset.

PLL configuration

The source clock for the PLL is configured using PLLSRC bit in the RRCC_CFGR register. Setting this bit configures HSE as the source of the PLL.

The PLL multiplication factor can be configured by modifying the PLLMULL bits in the RCCC_CFGR register. Setting these bits to PLLMULL9 multiplies the HSE clock by a factor of 9.

After the configuration is done, the PLL is turned on by setting the PLLON bit in RCC_CR register. The ready state is indicated by PLLRDY bit in the same register.

Core clock source selection

After the PLL is ready, it is now safe to set it as the main source of the clock signal for the core. It is done by modifying the RCC_CFGR_SWS bits in the RCC_CFGR register. Setting these bits to RCC_CFGR_SWS_PLL enables PLL as the source of the system clock.

Using the newly generated clock

Using the above steps, we have successfully set the clocks as follows

  • HCLK to 72MHz
  • SYSCLK to72MHz
  • AHBCLK to 72MHz
  • APB1CLK to 36MHz
  • APB2CLK to 72MHz

In the demo application for this article, this clock@72MHz is used to drive the SysTick timer which in turn is used as a timebase for the aplication.

To know more about systick programming on STM32, head over to this article:

Getting the source code

Entire source code and information related to building and running code on the Blue Pill board is available in the following repository

--

--

Rohit Nimkar

Know a little about coding but aim to self employ myself from it.