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
	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)


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
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


Check out the Video Below


You can help with the development by DONATING
To download the code, click DOWNLOAD button and view the Ad. The project will download after the Ad is finished.

22 Comments. Leave new

  • Berat Can ÇEKİÇ
    March 7, 2023 5:59 PM

    Hi Sir , i did already ask my question on the Youtube .. Im really stuck , when i wrote these codes – my card is STM32F4 Discovery Board , My CPU is STM32F407VET6- my PLL values doesnt changed
    void my_clock_config()
    /*************>>>>>>> STEPS FOLLOWED <<<<<<<<************
    1. ENABLE HSE and wait for the HSE to become Ready
    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

    //1.Enable HSE and wait for the HSE become Ready

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


    RCC->APB1ENR |= 1<<28; //Power Enabled – internal powe-
    PWR->CR |= 1<<14;  //VOS :1 = Scale 1 mode as is default

    //3.Configure the FLASH PREFETCH and the LATENCY Related Settings

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

    //4.Configure the PRESCALARS HCLK, PCLK1, PCLK2

    RCC->CFGR &= ~(1<<4);
    RCC->CFGR |= 5<<10;
    RCC->CFGR |= 4<<13;

    //5. Configure the MAIN PLL

    RCC->PLLCFGR |= 4<<0;
    RCC->PLLCFGR |= 168<<6;
    RCC->PLLCFGR |= 0<<16;

    RCC->PLLCFGR |= 1<<22;     //Choosing HSE for PLL source

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

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

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

    RCC->CFGR |= 2<<0;
    while(!(RCC->CFGR & (2<<2)));


    • Are you confused with the HSE for the PLL source?
      I mean it should be PLL source: RCC->PLLCFGR |= 2<<22.

  • I’m getting quite distracted and swamped by all the ads here. Is it possible to download this tutorial presentation ?

    • There is a download button(above the comment section) to download the code.
      If you want to read the whole article, then press cntrl+s to save the webpage, which you can read later.
      I know the ads are distracting and I am working on it. There is some testing going on and it will remain for another 20 days. After that the site will be stable (in terms of ads).

  • please tell me how could I know that the clock needs to be set in this order, if there was no this article? Where are these steps in the manual? Or how to use it to understand that everything needs to be done in that order? And

    • These steps are not mentioned anywhere, neither you could find them easily on the internet. If you want to learn these things, you have to start from the basic ARM devices like arm V6 / V7. Then move to 32 bit arm controllers and finally to STM32..

  • Md. Istiack Ahamed
    October 19, 2022 9:52 AM

    I have STM32F103C6T6A but couldn’t find the header file for this module. Should I get the exact stm32f446? or i can do it with this one?

  • Thank you very much, this tutorial helped me a lot … is it possible somehow to verify the modified clock speed ? e.g. in the debug mode (I use STMcubeIDE

    Thank you again

  • thank you very much. It was very helpful.

  • Thank you for awesome lessons, sir. i will continue to learn from you.

  • Dear Sir,
    Where do you set HSE Frequency ? I couldn’t find it in this code

    • I guess I have answered it on youtube..

         PWR->CR |= PWR_CR_VOS;

      these two lines ensures the proper power delivery to the MCU relating to the oscillator circuit, basically the external oscillator, which is fixed value by board design, the board he used has a 8mhz oscillator shared between st link and main mcu, that’s why he typed 8mhz in cubemx clock configuration flow chart. if u design a board with 16 mhz external oscillator then the HSE input clock would be 16mhz instead of 8mhz and to achieve max frequency u need to change PLL M,N,P etc and other Prescaler values to delivar the clock in different buses that avails clock for different peripherals.

      i’m using f429 discovery board by weave share electronics and it has separate ocillator for st link and main MCU HSE input, both are 8mhz.

      so this is external hardware, u can’t define the input as much u wish .

  • Sang Truong Tan
    August 5, 2021 7:26 AM

    Dear Sir,
    How to find Step by Step for each peripheral?

  • Saleh Pazouki
    January 19, 2021 7:29 PM

    Dear Sir,
    RCCclock_config.c & RccClock_config.h are not included in the download file. Is it neccessary to have it in order to run the code?

    • those files were not mentioned in this tutorial. Actually I created those files after writing this one.
      There is a sysclockconfig function in the main file, which takes care of the RCC configuration

      I created rccconfig.c in the second tutorial (you can check the second video in the playlist) so that it would be easier to include them in upcoming tutorials

  • Hello, I have STM32F4 Discovery but I have difficulties setting up the clock. I checked the reference manuals for register differences, I checked the syntax but I didn’t find any problems. When I download the code to the Discovery Board regardless of the delay function my LEDs (I tried the ones on the board and 3.5mm ones.) just lights up dim and doesn’t blink or do anything really. Can you help with this ?

    • The LED might be staying ON because the delay between the blink is low. You should debug your code and then check if the LED is turning OFF or not

  • Dear Sir,

    4. Configure the PRESCALARS HCLK, PCLK1, PCLK2
    The AHB Prescalar is 1, so the HPRE (bits 7:4) will be all 0s.
    So in that case, i think
    RCC->CFGR &= ~(F<<4);

    But you mentioned

    // AHB PR
    RCC->CFGR &= ~(1<<4);

    So why you only makes 4 bit zero.

    Please explain.


Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.


Adblocker detected! Please consider reading this notice.

We've detected that you are using AdBlock Plus or some other adblocking software which is preventing the page from fully loading.

We don't have any banner, Flash, animation, obnoxious sound, or popup ad. We do not implement these annoying types of ads!

We need money to operate the site, and almost all of it comes from our online advertising.

Please add to your ad blocking whitelist or disable your adblocking software.