Cotex-M3內核STM32F10XX系列時鐘及其配置方法
一、背景
最近做個項目,需要使用STM32,還是以前一樣的觀點,時鐘就是MCU心臟,供血即時鐘頻率輸出,想要弄明白一個MCU,時鐘是一個非常好的切入點。言歸正傳,網上已經有太多大神詳述過STM32的詳細配置方法了,在此就簡單介紹下STM32時鐘系統(tǒng),以及如何配置做個簡單記錄,方便以后的快速開發(fā)。
二、正文
廢話不多說,上一張STM32F10xx的時鐘樹圖:
由圖可知,STM32F10XX有兩級時鐘
第一級時鐘
* 高速內部時鐘(HSI)
* 鎖相環(huán)時鐘(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自身要能正常運作,即需要一個時鐘,這個時鐘既是系統(tǒng)時鐘(SYSCLK),而基本上所有外設的時鐘均來自于這個系統(tǒng)時鐘(SYSCLk)。然后由系統(tǒng)時鐘對外提供各種外設時鐘。詳見圖。
當然,也有例外,USB時鐘必須為48MHZ,這里的USB時鐘(USBCLK)由PLLCLK直接提供,RTC時鐘(RTCCLK)也不是來源于系統(tǒng)時鐘(SYSCLK),詳見圖?! ?/p>
時鐘結構大體也就如此,不再深究,網上有許多更加深入的講解,接下來說說如何去配置。用代碼來說明問題:
先貼文件"system_stm32f10x.c",此文件即庫文件。里面有一個很重要的函數"SystemInit()"
解析過STM32啟動代碼的朋友都應該知道,這個函數跑在進入main函數之前,里面做的事情即是配置系統(tǒng)時鐘。代碼如下:
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*/}}