• SystemInit()时钟系统初始化函数解析


    SystemInit()时钟系统初始化函数

    SystemInit() 函数在 system_stm32f10x.h头文件中可以看到函数声明,函数实现是在system_stm32f10x.c源文件中

    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;				//CR寄存器最低位置1,内部8MHz振荡器开启
    
      /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
    #ifndef STM32F10X_CL
      RCC->CFGR &= (uint32_t)0xF8FF0000;	//没有定义STM32F10X_CL,所以执行这句,把CFGR的对应位清零,英文注释有对应位
    #else
      RCC->CFGR &= (uint32_t)0xF0FF0000;
    #endif /* STM32F10X_CL */   
      
      /* Reset HSEON, CSSON and PLLON bits */
      RCC->CR &= (uint32_t)0xFEF6FFFF;		//CR寄存器的HSEON,CSSON,PLLON位设置为0
    
      /* Reset HSEBYP bit */
      RCC->CR &= (uint32_t)0xFFFBFFFF;		//CR寄存器的HSEBYP位设置为0
    
      /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
      RCC->CFGR &= (uint32_t)0xFF80FFFF;		//CFGR寄存器的PLLSRC,PLLXTPRE,PLLMUL,USBPRE/OTGFSPRE位设置为0
    
    #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 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    行数5:CR寄存器的最低位HSION(内部高速时钟使能)置1,内部8MHz振荡器开启

    行数9:CFGR寄存器的SW, HPRE, PPRE1, PPRE2, ADCPRE 和 MCO位清0

    ​ SW(系统时钟切换)[1:0]置00:HSI作为系统时钟

    ​ HPRE(AHB预分频)[3:0]置0000:SYSCLK不分频

    ​ PPRE2(高速APB预分频(APB2))[2:0]置000:HCLK不分频

    ​ ADCPRE(ADC预分频)[1:0]置00:PCLK2 2分频后作为ADC时钟

    ​ MCO(微控制器时钟输出)[2:0]置000:没有时钟输出

    行数15:CR寄存器的HSEON, CSSON 和 PLLON位清0

    ​ HSEON(外部高速时钟使能)位置0:HSE振荡器关闭

    ​ CSSON(时钟安全系统使能)位置0:时钟监测器关闭

    ​ PLLON(PLL使能)位置0:PLL关闭

    行数18:CR寄存器的HSEBYP位清0

    ​ HSEBYP(外部高速时钟旁路)位置0:外部4-16MHz振荡器没有旁路

    行数21:CFGR寄存器PLLSRC,PLLXTPRE,PLLMUL,USBPRE/OTGFSPRE位清0

    ​ PLLSRC(PLL输入时钟源)位置0:HSI振荡器时钟经2分频后作为PLL输入时钟

    ​ PLLXTPRE(HSE分频器作为PLL输入)位置0:HSE不分频

    ​ PLLMUL(PLL倍频系数)[3:0]位置0000:SYSCLK不分频

    ​ USBPRE(USB预分频)置0:PLL时钟1.5倍分频作为USB时钟

    行数40:CIR寄存器赋值为0x009F0000,禁用所有中断标志位并关闭所有就绪中断

    SetSysClock函数解析

    该函数也在system_stm32f10x.c源文件中,该文件中已经宏定义了SYSCLK_FREQ_72MHz,所以这里再调用了SetSysClockTo72()函数

    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) */ 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    SetSysClockTo72函数解析

    同样在system_stm32f10x.c源文件中,函数放在了#elif defined SYSCLK_FREQ_72MHz 的预处理命令下

    #elif defined SYSCLK_FREQ_72MHz
    /**
      * @brief  Sets System clock frequency to 72MHz and configure HCLK, PCLK2 
      *         and PCLK1 prescalers. 
      * @note   This function should be used only after reset.
      * @param  None
      * @retval None
      */
    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)			//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;
          
        /* 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 */
      }
    }
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103

    行数15:RCC_CR_HSEON为0x00010000,CR寄存器的HSEON(外部高速时钟使能)置1:HSE振荡器开启

    行数18-22:采用do while循环来检测HSERDY(外部高速时钟就绪标志)是否被硬件置1,若置1表示外部4-16MHz振荡器就绪,退出循环,同时增加一个计数器StartUpCounter,当计数器等于阈值HSE_STARTUP_TIMEOUT(0x0500)时也退出循环,表示HSE振荡器启动超时

    行数24-31:如果CR寄存器的HSERDY位不等于RESET(0)则对HSE标志位HSEStatus赋值0x01,表示HSE振荡器启动成功,如果HSERDY位等于0,则对HSEStatus赋值0x00,表示HSE振荡器启动失败,因为上面退出循环的条件可以是计数器超出阈值

    行数35-40:对FLASH的初始化,先不管

    行数44:RCC_CFGR_HPRE_DIV1为0x00000000,CFGR寄存器的HPRE位为0000,控制的是 AHB预分频,SYSCLK不分频,让HCLK = SYSCLK

    行数47:RCC_CFGR_PPRE2_DIV1为0x00000000,CFGR寄存器的PPRE2位置000,控制的是高速APB预分频(APB2),HCLK不分频,让PCLK2 = HCLK

    行数50:RCC_CFGR_PPRE1_DIV2为0x00000400,CFGR寄存器的PPRE1位置100,控制的是低速APB预分频(APB1)),HCLK 2分频,让PCLK1 = HCLK/2

    行数76:RCC_CFGR_PLLSRC = 0x00010000,RCC_CFGR_PLLXTPRE = 0x00020000,RCC_CFGR_PLLMULL = 0x003C0000,三个相或,得到0x003F0000,然后取反,得到0xFFC0FFFF,用&操作,CFGR寄存器的 21、20、19、18、17、16位清零,其他位不变

    行数78:RCC_CFGR_PLLSRC_HSE = 0x00010000,RCC_CFGR_PLLMULL9 = 0x001C0000,两个相或,得到0x001D0000,CFGR寄存器的16、18、19、20位置1;16位是PLLSRC(PLL输入时钟源),置1表示HSE时钟作为PLL输入时钟;17位为0表示HSE不分频,18-21位为0111,表示PLL 9倍频输出,这样就得到了PLLCLK = HSE * 9 = 72 MHz

    行数82:RCC_CR_PLLON = 0x01000000,CR寄存器的PLLON位置1,使能PLL

    行数85:RCC_CR_PLLRDY = 0x02000000,取出CR寄存器的PLLRDY位进行判断,如果该位是0,则一直循环等待,待该位为1时,表示PLL就绪,退出循环继续执行

    行数90:RCC_CFGR_SW = 0x00000003,CFGR寄存器的最低两位SW[1:0]清零

    行数91:RCC_CFGR_SW_PLL = 0x00000002,CFGR寄存器的第1位置1,SW为10,PLL输出作为系统时钟;

    行数94:RCC_CFGR_SWS = 0x0000000C,最低4位为1100,与操作取出SWS这两位,判断是否是0x80,如果是,则说明PLL输出作为系统时钟,退出循环,如果不是,则PLL还没作为系统时钟,继续循环等待

    调用SystemInit()函数初始化时钟

    在写LED灯点亮功能时,主函数main并没有调用SystemInit()函数对系统时钟进行初始化,但编写的功能代码却能正常运行,这时为什么呢?

    在startup_stm32f10x_md.s(大容量就是startup_stm32f10x_hd.s)文件中可以看到这样一段代码,下面注释大概说一下语句的作用,凭个人理解

    ; Reset handler
    Reset_Handler    PROC
                     EXPORT  Reset_Handler             [WEAK]
         IMPORT  __main	
         IMPORT  SystemInit									//导入SystemInit函数
                     LDR     R0, =SystemInit				//先加载SystemInit函数,也就是先调用SystemInit函数
                     BLX     R0									
                     LDR     R0, =__main					//再加载main函数
                     BX      R0
                     ENDP
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    _main是编译系统提供的一个函数,负责完成库函数的初始化和初始化应用程序执行环境,最后自动跳转到main()

    这段代码意思就是在系统启动时,先调用了SystemInit()函数初始化了系统时钟,再进入main函数里执行

    所以在编写功能代码时,并不用手动调用SystemInit()函数,这个启动文件已经帮我们调用了

  • 相关阅读:
    部署若依springboot-vue前后端分离项目(Nginx反向代理 2022)
    android 布局 横屏 android横屏适配
    前端培训丁鹿学堂:node入门之url模块和querystring模块
    22年6月工作笔记整理(前端)
    剖析容器运行时
    操作系统学习(九)死锁
    c++入门必学算法 并查集
    区块链、隐私计算、联邦学习、人工智能的关联
    Radis基础命令(Hash类型)对field进行的操作
    Dubbo服务调用扩展点Filter的介绍与使用
  • 原文地址:https://blog.csdn.net/weixin_46251230/article/details/126569007