STM32 clock system explanation

STM32 clock summary:

System clock diagram: (First go to the diagram of dismissal!)
Insert picture description here

1. Summary of clock system structure

1. STM32 has 5 clock sources: HSI, HSE, LSI, LSE, PLL. (After turning on the clock source, there will be a delay for it to stabilize!)
  ①, HSI is a high-speed internal clock, RC oscillator, the frequency is 8MHz, the accuracy is not high.
   ② HSE is a high-speed external clock, which can be connected to a quartz/ceramic resonator or an external
clock source. The frequency range is 4MHz~16MHz.
   ③ LSI is a low-speed internal clock, RC oscillator, with a frequency of 40kHz, providing a low-power clock. WDG
   ④, LSE is a low-speed external clock, connected to a quartz crystal with a frequency of 32.768kHz. RTC
   ⑤, PLL is a phase-locked loop frequency multiplication output, and its clock input source can be selected as HSI/2, HSE or HSE/2.
The multiplication frequency can be selected from 2 to 16 times, but the maximum output frequency should not exceed 72MHz.
2. The system clock SYSCLK can come from three clock sources:
①, HSI oscillator clock
②, HSE oscillator clock
③, PLL clock
3. STM32 can choose a clock signal to output to the MCO pin (PA8), which can be selected as PLL
Output divided by 2, HSI, HSE, or system clock.

4. Several important clocks:
SYSCLK (system clock):
AHB bus clock
APB1 bus clock (low speed): up to 36MHz
APB2 bus clock (high speed): up to 72MHz
PLL clock

4. Before any peripheral is used, its corresponding clock must be enabled first.

2. Summary of RCC register configuration

Each member in the call structure is the corresponding register : (Italic is the common configuration) are all 32 bits!
typedef struct
{ __IO uint32_t CR; //Enable and ready flags for HSI, HSE, CSS, PLL, etc. __IO uint32_t CFGR; //Clock source selection for PLL, etc., frequency division coefficient setting __IO uint32_t CIR; // Clear/ Enable clock ready interrupt __IO uint32_t APB2RSTR; //APB2 online peripheral reset register __IO uint32_t APB1RSTR; //APB1 online peripheral reset register __IO uint32_t AHBENR; //DMA, SDIO and other clock enable __IO uint32_t APB2ENR; // APB2 line peripheral clock enable __IO uint32_t APB1ENR; //APB1 line peripheral clock enable __IO uint32_t BDCR; //Backup domain control register __IO uint32_t CSR; //Control status register } RCC_TypeDef; detailed explanation of each register in stm32 Chinese There are detailed explanations in the reference guide . You need to check it yourself. To understand the principle of the register , you need to read more. After turning on the clock source, wait for it to stabilize












Stm32 library function analysis:
First go to SystemInit(); function
This function is used to initialize the registers written above

void SystemInit (void)
{
// 配置RCC_CR寄存器,对比指南:打开HSI RC时钟振荡器
  RCC->CR |= (uint32_t)0x00000001;

  /* 置零CFGR寄存器中 SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO 位 */
#ifndef STM32F10X_CL
  RCC->CFGR &= (uint32_t)0xF8FF0000;
#else
  RCC->CFGR &= (uint32_t)0xF0FF0000;
#endif /* STM32F10X_CL */   
  
  /* 置零CR寄存器中 HSEON, CSSON and PLLON 位 */
  RCC->CR &= (uint32_t)0xFEF6FFFF;

  /*置零CR寄存器中  HSEBYP */
  RCC->CR &= (uint32_t)0xFFFBFFFF;

  /* 置零CFGR寄存器中  PLLSRC, PLLXTPRE, PLLMUL  和 USBPRE/OTGFSPRE */
  RCC->CFGR &= (uint32_t)0xFF80FFFF;

#ifdef STM32F10X_CL
  /* 置零CR寄存器中  PLL2ON and PLL3ON*/
  RCC->CR &= (uint32_t)0xEBFFFFFF;

  /* Disable all interrupts and clear pending bits  */
  RCC->CIR = 0x00FF0000;

  /* Reset CFGR2 register */
  RCC->CFGR2 = 0x00000000;
#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
  /* Disable all interrupts and clear pending bits  */
  RCC->CIR = 0x009F0000;

  /* Reset CFGR2 register */
  RCC->CFGR2 = 0x00000000;      
#else
  /*关掉中断及其相应位 */
  RCC->CIR = 0x009F0000;
#endif /* STM32F10X_CL */
    
#if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)
  #ifdef DATA_IN_ExtSRAM
    SystemInit_ExtMemCtl(); 
  #endif /* DATA_IN_ExtSRAM */
#endif         // 一般未执行

//以上的配置完成,下面是一个重点函数涉及到具体设置系统时钟的频率
  SetSysClock();


以下结束
#ifdef VECT_TAB_SRAM
  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
#else
  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
#endif 
}

SetSysClock(); function specific configuration

static void SetSysClock(void)
{
// 配置对应的频率
#ifdef SYSCLK_FREQ_HSE
  SetSysClockToHSE();
#elif defined SYSCLK_FREQ_24MHz
  SetSysClockTo24();
#elif defined SYSCLK_FREQ_36MHz
  SetSysClockTo36();
#elif defined SYSCLK_FREQ_48MHz
  SetSysClockTo48();
#elif defined SYSCLK_FREQ_56MHz
  SetSysClockTo56();  
#elif defined SYSCLK_FREQ_72MHz
  SetSysClockTo72();
#endif
}

To call which frequency, the macro definition defines which frequency to configure:
keep the frequency you want to configure, and note the frequency that does not need to be configured
/* #define SYSCLK_FREQ_HSE HSE_VALUE /
/
#define SYSCLK_FREQ_24MHz 24000000 /
/
#define SYSCLK_FREQ_36MHz 36000000 /
/
#define SYSCLK_FREQ_48MHz 48000000 /
/
#define SYSCLK_FREQ_56MHz 56000000 /
#define SYSCLK_FREQ_72MHz 72000000
/
If none of the above definitions are enabled, HSI is used as the system clock source (default after reset) */

Explain the content of frequency configuration function in detail, take 72M as an example! (A big wave of warning!) The
last wave of macro definitions about registers is
too much to skip. . . Detailed interpretation!

static void SetSysClockTo72(void)
{
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
  
  /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/    
  /* 使能打开 HSE CR低16位 */    
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);
 
  /*  等待HSE稳定  */
  do
  {
    HSEStatus = RCC->CR & RCC_CR_HSERDY;   //CR_低17位
    StartUpCounter++;  
  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

  if ((RCC->CR & RCC_CR_HSERDY) != RESET)
  {
    HSEStatus = (uint32_t)0x01;
  }
  else
  {
    HSEStatus = (uint32_t)0x00;
  }  //判断就绪
  

  if (HSEStatus == (uint32_t)0x01)
  {
    /* 使能预取用缓存区,资料参考FALSH闪存参考资料! */
    FLASH->ACR |= FLASH_ACR_PRFTBE;

    /* 等待!参考资料*/
    FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;    

 //下面的是配置分频!分频!分频!,即配置开头图中AHB后面各个输出的频率(通过分频器分频)
    /* HCLK = SYSCLK  */
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
      
    /* PCLK2 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
    
    /* PCLK1 = HCLK/2  */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;


#ifdef STM32F10X_CL
    /* Configure PLLs ------------------------------------------------------*/
    /* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
    /* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */
        
    RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
                              RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
    RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
                             RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);
  
    /* Enable PLL2 */
    RCC->CR |= RCC_CR_PLL2ON;
    /* Wait till PLL2 is ready */
    while((RCC->CR & RCC_CR_PLL2RDY) == 0)
    {
    }
    
   
    /* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */ 
    RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | 
                            RCC_CFGR_PLLMULL9); 
#else  //CL系列的暂时不看
  
    /* 输入频率配置 PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
                                        RCC_CFGR_PLLMULL));
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);   // 倍频 9倍 8*9 = 72!
#endif /* STM32F10X_CL */

    /* 使能打开 PLL */
    RCC->CR |= RCC_CR_PLLON;

    /* 等待稳定 Wait till PLL is ready */
    while((RCC->CR & RCC_CR_PLLRDY) == 0)
    {
    }
    
    /*设置PLL作为系统时钟源  */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    

    /* 等待PLL生效 */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
    {
    }
  }
  else
  { 
  }
}

OVER

To add, a method to set the preset function before the main function:
insert : in the header file
:; is the meaning of the comment, this section is to execute the compilation SystemInit first (remove the comment first)

; Reset handler
Reset_Handler   PROC
                EXPORT  Reset_Handler             [WEAK]
                IMPORT  __main
				;寄存器版本代码,因为没有用到SystemInit函数,所以注释掉以下代码为防止报错!
				;库函数版本代码,建议加上这里(外部必须实现SystemInit函数),以初始化stm32时钟等。
                ;IMPORT  SystemInit			
                ;LDR     R0, =SystemInit	
                ;BLX     R0                  
                LDR     R0, =__main
                BX      R0
                ENDP

Guess you like

Origin blog.csdn.net/qq_45396672/article/details/103020133