Cotex-M3内核STM32F10XX系列时钟及其配置方法
扫描二维码
随时随地手机看文章
一、背景
最近做个项目,需要使用STM32,还是以前一样的观点,时钟就是MCU心脏,供血即时钟频率输出,想要弄明白一个MCU,时钟是一个非常好的切入点。言归正传,网上已经有太多大神详述过STM32的详细配置方法了,在此就简单介绍下STM32时钟系统,以及如何配置做个简单记录,方便以后的快速开发。
二、正文
废话不多说,上一张STM32F10xx的时钟树图:
由图可知,STM32F10XX有两级时钟
第一级时钟
* 高速内部时钟(HSI)
* 锁相环时钟(PLLCLK)
* 高速外部时钟(HSE)
第二级时钟
* 低速内部时钟(LSI)
* 低速外部时钟(LSE)
又由图可知,
* HSE由外部晶振从"OSC_OUT","OSC_IN"两脚输入提供。
* LSE由外部晶振从"OSC32_OUT","OSC32_IN"两脚输入提供。
* HSI由8MHZ高速内部RC震荡电路提供。
* LSI由40kHZ低速内部RC震荡电路提供。
STM32F10XX还可通过MCO脚向外提供时钟输出。时钟来源有PLLCLK/HSI/HSE/SYSCLK,由MCO选择器来选择。
研究过时钟来源,再来研究时钟的去向,MCU自身要能正常运作,即需要一个时钟,这个时钟既是系统时钟(SYSCLK),而基本上所有外设的时钟均来自于这个系统时钟(SYSCLk)。然后由系统时钟对外提供各种外设时钟。详见图。
当然,也有例外,USB时钟必须为48MHZ,这里的USB时钟(USBCLK)由PLLCLK直接提供,RTC时钟(RTCCLK)也不是来源于系统时钟(SYSCLK),详见图。
时钟结构大体也就如此,不再深究,网上有许多更加深入的讲解,接下来说说如何去配置。用代码来说明问题:
先贴文件"system_stm32f10x.c",此文件即库文件。里面有一个很重要的函数"SystemInit()"
解析过STM32启动代码的朋友都应该知道,这个函数跑在进入main函数之前,里面做的事情即是配置系统时钟。代码如下:
voidSystemInit(void){/*ResettheRCCclockconfigurationtothedefaultresetstate(fordebugpurpose)*//*SetHSIONbit*/RCC->CR|=(uint32_t)0x00000001;/*ResetSW,HPRE,PPRE1,PPRE2,ADCPREandMCObits*/#ifndefSTM32F10X_CLRCC->CFGR&=(uint32_t)0xF8FF0000;#elseRCC->CFGR&=(uint32_t)0xF0FF0000;#endif/*STM32F10X_CL*//*ResetHSEON,CSSONandPLLONbits*/RCC->CR&=(uint32_t)0xFEF6FFFF;/*ResetHSEBYPbit*/RCC->CR&=(uint32_t)0xFFFBFFFF;/*ResetPLLSRC,PLLXTPRE,PLLMULandUSBPRE/OTGFSPREbits*/RCC->CFGR&=(uint32_t)0xFF80FFFF;#ifdefSTM32F10X_CL/*ResetPLL2ONandPLL3ONbits*/RCC->CR&=(uint32_t)0xEBFFFFFF;/*Disableallinterruptsandclearpendingbits*/RCC->CIR=0x00FF0000;/*ResetCFGR2register*/RCC->CFGR2=0x00000000;#elifdefined(STM32F10X_LD_VL)||defined(STM32F10X_MD_VL)||(definedSTM32F10X_HD_VL)/*Disableallinterruptsandclearpendingbits*/RCC->CIR=0x009F0000;/*ResetCFGR2register*/RCC->CFGR2=0x00000000;#else/*Disableallinterruptsandclearpendingbits*/RCC->CIR=0x009F0000;#endif/*STM32F10X_CL*/#ifdefined(STM32F10X_HD)||(definedSTM32F10X_XL)||(definedSTM32F10X_HD_VL)#ifdefDATA_IN_ExtSRAMSystemInit_ExtMemCtl();#endif/*DATA_IN_ExtSRAM*/#endif/*ConfiguretheSystemclockfrequency,HCLK,PCLK2andPCLK1prescalers*//*ConfiguretheFlashLatencycyclesandenableprefetchbuffer*/SetSysClock();//此函数在该函数末尾#ifdefVECT_TAB_SRAMSCB->VTOR=SRAM_BASE|VECT_TAB_OFFSET;/*VectorTableRelocationinInternalSRAM.*/#elseSCB->VTOR=FLASH_BASE|VECT_TAB_OFFSET;/*VectorTableRelocationinInternalFLASH.*/#endif}staticvoidSetSysClock(void){//根据宏定义来设置时钟。#ifdefSYSCLK_FREQ_HSESetSysClockToHSE();#elifdefinedSYSCLK_FREQ_24MHzSetSysClockTo24();#elifdefinedSYSCLK_FREQ_36MHzSetSysClockTo36();#elifdefinedSYSCLK_FREQ_48MHzSetSysClockTo48();#elifdefinedSYSCLK_FREQ_56MHzSetSysClockTo56();#elifdefinedSYSCLK_FREQ_72MHzSetSysClockTo72();//以设置成最大频率72MHZ为例#endif/*Ifnoneofthedefineaboveisenabled,theHSIisusedasSystemclocksource(defaultafterreset)*/}staticvoidSetSysClockTo72(void){__IOuint32_tStartUpCounter=0,HSEStatus=0;/*SYSCLK,HCLK,PCLK2andPCLK1configuration---------------------------*//*EnableHSE*/RCC->CR|=((uint32_t)RCC_CR_HSEON);/*WaittillHSEisreadyandifTimeoutisreachedexit*/do{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;}else{HSEStatus=(uint32_t)0x00;}if(HSEStatus==(uint32_t)0x01){/*EnablePrefetchBuffer*/FLASH->ACR|=FLASH_ACR_PRFTBE;/*Flash2waitstate*/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;#ifdefSTM32F10X_CL/*ConfigurePLLs------------------------------------------------------*//*PLL2configuration:PLL2CLK=(HSE/5)*8=40MHz*//*PREDIV1configuration:PREDIV1CLK=PLL2/5=8MHz*/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);/*EnablePLL2*/RCC->CR|=RCC_CR_PLL2ON;/*WaittillPLL2isready*/while((RCC->CR&RCC_CR_PLL2RDY)==0){}/*PLLconfiguration:PLLCLK=PREDIV1*9=72MHz*/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/*PLLconfiguration:PLLCLK=HSE*9=72MHz*/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*//*EnablePLL*/RCC->CR|=RCC_CR_PLLON;/*WaittillPLLisready*/while((RCC->CR&RCC_CR_PLLRDY)==0){}/*SelectPLLassystemclocksource*/RCC->CFGR&=(uint32_t)((uint32_t)~(RCC_CFGR_SW));RCC->CFGR|=(uint32_t)RCC_CFGR_SW_PLL;/*WaittillPLLisusedassystemclocksource*/while((RCC->CFGR&(uint32_t)RCC_CFGR_SWS)!=(uint32_t)0x08){}}else{/*IfHSEfailstostart-up,theapplicationwillhavewrongclockconfiguration.Usercanaddheresomecodetodealwiththiserror*/}}