STM32 Clock Setup using Registers

This is a new tutorial series, where we will be programming our beloved STM32 by manipulating the Registers, and none of the libraries like HAL or SPL or LL will be used.

This is the first and the most important tutorial in this series, and today we will learn how to setup the clock

As the clock setup is a very complicated process, For today’s tutorial alone, we need some info from the CubeMX. So follow along

  • open the CubeMX
  • select your controller
  • choose the external crystal (RCC)
  • set the maximum value in the HCLK, and hit enter
  • keep it opened, as we will be using it

Create a project in Keil, and select the microcontroller


Now we need to include some basic files in our project, so select the CMCIC core, and the Device Startup files as shown below


Add the main file in the project, and along with that i have also added the RccConfig.h and RccConfig.c files. These are the files where the code for the clock setup will be written, and we can include them as it is in our upcoming projects.


Let’s Start the setup

below are the steps shown for the clock setup

	/*************>>>>>>> STEPS FOLLOWED <<<<<<<<************
	
	1. ENABLE HSE and wait for the HSE to become Ready
	2. Set the POWER ENABLE CLOCK and VOLTAGE REGULATOR
	3. Configure the FLASH PREFETCH and the LATENCY Related Settings
	4. Configure the PRESCALARS HCLK, PCLK1, PCLK2
	5. Configure the MAIN PLL
	6. Enable the PLL and wait for it to become ready
	7. Select the Clock Source and wait for it to be set
	
	********************************************************/

Let’s see all of them one by one

1. ENABLE HSE and wait for the HSE to become Ready

The HSE can be configured in the RCC_CR Register as you can see below

As you can see the 16th bit of this register can enable the HSE, and the 17th bit will set to 1, when the HSE is finally ready

RCC->CR |= 1<<16;  
while (!(RCC->CR & (1<<17)));

above, I have set the bit 16 to HIGH (to enable the HSE), and then I am waiting for the 17th bit to set HIGH (HSE to become Ready)


2. Set the POWER ENABLE CLOCK and VOLTAGE REGULATOR

The Power Enable Clock can be set in the RCC_APB1ENR Register as shown in the picture below

In order to enable the Power, i need to set the bit 28 of the RCC_APB1ENR Register

RCC->APB1ENR |= 1<<28;

The Voltage Regulator can be configured in the PWR_CR Register as shown below

In the RCC setup of the CubeMX, the voltage Regulator is selected for scale 1 by default. And i will also use the same for my application. Basically I need to write a 3 (11) in the 14th bit

PWR->CR |= 3<<14; 

3. Configure the FLASH PREFETCH and the LATENCY Related Settings

The settings are as shown in the RCC setup from the CubeMX below

To configure them, we need to look in the FLASH_ACR Register

As shown in the CubeMX picture above, the Instruction Cache, Prefetch Buffer, and the Data Cache all are enabled. Also the Flash Latency is 5WS

So i need to write a 1 in the 8th, 9th and the 10th positions. Also a 5 in the 0th position (for 5WS)

FLASH->ACR = (1<<8) | (1<<9)| (1<<10)| (5<<0);

4. Configure the PRESCALARS HCLK, PCLK1, PCLK2

Here we will set the values for AHB Prescalar, APB1 Presclar, and APB2 Prescalar
The values are shown below (in RED color) in the Clock Setup from the CubeMX

To configure them, we will look into the RCC_CFGR Register

As shown in the CubeMX setup above

  • The AHB Prescalar is 1, so the HPRE (bits 7:4) will be all 0s.
  • APB1 Prescalar is 4, so the PPRE1 (bits 12:10) will be “101” i.e write 5 to the 10th position
  • APB2 Prescalar is 2, so the PPRE2 (bits 15:13) will be “100” i.e write 4 to the 13th position
// AHB PR
RCC->CFGR &= ~(1<<4);
	
// APB1 PR
RCC->CFGR |= (5<<10);
	
// APB2 PR
RCC->CFGR |= (4<<13);

5. Configure the MAIN PLL

Here we will configure the PLL source (HSE or HSI), and also set the values for PLLM, PLLN and PLLP
The vales are shown below (in the BLUE color)

The configuration can be set in the RCC_PLLCFGR Register

We can directly push the required values to the PLLM and PLLN Bits, while the care must be taken when setting the PLLP value.

  • The PLLP value, according to the CubeMX is 2, and to set it, I need to write 0s in the PLLP (Bits 17:16)
  • PLLM and PLLN values are 4 and 180, according to the CubeMX, and I will directly set them in the PLLM (Bits 5:0) and PLLN (Bits 14:6)
  • As I am using HSE crystal for the clock, I need to set the PLLSRC (Bit 22) to 1.
#define PLL_M 	4
#define PLL_N 	180
#define PLL_P 	0  // PLLP = 2

RCC->PLLCFGR = (PLL_M <<0) | (PLL_N << 6) | (PLL_P <<16) | (1<<22);

6. Enable the PLL and wait for it to become ready

The PLL can be enabled in the RCC_CR Register as shown below

To enable the PLL, we must write a 1 to the PLL ON (24th bit), and then we will wait for the PLL RDY (25th bit) to set, which will indicate that the PLL is ready.

RCC->CR |= (1<<24);
while (!(RCC->CR & (1<<25)));


7. Select the Clock Source and wait for it to be set

The clock source can be selected in the RCC_CFGR Register

  • SW[1:0] is used to set the system clock. Since I am using the PLL_P as the system clock, I will write a 2 (1:0) to the SW Bits
  • SWS[3:2] is used to monitor the status of the system clock. So here we will wait for these bits to indicate that the PLL_P has been set as the system clock (wait for the SWS bits to indicate 2 (1:0)).
RCC->CFGR |= (2<<0);
while (!(RCC->CFGR & (2<<2)));

That completes the setup process. The above setup will allow my controller to run at 180 MHz, as I did setup in the cubeMX



RESULT

Check out the Video Below




Info

You can help with the development by DONATING Below.
To download the project, click the DOWNLOAD button.

Subscribe
Notify of

26 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
keyboard_arrow_up