時鍾就是整個系統正常運行的命脈,時鍾配置不對或者理解不全,后面定時器的配置就會出問題
系統運行時首先是從下圖這里開始,先加載SystemInit函數,然后加載main函數
SystemInit()是廠家封裝好的,不用改動,只要理解就行了。
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 RCU clock configuration to the default reset state ------------*/ /* Set IRC16MEN bit */ RCU_CTL |= RCU_CTL_IRC16MEN; RCU_MODIFY; //源代碼沒‘;’這會導致代碼查看有問題(雖然執行上沒問題) /* Reset CFG0 register */ RCU_CFG0 = 0x00000000U; /* Reset HXTALEN, CKMEN and PLLEN bits */ RCU_CTL &= ~(RCU_CTL_PLLEN | RCU_CTL_CKMEN | RCU_CTL_HXTALEN); /* Reset PLLCFGR register */ RCU_PLL = 0x24003010U; /* Reset HSEBYP bit */ RCU_CTL &= ~(RCU_CTL_HXTALBPS); /* Disable all interrupts */ RCU_INT = 0x00000000U; /* Configure the System clock source, PLL Multiplier and Divider factors, AHB/APBx prescalers and Flash settings ----------------------------------*/ system_clock_config(); }
前面都不用管,都是系統進行的初始化操作,重點看system_clock_config()里,它會根據用戶定義的時鍾源選擇相應 的時鍾初始化函數
時鍾源的選擇要看下用戶手冊,然后跟硬件工程師確認下。這里我就犯了一個錯誤,看到GD的demo里他們用的是外部25M的高速時鍾,我也理所當然的用了這個。結果調試定時器死活調不對,輸出的PWM也不對。問了硬件工程師才知道,原來我們外部的高速時鍾源是8M的。而內部的16M的雖然也可以用,但是它的精度不高,不推薦用。當初從STM換到GD,移植這塊的時候就糊里糊塗的沒細究,結果后面還是會被卡脖子。
我們這里選擇的是外部高速時鍾__SYSTEM_CLOCK_200M_PLL_8M_HXTAL
其時鍾初始化函數如下:
7 static void system_clock_200m_25m_hxtal(void) 8 { 9 uint32_t timeout = 0U; 10 uint32_t stab_flag = 0U; 11 12 /* enable HXTAL */ 13 RCU_CTL |= RCU_CTL_HXTALEN; 14 15 /* wait until HXTAL is stable or the startup time is longer than HXTAL_STARTUP_TIMEOUT */ 16 do{ 17 timeout++; 18 stab_flag = (RCU_CTL & RCU_CTL_HXTALSTB); 19 }while((0U == stab_flag) && (HXTAL_STARTUP_TIMEOUT != timeout)); 20 21 /* if fail */ 22 if(0U == (RCU_CTL & RCU_CTL_HXTALSTB)){ 23 while(1){ 24 } 25 } 26 27 RCU_APB1EN |= RCU_APB1EN_PMUEN; 28 PMU_CTL |= PMU_CTL_LDOVS; 29 30 /* HXTAL is stable */ 31 /* AHB = SYSCLK = 200M */ 32 RCU_CFG0 |= RCU_AHB_CKSYS_DIV1; 33 /* APB2 = AHB/2 = 100M */ 34 RCU_CFG0 |= RCU_APB2_CKAHB_DIV2; 35 /* APB1 = AHB/4 = 50M */ 36 RCU_CFG0 |= RCU_APB1_CKAHB_DIV4; 37 38 /* Configure the main PLL, PSC = 25, PLL_N = 400, PLL_P = 2, PLL_Q = 9 */ 39 RCU_PLL = (25U | (400U << 6U) | (((2U >> 1U) - 1U) << 16U) | 40 (RCU_PLLSRC_HXTAL) | (9U << 24U)); 41 42 /* enable PLL */ 43 RCU_CTL |= RCU_CTL_PLLEN; 44 45 /* wait until PLL is stable */ 46 while(0U == (RCU_CTL & RCU_CTL_PLLSTB)){ 47 } 48 49 /* Enable the high-drive to extend the clock frequency to 200 Mhz */ 50 PMU_CTL |= PMU_CTL_HDEN; 51 while(0U == (PMU_CS & PMU_CS_HDRF)){ 52 } 53 54 /* select the high-drive mode */ 55 PMU_CTL |= PMU_CTL_HDS; 56 while(0U == (PMU_CS & PMU_CS_HDSRF)){ 57 } 58 59 /* select PLL as system clock */ 60 RCU_CFG0 &= ~RCU_CFG0_SCS; 61 RCU_CFG0 |= RCU_CKSYSSRC_PLLP; 62 63 /* wait until PLL is selected as system clock */ 64 while(0U == (RCU_CFG0 & RCU_SCSS_PLLP)){ 65 } 66 }
1. 開啟高速時鍾源
RCU_CTL |= RCU_CTL_HXTALEN;
2.配置 APB1 = AHB/4
RCU_CFG0 |= RCU_APB1_CKAHB_DIV4;
3.配置PLL為系統時鍾源
這樣系統時鍾就是200M的時鍾了
那么APB1是多少呢?
根據RCU_CFG1的寄存器說明:
AHB = SYSCLK;
APB1 = AHB/4= 200M/4 = 50MHz;
CK_TIMERx = 2 * CK_APB1 = 100MHz
若對時鍾配置寄存器 1 進行時鍾配置的話,
rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);
則:
CK_TIMERx = 4 * CK_APB1 = 200MHz