打印
[信息]

stm32 RCC 时钟彻底分析

[复制链接]
1442|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
mintspring|  楼主 | 2013-11-30 20:21 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
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不能用,则跳入死循环
    {
    }
  }
}

       
                               

沙发
zhangmangui| | 2013-11-30 20:22 | 只看该作者
不懂  帮忙顶

使用特权

评论回复
板凳
fangxingyi| | 2013-11-30 22:13 | 只看该作者
很不错

使用特权

评论回复
地板
地瓜patch| | 2013-11-30 22:18 | 只看该作者
不错,不错,楼主厉害

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

296

主题

4896

帖子

24

粉丝