时钟树详解

在STM32的启动文件中会调用调用固件库函数中的SystemInit(在文件system_stm32f10x.c)来初始化时钟,把时钟初始化为72Mhz,先来看下时钟树的整体图
时钟树详解_第1张图片
先看锁相环时钟的设置
我们先看到HSE,什么是HSE,HSE就是High Speed External Clock signal,即高速的外部时钟,它的来源是无源晶振(4-16M),通常使用8M,用RCC_CR时钟控制寄存器的位16:HSEON控制,看到我们的开发板原理图,当使用无源晶振的时候需要用到我们的电容,当使用有源晶振时就只需要IN引脚进入单片机里面
时钟树详解_第2张图片
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200308164522381.png
与HSE相对有一个内部的叫HSI,高速的内部时钟,默认为8Mhz,当系统发生故障的时,系统时钟会自动切换到HSI,直到HSE启动成功,用RCC_CR时钟控制及寄存器的位0:HSION控制

看到锁相环,锁相环的作用就是倍频,由倍频因子PLLMUL决定,它的来源可以是内部的HSI的1/2(当使用HSI的时候PLLMUL最大是16,PLLCLK最大只能是64M),也可以是HSE的1/2或者HSE本身(由PLLXTPRE决定),
时钟树详解_第3张图片
系统时钟的设置
由图可以直到系统时钟的来源可以是PLLCLK,HSI,HSE,最大为72M,一般的配置是系统时钟等于PLLCLK,经系统时钟出来后会经过AHB预分频器,接着会经过APB1(最大36Mhz),APB2分频器分频后供外设使用(由时钟配置寄存器RCC_CFGR配置)
时钟树详解_第4张图片
时钟树详解_第5张图片
时钟树详解_第6张图片
其中需要理解的是 APB1 和 APB2 的区别, APB1 上面连接的是低速外设,包括电源接口、备份接口、 CAN、 USB、 I2C1、 I2C2、 UART2、 UART3 等等, APB2 上面连接的是高速外设包括 UART1、 SPI1、 Timer1、 ADC1、 ADC2、所有普通 IO 口(PA~PE)、第二功能 IO 口等

引入的一个还有RTC时钟和看门狗时钟
时钟树详解_第7张图片
时钟树详解_第8张图片
MCO时钟
通过MCO可以给别的芯片提供时钟,节省晶振,节约成本,还能改善EMI,如下图
时钟树详解_第9张图片
MCO引脚在F103系列是PA8
在这里插入图片描述
特殊点
时钟树详解_第10张图片
时钟安全系统(CSS) 时钟安全系统可以通过软件被激活.一旦其被激活,时钟监测器将在HSE振荡器启动延迟后被使能,并在HSE时钟关闭后关闭. 如果HSE时钟发生故障,HSE振荡器被自动关闭,时钟失效事件将被送到高级定时器(TIM1和 TIM8)的刹车输入端(TIMx_BKIN),并产生时钟安全中断CSSI,允许软件完成营救操作.此CSSI中断连接到 Cortex™-M3的NMI中断(不可屏蔽中断)。
在这里插入图片描述
注意:
一旦 CSS 被激活,并且 HSE 时钟出现故障,CSS 中断就产生,并且 NMI 也自动产生. NMI 将被不断执行,直到 CSS 中断挂起位被清除.因此,在 NMI 的处理程序中必须通过设置时钟中断寄存器 (RCC_CIR) 里的 CSSC 位来清除 CSS 中断。
如果HSE振荡器被直接或间接地作为系统时钟,(间接的意思是:它被作为PLL输入时钟,并且 PLL时钟被作为系统时钟),时钟故障将导致系统时钟自动切换到HSI振荡器,同时外部HSE振荡 器被关闭.在时钟失效时,如果HSE振荡器时钟(被分频或未被分频)是用作系统时钟的PLL的输 入时钟,PLL也将被关闭.
最后我们来讲解下文件system_stm32f10x.c中的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 
}

可以看出这函数调用了SetSysClock()这个函数,继续看

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) */ 
}

用宏作为开关来设置不同的时钟,一般默认定义SYSCLK_FREQ_72MHz,用来输出72Mhz给系统时钟,分析SetSysClockTo72()函数

static void SetSysClockTo72(void)
{
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
  
  /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/    
  /* 使能HSE */    
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);
 
  /* 等待HSE就绪并做超时处理 */
  do
  {
    HSEStatus = RCC->CR & RCC_CR_HSERDY;//如果标志位为1,则HSEStatus为1
    StartUpCounter++;  
  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

  if ((RCC->CR & RCC_CR_HSERDY) != RESET)
  {
    HSEStatus = (uint32_t)0x01;
  }//再判断一遍
  else
  {
    HSEStatus = (uint32_t)0x00;
  }  
   
  //HSE启动成功则继续往下执行
  if (HSEStatus == (uint32_t)0x01)
  {
   //使能预处理指令,即一条指令取出另一条指令已经准备好被取
    FLASH->ACR |= FLASH_ACR_PRFTBE;

    /* Flash 2 wait state */  
    FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;    

 
    /* HCLK = SYSCLK = 72M*/
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
      
    /* PCLK2 = HCLK = 72M*/
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
    
    /* PCLK1 = HCLK = 36M*/
    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    
    /*  配置锁相环: 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);
#endif /* STM32F10X_CL */

    /*使能锁相环 */
    RCC->CR |= RCC_CR_PLLON;

    /* 等待PLL稳定*/
    while((RCC->CR & RCC_CR_PLLRDY) == 0)
    {
    }
    
    /*选项PLLCLK作为系统时钟*/
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    

    /* 等待PLLCLK切换为系统时钟 */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
    {
    }
  }
  else//启动失败,用户可以在这里定义错误处理代码
  { /* If HSE fails to start-up, the application will have wrong clock 
         configuration. User can add here some code to deal with this error */
         
  }
}
#endif

你可能感兴趣的:(STM32)