STM32時鐘初始化函數(shù)SystemInit()詳解
花了一天的時間,總算是了解了SystemInit()函數(shù)實現(xiàn)了哪些功能,初學STM32,,現(xiàn)記錄如下(有理解錯誤的地方還請大俠指出):
本文引用地址:http://butianyuan.cn/article/201609/310557.htm使用的是3.5的庫,用的是STM32F107VC,開發(fā)環(huán)境RVMDK4.23
我已經(jīng)定義了STM32F10X_CL,SYSCLK_FREQ_72MHz
函數(shù)調(diào)用順序:
startup_stm32f10x_cl.s(啟動文件) → SystemInit() → SetSysClock () → SetSysClockTo72()
初始化時鐘用到的RCC寄存器復位值:
RCC_CR = 0x0000 xx83; RCC_CFGR = 0x0000 0000;RCC_CIR = 0x0000 0000; RCC_CFGR2 = 0x0000 0000;
SystemInit()
在調(diào)用 SetSysClock()之前RCC寄存器的值如下(都是一些與運算,或運算,在此就不贅述了):
RCC->CR = 0x0000 0083; RCC->CIR = 0x00FF0000; RCC->CFGR2 = 0x00000000;至于這些寄存器都代表著什么意思,詳見芯片資料RCC寄存器,該文重點不在此處;
SetSysClock()函數(shù)如下:
static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSE
SetSysClockToHSE();
#elif defined SYSCLK_FREQ_24MHz
SetSysClockTo24();
#elif defined SYSCLK_FREQ_36MHz
SetSysClockTo36();
#elif defined SYSCLK_FREQ_48MHz
SetSysClockTo48();
#elif defined SYSCLK_FREQ_56MHz
SetSysClockTo56();
#elif defined SYSCLK_FREQ_72MHz //我的定義的是SYSCLK_FREQ_72MHz,所以調(diào)用SetSysClockTo72()
SetSysClockTo72();
#endif
}
SetSysClockTo72()函數(shù)如下:
static void SetSysClockTo72(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/
/* 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)
{
/* Enable Prefetch Buffer */
FLASH->ACR |= FLASH_ACR_PRFTBE;
/* Flash 2 wait state */
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;
/* HCLK = SYSCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
#ifdef STM32F10X_CL
/* Configure PLLs ------------------------------------------------------*/
/* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
/* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */
RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);
/* Enable PLL2 */
RCC->CR |= RCC_CR_PLL2ON;
/* Wait till PLL2 is ready */
while((RCC->CR & RCC_CR_PLL2RDY) == 0)
{
}
/* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */
RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 |
RCC_CFGR_PLLMULL9);
#else
/* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
#endif /* STM32F10X_CL */
/* Enable PLL */
RCC->CR |= RCC_CR_PLLON;
/* Wait till PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
{
}
}
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 */
}
}
1:AHB, APB1,APB2時鐘確定
//HCLK = SYSCLK ,從下面的分析可以得出SYSCLK是使用PLLCLK時鐘的,也就是72MHZ(至于72MHZ如何得來,請看下面分析)
//那么就是HCLK(AHB總線時鐘)=PLLCLK = 72MHZ
//AHB總線時鐘等于系統(tǒng)時鐘SYSCLK,也就是 AHB時鐘 = HCLK = SYSCLK = 72MHZ
/* HCLK = SYSCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
//PLCK2等于HCLK一分頻, 所以PCLK2 = HCLK,HCLK = 72MHZ, 那么PLCK2(APB2總線時鐘) = 72MHZ
//APB2總線時鐘等于HCLK的一分頻,也就是不分頻;APB2 時鐘 = HCLK = SYSCLK = 72MHZ
/* PCLK2 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
//PCLK1 = HCLK / 2;PCLK1 等于HCLK時鐘的二分頻,那么PCLK1(APB1) = 72MHZ / 2 = 36MHZ
//APB1總線時鐘等于HCLK的二分頻,也就是 APB1時鐘= HCLK / 2 = 36MHZ
/* PCLK1 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
2:如何得出SYSCLK(系統(tǒng)時鐘)為72MHZ(外部晶振25MHZ)
//記得參考英文芯片資料的時鐘樹P115頁和RCC時鐘寄存器進行理解
RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 | RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);
RCC_CFGR2_PREDIV2_DIV5: PREDIV2 = 5; 5分頻
也就是PREDIV2對輸入的外部時鐘 5分頻,那么PLL2和PLL3沒有倍頻前是25 /5 = 5MHZ
RCC_CFGR2_PLL2MUL8 : PLL2MUL = 8; 8倍頻
8倍頻后,PLL2時鐘 = 5 * 8 = 40MHZ; 因此 PLL2CLK = 40MHZ
RCC_CFGR2_PREDIV1SRC_PLL2 : RCC_CFGR2的第16位為1, 選擇PLL2CLK 作為PREDIV1的時鐘源
RCC_CFGR2_PREDIV1_DIV5:PREDIV1 = 5;PREDIV1對輸入時鐘5分頻 PREDIV1CLK = PLL2CLK / 5 = 8MHZ
--------------------------------------------------------------------------------------
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 |
RCC_CFGR_PLLMULL9);
RCC_CFGR_PLLXTPRE_PREDIV1 :操作的是RCC_CFGR的第17位PLLXTPRE,操作這一位和操作RCC_CFGR2寄存器的 位[3:0]中的最低位是相同的效果
RCC_CFGR_PLLSRC_PREDIV1 :選擇PREDIV1輸出作為PLL輸入時鐘;PREDIV1CLK = 8MHZ,所以輸入給PLL倍頻的 時鐘源是8MHZ
RCC_CFGR_PLLMULL9 :PLLMUL = 9;PLL倍頻系數(shù)為9,也就是對 PLLCLK = PREDIV1CLK * 8 = 72MHZ
以上是對RCC_CFGR進行的配置
---------------------------------------------------------------------------------------------------
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; //選擇PLLCLK作為系統(tǒng)時鐘源
--------------------------------------------------------------------------------------------------
至此基本配置已經(jīng)完成,配置的時鐘如下所述:
SYSCLK(系統(tǒng)時鐘) = 72MHZ
AHB總線時鐘 = 72MHZ
APB1總線時鐘 = 36MHZ
APB2總線時鐘 = 72MHZ
PLL時鐘 = 72MHZ
PLL2時鐘 = 40MHZ
評論