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