码迷,mamicode.com
首页 > 其他好文 > 详细

stm32 RCC 时钟分析

时间:2015-03-21 18:44:29      阅读:176      评论:0      收藏:0      [点我收藏+]

标签:

stm32芯片手册上有张图表示的很清楚,一共有4个时钟源:
1.HSI(内部高速时钟 8MHz)提供可以位系统时钟提供时钟源
2.HSE(外部高速时钟)可以提供系统时钟和RTC时钟时钟源
3.LSE(低速外部时钟32.768kHz)可以为可以为RTC提供时钟源
4.LSI(低速内部时钟)可以为独立看门狗提供时钟源


首先分析一下ST公司给的库函数:我用的是3.5的库


我们看看SystemInit里是什么


void SystemInit (void)
{
RCC->CR |= (uint32_t)0x00000001;  //打开HSI内部高速时钟
#ifndef STM32F10X_CL
RCC->CFGR &= (uint32_t)0xF8FF0000;//CFCG寄存器的27位没用,所以这个宏没用
#else  //MCO的两位清零,不往外输出时钟,0-15位清零,PLCK 2分频给ADC,HCLK不分频给APB2
RCC->CFGR &= (uint32_t)0xF0FF0000;//HCLK不分频给APB1,sysclk不分频给AHB,HSI用作系统时钟,
#endif /* STM32F10X_CL */   
  
/* Reset HSEON, CSSON and PLLON bits */
RCC->CR &= (uint32_t)0xFEF6FFFF;  //HSE禁用


/* Reset HSEBYP bit */
RCC->CR &= (uint32_t)0xFFFBFFFF; //外部高速时钟未被旁路


/* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
RCC->CFGR &= (uint32_t)0xFF80FFFF;     //PLL 1.5分频,给USBpre,PLLMUL *2,HSE未分频做PLL输入HSI/2做PLL输入


#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; /*中断向量表定位在SRAM_BASE(0X20000000)+VECT_TAB_OFFSET(0X0)处*/
#else
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /*中断向量表定位在FLASH_BASE(0X08000000)+VECT_TAB_OFFSET(0X0)处 */
#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
 
 /* 如果上面没有一个宏成立,则HSI用作系统时钟源,一般调用SetSysClockTo72()函数*/ 
}


static void SetSysClockTo72(void)
{
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;  //__IO uint32_t即vu32
  
  /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/    
  /* Enable HSE */    
  RCC->CR |= ((uint32_t)RCC_CR_HSEON); // RCC_CR_HSEON((uint32_t)0x00010000) HSE使能
 
  /* Wait till HSE is ready and if Time out is reached exit */
  do
  {
    HSEStatus = RCC->CR & RCC_CR_HSERDY;//RCC_CR_HSERDY((uint32_t)0x00020000) 测试HSE状态
    StartUpCounter++;   //计数等待
  } while((HSEStatus == 0) && (StartUpCounter != HSEStartUp_TimeOut));   //当计数 > HSEStartUp_TimeOut(0x500)时且HSE可用则跳出


  if ((RCC->CR & RCC_CR_HSERDY) != RESET)  //如果HSE可用
  {
    HSEStatus = (uint32_t)0x01; //HSEStatus置1
  }
  else
  {
    HSEStatus = (uint32_t)0x00; //HSEStatus置0
  }  


  if (HSEStatus == (uint32_t)0x01)      //当hse可以用时
  {
    /* 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;  //HCLK等于系统时钟
      
    /* PCLK2 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;//APB高速预分频为HCLK
    
    /* PCLK1 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;//APB高低速预分频为HCLK/2


#ifdef STM32F10X_CL
    /* Configure PLLs ------------------------------------------------------*/ //没有PLL2
    /* 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_DIV3);
  
    /* 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 */ //PLL9倍频==72MHz
    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; //使能PLL


    /* Wait till PLL is ready */
    while((RCC->CR & RCC_CR_PLLRDY) == 0)  //等待PLL准备好
    {
    }
    
    /* Select PLL as system clock source */  //设置系统时钟为PLL时钟源
    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 */    


    /* Go to infinite loop */
    while (1)   //如果HSE不能用,则跳入死循环
    {
    }
  }
}



stm32 RCC 时钟分析

标签:

原文地址:http://blog.csdn.net/kobesdu/article/details/44517043

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!