• STM32F10x_StdPeriph_Lib_V3.5.0库时钟分析及如何配置


    [操作环境]:KEIL MDK4.10  Lib_V3.5.0

    阅读了STM32F10x_StdPeriph_Lib_V3.5.0库关于时钟部分代码,发现设备初始化时钟默认为外部晶振8MHz,经过PLL倍频后,内部核心时钟为72MHz.

    其处理流程大致如下:
    1、启动文件(startup_stm32f10x_md.s)里有如下代码:

    ; Reset handler
    Reset_Handler    PROC
                     EXPORT  Reset_Handler             [WEAK]
         IMPORT  __main
         IMPORT  SystemInit
                     LDR     R0, =SystemInit
                     BLX     R0
                     LDR     R0, =__main
                     BX      R0
                     ENDP

    2、系统复位后,会先执行SystemInit函数,这个函数位于库CMSISCM3DeviceSupportSTSTM32F10xsystem_stm32f10x.c文件中,该函数的主要功能是配置RCC的相关寄存器,如CR、CFGR、CIR等,
    先将这些寄存器进行复位,然后调用SetSysClock()来设置系统时钟,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) */ 
    }

    这个函数是通过宏定义来区分调用不同的时钟频率设置函数。在文件system_stm32f10x.c的第83行处,定义了默认的系统时钟为72MHz。

    #if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) 
    /* #define SYSCLK_FREQ_HSE    HSE_Value */
     #define SYSCLK_FREQ_24MHz  24000000
    #else
    /* #define SYSCLK_FREQ_HSE    HSE_Value */
    /* #define SYSCLK_FREQ_24MHz  24000000 */ 
    /* #define SYSCLK_FREQ_36MHz  36000000 */
    /* #define SYSCLK_FREQ_48MHz  48000000 */
    /* #define SYSCLK_FREQ_56MHz  56000000 */
    #define SYSCLK_FREQ_72MHz  72000000
    #endif

    如需更改成其它值的系统时钟,有两种方式:1、在这里把默认的宏定义注释掉,然后打开其他的宏定义;2、或者这里只注释掉宏定义,然后再KEIL-MDK编译器中设置该宏,设置方法如图:

    这样在编译的过程中,编译器会自动将设置的宏定义传入代码中。

    3、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 != HSEStartUp_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 */
        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 */
      }
    }

    其中有一段代码:

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

    3.5库默认是外部晶振为8M,所以这样的倍频系数选择为9,这样可以达到72M。如果外面是12M晶振,那这里的倍频系数是否要改成6呢??答案是,可以更改,也可以不用更改。为什么不用改?不更改的话,那岂不是要到108MHz啦?超频啦!!不会超频的,因为STM32F10x芯片最高时钟为72M,不会超过这个值。看下面的时钟树图,就能找到答案。

    4、执行完上面的SetSysClock()函数,库的时钟初始化就算完成了,接下来启动文件会将程序指针指向用户的main()函数,由用户做其他工作。

    问题:如何更改外部晶振的默认值,比如由8M更改到12M?

    有两种方式可以达成目的:
    1、通过修改库源文件,在文件stm32f10x.h第95行宏定义了外部晶振的值。
    2、不修改源文件,直接在编译器里面添加宏定义,通过宏定义传值给代码,如图:

    如果传递多个宏定义值的话,每个定义之前用空格隔开。

  • 相关阅读:
    BZOJ4403: 序列统计【lucas定理+组合数学】
    BZOJ4767: 两双手【组合数学+容斥原理】
    BZOJ5340: [Ctsc2018]假面【概率+期望】【思维】
    BZOJ4710: [Jsoi2011]分特产【组合数学+容斥】
    BZOJ5091: [Lydsy1711月赛]摘苹果【期望DP】
    BZOJ3473: 字符串【后缀数组+思维】
    BZOJ3879: SvT【后缀数组+单调栈】
    BZOJ1369/BZOJ2865 【后缀数组+线段树】
    BZOJ3230: 相似子串【后缀数组】
    BZOJ4310: 跳蚤 【后缀数组+二分】
  • 原文地址:https://www.cnblogs.com/swblog/p/3349137.html
Copyright © 2020-2023  润新知