STM32F10x_StdPeriph_Lib_V3.5.0库时钟分析及如何配置
[操作环境]:KEIL MDK4.10 Lib_V3.5.0
阅读了STM32F10x_StdPeriph_Lib_V3.5.0库关于时钟部分代码,发现设备初始化时钟默认为外部晶振8MHz,经过PLL倍频后,内部核心时钟为72MHz.
其处理流程大致如下:
1、启动文件(startup_stm32f10x_md.s)里有如下代码:
; Reset handler Reset_Handler PROC EXPORT Reset_Handler [WEAK] IMPORT __main IMPORT SystemInit LDR R0, =SystemInit BLX R0 LDR R0, =__main BX R0 ENDP
2、系统复位后,会先执行SystemInit函数,这个函数位于库\CMSIS\CM3\DeviceSupport\ST\STM32F10x\system_stm32f10x.c文件中,该函数的主要功能是配置RCC的相关寄存器,如CR、CFGR、CIR等,
先将这些寄存器进行复位,然后调用SetSysClock()来设置系统时钟,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) */ }
这个函数是通过宏定义来区分调用不同的时钟频率设置函数。在文件system_stm32f10x.c的第83行处,定义了默认的系统时钟为72MHz。
#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) /* #define SYSCLK_FREQ_HSE HSE_Value */ #define SYSCLK_FREQ_24MHz 24000000 #else /* #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
如需更改成其它值的系统时钟,有两种方式:1、在这里把默认的宏定义注释掉,然后打开其他的宏定义;2、或者这里只注释掉宏定义,然后再KEIL-MDK编译器中设置该宏,设置方法如图:
这样在编译的过程中,编译器会自动将设置的宏定义传入代码中。
3、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); /* Wait till HSE is ready and if Time out is reached exit */ do { HSEStatus = RCC->CR & RCC_CR_HSERDY; StartUpCounter++; } while((HSEStatus == 0) && (StartUpCounter != HSEStartUp_TimeOut)); if ((RCC->CR & RCC_CR_HSERDY) != RESET) { HSEStatus = (uint32_t)0x01; } else { HSEStatus = (uint32_t)0x00; } if (HSEStatus == (uint32_t)0x01) { /* 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; /* PCLK2 = HCLK */ RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; /* PCLK1 = HCLK */ RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2; #ifdef STM32F10X_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)); RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9); #endif /* STM32F10X_CL */ /* Enable PLL */ RCC->CR |= RCC_CR_PLLON; /* Wait till PLL is ready */ while((RCC->CR & RCC_CR_PLLRDY) == 0) { } /* Select PLL as system clock source */ 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 */ } }
其中有一段代码:
/* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */ 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);
3.5库默认是外部晶振为8M,所以这样的倍频系数选择为9,这样可以达到72M。如果外面是12M晶振,那这里的倍频系数是否要改成6呢??答案是,可以更改,也可以不用更改。为什么不用改?不更改的话,那岂不是要到108MHz啦?超频啦!!不会超频的,因为STM32F10x芯片最高时钟为72M,不会超过这个值。看下面的时钟树图,就能找到答案。
4、执行完上面的SetSysClock()函数,库的时钟初始化就算完成了,接下来启动文件会将程序指针指向用户的main()函数,由用户做其他工作。
问题:如何更改外部晶振的默认值,比如由8M更改到12M?
有两种方式可以达成目的:
1、通过修改库源文件,在文件stm32f10x.h第95行宏定义了外部晶振的值。
2、不修改源文件,直接在编译器里面添加宏定义,通过宏定义传值给代码,如图:
如果传递多个宏定义值的话,每个定义之前用空格隔开。