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。代码执行流程如下