SystemInit():
在工程文件的system_stm32f10x.c中有如下代码:
这里将为大家逐个注释,让大家了解。
void SystemInit (void)
{
RCC->CR |= (uint32_t)0x00000001;//把HSI时钟打开
//HSION:内部高速时钟使能 (Internal high-speed clock enable) 由软件置’1’或清零。
//当从待机和停止模式返回或用作系统时钟的外部4-16MHz振荡器发生故障时,该位由硬件置’1’ 来启动内部8MHz的RC振荡器。
//当内部8MHz振荡器被直接或间接地用作或被选择将要作为系 统时钟时,该位不能被清零。
//0:内部8MHz振荡器关闭;
//1:内部8MHz振荡器开启。
//该部分是把相关位设置为0
/* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
#ifndef STM32F10X_CL
RCC->CFGR &= (uint32_t)0xF8FF0000;
#else
RCC->CFGR &= (uint32_t)0xF0FF0000;
#endif /* STM32F10X_CL */
/* Reset HSEON, CSSON and PLLON bits */
RCC->CR &= (uint32_t)0xFEF6FFFF;
/* Reset HSEBYP bit */
RCC->CR &= (uint32_t)0xFFFBFFFF;
/* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
RCC->CFGR &= (uint32_t)0xFF80FFFF;
#ifdef STM32F10X_CL //判断宏定义标识符(如果是_HD,这段不执行)
/* 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 //_HD执行该段
/* Disable all interrupts and clear pending bits */
RCC->CIR = 0x009F0000;
#endif /* STM32F10X_CL */
//hd同样不执行该段
#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
}
//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
//注释对应的宏定义的标识符即可改变频率
/* If none of the define above is enabled, the HSI is used as System clock
source (default after reset) */
}
COPY
SetSysClock():
这里选择讲解72MHz为例,该函数的步骤为:
- 打开HSE时钟(3-8行)
- 等待HSE时钟就绪(9-24行)
- 设置flash和三个时钟,确定关系(26-51行)
- 设置CFGR寄存器确定PLL指针来源和倍频系数(75-80行)
- 把PLL时钟作为系统时钟的来源(84-97行)
最后有所使用寄存器和系统时钟图参考.
static void SetSysClockTo72(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
/* 使能 HSE 时钟*/
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
//在头文件中宏定义了RCC_CR_HSEON对应地址为0x000100000 即位十六——外部高速时钟使能
/* 等待HSE时钟稳定 */
do
{
//通过判断RCC_CR_HSERDY(外部高速时钟就绪标志,地址对应0x000200000,位17)= 1,则表示稳定
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;//如果就绪了,则让HSEStatus=0x01
}
else
{
HSEStatus = (uint32_t)0x00;
}
//判断就绪,然后继续执行
if (HSEStatus == (uint32_t)0x01)
{
//由于cpu速度快于芯片flash很多,所以操作前要等待几个时钟
//ACR寄存器:LATENCY:时延
//这些位表示SYSCLK(系统时钟)周期与闪存访问时间的比例000:零等待状态,当0<sYSCLK≤24MHz
//001:一个等待状态,当24MHz< sYSCLK ≤48MHz
//010:两个等待状态,当48MHzACR |= FLASH_ACR_PRFTBE;
/* 两个等待状态 */
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;
//根据图解可知频率关系
/* HCLK = SYSCLK 72MHz*/
//实现则需要AHB预分频器要设置为1
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
//RCC_CFGR_HPRE_DIV1对应地址0x00000000 不分频的位7:4为0xxx
/* PCLK2 = HCLK 72MHz*/
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
//RCC_CFGR_PPRE2_DIV1对应地址0x00000000 不分频的位13:11为0xx
/*36MHz PCLK1 = HCLK/2 72MHz*/
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
//RCC_CFGR_PPRE2_DIV1对应地址0x00000400 二分频的位10:8为100
#ifdef STM32F10X_CL //判断为_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 //非_CL 执行
/* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
RCC_CFGR_PLLMULL));
//直接将HSE作为PLL时钟的来源
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);//设置PLL 9倍频
#endif /* STM32F10X_CL */
/* 使能 PLL时钟 */
RCC->CR |= RCC_CR_PLLON;
//RCC_CR_PLLON地址对应0x010000000 位24为1:使能PLL
/* 等待 PLL时钟 稳定 */
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}
/* 选择 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 */
}
}
COPY
寄存器和系统时钟图参考:
42行:位7:4
HPRE[3:0]:AHB预分频(AHB Prescaler)
由软件置’1’或清0’来控制AHB时钟的预分频系数。
0xxx: sYSCLK不分频
1000: sYSCLK 2分频 1100: sYSCLK64分频
1001: sYSCLK4分频 1101: sYSCLK 128分频
1010: sYSCLK8分频 1110: sYSCLK 256分频
1011:sYSCLK 16分频 1111:sYSCLK 512分频
注意:当AHB时钟的预分频系数大于1时,必须开启预取缓冲器。详见闪存读取(第2.3.3节).
46行:位13:11
PPRE2[2:0]:高速APB预分频(APB2)(APB high-speed prescaler (APB2))由软件置’1’或清’0’来控制高速APB2时钟(PCLK2)的预分频系数。
0xx:HCLK不分频
100:HCLK 2分频
101:HCLK 4分频
110:HCLK 8分频
111:HCLK 16分频
50行:位10:8
PPRE1[2:0]低速APB预分频(APB1) (APB low-speed prescaler (APB1))
由软件置’1’或清’0’来控制低速APB1时钟(PCLK1)的预分频系数。
警告:软件必须保证APB1时钟频率不超过36MHz。
0xx:HCLK不分频
100:HCLK 2分频
101:HCLK 4分频
110:HCLK 8分频
111:HCLK 16分频
本文转载自: Systemlnit时钟系统初始化函数剖析 – 布尔博客