STM32学习心得八:SystemInit时钟系统初始化函数解读

Willow ·
更新时间:2024-09-21
· 601 次阅读

记录一下,方便以后翻阅~
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)熟悉相关寄存器参数。


作者:闲人Ne



系统初始化 学习心得 stm32 学习 函数 系统 初始化

需要 登录 后方可回复, 如果你还没有账号请 注册新账号