在前幾天的文章《晶振原理解析》中介紹了晶振如何產生時鐘的,板子使用的是25M無源晶振,下文將介紹STM32F207的時鐘系統如何將25M晶振時鐘轉換為120M系統主頻時鐘的。
01、時鐘系統介紹
▲時鐘系統專業名詞縮寫
時鐘系統關鍵組成部分
01 內部高速時鐘(HSI)
HSI時鐘訊號可以通過內部16MHZ的RC振盪器產生,可以直接用於系統時鐘或者用於PLL輸入。
HSI的RC振盪器的優勢是:在最小成本(沒有外部器件)情況下提供一個時鐘源。它的啟動速度要比HSE晶體振盪器更快,但是即使校準頻率後,它的精度仍然小於外部晶體振盪器或陶瓷諧振器。
02 外部高速時鐘(HSE)
外部高速時鐘資訊(HSE)可以通過兩個時鐘源產生:
① 外部晶體/陶瓷諧振器
② 外部使用者時鐘
▲兩種時鐘源接入示意圖
03 主鎖相環時鐘(PLL)
STM32F2xx具有兩個PLL
① 主要的PLL通過HSE或HSI提供時鐘,並且有兩個輸出時鐘;
② 專用的PLL(PLLI2S)被用於產生一個精確的時鐘去實現高質量音訊效果在I2S介面;
HSE/M*N/P得到PLL時鐘
關於PLL鎖相環說明
從1處輸入,3處輸出是1的N倍。
3處除以N又作為輸入,當1和2的頻率一樣,就鎖定了。(之所以圖上是xN,因為從2看向3的)
04 低速外部時鐘(LSE)
LSE是一個32.768KHZ低速外部晶振或陶瓷諧振器。
它的優點:提供低速但是高精度時鐘給RTC外設,為時鐘/日曆或其他時間應用。
05低速內部時鐘(LSI)
LSI RC作為一個低速時鐘源,它可以執行在停止和待機模式中給獨立看門狗(IWDG)和自動喚醒(AWU)。它的時脈頻率在32MHZ左右。
02、程式碼分析
時鐘初始化程式碼在system_stm32f2xx.c檔案中,大部分時候我們不需要修改時鐘程式碼的,各個匯流排的頻率我們可以在檔案頭看到。
============================================================================= *============================================================================= * Supported STM32F2xx device revision | Rev B and Y *----------------------------------------------------------------------------- * System Clock source | PLL (HSE) *----------------------------------------------------------------------------- * SYSCLK(Hz) | 120000000 *----------------------------------------------------------------------------- * HCLK(Hz) | 120000000 *----------------------------------------------------------------------------- * AHB Prescaler | 1 *----------------------------------------------------------------------------- * APB1 Prescaler | 4 *----------------------------------------------------------------------------- * APB2 Prescaler | 2 *----------------------------------------------------------------------------- * HSE Frequency(Hz) | 25000000 *----------------------------------------------------------------------------- * PLL_M | 25 *----------------------------------------------------------------------------- * PLL_N | 240 *----------------------------------------------------------------------------- * PLL_P | 2 *----------------------------------------------------------------------------- * PLL_Q | 5 *----------------------------------------------------------------------------- * PLLI2S_N | NA *----------------------------------------------------------------------------- * PLLI2S_R | NA *----------------------------------------------------------------------------- * I2S input clock | NA *----------------------------------------------------------------------------- * VDD(V) | 3.3 *----------------------------------------------------------------------------- * Flash Latency(WS) | 3 *----------------------------------------------------------------------------- * Prefetch Buffer | ON *----------------------------------------------------------------------------- * Instruction cache | ON *----------------------------------------------------------------------------- * Data cache | ON *----------------------------------------------------------------------------- * Require 48MHz for USB OTG FS, | Enabled * SDIO and RNG clock | *----------------------------------------------------------------------------- *============================================================================= ******************************************************************************
在檔案開始定義的有系統時脈頻率的全域性變數SystemCoreClock,其他地方需要時脈頻率,可以直接使用該變數。
uint32_t SystemCoreClock = 120000000;
時鐘配置從SystemInit函式執行,呼叫SystemInit的在彙編檔案中startup_stm32f2xx.s(Keil編譯環境)。
IMPORT __main LDR R0, =SystemInit BLX R0 LDR R0, =__main BX R0 ENDP
在這裡說明一下文件版本的問題:
▲STM32F20X_User_manual的V7版和V8版對比圖
上述兩圖的區別是系統最大時鐘從120MHZ變成了168MHZ,我的理解是同樣是STM32F20X,ST由於技術進步或其他,使得新版STM32F207晶片超頻支援168MHZ。
文件下載地址:
https://www.st.com/en/microcontrollers-microprocessors/stm32f2x7.html#resource
線上預覽地址:
下面我們主要分析SystemCoreClock的120M時鐘怎麼從一個外部25MHZ的HSE得到的。
我們要從25MHZ的外部時鐘得到120M的系統時鐘,需要上圖中標註的重要4點:
1、使能HSE
2、選擇HSE作為主PLL的輸入時鐘
3、主PLL倍頻後得到120MHZ時鐘
4、系統時鐘選擇主PLL時鐘輸出作為系統時鐘
我們找到對應的程式碼
1、使能HSE
/* Enable HSE */ RCC->CR |= ((uint32_t)RCC_CR_HSEON);
在RCC_CR暫存器(RCCclock control register RCC時鐘控制器)中,有開啟HSE的控制位
輸入時鐘
/* Configure the main PLL */ RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) | (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
RCC_PLLCFGR_PLLSRC_HSE就是配置HSE作為主PLL的輸入時鐘
3、主PLL倍頻後得到120MHZ時鐘
/* Configure the main PLL */ RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) | (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
4、配置主PLL作為系統時鐘的輸入時鐘
/* Select the main PLL as system clock source */ RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); RCC->CFGR |= RCC_CFGR_SW_PL
對於主PLL的配置暫存器,在RCC_PLLCFGR暫存器中有說明
整理後得知f(out)=f(in)* N / M / P
/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */ #define PLL_M 25 #define PLL_N 240 /* SYSCLK = PLL_VCO / PLL_P */ #define PLL_P 2
這樣就獲得了120M時鐘
注意:
PLL_M大於等於2且小於等於63
PLL_N大於等於64且小於等於432
PLL_P只能是2、4、6、或8
但2對應0,4對應1,6對應2,8對應3。
ST並沒有使用if或case語句判斷,因為對應的資料除以2減去1就是暫存器這兩位的值,所以可以按照下面這樣寫,這種寫法值得我們學習。
(((PLL_P >> 1) -1) << 16)
其他外設的時鐘配置時
/* 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;
03、備 注
時鐘中斷
可以配置外部晶振出錯時的中斷,還有RCC中斷,因此我們可以在外部時鐘出問題時,切換為內部時鐘,不至於整個系統掛掉。具體見ST給的官方程式碼。
無源晶振不起振
沒有程式,無源晶振是不起振的,需要配置RCC時鐘控制暫存器的HSEON位開啟或關閉HSE振盪器。具體可以看之前的文章《晶振原理解析》。
關於APB和PCLK
F207是時鐘圖沒有顯示PCLK1和PCLK2,應該就是APB1和APB2
應該指的是一個PCLK應該是PeripheralClock的簡稱,看F105手冊
點選檢視本文所在的專輯,STM32F207教程