We will use STM32F103 series for these examples. First, before we do anything, we must set up the chip clock. That means to determine frequency at which the chip will work, select clock source, enable/disable real time clock if we need it etc... First we will download the reference manual for STM32F103C8T6 from ST page and open it on chapter 7, Low, medium, high and XL density reset and clock control (RCC). RCC is short name for that register group.
From this schematics we can see exactly what we need to do. If we look at the symbol named SW, we can choose between 3 clock sources:
external oscillator, PLL and internal 8MHz oscillator.
We will use PLL with external oscillator so we need to set PLLCLK for SW and choose PLLSRC as HSE OSC. PLLMUL is PLL multiplier, we will set it to 9.
According to schematics, maximum clock speed for APB1 is 36MHz, so we will need to use APB1 prescaler of 2 to lower the clock speed from 72MHz down to 36MHz. AHB prescaler can stay 1.
Starting point of our coding is manufacturer's website. https://www.st.com/en/microcontrollers-microprocessors/stm32f103c8.html
Download datasheet and reference manual. We start on page 90 of reference manual: Low-, medium-, high- and XL-density reset and clock control (RCC)
RCC->CR|=RCC_CR_HSEON_Msk;
while(!(RCC->CR & RCC_CR_HSERDY))
RCC->CFGR&=~0xFFFF;
RCC->CFGR|=0b0111<< RCC_CFGR_PLLMULL_Pos;
CFGR|=RCC_CFGR_PLLSRC_Msk;
RCC->CR|=RCC_CR_PLLON_Msk;
Enable HSE - High speed external oscillator by writing 1 into Clock control register (RCC_CR) bit HSE ON
RCC->CR |=RCC_CR_HSEON;
And now we wait until HSE Ready flag has been set
while(!(RCC->CR & RCC_CR_HSERDY))
A simple while loop will do it for us. We wait while RCC_CR_HSERDY has been set in RCC_CR register
Search the registers and you'll find it in RCC_CFGR register where the datasheet says
Bit 17
PLLXTPRE: HSE divider for PLL entry
Set and cleared by software to divide HSE before PLL entry. This bit can be written only when PLL is disabled.
0: HSE clock not divided
1: HSE clock divided by 2
we will choose not to divide HSE clock, doesn't matter really since we can adjust the PLL multiplier. So we leave this one alone or set it to 0 to be sure it's zero.
RCC->CFGR &=~RCC_CFGR_PLLXTPRE;
RCC_CFGR register, bit 16
Bit 16
PLLSRC: PLL entry clock source
Set and cleared by software to select PLL clock source. This bit can be written only when PLL is disabled.
0: HSI oscillator clock / 2 selected as PLL input clock
1: HSE oscillator clock selected as PLL input clock
We want to use HSE oscillator as PLL input clock so we set it to 1:
RCC->CFGR |=RCC_CFGR_PLLSRC;
RCC_CFGR register, bits 18-21
To get main clock of 72MHz we will choose multiplier 9 and from datasheet we find out what value we must write into a register 0111: PLL input clock x 9
We need to write 0b0111 shifted by 18 bits
RCC->CFGR |=0b0111<< RCC_CFGR_PLLMUL_Pos;
RCC_CFGR_PLLMUL_Pos is just a name (define) for number 18 - position of PLLMUL bits
Copyright 2024, Mario Matovina
Send me an e-mail