RCC Clock Configuration Practice

 

When the program runs, the SystemInit() function (the SetSysClockTo72() function is finally called) is called in the startup file (startup_stm32f10x_xx.s) to initialize the system clock to 72MHz. In other words, when the system clock is not modified, it defaults to 72MHz. If you need to modify it, you should redefine and call the initialization function.

We judge the clock configuration by observing how fast the LED lights flash at different clock frequencies.

In general, we will use HSE to configure the system clock after PLL multiplication. For HSE, we often use 8MHz passive crystal oscillators. We take the HSE configuration system clock as an example, and complete the code according to the clock tree construction process. Figure 4-1 below is the clock tree of STM32.

 

Figure 4-1 STM32 clock tree

 

The number sequence in the figure is the configuration process sequence, and the code is also written according to this process. We briefly analyze the relevant configuration of each step.


1. As shown in Figure 4-2, this step depends on the PLL clock source PLLSRC of the second step, which is set by bit 17 of the clock configuration register RCC_CFGR: PLLXTPRE, "clear to 0" means HSE does not divide the frequency, "set to 1" means HSE 2 frequency division. We choose HSE not to divide the frequency here, that is, "clear to 0". The code is shown in the second step, the macro RCC_PLLSource_HSE_Div1 is the HSE without frequency division as the PLL input clock.

 

Figure 4-2

 

We need to enable HSE first, wait for HSE to stabilize, and before that we also need to reset the RCC register, the code is as follows.

#define RCC_HSE_ON                       ((uint32_t)0x00010000)
ErrorStatus HSEStatus;
	
// 把RCC寄存器复位
RCC_DeInit(); // 使能HSE RCC_HSEConfig(RCC_HSE_ON); // 返回HSE状态,等待HSE稳定 HSEStatus = RCC_WaitForHSEStartUp(); 

2. This step is to configure the PLL clock source. Set by bit 16 of the CFGR register: PLLSRC, "clear to 0" means that HSI is divided by 2 as the PLL input clock, "set to 1" means HSE as the PLL input clock, as shown in Figure 4-3.

 

Figure 4-3

 

Here we choose HSE as the clock source of the PLL, that is, "set to 1".

#define RCC_PLLSource_HSE_Div1           ((uint32_t)0x00010000)
#define RCC_PLLMul_9                     ((uint32_t)0x001C0000)
// 配置锁相环(PLLCLK = HSE * 9 = 72MHz),必须在使能PLL前配置
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); 

This function is in the stm32f10x_rcc.c file and is used to configure the PLL clock source and multiplication factor.

3. Set the frequency multiplication factor of the PLL, and multiply the frequency of the PLL clock source. The specific frequency multiplication is configured by bits 21-18 of the CFGR register: PLLMUL[3:0]. For example, we can set the frequency to 9 times. We mentioned earlier that the HSE is a passive crystal oscillator of 8MHz, so after frequency multiplication, the PLL clock PLLCLK = 8MHz * 9 = 72MHz, which is the stable clock frequency officially recommended by ST. We can also choose to increase the multiplier factor for overclocking, up to 128MHz. Figure 4-4 describes the frequency multiplication factor. The code is as shown in the previous step, configured as RCC_PLLMul_9.


Figure 4-4

4. Configure the system clock SYSCLK. The SYSCLK source can be HSI, PLLCLK, HSE, here we configure it as SYSCLK = PLLCLK = 72MHz, configured by bits 1-0:SW[1:0] of the CFGR register. Figure 4-5.


 

Figure 4-5

 

#define RCC_SYSCLKSource_PLLCLK          ((uint32_t)0x00000002)
// 选择PLLCLK作为系统时钟
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); 

5. AHB bus clock HCLK. HCLK is obtained by dividing SYSCLK by the AHB prescaler, and is configured by bits 7-4 of the CFGR register: HPRE[3:0]. As shown in the clock tree of Figure 4-1, most of the on-chip peripheral clocks are obtained by dividing the frequency of HCLK. Here we set it to not divide the frequency, namely: HCLK = SYSCLK = 72MHz. See Figure 4-6 below.

 

Figure 4-6

 

#define RCC_SYSCLK_Div1                  ((uint32_t)0x00000000)
// 配置AHB总线时钟HCLK
RCC_HCLKConfig(RCC_SYSCLK_Div1); 

6. APB2 bus clock PCLK2. PCLK2 is derived from the high-speed APB2 prescaler and configured by Bits 13-11:PPRE2[2:0] of the CFGR register. The APB2 bus is a high-speed bus, and the high-speed peripherals on the chip, such as GPIO, USART1, SPI1, etc., are all mounted on the APB2 bus. So we set no frequency division here, that is: PCLK2 = HCLK = 72MHz. See Figure 4-7 below.

 

Figure 4-7

 

#define RCC_HCLK_Div1                    ((uint32_t)0x00000000)
// 配置APB2总线时钟PCLK2
RCC_PCLK2Config(RCC_HCLK_Div1); 

7. APB1 bus clock PCLK1. PCLK1 is derived from the low-speed APB1 prescaler and configured by Bits 10-8:PPRE1[2:0] of the CFGR register. PCLK1 is a low-speed bus clock, with a maximum of 36MHz. On-chip low-speed peripherals, such as USART2/3/4/5, SPI2/3, I2C1/2, etc., are all mounted on the APB1 bus. We set it to divide by 2, ie: PCLK1 = HCLK/2 = 36MHz. See Figure 4-8 below.

 

Figure 4-8

 

#define RCC_HCLK_Div2                    ((uint32_t)0x00000400)
// 配置APB1总线时钟PCLK1
RCC_PCLK1Config(RCC_HCLK_Div2); 

After the above brief analysis, we probably know the configuration process of the clock. Now we organize the above code and encapsulate it as a function.

/**
  * @brief  配置HSE作为系统时钟来源
  * @param  RCC_PLLMul_x:PLL倍频因子,
  *         x可以是:[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
 * @retval 无  */ void HSE_SetSysClk(uint32_t RCC_PLLMul_x){ ErrorStatus HSEStatus; // 把RCC寄存器复位 RCC_DeInit(); // 使能HSE RCC_HSEConfig(RCC_HSE_ON); // 返回HSE状态,等待HSE稳定 HSEStatus = RCC_WaitForHSEStartUp(); if(HSEStatus == SUCCESS){ // 使能预取指 FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); // 2个等待周期 FLASH_SetLatency(FLASH_Latency_2); // 配置AHB总线时钟HCLK RCC_HCLKConfig(RCC_SYSCLK_Div1); // 配置APB2总线时钟PCLK2,PCLK2 = HCLK RCC_PCLK2Config(RCC_HCLK_Div1); // 配置APB1总线时钟PCLK1,PCLK1 = HCLK/2 RCC_PCLK1Config(RCC_HCLK_Div2); // 配置锁相环时钟(PLLCLK = HSE * 9 = 72MHz),必须在使能PLL前配置 RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_x); // 使能PLL RCC_PLLCmd(ENABLE); // 等待PLL稳定 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); // 选择PLLCLK作为系统时钟 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); while(RCC_GetSYSCLKSource() != 0x08); }else{ /* 如果HSE启动失败,则可以在这里添加处理错误的代码 */ } } 

Even if the above function is encapsulated, it can be called in the main function to reconfigure the system clock.

int main(void){ // 倍频因子设置为9,则系统时钟配置为8MHZ * 9 = 72MHz HSE_SetSysClk(RCC_PLLMul_9); // 初始化LED灯 LED_GPIO_Config(); while(1){ GPIO_SetBits(GPIOB, GPIO_Pin_0); // 高电平关闭LED Delay(0xFFFFF); GPIO_ResetBits(GPIOB, GPIO_Pin_0); // 低电平开启LED Delay(0xFFFFF); } } 

We can output different clock frequencies by changing the multiplier size. For example, if it is modified to RCC_PLLMul_16, the clock frequency output is 8MHZ * 16 = 128MHz. Different clock frequency output, the flashing speed of the light is also different, the larger the frequency multiplier factor, the higher the frequency, the faster the light flashes; the smaller the frequency multiplier factor, the opposite is the experimental effect.

In addition, there is an MCO output in the lower left corner of the clock tree in Figure 4-1, which can output the clock frequency to the outside world. We can use an oscilloscope to monitor the output frequency of the MCO pin to check whether the system clock is configured correctly.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325936659&siteId=291194637