【STM32】STM32F4时钟系统
00. 目錄
文章目錄
- 00. 目錄
- 01. STM32F4時鐘系統概述
- 02. STM32F4時鐘系統圖
- 03. STM32F4時鐘初始化配置
- 04. 時鐘配置總結
- 05. 預留
- 06. 附錄
- 07. 聲明
01. STM32F4時鐘系統概述
時鐘系統是 CPU 的脈搏,就像人的心跳一樣。所以時鐘系統的重要性就不言而喻了。 STM32F4 的時鐘系統比較復雜,不像簡單的 51 單片機一個系統時鐘就可以解決一切。于是有人要問,采用一個系統時鐘不是很簡單嗎?為什么 STM32 要有多個時鐘源呢? 因為首先 STM32 本身非常復雜,外設非常的多,但是并不是所有外設都需要系統時鐘這么高的頻率,比如看門狗以及 RTC 只需要幾十 k 的時鐘即可。同一個電路,時鐘越快功耗越大,同時抗電磁干擾能力也會越弱,所以對于較為復雜的 MCU 一般都是采取多時鐘源的方法來解決這些問題。
02. STM32F4時鐘系統圖
在 STM32F4 中,有 5 個最重要的時鐘源,為 HSI、HSE、LSI、LSE、PLL。其中 PLL 實際是分為兩個時鐘源,分別為主 PLL 和專用 PLL。從時鐘頻率來分可以分為高速時鐘源和低速時鐘源,在這 5 個中 HSI,HSE 以及 PLL 是高速時鐘,LSI 和 LSE 是低速時鐘。從來源可分為外部時鐘源和內部時鐘源,外部時鐘源就是從外部通過接晶振的方式獲取時鐘源,其中 HSE 和LSE 是外部時鐘源,其他的是內部時鐘源。下面我們看看 STM32F4 的這 5 個時鐘源,我們講解順序是按圖中紅圈標示的順序:
①、LSI 是低速內部時鐘,RC 振蕩器,頻率為 32kHz 左右。供獨立看門狗和自動喚醒單元使用。
②、LSE 是低速外部時鐘,接頻率為 32.768kHz 的石英晶體。這個主要是 RTC 的時鐘源。
③、HSE 是高速外部時鐘,可接石英/陶瓷諧振器,或者接外部時鐘源,頻率范圍為 4MHz~26MHz。我們的開發板接的是 8M 的晶振。HSE 也可以直接做為系統時鐘或者 PLL 輸入。
④、HSI 是高速內部時鐘,RC 振蕩器,頻率為 16MHz。可以直接作為系統時鐘或者用作 PLL輸入。
⑤、PLL 為鎖相環倍頻輸出。STM32F4 有兩個 PLL:
1) 主 PLL(PLL)由 HSE 或者 HSI 提供時鐘信號,并具有兩個不同的輸出時鐘。
第一個輸出 PLLP 用于生成高速的系統時鐘(最高 168MHz)
第二個輸出 PLLQ 用于生成 USB OTG FS 的時鐘(48MHz),隨機數發生器的時鐘和 SDIO時鐘。
2)專用 PLL(PLLI2S)用于生成精確時鐘,從而在 I2S 接口實現高品質音頻性能。
A. 這里是看門狗時鐘輸入。從圖中可以看出,看門狗時鐘源只能是低速的 LSI 時鐘。
B. 這里是 RTC 時鐘源,從圖上可以看出,RTC 的時鐘源可以選擇 LSI,LSE,以及HSE 分頻后的時鐘,HSE 分頻系數為 2~31。
C. 這里是 STM32F4 輸出時鐘 MCO1 和 MCO2。MCO1 是向芯片的 PA8 引腳輸出時鐘。它有四個時鐘來源分別為:HSI,LSE,HSE 和 PLL 時鐘。MCO2 是向芯片的PC9 輸出時鐘,它同樣有四個時鐘來源分別為:HSE,PLL,SYSCLK 以及 PLLI2S時鐘。MCO 輸出時鐘頻率最大不超過 100MHz。
D. 這里是系統時鐘。從圖 4.3.1 可以看出,SYSCLK 系統時鐘來源有三個方面:HSI,HSE 和 PLL。在我們實際應用中,因為對時鐘速度要求都比較高我們才會選用 STM32F4 這種級別的處理器,所以一般情況下,都是采用 PLL 作為 SYSCLK時鐘源。根據前面的計算公式,大家就可以算出你的系統的 SYSCLK 是多少。
E. 這里我們指的是以太網 PTP 時鐘,AHB 時鐘,APB2 高速時鐘,APB1 低速時鐘。這些時鐘都是來源于 SYSCLK 系統時鐘。其中以太網 PTP 時鐘是使用系統時鐘。AHB,APB2 和 APB1 時鐘是經過 SYSCLK 時鐘分頻得來。這里大家記住,AHB最大時鐘為168MHz, APB2高速時鐘最大頻率為84MHz,而APB1低速時鐘最大頻率為 42MHz。
F. 這里是指 I2S 時鐘源。從圖 4.3.1 可以看出,I2S 的時鐘源來源于 PLLI2S 或者映射到 I2S_CKIN 引腳的外部時鐘。I2S 出于音質的考慮,對時鐘精度要求很高。探索者 STM32F4 開發板使用的是內部 PLLI2SCLK。
G. 這是 STM32F4 內部以太網 MAC 時鐘的來源。對于 MII 接口來說,必須向外部PHY 芯片提供 25Mhz 的時鐘,這個時鐘,可以由 PHY 芯片外接晶振,或者使用STM32F4 的 MCO 輸出來提供。然后,PHY 芯片再給 STM32F4 提供ETH_MII_TX_CLK 和 ETH_MII_RX_CLK 時鐘。對于 RMII 接口來說,外部必須提供 50Mhz 的時鐘驅動 PHY 和 STM32F4 的 ETH_RMII_REF_CLK,這個 50Mhz時鐘可以來自 PHY、有源晶振或者 STM32F4 的 MCO。我們的開發板使用的是RMII 接 口 , 使 用 PHY 芯 片 提 供 50Mhz 時 鐘 驅 動 STM32F4 的ETH_RMII_REF_CLK。
H. 這里是指外部 PHY 提供的 USB OTG HS(60MHZ)時鐘。
03. STM32F4時鐘初始化配置
STM32F4 時鐘系統初始化是在 system_stm32f4xx.c 中的 SystemInit()函數中完成的。對于系統時鐘關鍵寄存器設置主要是在 SystemInit 函數中調用 SetSysClock()函數來設置的。我們可以先看看 SystemInit ()函數體。
/*** @brief Setup the microcontroller system* Initialize the Embedded Flash Interface, the PLL and update the * SystemFrequency variable.* @param None* @retval None*/ 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_SRAMSCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */ #elseSCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */ #endif }在設置完相關寄存器后,接下來 SystemInit 函數內部會調用 SetSysClock 函數。
/*** @brief Configures the System clock source, PLL Multiplier and Divider factors, * AHB/APBx prescalers and Flash settings* @Note This function should be called only once the RCC clock configuration * is reset to the default reset state (done in SystemInit() function). * @param None* @retval None*/ static void SetSysClock(void) { #if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F401xx) || defined(STM32F412xG) || defined(STM32F413_423xx) || defined(STM32F446xx)|| defined(STM32F469_479xx) /******************************************************************************/ /* PLL (clocked by HSE) used as System clock source */ /******************************************************************************/__IO uint32_t StartUpCounter = 0, HSEStatus = 0;/* Enable HSE */ //HSE時鐘使能RCC->CR |= ((uint32_t)RCC_CR_HSEON);//等待HSE時鐘穩定/* 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 */RCC->APB1ENR |= RCC_APB1ENR_PWREN;PWR->CR |= PWR_CR_VOS;//AHB不分頻/* HCLK = SYSCLK / 1*/RCC->CFGR |= RCC_CFGR_HPRE_DIV1;#if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F412xG) || defined(STM32F446xx) || defined(STM32F469_479xx) /* PCLK2 = HCLK / 2*/ //高速APB二分頻RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;/* PCLK1 = HCLK / 4*/ //低速APB4分頻RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; #endif /* STM32F40_41xxx || STM32F427_437x || STM32F429_439xx || STM32F412xG || STM32F446xx || STM32F469_479xx */#if defined(STM32F401xx) || defined(STM32F413_423xx)/* PCLK2 = HCLK / 1*/RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;/* PCLK1 = HCLK / 2*/RCC->CFGR |= RCC_CFGR_PPRE1_DIV2; #endif /* STM32F401xx || STM32F413_423xx */#if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F401xx) || defined(STM32F469_479xx) /* Configure the main PLL */RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |(RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24); #endif /* STM32F40_41xxx || STM32F401xx || STM32F427_437x || STM32F429_439xx || STM32F469_479xx */#if defined(STM32F412xG) || defined(STM32F413_423xx) || defined(STM32F446xx)/* Configure the main PLL */RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |(RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24) | (PLL_R << 28); #endif /* STM32F412xG || STM32F413_423xx || STM32F446xx */ /* Enable the main PLL */RCC->CR |= RCC_CR_PLLON;/* Wait till the main PLL is ready */while((RCC->CR & RCC_CR_PLLRDY) == 0){}#if defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F446xx) || defined(STM32F469_479xx)/* Enable the Over-drive to extend the clock frequency to 180 Mhz */PWR->CR |= PWR_CR_ODEN;while((PWR->CSR & PWR_CSR_ODRDY) == 0){}PWR->CR |= PWR_CR_ODSWEN;while((PWR->CSR & PWR_CSR_ODSWRDY) == 0){} /* Configure Flash prefetch, Instruction cache, Data cache and wait state */FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS; #endif /* STM32F427_437x || STM32F429_439xx || STM32F446xx || STM32F469_479xx */#if defined(STM32F40_41xxx) || defined(STM32F412xG) /* Configure Flash prefetch, Instruction cache, Data cache and wait state */FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS; #endif /* STM32F40_41xxx || STM32F412xG */#if defined(STM32F413_423xx) /* Configure Flash prefetch, Instruction cache, Data cache and wait state */FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_3WS; #endif /* STM32F413_423xx */#if defined(STM32F401xx)/* Configure Flash prefetch, Instruction cache, Data cache and wait state */FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_2WS; #endif /* STM32F401xx *//* 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 clockconfiguration. User can add here some code to deal with this error */} #elif defined(STM32F410xx) || defined(STM32F411xE) #if defined(USE_HSE_BYPASS) /******************************************************************************/ /* PLL (clocked by HSE) used as System clock source */ /******************************************************************************/__IO uint32_t StartUpCounter = 0, HSEStatus = 0;/* Enable HSE and HSE BYPASS */RCC->CR |= ((uint32_t)RCC_CR_HSEON | RCC_CR_HSEBYP);/* 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 */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_DIV1;/* PCLK1 = HCLK / 4*/RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;/* 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_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_2WS;/* 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 clockconfiguration. User can add here some code to deal with this error */} #else /* HSI will be used as PLL clock source *//* Select regulator voltage output Scale 1 mode */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_DIV1;/* PCLK1 = HCLK / 4*/RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;/* Configure the main PLL */RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) | (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_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_2WS;/* 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);{} #endif /* USE_HSE_BYPASS */ #endif /* STM32F40_41xxx || STM32F427_437xx || STM32F429_439xx || STM32F401xx || STM32F469_479xx */ }先使能外部時鐘 HSE,等待 HSE 穩定之后,配置AHB,APB1,APB2 時鐘相關的分頻因子,也就是相關外設的時鐘。等待這些都配置完成之后,打開主 PLL 時鐘,然后設置主 PLL 作為系統時鐘 SYSCLK 時鐘源。如果 HSE 不能達到就緒狀態(比如外部晶振不能穩定或者沒有外部晶振),那么依然會是 HSI 作為系統時鐘。
在這里要特別提出來,在設置主 PLL 時鐘的時候,會要設置一系列的分頻系數和倍頻系數參數。大家可以從 SetSysClock 函數的這行代碼看出:
/* Configure the main PLL */RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |(RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);這些參數是通過宏定義標識符的值來設置的。默認的配置在 System_stm32f4xx.c 文件開頭的地方配置。對于我們開發板,我們的設置參數值如下:
#define PLL_M 8 #define PLL_Q 7 #define PLL_N 336 #define PLL_P 2這里還有個特別需要注意的地方,就是我們還要同步修改 stm32f4xx.h 中宏定義標識符HSE_VALUE 的值為我們的外部時鐘:
#if !defined (HSE_VALUE) #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ #endif /* HSE_VALUE */這里默認固件庫配置的是 25000000,我們外部時鐘為 8MHz,所以我們根據我們硬件情況修改為 8000000 即可。
04. 時鐘配置總結
最后我們總結一下 SystemInit()函數中設置的系統時鐘大小:
SYSCLK(系統時鐘) =168MHz
AHB 總線時鐘(HCLK=SYSCLK) =168MHz
APB1 總線時鐘(PCLK1=SYSCLK/4) =42MHz
APB2 總線時鐘(PCLK2=SYSCLK/2) =84MHz
PLL 主時鐘 =168MHz
05. 預留
06. 附錄
6.1 【STM32】STM32系列教程匯總
網址:【STM32】STM32系列教程匯總
07. 聲明
總結
以上是生活随笔為你收集整理的【STM32】STM32F4时钟系统的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【STM32】时钟
- 下一篇: 【STM32】SysTick定时器