当前位置: 首页 > article >正文

06:(寄存器开发)对上电/复位的SystemInit函数进行分析

SystemInit函数分析

 通过第5章的时钟树的学习,基本了解了SystemClock总线,AHB总线,APB1总线,APB2总线的时钟频率。那么单片机一上电或者按下复位时,这些总线的时钟频率是如何变化的喃?

这和STM32的启动文件有关,STM32F103C8T6是一个中密度的产品,所以启动文件为startup_stm32f10x_md.s。如下图所示:
                  在这里插入图片描述

在单片机一上电时,单片机就去执行这个文件里面的汇编代码指令。而执行中有一句为如下:

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

这段的代码的大概意思就是单片机复位后先执行SystemInit函数的代码后,在去执行主函数main函数的代码。
那SystemInit()的作用是什么?解释如下图所示:

在这里插入图片描述

对SystemInit函数源码分析如下:
【注】源码中有STM32互联型STM32F10X_CL的配置,而C8T6的中密度主流型的产品,所以忽略对互联型的源码如下:

void SystemInit (void)
{
  /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
  /* Set HSION bit */
  RCC->CR |= (uint32_t)0x00000001;//开启HSI内部高速晶振
   
  /* Reset HSEON, CSSON and PLLON bits */
  RCC->CR &= (uint32_t)0xFEF6FFFF;//关闭HSE,关闭PLL,关闭时钟监测器

  /* Reset HSEBYP bit */
  RCC->CR &= (uint32_t)0xFFFBFFFF;//让HSE没有旁路

  /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
  RCC->CFGR &= (uint32_t)0xFF80FFFF;//HSI振荡器时钟经2分频后作为PLL输入时钟 
  								    //HSE不分频 
  								    //PLL 2倍频输出
  
  SetSysClock();//执行SetSysClock函数
}

对SetSysClock函数源码分析如下:

在这里插入图片描述

对SetSysClockTo72函数源码分析如下:

static void SetSysClockTo72(void)
{
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;//定义2个变量
  
  /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/    
  /* Enable HSE */    
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);//开启HSE晶振
 
  /* Wait till HSE is ready and if Time out is reached exit */
  do
  {
    HSEStatus = RCC->CR & RCC_CR_HSERDY;//判断HSE晶振是否准备就绪
    StartUpCounter++;  
  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));//准备就绪HSEStatus == 1,跳出循环

  if ((RCC->CR & RCC_CR_HSERDY) != RESET)//如果HSE晶振准备就绪
  {
    HSEStatus = (uint32_t)0x01;//HSEStatus = 1
  }
  else//如果HSE晶振没有准备就绪
  {
    HSEStatus = (uint32_t)0x00;//HSEStatus = 0
  }  

  if (HSEStatus == (uint32_t)0x01)//HSEStatus = 1,代表准备就绪
  {
    /* Enable Prefetch Buffer */
    FLASH->ACR |= FLASH_ACR_PRFTBE;//使能Flash预取缓冲区

    /* Flash 2 wait state */
    FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;//设置系统时钟进行2个等待周期   

 
    /* HCLK = SYSCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;//AHB预分频系数1
      
    /* PCLK2 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;//APB2预分频系数1
    
    /* PCLK1 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;//APB1预分频系数2

	/*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
                                        RCC_CFGR_PLLMULL));//PLL是时钟源为为分频HSE
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);//PLL9倍频

	/* 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 */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));//清除SW位
    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;//PLL输出作为系统时钟;

    /* Wait till PLL is used as system clock source */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)//等待设置PLL为系统时钟源成功
    {
    }
  }
  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 */
 	}

综上代码:上电/复位执行SetSysClockTo72()函数是将系统时钟SystemClock配置为72MHz,AHB总线时钟配置为72MHz,APB1总线时钟配置为36MHz,APB2总线时钟配置为72MHz。代码执行流程如下
在这里插入图片描述


http://www.kler.cn/a/388023.html

相关文章:

  • 如何用C#和Aspose.PDF实现PDF转Word工具
  • 使用elementUI实现表格行拖拽改变顺序,无需引入外部库
  • C++单例模式实现
  • qt QVideoWidget详解
  • 【秋招笔试-支持在线评测】11.13花子秋招(已改编)-三语言题解
  • C++组合复用中,委托的含义与作用
  • 【Java项目】基于SpringBoot的【生鲜交易系统】
  • MySQL —— Innodb 索引数据结构
  • 《操作系统 - 清华大学》3 -1:计算机体系接口及内存分层体系
  • Rust项目中的Labels
  • MYSQL备库的并行复制
  • 压缩Minio桶中的文件为ZIP,并通过 HTTP 响应输出
  • solidworks、sw_to_urdf的一些心得
  • Web实时消息推送
  • 一文学习Android中的Property
  • [Redis] Redis主从复制模式
  • 在vue3的vite网络请求报错 [vite] http proxy error:
  • 微星爆破弹ddr4wifi接线梳理研究
  • Flink滑动窗口(Sliding)中window和windowAll的区别
  • redis用法(二)
  • 项目功能--运营数据统计报表导出
  • 【真题笔记】21年系统架构设计师案例理论点总结
  • 【SpringBoot】19 文件/图片下载(MySQL + Thymeleaf)
  • 说说webpack中常见的Plugin?解决了什么问题?
  • Ubuntu18.04更换PREEMPT RT内核
  • 软考:论容器编排