stm32芯片手册上有张图表示的很清楚,一共有4个时钟源:
1.HSI(内部高速时钟 8MHz)提供可以位系统时钟提供时钟源
2.HSE(外部高速时钟)可以提供系统时钟和RTC时钟时钟源
3.LSE(低速外部时钟32.768kHz)可以为可以为RTC提供时钟源
4.LSI(低速内部时钟)可以为独立看门狗提供时钟源
首先分析一下ST公司给的库函数:我用的是3.5的库
我们看看SystemInit里是什么
void SystemInit (void)
{
RCC->CR |= (uint32_t)0x00000001;
//打开HSI内部高速时钟
#ifndef STM32F10X_CL
RCC->CFGR &= (uint32_t)0xF8FF0000;//CFCG寄存器的27位没用,所以这个宏没用
#else //MCO的两位清零,不往外输出时钟,0-15位清零,PLCK 2分频给ADC,HCLK不分频给APB2
RCC->CFGR &= (uint32_t)0xF0FF0000;//HCLK不分频给APB1,sysclk不分频给AHB,HSI用作系统时钟,
#endif /* STM32F10X_CL */
/* Reset HSEON, CSSON and PLLON bits */
RCC->CR &= (uint32_t)0xFEF6FFFF;
//HSE禁用
/* Reset HSEBYP bit */
RCC->CR &= (uint32_t)0xFFFBFFFF;
//外部高速时钟未被旁路
/* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
RCC->CFGR &= (uint32_t)0xFF80FFFF; //PLL 1.5分频,给USBpre,PLLMUL *2,HSE未分频做PLL输入HSI/2做PLL输入
#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; /*中断向量表定位在SRAM_BASE(0X20000000)+VECT_TAB_OFFSET(0X0)处*/
#else
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /*中断向量表定位在FLASH_BASE(0X08000000)+VECT_TAB_OFFSET(0X0)处 */
#endif
}
下面看看SetSysClock()函数
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
/* 如果上面没有一个宏成立,则HSI用作系统时钟源,一般调用SetSysClockTo72()函数*/
}
static void SetSysClockTo72(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0; //__IO uint32_t即vu32
/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/
/* Enable HSE */
RCC->CR |= ((uint32_t)RCC_CR_HSEON); // RCC_CR_HSEON((uint32_t)0x00010000) HSE使能
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;//RCC_CR_HSERDY((uint32_t)0x00020000) 测试HSE状态
StartUpCounter++; //计数等待
} while((HSEStatus == 0) && (StartUpCounter != HSEStartUp_TimeOut)); //当计数 > HSEStartUp_TimeOut(0x500)时且HSE可用则跳出
if ((RCC->CR & RCC_CR_HSERDY) != RESET) //如果HSE可用
{
HSEStatus = (uint32_t)0x01; //HSEStatus置1
}
else
{
HSEStatus = (uint32_t)0x00; //HSEStatus置0
}
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; //HCLK等于系统时钟
/* PCLK2 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;//APB高速预分频为HCLK
/* PCLK1 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;//APB高低速预分频为HCLK/2
#ifdef STM32F10X_CL
/* Configure PLLs ------------------------------------------------------*/ //没有PLL2
/* 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_DIV3);
/* 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 */ //PLL9倍频==72MHz
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; //使能PLL
/* Wait till PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == 0) //等待PLL准备好
{
}
/* Select PLL as system clock source */ //设置系统时钟为PLL时钟源
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 */
/* Go to infinite loop */
while (1) //如果HSE不能用,则跳入死循环
{
}
}
}