zoukankan      html  css  js  c++  java
  • STM32时钟初始化函数SystemInit()详解【转】

    花了一天的时间,总算是了解了SystemInit()函数实现了哪些功能,初学STM32,,现记录如下(有理解错误的地方还请大侠指出):

    使用的是3.5的库,用的是STM32F107VC,开发环境RVMDK4.23
    我已经定义了STM32F10X_CL,SYSCLK_FREQ_72MHz
    函数调用顺序:
    startup_stm32f10x_cl.s(启动文件) → SystemInit() →  SetSysClock () → SetSysClockTo72()
    初始化时钟用到的RCC寄存器复位值:
    RCC_CR = 0x0000 xx83; RCC_CFGR = 0x0000 0000;RCC_CIR = 0x0000 0000; RCC_CFGR2 = 0x0000 0000;
    SystemInit()
    在调用 SetSysClock()之前RCC寄存器的值如下(都是一些与运算,或运算,在此就不赘述了):
    RCC->CR = 0x0000 0083;  RCC->CIR = 0x00FF0000; RCC->CFGR2 = 0x00000000;至于这些寄存器都代表着什么意思,详见芯片资料RCC寄存器,该文重点不在此处;
    SetSysClock()函数如下:
     1 static void SetSysClock(void)
     2 {
     3 #ifdef SYSCLK_FREQ_HSE
     4   SetSysClockToHSE();
     5 #elif defined SYSCLK_FREQ_24MHz
     6   SetSysClockTo24();
     7 #elif defined SYSCLK_FREQ_36MHz
     8   SetSysClockTo36();
     9 #elif defined SYSCLK_FREQ_48MHz
    10   SetSysClockTo48();
    11 #elif defined SYSCLK_FREQ_56MHz
    12   SetSysClockTo56();  
    13 #elif defined SYSCLK_FREQ_72MHz//我的定义的是SYSCLK_FREQ_72MHz,所以调用SetSysClockTo72()
    14   SetSysClockTo72();
    15 #endif
    16 }
    SetSysClockTo72()函数如下:
     1 static void SetSysClockTo72(void)
     2 {
     3   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
     4    /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/    
     5   /* Enable HSE */    
     6   RCC->CR |= ((uint32_t)RCC_CR_HSEON);
     7  
     8   /* Wait till HSE is ready and if Time out is reached exit */
     9   do
    10   {
    11     HSEStatus = RCC->CR & RCC_CR_HSERDY;
    12     StartUpCounter++;  
    13   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
    14  
    15   if ((RCC->CR & RCC_CR_HSERDY) != RESET)
    16   {
    17     HSEStatus = (uint32_t)0x01;
    18   }
    19   else
    20   {
    21     HSEStatus = (uint32_t)0x00;
    22   }  
    23   if (HSEStatus == (uint32_t)0x01)
    24   {
    25     /* Enable Prefetch Buffer */
    26     FLASH->ACR |= FLASH_ACR_PRFTBE;
    27  
    28     /* Flash 2 wait state */
    29     FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    30     FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;    
    31     /* HCLK = SYSCLK */
    32     RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
    33       
    34     /* PCLK2 = HCLK */
    35     RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
    36     
    37     /* PCLK1 = HCLK */
    38     RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
    39 #ifdef STM32F10X_CL
    40     /* Configure PLLs ------------------------------------------------------*/
    41     /* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
    42     /* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */
    43         
    44     RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
    45                               RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
    46     RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
    47                              RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);
    48      /* Enable PLL2 */
    49     RCC->CR |= RCC_CR_PLL2ON;
    50     /* Wait till PLL2 is ready */
    51     while((RCC->CR & RCC_CR_PLL2RDY) == 0)
    52     {
    53     }
    54       /* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */ 
    55     RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);
    56     RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | 
    57                             RCC_CFGR_PLLMULL9); 
    58 #else    
    59     /*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
    60     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
    61                                         RCC_CFGR_PLLMULL));
    62     RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
    63 #endif /* STM32F10X_CL */
    64  
    65     /* Enable PLL */
    66     RCC->CR |= RCC_CR_PLLON;
    67  
    68     /* Wait till PLL is ready */
    69     while((RCC->CR & RCC_CR_PLLRDY) == 0)
    70     {
    71     }
    72     
    73     /* Select PLL as system clock source */
    74     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    75     RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    
    76  
    77     /* Wait till PLL is used as system clock source */
    78     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
    79     {
    80     }
    81   }
    82   else
    83   { /* If HSE fails to start-up, the application will have wrong clock 
    84          configuration. User can add here some code to deal with this error */
    85   }
    86 }
     
     
    1:AHB, APB1,APB2时钟确定
    //HCLK = SYSCLK ,从下面的分析可以得出SYSCLK是使用PLLCLK时钟的,也就是72MHZ(至于72MHZ如何得来,请看下面分析
       //那么就是HCLK(AHB总线时钟)=PLLCLK = 72MHZ    
        //AHB总线时钟等于系统时钟SYSCLK,也就是 AHB时钟 = HCLK = SYSCLK = 72MHZ
       /* HCLK = SYSCLK */
        RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
     
       //PLCK2等于HCLK一分频, 所以PCLK2 = HCLK,HCLK = 72MHZ, 那么PLCK2(APB2总线时钟) = 72MHZ   
       //APB2总线时钟等于HCLK的一分频,也就是不分频;APB2 时钟 = HCLK = SYSCLK = 72MHZ 
        /* PCLK2 = HCLK */
        RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
     
        //PCLK1 = HCLK / 2;PCLK1 等于HCLK时钟的二分频,那么PCLK1(APB1) = 72MHZ / 2 = 36MHZ    
        //APB1总线时钟等于HCLK的二分频,也就是 APB1时钟= HCLK / 2 = 36MHZ
        /* PCLK1 = HCLK */
        RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
     
    2:如何得出SYSCLK(系统时钟)为72MHZ(外部晶振25MHZ)
    //记得参考英文芯片资料的时钟树P115页和RCC时钟寄存器进行理解
    RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);
     
    RCC_CFGR2_PREDIV2_DIV5:  PREDIV2 = 5; 5分频
              也就是PREDIV2对输入的外部时钟 5分频,那么PLL2和PLL3没有倍频前是25 /5 = 5MHZ
    RCC_CFGR2_PLL2MUL8  : PLL2MUL = 8; 8倍频  
              8倍频后,PLL2时钟 = 5 * 8 = 40MHZ; 因此 PLL2CLK = 40MHZ
    RCC_CFGR2_PREDIV1SRC_PLL2 : RCC_CFGR2的第16位为1, 选择PLL2CLK 作为PREDIV1的时钟源
    RCC_CFGR2_PREDIV1_DIV5:PREDIV1 = 5;PREDIV1对输入时钟5分频 PREDIV1CLK = PLL2CLK / 5 = 8MHZ
     
    以上是对RCC_CFGR2进行的配置
    --------------------------------------------------------------------------------------
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | 
     RCC_CFGR_PLLMULL9); 
     
    RCC_CFGR_PLLXTPRE_PREDIV1 :操作的是RCC_CFGR的第17位PLLXTPRE,操作这一位和操作RCC_CFGR2寄存器的位[3:0]中的最低位是相同的效果  
    RCC_CFGR_PLLSRC_PREDIV1 :选择PREDIV1输出作为PLL输入时钟;PREDIV1CLK = 8MHZ,所以输入给PLL倍频的时钟源是8MHZ
    RCC_CFGR_PLLMULL9 :PLLMUL = 9;PLL倍频系数为9,也就是对 PLLCLK PREDIV1CLK * 8 = 72MHZ
     
    以上是对RCC_CFGR进行的配置
    ---------------------------------------------------------------------------------------------------
     
     RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;   //选择PLLCLK作为系统时钟源 
     
    --------------------------------------------------------------------------------------------------
    至此基本配置已经完成,配置的时钟如下所述:
    SYSCLK(系统时钟) = 72MHZ
    AHB总线时钟   = 72MHZ
    APB1总线时钟  = 36MHZ
    APB2总线时钟  = 72MHZ
    PLL时钟   = 72MHZ
    PLL2时钟  = 40MHZ
    来自:http://home.eeworld.com.cn/home.php?mod=space&uid=285003&do=blog&id=70474
    这里有一篇文章讲解时钟树,觉得不错:http://bbs.eeworld.com.cn/thread-291915-1-1.html
  • 相关阅读:
    20155239 2016-2017-2 《Java程序设计》第7周学习总结
    20155231 2016-2017-2 《Java程序设计》第4周学习总结
    20155231 2016-2017-2 《Java程序设计》第3周学习总结
    20155231 2016-2017-2 《Java程序设计》第2周学习总结
    20155231 2016-2017-2 《Java程序设计》第1周学习总结
    第三次预作业20155231邵煜楠:虚拟机上的Linux学习
    预备作业2:阅读心得(20155231邵煜楠)
    博客初体验:我期望的师生关系
    安装虚拟机
    20155227第二次预备作业
  • 原文地址:https://www.cnblogs.com/flyheart33/p/3571582.html
Copyright © 2011-2022 走看看