STM32F1时钟系统简单分析

一、概述

  时钟系统是CPU的脉搏,所以说要想深入理解STM32的外设,学习时钟系统是非常有必要的。首先,让我们看看网上找到的STM32F1时钟框图:

STM32F1时钟系统框图

  在STM32中,有5个时钟源,为HSI、HSE、LSI、LSE和PLL。从时钟频率来分可以分为高速时钟源和低速时钟源,在这5个中HIS、HSE以及PLL是高速时钟,LSI和LSE是低速时钟。从来源可分为外部时钟源和内部时钟源,外部时钟源就是从外部通过接晶振的方式获取时钟源,其中HSE和LSE是外部时钟源,其他的是内部时钟源。

下面我们具体分析这5个时钟源:

  • HSI是高速内部时钟,RC振荡器,频率为8MHz。
  • HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。
  • LSI是低速内部时钟,RC振荡器,频率为40KHz。独立看门狗的时钟源只能是LSI,同时LSI还可以作为RTC的时钟源。
  • LSE是低速外部时钟,接频率为32.768KHz的石英晶体。这个主要用于作为内部RTC的时钟源。
  • PLL为锁相环倍频输出,其时钟输入源可以选择HSI/2、HSE或者HSE/2。倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。

  从上面我们已经基本理解STM32的5个时钟源的特性,那么这个5个时钟源主要是给什么外设和系统提供时钟的呢?我们继续从《STM32中文参考手册_V10》提供的时钟框图继续分析。

  • A:MCO是STM32的一个时钟输出IO,它可以选择一个时钟信号输出,可以选择为PLL输出的2分频、HSI、HSE 或者系统时钟。这个时钟可以用来给外部其他系统提供时钟源。
  • B:这里是RTC时钟源,从图上可以看出,RTC的时钟源可以选择LSI,LSE以及HSE的128分频。
  • C:这里是USB的时钟源,STM32可以作为一个全速的USB设备,其串行接口引擎需要一个频率为48MHz的时钟源。该时钟源只能从PLL输出端获取,可以选择1.5分频或者1分频,也就是说使用USB模块时,需要开启PLL时钟,并将时钟频率配置成48MHz或者72MHz。
  • D:这里是STM32的系统时钟SYSCLK,它是供STM32中绝大部分部件工作的时钟源。系统时钟可以选择为PLL输出、HSI或者HSE,系统时钟最大频率为72MHz。
  • E:这里就是其他所有外设的时钟源了。从时钟图上可以看出,其他所有外设的时钟最终来源都是SYSCLK。SYSCLK通过 AHB分频器分频后送给各模块使用。

二、代码分析

void RCC_Configuration(void)
{
	RCC_DeInit();
  	RCC_HSEConfig(RCC_HSE_ON);   //RCC_HSE_ON——HSE晶振打开(ON)
  	HSEStartUpStatus = RCC_WaitForHSEStartUp();
  	if(HSEStartUpStatus == SUCCESS)        //SUCCESS:HSE晶振稳定且就绪
 	{   
    	RCC_HCLKConfig(RCC_SYSCLK_Div1);  //RCC_SYSCLK_Div1——AHB时钟 = 系统时钟
    	RCC_PCLK2Config(RCC_HCLK_Div1);   //RCC_HCLK_Div1——APB2时钟 = HCLK
    	RCC_PCLK1Config(RCC_HCLK_Div2);   //RCC_HCLK_Div2——APB1时钟 = HCLK / 2
    	FLASH_SetLatency(FLASH_Latency_2);    //FLASH_Latency_2  2延时周期
    	FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);       // 预取指缓存使能
    	RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);    
   		// PLL的输入时钟 = HSE时钟频率;RCC_PLLMul_9——PLL输入时钟x 9
    	RCC_PLLCmd(ENABLE);
    	while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) ;    
    	RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
   		//RCC_SYSCLKSource_PLLCLK——选择PLL作为系统时钟
    	while(RCC_GetSYSCLKSource() != 0x08);        //0x08:PLL作为系统时钟
  	}
  	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |
  	RCC_APB2Periph_GPIOC , ENABLE);
}

使用HSE时钟,程序设置时钟参数流程:

  1. 将RCC寄存器重新设置为默认值(RCC_DeInit)
  2. 打开外部高速时钟晶振HSE(RCC_HSEConfig(RCC_HSE_ON))
  3. 等待外部高速时钟晶振工作(HSEStartUpStatus = RCC_WaitForHSEStartUp())
  4. 设置AHB时钟(RCC_HCLKConfig)
  5. 设置高速AHB时钟(RCC_PCLK2Config)
  6. 设置低速速AHB时钟(RCC_PCLK1Config)
  7. 设置PLL(RCC_PLLConfig)
  8. 打开PLL(RCC_PLLCmd(ENABLE))
  9. 等待PLL工作(while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET))
  10. 设置系统时钟(RCC_SYSCLKConfig)
  11. 判断是否PLL是系统时钟(while(RCC_GetSYSCLKSource() != 0x08))
  12. 打开要使用的外设时钟(RCC_APB2PeriphClockCmd()/RCC_APB1PeriphClockCmd())
Reset_Handler   PROC
               EXPORT  Reset_Handler             [WEAK]
               IMPORT  __main
               IMPORT  SystemInit
               LDR     R0, =SystemInit
               BLX     R0               
               LDR     R0, =__main
               BX      R0
               ENDP
                                   ...
                                   ...
                                   ...

通过分析STM32的启动过程,我们可以知道单片机复位后会调用外部文件的SystemInit函数。

void SystemInit (void)
{
  /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
  /* Set HSION bit */
  RCC->CR |= (uint32_t)0x00000001;

  /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
#ifndef STM32F10X_CL
  RCC->CFGR &= (uint32_t)0xF8FF0000;
#else
  RCC->CFGR &= (uint32_t)0xF0FF0000;
#endif /* STM32F10X_CL */   
  
  /* Reset HSEON, CSSON and PLLON bits */
  RCC->CR &= (uint32_t)0xFEF6FFFF;

  /* Reset HSEBYP bit */
  RCC->CR &= (uint32_t)0xFFFBFFFF;

  /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
  RCC->CFGR &= (uint32_t)0xFF80FFFF;

#ifdef STM32F10X_CL
  /* Reset PLL2ON and PLL3ON bits */
  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
  /* Disable all interrupts and clear pending bits  */
  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 

  /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */
  /* Configure the Flash Latency cycles and enable prefetch buffer */
  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 
}

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
 
 /* If none of the define above is enabled, the HSI is used as System clock
    source (default after reset) */ 
}

通过分析这两个库函数,我们可以知道要设置系统时钟无非就是对一些宏定义的设置,其余的工作库函数已经帮我们做了。所以我们只需对应打开所需的频率设置宏定义即可,比如我们需要配置72MHz的频率时钟。

#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */
 #define SYSCLK_FREQ_24MHz  24000000
#else
/* #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
#endif

这里总结一下SystemInit()函数中设置的系统时钟大小:
SYSCLK(系统时钟) = 72MHz
AHB总线时钟(使用SYSCLK) = 72MHz
APB1总线时钟(PCLK1) = 36MHz
APB2总线时钟(PCLK2) = 72MHz
PLL时钟 = 72MHz

三、总结

  通过简单分析STM32的时钟系统,我们可以初步了解STM32的系统架构,对我们深度学习STM32有很大的助力。由于库函数提供的时钟频率并没有64MHz,如果有项目需要使用内部HSI倍频至64MHz的,请参考:STM32F1一种相对简单的使用HSI配置系统时钟为64MHz的方法

参考文献:
STM32中文参考手册_V10.pdf

猜你喜欢

转载自blog.csdn.net/SammySum/article/details/92710835