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

记录一下,方便以后翻阅~
主要内容:
1)了解SystemInit()函数及其涉及的相关寄存器。
官方资料:《STM32中文参考手册V10》第六章 复位和时钟控制 RCC
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)熟悉相关寄存器参数。

发布了24 篇原创文章 · 获赞 2 · 访问量 4125

猜你喜欢

转载自blog.csdn.net/Leisure_ksj/article/details/105255484