SystemInit函数分析
通过第5章的时钟树的学习,基本了解了SystemClock总线,AHB总线,APB1总线,APB2总线的时钟频率。那么单片机一上电或者按下复位时,这些总线的时钟频率是如何变化的喃?
这和STM32的启动文件有关,STM32F103C8T6是一个中密度的产品,所以启动文件为startup_stm32f10x_md.s。如下图所示:
在单片机一上电时,单片机就去执行这个文件里面的汇编代码指令。而执行中有一句为如下:
Reset_Handler PROC EXPORT Reset_Handler [WEAK]IMPORT __mainIMPORT SystemInitLDR R0, =SystemInitBLX R0LDR R0, =__mainBX R0ENDP
这段的代码的大概意思就是单片机复位后先执行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是时钟源为为分频HSERCC->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。代码执行流程如下