STM32F4如何設定系統時鐘,非常重要
阿新 • • 發佈:2019-02-16
STM32F4系統時鐘樹
STM32F4的系統時鐘非常重要,涉及到整個系統的執行結果,無論是什麼操作,都需要時鐘訊號,不同型號的微控制器的預設系統時鐘配置是不同的,這裡,給出兩種配置STM32F407系統時鐘的方法。
方法一,採用官方庫提供的配置(這裡外部晶振8MHz,系統配置為168MHz)
- STM32F4啟動與STM32F10X不同,時鐘已經預設配置好
- 啟動程式碼,檔案:startup_stm32f4xx.s
Reset_Handler PROC EXPORT Reset_Handler [WEAK] IMPORT SystemInit IMPORT __main LDR R0, =SystemInit BLX R0 LDR R0, =__main BX R0 ENDP
可以看出,在進入main函式之前,系統呼叫了SystemInit函式.
- SystemInit函式分析:SystemInit函式位於system_stm32f4xx.c檔案中.此檔案提供幾個巨集定義可以設定各個時鐘:
我使用的是STM32F407,篩選可用資訊如下:/************************* PLL Parameters *************************************/ #if defined (STM32F40_41xxx) || defined (STM32F427_437xx) || defined (STM32F429_439xx) || defined (STM32F401xx) /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */ #define PLL_M 8 #else /* STM32F411xE */ #if defined (USE_HSE_BYPASS) #define PLL_M 8 #else /* STM32F411xE */ #define PLL_M 16 #endif /* USE_HSE_BYPASS */ #endif /* STM32F40_41xxx || STM32F427_437xx || STM32F429_439xx || STM32F401xx */ /* USB OTG FS, SDIO and RNG Clock = PLL_VCO / PLLQ */ #define PLL_Q 7 #if defined (STM32F40_41xxx) #define PLL_N 336 /* SYSCLK = PLL_VCO / PLL_P */ #define PLL_P 2 //2 //2---168M 4---84M #endif /* STM32F40_41xxx */ #if defined (STM32F427_437xx) || defined (STM32F429_439xx) #define PLL_N 360 /* SYSCLK = PLL_VCO / PLL_P */ #define PLL_P 2 #endif /* STM32F427_437x || STM32F429_439xx */ #if defined (STM32F401xx) #define PLL_N 336 /* SYSCLK = PLL_VCO / PLL_P */ #define PLL_P 4 #endif /* STM32F401xx */ #if defined (STM32F411xE) #define PLL_N 400 /* SYSCLK = PLL_VCO / PLL_P */ #define PLL_P 4 #endif /* STM32F411xx */ /******************************************************************************/
/************************* PLL Parameters *************************************/ /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */ #define PLL_M 8 #define PLL_N 336 /* SYSCLK = PLL_VCO / PLL_P */ #define PLL_P 2 /* USB OTG FS, SDIO and RNG Clock = PLL_VCO / PLLQ */ #define PLL_Q 7 /******************************************************************************/
而晶振頻率則是在檔案stm32f4xx.h中進行設定:
外部晶振:
#if !defined (HSE_VALUE) #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ #endif /* HSE_VALUE */
- 內部晶振:
#if !defined (HSI_VALUE) #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ #endif /* HSI_VALUE */
綜上,如果使用外部晶振8MHz,則可以得出預設配置中:
鎖相環壓腔振盪器時鐘PLL_VCO =(HSE_VALUE/PLL_M)* PLL_N=8/ 8* 336 = 336MHz
系統時鐘SYSCLK = PLL_VCO / PLL_P=336 / 2 = 168MHz
USB,SD卡時鐘 = PLL_VCO / PLLQ=336 / 7 = 48MHz
- SystemInit函式程式碼:
void SystemInit(void) { /* FPU settings ------------------------------------------------------------*/ #if (__FPU_PRESENT == 1) && (__FPU_USED == 1) SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */ #endif /* Reset the RCC clock configuration to the default reset state ------------*/ /* Set HSION bit */ RCC->CR |= (uint32_t)0x00000001; /* Reset CFGR register */ RCC->CFGR = 0x00000000; /* Reset HSEON, CSSON and PLLON bits */ RCC->CR &= (uint32_t)0xFEF6FFFF; /* Reset PLLCFGR register */ RCC->PLLCFGR = 0x24003010; /* Reset HSEBYP bit */ RCC->CR &= (uint32_t)0xFFFBFFFF; /* Disable all interrupts */ RCC->CIR = 0x00000000; #if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM) SystemInit_ExtMemCtl(); #endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */ /* Configure the System clock source, PLL Multiplier and Divider factors, AHB/APBx prescalers and Flash settings ----------------------------------*/ SetSysClock(); /* Configure the Vector Table location add offset address ------------------*/ #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 }
- SetSysClock函式分析,在SetSysClock函式中,配置了系統時鐘,PLL倍頻以及分頻係數:
static void SetSysClock(void) { /******************************************************************************/ /* PLL (clocked by HSE) used as System clock source */ /******************************************************************************/ __IO uint32_t StartUpCounter = 0, HSEStatus = 0; /* 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 != HSE_STARTUP_TIMEOUT)); if ((RCC->CR & RCC_CR_HSERDY) != RESET) { HSEStatus = (uint32_t)0x01; } else { HSEStatus = (uint32_t)0x00; } if (HSEStatus == (uint32_t)0x01) { /* Select regulator voltage output Scale 1 mode, System frequency up to 168 MHz */ RCC->APB1ENR |= RCC_APB1ENR_PWREN; PWR->CR |= PWR_CR_VOS; /* HCLK = SYSCLK / 1*/ RCC->CFGR |= RCC_CFGR_HPRE_DIV1; /* PCLK2 = HCLK / 2*/ RCC->CFGR |= RCC_CFGR_PPRE2_DIV2; /* PCLK1 = HCLK / 4*/ RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; /* Configure the main PLL */ RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) | (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24); 點選開啟連結 /* Enable the main PLL */ RCC->CR |= RCC_CR_PLLON; /* Wait till the main PLL is ready */ while((RCC->CR & RCC_CR_PLLRDY) == 0) { } /* Configure Flash prefetch, Instruction cache, Data cache and wait state */ FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS; /* Select the main PLL as system clock source */ RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); RCC->CFGR |= RCC_CFGR_SW_PLL; /* Wait till the main PLL is used as system clock source */ while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL); { } } 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 */ } }
如果外部時鐘啟動失敗,系統會使用內部時鐘
預設配置:
HCLK = SYSCLK / 1 = 168MHz ,AHB匯流排時鐘
PCLK2 = HCLK / 2 = 84MHz
PCLK1 = HCLK / 4 = 42MHz定時器初始化設定時計算定時時間需要用到該定時器時鐘頻率,具體原因詳細看我整理的一篇部落格文章,連結如下:
方法二,根據需要重新進行配置(這裡外部晶振25MHz,系統配置為168MHz)
- 自己根據自己外部晶振大小和需要進行配置
/******************************************************************************* * Function Name : RCC_Configuration * Description : Configures the different system clocks. * Input : None * Output : None * Return : None *******************************************************************************/ void RCC_Configuration(void) { ErrorStatus HSEStartUpStatus; uint32_t PLL_M_Temp = 0; uint32_t PLL_N_Temp = 0; uint32_t PLL_P_Temp = 0; uint32_t PLL_Q_Temp = 0; RCC_DeInit(); //½«ËùÓÐRCCÖØÖÃΪ³õʼֵ RCC_HSEConfig(RCC_HSE_ON); HSEStartUpStatus = RCC_WaitForHSEStartUp(); //Ñ¡ÔñÍⲿ¾§Õñ(HSE)×÷ΪʱÖÓÔ´ µÈ´ýÍⲿʱÖÓ×¼±¸ºÃ if (HSEStartUpStatus == SUCCESS) //ÉèÖÃʱÖÓΪ168M { /* Enable Prefetch Buffer */ //FLASH_PrefetchBufferCmd(ENABLE); /* Flash 2 wait state */ //FLASH_SetLatency(FLASH_Latency_5); //HSE_VALUE = 8MHz,PLL_VCO input clock = (HSE_VALUE or HSI_VALUE)/PLL_M,½¨Òé´ËֵΪ1~2MHz,Òò´ËÈ¡PLL_M=8£¬ //PLL_VCO input clock = 1MHz; PLL_M_Temp = 8; //PLL_VCO output clock = (PLL_VCO input clock)*PLL_N //PLL_VCO output clock = 336; PLL_N_Temp = 336; //System Clock = (PLL_VCO output clock)/PLL_P , //System Clock = 84MHz PLL_P_Temp = 4; //´ËϵÊýÓÃÓÚÉèÖÃSD¿¨¶Áд£¬USBµÈ¹¦ÄÜ£¬ÔÝʱ²»Óà PLL_Q_Temp = 7; /* PLL configuration */ RCC_PLLConfig(RCC_PLLSource_HSE, PLL_M_Temp, PLL_N_Temp, PLL_P_Temp, PLL_Q_Temp); /* Enable PLL */ RCC_PLLCmd(ENABLE); /* Wait till PLL is ready */ while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) { } /* Select PLL as system clock source */ RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); /* Wait till PLL is used as system clock source */ while(RCC_GetSYSCLKSource() != 0x08) { } } }