STM32f429在啟動時會在startup_stm32f429_439xx.s中調用static void SetSysClock(void)函數。默認使用的是25M晶振,把系統時鍾設置為180M.
在system_stm32f4xx.c中給出了相關的默認時鍾參數設置。static void SetSysClock(void)函數執行的就是這個參數設置的過程。
*============================================================================= * Supported STM32F42xxx/43xxx devices *----------------------------------------------------------------------------- * System Clock source | PLL (HSE) *----------------------------------------------------------------------------- * SYSCLK(Hz) | 180000000 *----------------------------------------------------------------------------- * HCLK(Hz) | 180000000 *----------------------------------------------------------------------------- * AHB Prescaler | 1 *----------------------------------------------------------------------------- * APB1 Prescaler | 4 *----------------------------------------------------------------------------- * APB2 Prescaler | 2 *----------------------------------------------------------------------------- * HSE Frequency(Hz) | 25000000 *----------------------------------------------------------------------------- * PLL_M | 25 *----------------------------------------------------------------------------- * PLL_N | 360 *----------------------------------------------------------------------------- * PLL_P | 2 *----------------------------------------------------------------------------- * PLL_Q | 7 *----------------------------------------------------------------------------- * PLLI2S_N | NA *----------------------------------------------------------------------------- * PLLI2S_R | NA *----------------------------------------------------------------------------- * I2S input clock | NA *----------------------------------------------------------------------------- * VDD(V) | 3.3 *----------------------------------------------------------------------------- * Main regulator output voltage | Scale1 mode *----------------------------------------------------------------------------- * Flash Latency(WS) | 5 *----------------------------------------------------------------------------- * Prefetch Buffer | ON *----------------------------------------------------------------------------- * Instruction cache | ON *----------------------------------------------------------------------------- * Data cache | ON *----------------------------------------------------------------------------- * Require 48MHz for USB OTG FS, | Disabled * SDIO and RNG clock | *----------------------------------------------------------------------------- *=============================================================================
假設外部晶振改成了其他的數值比如說8M ,要修改 "stm32f4xx.h " 文件中的 "HSE_VALUE" 宏定義。
如果程序在運行過程中動態修改了PLL倍頻系數,或者切換了時鍾源,請務必執行一次 SystemCoreClockUpdate()函數,這個函數會自動根據PLL倍頻參數計算出實際的主頻。
void SystemCoreClockUpdate(void)函數會檢測 RCC clock configurat ion register (RCC_CFGR)寄存器的 Bits 3:2 這兩位是只讀的,由硬件清除和設置,不能軟件寫入。

Bits 3:2 SWS: System clock switch status
Set and cleared by hardware to indicate which clock source is used as the system clock.
00: HSI oscillator used as the system clock
01: HSE oscillator used as the system clock
10: PLL used as the system clock
11: not applicable
根據這兩位通過置swtich語句分析設置源的選擇,進一步進行設置,如果是用PLL還要讀取RCC_PLLCFGR寄存器的值
獲取P N M PLLSRC等參數,來更新系統時鍾。系統時鍾SYSCLK 有下列公式決定。
PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N
SYSCLK = PLL_VCO / PLL_P
最后獲得HCLK frequency :
tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
/* HCLK frequency */
SystemCoreClock >>= tmp;
void SystemCoreClockUpdate(void) { uint32_t tmp = 0, pllvco = 0, pllp = 2, pllsource = 0, pllm = 2; #if defined(STM32F446xx) uint32_t pllr = 2; #endif /* STM32F446xx */ /* Get SYSCLK source -------------------------------------------------------*/ tmp = RCC->CFGR & RCC_CFGR_SWS; switch (tmp) { case 0x00: /* HSI used as system clock source */ SystemCoreClock = HSI_VALUE; break; case 0x04: /* HSE used as system clock source */ SystemCoreClock = HSE_VALUE; break; case 0x08: /* PLL P used as system clock source */ /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N SYSCLK = PLL_VCO / PLL_P */ pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) >> 22; pllm = RCC->PLLCFGR & RCC_PLLCFGR_PLLM; #if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F401xx) || defined(STM32F446xx) || defined(STM32F469_479xx) if (pllsource != 0) { /* HSE used as PLL clock source */ pllvco = (HSE_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6); } else { /* HSI used as PLL clock source */ pllvco = (HSI_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6); } #elif defined(STM32F410xx) || defined(STM32F411xE) #if defined(USE_HSE_BYPASS) if (pllsource != 0) { /* HSE used as PLL clock source */ pllvco = (HSE_BYPASS_INPUT_FREQUENCY / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6); } #else if (pllsource == 0) { /* HSI used as PLL clock source */ pllvco = (HSI_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6); } #endif /* USE_HSE_BYPASS */ #endif /* STM32F40_41xxx || STM32F427_437xx || STM32F429_439xx || STM32F401xx || STM32F446xx || STM32F469_479xx */ pllp = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLP) >>16) + 1 ) *2; SystemCoreClock = pllvco/pllp; break; #if defined(STM32F446xx) case 0x0C: /* PLL R used as system clock source */ /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N SYSCLK = PLL_VCO / PLL_R */ pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) >> 22; pllm = RCC->PLLCFGR & RCC_PLLCFGR_PLLM; if (pllsource != 0) { /* HSE used as PLL clock source */ pllvco = (HSE_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6); } else { /* HSI used as PLL clock source */ pllvco = (HSI_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6); } pllr = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLR) >>28) + 1 ) *2; SystemCoreClock = pllvco/pllr; break; #endif /* STM32F446xx */ default: SystemCoreClock = HSI_VALUE; break; } /* Compute HCLK frequency --------------------------------------------------*/ /* Get HCLK prescaler */ tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)]; /* HCLK frequency */ SystemCoreClock >>= tmp; }
另外也可以自己實現兩個設置時鍾的函數:
/* * 使用HSE時,設置系統時鍾的步驟 * 1、開啟HSE ,並等待 HSE 穩定 * 2、設置 AHB、APB2、APB1的預分頻因子 * 3、設置PLL的時鍾來源 * 設置VCO輸入時鍾 分頻因子 m * 設置VCO輸出時鍾 倍頻因子 n * 設置PLLCLK時鍾分頻因子 p * 設置OTG FS,SDIO,RNG時鍾分頻因子 q * 4、開啟PLL,並等待PLL穩定 * 5、把PLLCK切換為系統時鍾SYSCLK * 6、讀取時鍾切換狀態位,確保PLLCLK被選為系統時鍾 */ /* * m: VCO輸入時鍾 分頻因子,取值2~63 * n: VCO輸出時鍾 倍頻因子,取值192~432 * p: PLLCLK時鍾分頻因子 ,取值2,4,6,8 * q: OTG FS,SDIO,RNG時鍾分頻因子,取值4~15 * 函數調用舉例,使用HSE設置時鍾 * SYSCLK=HCLK=180M,PCLK2=HCLK/2=90M,PCLK1=HCLK/4=45M * HSE_SetSysClock(25, 360, 2, 7); * HSE作為時鍾來源,經過PLL倍頻作為系統時鍾,這是通常的做法 * 系統時鍾超頻到216M爽一下 * HSE_SetSysClock(25, 432, 2, 9); */ void HSE_SetSysClock(uint32_t m, uint32_t n, uint32_t p, uint32_t q) { __IO uint32_t HSEStartUpStatus = 0; // 使能HSE,開啟外部晶振,秉火F429使用 HSE=25M RCC_HSEConfig(RCC_HSE_ON); // 等待HSE啟動穩定 HSEStartUpStatus = RCC_WaitForHSEStartUp(); if (HSEStartUpStatus == SUCCESS) { // 調壓器電壓輸出級別配置為1,以便在器件為最大頻率 // 工作時使性能和功耗實現平衡 RCC->APB1ENR |= RCC_APB1ENR_PWREN; PWR->CR |= PWR_CR_VOS; // HCLK = SYSCLK / 1 RCC_HCLKConfig(RCC_SYSCLK_Div1); // PCLK2 = HCLK / 2 RCC_PCLK2Config(RCC_HCLK_Div2); // PCLK1 = HCLK / 4 RCC_PCLK1Config(RCC_HCLK_Div4); // 如果要超頻就得在這里下手啦 // 設置PLL來源時鍾,設置VCO分頻因子m,設置VCO倍頻因子n, // 設置系統時鍾分頻因子p,設置OTG FS,SDIO,RNG分頻因子q RCC_PLLConfig(RCC_PLLSource_HSE, m, n, p, q); // 使能PLL RCC_PLLCmd(ENABLE); // 等待 PLL穩定 while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) { } /*-----------------------------------------------------*/ //開啟 OVER-RIDE模式,以能達到更高頻率 PWR->CR |= PWR_CR_ODEN; while((PWR->CSR & PWR_CSR_ODRDY) == 0) { } PWR->CR |= PWR_CR_ODSWEN; while((PWR->CSR & PWR_CSR_ODSWRDY) == 0) { } // 配置FLASH預取指,指令緩存,數據緩存和等待狀態 FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_5WS; /*-----------------------------------------------------*/ // 當PLL穩定之后,把PLL時鍾切換為系統時鍾SYSCLK RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); // 讀取時鍾切換狀態位,確保PLLCLK被選為系統時鍾 while (RCC_GetSYSCLKSource() != 0x08) { } } else { // HSE啟動出錯處理 while (1) { } } } /* * 使用HSI時,設置系統時鍾的步驟 * 1、開啟HSI ,並等待 HSI 穩定 * 2、設置 AHB、APB2、APB1的預分頻因子 * 3、設置PLL的時鍾來源 * 設置VCO輸入時鍾 分頻因子 m * 設置VCO輸出時鍾 倍頻因子 n * 設置SYSCLK時鍾分頻因子 p * 設置OTG FS,SDIO,RNG時鍾分頻因子 q * 4、開啟PLL,並等待PLL穩定 * 5、把PLLCK切換為系統時鍾SYSCLK * 6、讀取時鍾切換狀態位,確保PLLCLK被選為系統時鍾 */ /* * m: VCO輸入時鍾 分頻因子,取值2~63 * n: VCO輸出時鍾 倍頻因子,取值192~432 * p: PLLCLK時鍾分頻因子 ,取值2,4,6,8 * q: OTG FS,SDIO,RNG時鍾分頻因子,取值4~15 * 函數調用舉例,使用HSI設置時鍾 * SYSCLK=HCLK=180M,PCLK2=HCLK/2=90M,PCLK1=HCLK/4=45M * HSI_SetSysClock(16, 360, 2, 7); * HSE作為時鍾來源,經過PLL倍頻作為系統時鍾,這是通常的做法 * 系統時鍾超頻到216M爽一下 * HSI_SetSysClock(16, 432, 2, 9); */ void HSI_SetSysClock(uint32_t m, uint32_t n, uint32_t p, uint32_t q) { __IO uint32_t HSIStartUpStatus = 0; // 把RCC外設初始化成復位狀態 RCC_DeInit(); //使能HSI, HSI=16M RCC_HSICmd(ENABLE); // 等待 HSI 就緒 HSIStartUpStatus = RCC->CR & RCC_CR_HSIRDY; // 只有 HSI就緒之后則繼續往下執行 if (HSIStartUpStatus == RCC_CR_HSIRDY) { // 調壓器電壓輸出級別配置為1,以便在器件為最大頻率 // 工作時使性能和功耗實現平衡 RCC->APB1ENR |= RCC_APB1ENR_PWREN; PWR->CR |= PWR_CR_VOS; // HCLK = SYSCLK / 1 RCC_HCLKConfig(RCC_SYSCLK_Div1); // PCLK2 = HCLK / 2 RCC_PCLK2Config(RCC_HCLK_Div2); // PCLK1 = HCLK / 4 RCC_PCLK1Config(RCC_HCLK_Div4); // 如果要超頻就得在這里下手啦 // 設置PLL來源時鍾,設置VCO分頻因子m,設置VCO倍頻因子n, // 設置系統時鍾分頻因子p,設置OTG FS,SDIO,RNG分頻因子q RCC_PLLConfig(RCC_PLLSource_HSI, m, n, p, q); // 使能PLL RCC_PLLCmd(ENABLE); // 等待 PLL穩定 while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) { } /*-----------------------------------------------------*/ //開啟 OVER-RIDE模式,以能達到更高頻率 PWR->CR |= PWR_CR_ODEN; while((PWR->CSR & PWR_CSR_ODRDY) == 0) { } PWR->CR |= PWR_CR_ODSWEN; while((PWR->CSR & PWR_CSR_ODSWRDY) == 0) { } // 配置FLASH預取指,指令緩存,數據緩存和等待狀態 FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS; /*-----------------------------------------------------*/ // 當PLL穩定之后,把PLL時鍾切換為系統時鍾SYSCLK RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); // 讀取時鍾切換狀態位,確保PLLCLK被選為系統時鍾 while (RCC_GetSYSCLKSource() != 0x08) { } } else { // HSI啟動出錯處理 while (1) { } } }
