SystemInit() 函数在 system_stm32f10x.h头文件中可以看到函数声明,函数实现是在system_stm32f10x.c源文件中
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
}
行数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,禁用所有中断标志位并关闭所有就绪中断
该函数也在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) */
}
同样在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
行数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还没作为系统时钟,继续循环等待
在写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
_main是编译系统提供的一个函数,负责完成库函数的初始化和初始化应用程序执行环境,最后自动跳转到main()
这段代码意思就是在系统启动时,先调用了SystemInit()函数初始化了系统时钟,再进入main函数里执行
所以在编写功能代码时,并不用手动调用SystemInit()函数,这个启动文件已经帮我们调用了