stm32启动文件和RCC时钟树-学习笔记

简介:

        最近在学习时钟树时,顺便看了一下启动文件,启动文件涉及到汇编和很多底层堆栈,暂时不做过多的记录,主要是记录RCC时钟树,是怎么配置PLL、System、AHB、APB2、APB1总线和外设时钟的。

我们的目标是:了解stm32f103外接8M晶振时,系统上电后调用SystemInitSet将PLLCLK、SYSCLK、AHBCLK、APBCLK2的时钟初始化为72MHZ,APBCLK1的时钟初始化为SYSCLK的一半即36MHZ的这个过程。

        这个工作在SystemInitSet->SysClock()->SetSysClockTo72()中已经完成,我们在此处只是学习他到底是如何初始化的。即main函数执行之前,系统一上电之后就会先执行SystemInitSet完成总线时钟初始化,然后再调用main函数,后续我们在main函数中只需要开启外设的时钟即可。下面先讲述启动文件,再讲SystemInit函数。

一、stm32f10x启动文件startup_stm32f10x_hd.s

1.在startup_stm32f10x_hd.s文件的114行有如下代码     

   单片机上电复位之后,会先执行此处Reset_Hander的汇编代码,然后调用SystemInit函数初始RCC时钟,然后调用__main函数,最后调用我们的main()函数。SystemInit函数里面就执行了初始化RCC的命令。

        SystemInit函数在system_stm32f10x.c中实现,SystemInit调用了SetSysClock()调用了SetSysClockTo72()。SetSysClockTo72()函数将SystemCLK初始化到72M。

二、stm32f10x的RCC时钟树

        要弄懂RCC是怎么初始化总线和外设时钟的,需要查看《stm32f10x参考手册》里面RCC章节的时钟树和RCC寄存器章节的控制寄存器和配置寄存器(CR和CFG)。

1.时钟树

        重点关注图中的①②③④⑤⑥⑦部分,看图从左往右看,从①依次看到⑦。stm32一共四个时钟源,外部高速时钟、外部低速时钟、内部高速时钟、内部低速时钟。但是我们常用外部高速时钟HSE,即①号处外接两个电容+8M晶振。

        野火的stm32f103指南者开发板也是外接8M晶振,然后调用SystemInit函数初始化RCC的,图中PLLXTPRE、PLLSRC、PLLMUL、SW、AHB、APB1、APB2均是RCC的配置寄存器里面某个位的名称,具体作用需要看《参考手册》,下面我从手册中截图如下。下面的配置是按照我们的目标来配置的。

即PLLCLK=SysCLK=AHBCLK = APBCLK2 = 72MHZ,APBCLK1 = SysCLK/2 = 36MHZ。

2.参考手册中,对RCC控制寄存器定义如下。

对应的各位的解释如下(此处截图野火提供的中文版参考手册,上图寄存器定义是截的英文手册的图)

①PLLXTPRE:在①处可以看到PLLXTPRE可以将HSE二分频或者不分,此处我们的HSE是8M,我们选择不分频。故我们需要将PLLXTPRE置0.

②PLLSRC:在②处,我们选择HSE还是HSI作为PLL的输入时钟,此处我们选择HSE,故我们需要将PLLSRC置为1。

③PLLMUL:③处是将HSE频率放大多少倍,我们选择放大9倍,则PLLCLK等于8*9=72MHZ。我们需要将PLLMUL位置为0111.

④SW:④处sw的可以选择HSI、HSE、PLLCLK作为SYSCLK的时钟源,我们选择常规PLLCLK,故我们要将SW为置为10.另外SWS是我们置了SW位之后,用来读取的,看SYSCLK时钟源选择是否成功的标志位,是只读的。

⑤AHB预分频器:可以对SYSCLK进行分频,但是往往我们不分频。即把HPRE置为0000.故SYSCLK = PLLCLK = 72M。

⑥APB1预分频器:由于APB1是低速总线,我们常常将它设置为SYSCLK的一半,即AP1CLK = 72/2=36MHZ.我们将PPRE1置为100.

⑦APB2预分频器:由于APB2是低速总线,我们常常将它设置为SYSCLK一样,即APCLK2 = SYSCLK = 72MHZ.我们将PPRE2置为000.

3.systemInit->SetSysClock->SetSysClockTo72源码实现如下:

//1.上电后调用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 
}

//2.SystemInit调用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) */ 
}

//3.SetSysClock()调用SetSysClockTo72()
static void SetSysClockTo72(void)
{
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
  
  /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/    
  /* Enable HSE */    
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);
 
  /* Wait till HSE is ready and if Time out is reached exit */
  do
  {
    HSEStatus = RCC->CR & RCC_CR_HSERDY;
    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)
  {
    /* Enable Prefetch Buffer */
    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 */
    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    
    /*  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);
#endif /* STM32F10X_CL */

    /* Enable PLL */
    RCC->CR |= RCC_CR_PLLON;

    /* Wait till PLL is ready */
    while((RCC->CR & RCC_CR_PLLRDY) == 0)
    {
    }
    
    /* Select PLL as system clock source */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    

    /* Wait till PLL is used as system clock source */
    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 */
  }
}

三、总结

1.原来没有看懂RCC时钟树的组织图,感觉里面名字好多,没耐心看

2.其实归根结底还是去配置寄存器,但是参考手册看着太抽象,所以刚开始最好是跟着教程,然后根据教程自己学着看参考手册,最后就是参考源码的实现。

3.然后自己参照着源码写一遍,或者以HSI作为时钟源,自己来配置SYSCLK。

  • 22
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值