概述
????????本文主要描述了STM32F103初始化過程系統時鐘的初始化,主要描述了系統時鐘的初始化,AHB總線時鐘,APB總線時鐘等的初始化。
硬件板卡3d圖
時鐘樹
STM32F103的時鐘樹,如下所示:
時鐘源選擇
從STM32F103的時鐘樹框圖,我們可以看到:
1、有可選的1路高速外部時鐘接口,作為系統時鐘的時鐘源;
2、1路32.768的可選低速時鐘,作為系統RTC和watchdog的時鐘源;
3、1路內部的可選8M 高速時鐘,作為系統時鐘的時鐘源;
系統時鐘選擇
根據時鐘樹所示,可選的系統的時鐘選擇,如下所示:
1、內部8M的HSI直接作為系統的時鐘源,如果使用HSI作為系統時鐘源的話,最大SYSCLK只能輸出到64MHz;
2、HSI或者HSE的通過PLL的倍頻后,作為系統時鐘源;
3、HSE的輸出,直接作為系統的時鐘源;
通過系統時鐘源的來源描述,系統的時鐘源可以根據硬件板卡的制作情況,進行選擇;作者自己設計的PCB板子上,因為沒有連接外部晶振,因此將HSI作為系統的時鐘源選擇。后續的時鐘初始化代碼分析,會講解怎么將HSI設置為系統的時鐘源;
其他外設時鐘
根據STM32F103的時鐘樹,其他外設控制器的時鐘的來源如下所示:
1、USB控制器的時鐘,直接來源于PLLCLK,然后經過USB預分頻,最終達到48M的時鐘輸出,作為USB控制器的時鐘;
2、I2S音頻控制器的時鐘,直接來源于SYSCLK, 和SYSCLK的時鐘相同;
3、SDIO, FSMC, HCLK 等時鐘,直接來自于AHB總線的時鐘輸出;
4、剩余外設的時鐘自于APB1或者APB2,這里不再這里詳細描述;
時鐘初始化設置
由于作者自己設計的硬件板子,使用了內部的8M作為整個CPU的時鐘源,因此,下面以使用內部8M的高速時鐘的情況,進行源碼講解,設置源碼如下所示:
void SystemClock_Config(void)
{RCC_ClkInitTypeDef clkinitstruct = {0};RCC_OscInitTypeDef oscinitstruct = {0};/* Configure PLL ------------------------------------------------------*//* PLL configuration: PLLCLK = (HSI / 2) * PLLMUL = (8 / 2) * 16 = 64 MHz *//* PREDIV1 configuration: PREDIV1CLK = PLLCLK / HSEPredivValue = 64 / 1 = 64 MHz *//* Enable HSI and activate PLL with HSi_DIV2 as source */oscinitstruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; /* HSI作為系統時鐘源 */oscinitstruct.HSEState = RCC_HSE_OFF; /* 關閉HSE時鐘 */oscinitstruct.LSEState = RCC_LSE_OFF; /* 關閉LSE時鐘 */oscinitstruct.HSIState = RCC_HSI_ON; /* 開啟HSI時鐘 */oscinitstruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;oscinitstruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;oscinitstruct.PLL.PLLState = RCC_PLL_ON;oscinitstruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;oscinitstruct.PLL.PLLMUL = RCC_PLL_MUL16;if (HAL_RCC_OscConfig(&oscinitstruct)!= HAL_OK){/* Initialization Error */while(1);}/* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2clocks dividers 將PLL的輸出,作為系統時鐘*/clkinitstruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);clkinitstruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;clkinitstruct.AHBCLKDivider = RCC_SYSCLK_DIV1;clkinitstruct.APB2CLKDivider = RCC_HCLK_DIV1;clkinitstruct.APB1CLKDivider = RCC_HCLK_DIV2;if (HAL_RCC_ClockConfig(&clkinitstruct, FLASH_LATENCY_2)!= HAL_OK){/* Initialization Error */while(1);}
}
????????由于作者為了減少PCB板子的尺寸,因此在設計過程中,硬件上沒有接外部晶振和32.768的低速晶振。因此只能使用內部HSI作為時鐘源,但是在使用HSI作為時鐘源時,系統的時鐘最大只能設置到64MHz;
代碼主要邏輯如下:
1、將HSI的晶振作為系統的晶振輸入;
2、關閉HSE時鐘源;
3、關閉LSE時鐘源;
4、計算出SYSCLK = HSI /2 * PLL_MUl16 = 8/2 * 16 = 64M;
5、調用HAL_RCC_OscConfig()接口,設置系統時鐘源;
6、選擇PLLCLK的輸出,最為系統時鐘(64M);
總結
????????本文主要描述了,在STM32F103 CPU初始化過程中,系統時鐘的初始化。雖然,我們可以利用ST提供的上位機圖形化工具進行時鐘配置,簡單的勾選就可以產生我們需要的代碼。但是,作為一個嵌入式開發程序員,我覺得,還是有必要去分析源碼,了解CPU的內部原理和HAL層代碼,這樣才能根據自己產品的實際需求情況,設計出更具有性價比的產品。
鏈接
yanl1229/STM32F103