记录一下,方便以后翻阅~
1. 基础知识:
1.1 SystemInit()函数申明位于system_stm32f10x.h头文件中,内容在system_stm32f10x.c文件中;
1.2 因为采用STM32F10X_HD,所以SystemInit()函数中部分函数不会运行。
2. 涉及主要寄存器:
3. SystemInit()函数解读:
备注:代码中符号 / / * * … * * / / 表示该代码实际在源函数中,但是不执行。
void SystemInit(void)
{
/*Reset the RCC clock configuration to the default reset state(for debug purpose)*/
/*Set HSI ON bit */
RCC->CR |= (uint32_t)0x00000001; /*时钟控制寄存器(RCC_CR),内部8MHz振荡器开启*/
/*Reset SW,SWS, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
#ifndef STM32F10X_CL
RCC->CFGR &= (uint32_t)0xF8FF0000; /*因为用STM32F10X_HD,所以运行这一行代码*/
#else
//** RCC->CFGR &= (uint32_t)0xF0FF0000; **// /*不执行*/
#endif
/*Reset HSEON, CSSON and PLLON bits */
RCC->CR &= (uint32_t)0xFEF6FFFF; /*将HSEON, CSSON 和 PLLON置0 */
/*Reset HSEBYP bit */
RCC->CR &= (uint32_t)0xFFFBFFFF; /* 将HSEBYP置0 */
/*Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
RCC->CFGR &=(uint32_t)0xFF80FFFF; /*将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; /*CIR时钟中断寄存器*/
#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
}
4. 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
因为:
/*#define SYSCLK_FREQ_HSE HSE_VALUE */
/*#define SYSCLK_FREQ_24MHz 24000000 */
/*#define SYSCLK_FREQ_36MHz 36000000 */
/*#define SYSCLK_FREQ_48MHz 48000000 */
/*#define SYSCLK_FREQ_56MHz 56000000 */
#define SYSCLK_FREQ_72MHz 72000000 /*只有这条激活*/
#endif
5. SetSysClockTo72()函数解读:
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); /*对应#define RCC_CR_HSEON ((uint32_t)0x00010000),将HSEON置1*/
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
/*对应#define RCC_CR_HSERDY ((uint32_t)0x00020000),读取HSERDY值,其值为1时外部振荡器就绪*/
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
/*对应#define HSE_STARTUP_TIMEOUT ((uint16_t)0x0500),当HSEStatus为0时,则没准备就绪,继续循环,只有当HSEStatus为1(即HSERDY值为1),或等于HSE_STARTUP_TIMEOUT(超时)时,跳出循环。*/
if ((RCC->CR & RCC_CR_HSERDY) !=RESET) /*如果CR值不等于0*/
{
HSEStatus = (uint32_t)0x01; /*则,HSEStatus值为1*/
}
else
{
HSEStatus = (uint32_t)0x00; /*否则,HSEStatus值为0*/
}
if (HSEStatus == (uint32_t)0x01) /*如果,HSEStatus值为1,即HSE准备就绪*/
{
/*Enable Prefetch Buffer */
FLASH->ACR |= FLASH_ACR_PRFTBE; /*对应/#define FLASH_ACR_PRFTBE ((uint8_t)0x10),启用预取缓冲区*/
/* Flash 2 wait state */
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY); /*对应#define FLASH_ACR_LATENCY ((uint8_t)0x03),无解释*/
FLASH->ACR |=(uint32_t)FLASH_ACR_LATENCY_2; /*对应#define FLASH_ACR_LATENCY_2 ((uint8_t)0x02),两个等待状态*/
/*HCLK = SYSCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
/*对应#define RCC_CFGR_HPRE_DIV1 ((uint32_t)0x00000000),即对AHP预分频执行不分频命令*/
/*PCLK2 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
/*对应#define RCC_CFGR_PPRE2_DIV1 ((uint32_t)0x00000000),即对高速APB预分频(APB2)执行不分频命令*/
/*PCLK1 = HCLK/2 */
RCC->CFGR |=(uint32_t)RCC_CFGR_PPRE1_DIV2;
/*对应#define RCC_CFGR_PPRE1_DIV2 ((uint32_t)0x00000400),即对低速APB预分频(APB1)执行2分频命令*/
#ifdefSTM32F10X_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));
/*对应#define RCC_CFGR_PLLSRC ((uint32_t)0x00010000);#define RCC_CFGR_PLLXTPRE ((uint32_t)0x00020000);#define RCC_CFGR_PLLMULL ((uint32_t)0x003C0000)*/
RCC->CFGR |=(uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
/*对应#define RCC_CFGR_PLLSRC_HSE ((uint32_t)0x00010000);#define RCC_CFGR_PLLMULL9 ((uint32_t)0x001C0000) */
#endif /* STM32F10X_CL */
/*Enable PLL */
RCC->CR |= RCC_CR_PLLON; /*对应#define RCC_CR_PLLON ((uint32_t)0x01000000)*/
/*Wait till PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY)== 0) /*对应#define RCC_CR_PLLRDY ((uint32_t)0x02000000)*/
{
}
/*Select PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); /*对应#define RCC_CFGR_SW ((uint32_t)0x00000003)*/
RCC->CFGR |=(uint32_t)RCC_CFGR_SW_PLL; /*对应#define RCC_CFGR_SW_PLL ((uint32_t)0x00000002)*/
/*Wait till PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)/*对应#define RCC_CFGR_SWS ((uint32_t)0x0000000C)*/
{
}
}
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
6. SystemInit()函数步骤解读:
1.1 RCC_CR //Set HSION bit,或运算//
xxxx xxxx xxxx xxxx | xxxx xxxx xxxx xxx1
1.2 RCC_CFGR //Reset SW, SWS, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits,与运算 //
xxxx x000 xxxx xxxx | 0000 0000 0000 0000
1.3 RCC_CR //Reset HSEON, CSSON and PLLON bits,与运算 //
xxxx xxx0 xxxx 0xx0 | xxxx xxxx xxxx xxxx
1.4 RCC_CR //Reset HSEBYP bit,与运算 //
xxxx xxxx xxxx x0xx | xxxx xxxx xxxx xxxx
1.5 RCC_CFGR //Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits,与运算 //
xxxx xxxx x000 0000 | xxxx xxxx xxxx xxxx
1.6 RCC_CIR //Disable all interrupts and clear pending bits,=运算//
0000 0000 1001 1111 | 0000 0000 0000 0000
1.7 进入到SetSysClock()函数中;
1.8 进入到SetSysClockTo72()函数中;
1.9 设__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
1.10 RCC->CR |= ((uint32_t)RCC_CR_HSEON);
//RCC_CR_HSEON为0x00010000,将HSEON置1//
xxxx xxxx xxxx xxx1 | xxxx xxxx xxxx xxxx
1.11 HSEStatus=RCC->CR & RCC_CR_HSERDY;
//RCC_CR_HSERDY为0x00020000),将HSERDY值赋给HSEStatus//
0000 0000 0000 00x0 | 0000 0000 0000 0000
1.12 //若上一步读取的HSERDY为1时,或超时,继续下一步,否则,一直循环上一步//
1.13 ** if ((RCC->CR & RCC_CR_HSERDY) != RESET)**
//若RCC_CR不为 0000 0000 0000 0000 | 0000 0000 0000 0000//
HSEStatus = (uint32_t)0x01; //则,HSEStatus值为0x01//
else
HSEStatus = (uint32_t)0x00; //否则,HSEStatus值为0x00,即5.11步骤是因为超时跳出循环的//
1.14 if (HSEStatus == (uint32_t)0x01) //若HSEStatus值为0x01,即外部振荡器就绪,则进行如下步骤//
1.15 //再次申明,以下步骤仅在HSEStatus值为0x01时运行!//
1.16 FLASH->ACR |= FLASH_ACR_PRFTBE; //FLASH_ACR_PRFTBE为0x10),启用预取缓冲区//
1.17 **FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY); **
//FLASH_ACR_LATENCY为0000 0011,取非则为 1111 1100,因此与运算后,ACR为xxxx xx00先清零//
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;
//FLASH_ACR_LATENCY_2 为0000 0010,或运算后,ACR又变为xxxx xx10,再赋值,即两个等待状态//
1.18 RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
//RCC_CFGR_HPRE_DIV1为0x00000000),其实对原CFGR值无影响 //
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
//RCC_CFGR_PPRE2_DIV1为0x00000000),其实对原CFGR值无影响//
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
//RCC_CFGR_PPRE1_DIV2为0x00000400),或运算后,CFGR为xxxx xxxx xxxx xxxx | xxxx x1xx xxxx xxxx //
1.19 RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
//RCC_CFGR_PLLSRC为0x00010000);RCC_CFGR_PLLXTPRE为0x00020000);RCC_CFGR_PLLMULL 为0x003C0000),因此三个或之后为 0000 0000 0011 1111 | 0000 0000 0000 0000,取非后为 1111 1111 1100 0000 | 1111 1111 1111 1111,与运算后为 xxxx xxxx xx00 0000 | xxxx xxxx xxxx xxxx//
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
//RCC_CFGR_PLLSRC_HSE为0000 0000 0000 0001 | 0000 0000 0000 0000);RCC_CFGR_PLLMULL9为0000 0000 0001 1100 | 0000 0000 0000 0000),两者或之后为 0000 0000 0001 1101 | 0000 0000 0000 0000,或运算后为xxxx xxxx xxx1 11x1 | xxxx xxxx xxxx xxxx //
1.20 RCC->CR |= RCC_CR_PLLON;
//RCC_CR_PLLON为0x01000000,或运算xxxx xxx1 xxxx xxxx | xxxx xxxx xxxx xxxx //
1.21 **while((RCC->CR & RCC_CR_PLLRDY)== 0) **
//RCC_CR_PLLRDY为0000 0010 0000 0000 | 0000 0000 0000 0000,与运算后0000 00x0 0000 0000 | 0000 0000 0000 0000,当x为0时,即PLL未锁定,0==0,while循环继续,当x为1时,即PLL锁定,while循环跳出//
1.22 RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
//RCC_CFGR_SW 为0x00000003,取非后1111 1111 1111 1111 | 1111 1111 1111 1100,与运算后 xxxx xxxx xxxx xxxx | xxxx xxxx xxxx xx00//
RCC->CFGR |=(uint32_t)RCC_CFGR_SW_PLL;
// RCC_CFGR_SW_PLL为0x00000002,或运算后xxxx xxxx xxxx xxxx|xxxx xxxx xxxx xx10,即PLL输出作为系统时钟 //
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
//RCC_CFGR_SWS为0x0000000C,与运算后CFGR为0000 0000 0000 0000 | 0000 0000 0000 xx00,当xx为10时,则SWS显示PLL输出作为系统时钟//
1.23 #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. //
7. 在启动文件startup_stm32f10x_hd.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函数,这就是为什么main函数里一般没有SystemInit函数的原因。
知识点:
1)参照时钟系统框图可更好理解SystemInit函数,可参考STM32学习心得七:STM32时钟系统框图解读及相关函数;
2)熟悉相关寄存器参数。