眾所周知,時鐘是MCU能正常運行的基本條件,就好比心跳或脈搏,為所有的工作單元提供時間 基數。時鐘控制單元提供了一系列頻率的時鐘功能,包括多個內部RC振蕩器時鐘(IRC)、一個外部 高速晶體振蕩器時鐘(HXTAL)、一個外部低速晶體振蕩器時鐘(LXTAL)、一個或多個鎖相環(PLL) 一個HXTAL時鐘和LXTAL時鐘監視器、時鐘預分頻器、時鐘多路復用器和時鐘門控電路等。 本章,我們將通過一個“輸出HXTAL時鐘信號” 的實驗來熟悉RCU的工作流程。
1.1RCU 配置
GD32系列MCU在啟動后首先會執行Reset Handler,緊接著就會執行SystemInit()函數,而時鐘的初始化,就是在這個函數中進行,其主要的功能是配置系統時鐘CK_SYS(即主頻),AHB、APB1以及APB2時鐘。SystemInit()函數由GD32官方庫提供,不同系列的MCU有一些差別,但實現方式基本相同:首先將RCU關于CK_SYS,AHB、APB1以及APB2時鐘配置的一些寄存器恢復到默認值,然后再執行system_clock_config()函數,用于具體的時鐘配置。
實際上用戶可以不用過于關心上述的實現方式,因為GD32庫已經為您提供了多種時鐘源及時鐘選擇,您只需按照以下步驟即可將時鐘設置為您期望的值(以GD32F30x為例,其他系列類似):
(1) 在system_gd32f30x.c中,用戶可通過選擇宏來進行預設的時鐘配置,如下圖代碼清單時鐘配置選擇宏定義,選擇了HXTAL作為PLL時鐘源,且配置CK_SYS為120MHz。
/* system frequency define */ #define __IRC8M (IRC8M_VALUE) /* internal 8 MHz RC oscillator frequency */ #define __HXTAL (HXTAL_VALUE) /* high speed crystal oscillator frequency */ #define __SYS_OSC_CLK (__IRC8M) /* main oscillator frequency */ /* select a system clock by uncommenting the following line */ /* use IRC8M */ //#define __SYSTEM_CLOCK_IRC8M (uint32_t)(__IRC8M) //#define __SYSTEM_CLOCK_48M_PLL_IRC8M (uint32_t)(48000000) //#define __SYSTEM_CLOCK_72M_PLL_IRC8M (uint32_t)(72000000) //#define __SYSTEM_CLOCK_108M_PLL_IRC8M (uint32_t)(108000000) //#define __SYSTEM_CLOCK_120M_PLL_IRC8M (uint32_t)(120000000) /* use HXTAL(XD series CK_HXTAL = 8M, CL series CK_HXTAL = 25M) */ //#define __SYSTEM_CLOCK_HXTAL (uint32_t)(__HXTAL) //#define __SYSTEM_CLOCK_48M_PLL_HXTAL (uint32_t)(48000000) //#define __SYSTEM_CLOCK_72M_PLL_HXTAL (uint32_t)(72000000) //#define __SYSTEM_CLOCK_108M_PLL_HXTAL (uint32_t)(108000000) #define __SYSTEM_CLOCK_120M_PLL_HXTAL (uint32_t)(120000000)
但這種情況下您使用的外部晶振需要是默認值,此值由HXTAL_VALUE定義,如為8000000,那么您應該選擇8MHz的外部晶振。
當然,您可以使用其他規格的外部晶振,這種情況下就需要去修改RCU配置函數里面的一些參數,主要是分頻和倍頻系數,以達到期望的配置,具體如何修改,可以結合GD32的User manual中定義的RCU寄存器來對配置函數進行分析。
(2) 設置HXTAL_VALUE的值。
此數值和RCU的初始化其實并沒有太大關系,但如果您使用的外部晶振不是默認值,那么除了按照步驟(1)修改配置參數外,您還必須將此HXTAL_VALUE的值修改為實際的外部晶振頻率,這是因為在一些通信外設配置時,庫函數會調用HXTAL_VALUE值來設置波特率,如此值設置錯誤,會導致通信異常。
1.2.非默認外部晶振配置時鐘實例
GD32各系列固件庫都已提供配置系統時鐘的函數。需要注意的是,在使用外部晶振時,固件庫中HXTAL_VALUE值規定了 外部晶振的默認值,以 GD32F30x系列為例,如下圖代碼清單HXTAL_VALUE選擇宏定義所示,當芯片為非互聯型(GD32F303)時,默認使用的外部晶振頻率為8MHz,當芯片為互聯型(GD32F305/307)時,默認使用的外部晶振頻率為25MHz。
#ifdef GD32F30X_CL #define HXTAL_VALUE ((uint32_t)25000000) #else #define HXTAL_VALUE ((uint32_t)8000000)
那么,當我們使用非默認值的外部晶振時,該如何修改時鐘配置函數呢?以GD32F303為例,首先我們先看下GD32F303的時鐘樹,如圖所示。

預分頻器可以配置AHB、APB2和APB1域的時鐘頻率。 AHB、APB2、APB1域的最高時鐘頻率分別為120MHz、120MHz、60MHz。RCU通過AHB時鐘(HCLK)8分頻后作為Cortex系統定時器(SysTick)的外部時鐘。通過對SysTick控制和狀態寄存器的設置,可選擇上述時鐘或AHB(HCLK)時鐘作為SysTick時鐘。
ADC時鐘由APB2時鐘經2、4、6、8、12、16分頻或由AHB時鐘經5、6、10、20分頻獲得,它們是通過設置RCU_CFG0和RCU_CFG1寄存器的ADCPSC位來選擇。
SDIO, EXMC的時鐘由CK_AHB提供。
TIMER時鐘由CK_APB1和CK_APB2時鐘分頻獲得,如果APBx(x=0,1)的分頻系數不為1,則TIMER時鐘為CK_APBx(x=0,1)的兩倍。
USBD的時鐘由CK48M時鐘提供。通過配置 RCU_ADDCTL寄存器的CK48MSEL及PLL48MSEL位可以選擇CK_PLL時鐘或IRC48M時鐘做為CK48M的時鐘源。
CTC時鐘由IRC48M時鐘提供,通過CTC單元,可以實現IRC48M時鐘精度的自動調整。
I2S的時鐘由CK_SYS提供。
通過配置RCU_BDCTL寄存器的RTCSRC位, RTC時鐘可以選擇由LXTAL時鐘、IRC40K時鐘或HXTAL時鐘的128分頻提供。RTC時鐘選擇HXTAL時鐘的128分頻做為時鐘源后,當1.2V內核電壓域掉電時,時鐘將停止。 RTC時鐘選擇IRC40K時鐘做為時鐘源后,當VDD掉電時,時鐘將停止。
RTC時鐘選擇LXTAL時鐘做為時鐘源后,當VDD和VBAT都掉電時,時鐘將停止。
當FWDGT啟動時, FWDGT時鐘被強制選擇由IRC40K時鐘做為時鐘源。
現在,我們結合圖GD32F303系統時鐘樹對時鐘樹進行分析:
(1) 標注A為CK_SYS,即系統主時鐘,它一條線連接至CK_I2S,給I2S外設提供時鐘,另一條線經過AHB分頻器,輸出到CK_AHB,即標注B。
(2) CK_AHB為AHB總線時鐘,AHB總線時鐘或直連,或經過APB1/APB2分頻,給標注C位置的外設提供時鐘。
(3) 那么,CK_SYS從何而來呢,我們看標注A的左邊,CK_SYS通過SCS位域選擇CK_IRC8M、CK_PLL、CK_HXTAL作為時鐘來源,其中CK_IRC8M來源于標注D,即IRC8M(MCU內部8M RC時鐘);CK_HXTAL來源于標注F,即HXTAL(外部時鐘);CK_PLL的來源較復雜,我們單獨拿出來說。
(4) CK_PLL來源于鎖相環倍頻器輸出,倍頻系數通過PLLMF位域選擇,而PLLMF來源于兩個地方,一個為 IRC8M 的 2 分 頻 , 另 外 一 個 為 預 分 頻 器 PREDV0 , 而 PREDV0 來 源 于 標 注 E, 即CK_IRC48M(內部48M RC時鐘)和標注F,即HXTAL(外部高速時鐘)。
(5) 通過以上分析可以得出結論,CK_PLL的時鐘源為D:IRC8M、E:IRC48M、F:HXTAL,用戶通過相關寄存器設置選擇時鐘線。
(6) 和前面分析相同,RTC的時鐘來自于F:HXTAL的128分頻、G:LXTAL(外部32.768K低速時鐘)、F:IRC40K(內部40K RC時鐘);FWDGT的時鐘來源于F:IRC40K。
(7) 標注I位置為時鐘輸出線,它的作用是將MCU內部的一些時鐘信號線輸出到特定IO口上(大部分系列MCU的PA8口都可被設置為時鐘輸出口0,有些系列MCU含有兩組輸出IO,具體IO配置請參考各系列MCU Datasheet)用來給其他器件提供基準時鐘。由圖中可看出通過設置位域CK_OUT0,輸出的時鐘包括CK_PLL、CK_IRC8M、CK_HXTAL、CK_PLL的2分頻。
結合以上分析,我們來看下GD32F30x固件庫時鐘配置函數(因篇幅有限,只貼出各分頻和倍頻配置部分),還是以GD32F303芯片為例,如下圖代碼清單時鐘配置部分代碼所示:
/* select HXTAL/2 as clock source */ RCU_CFG0 &= ~(RCU_CFG0_PLLSEL | RCU_CFG0_PREDV0); RCU_CFG0 |= (RCU_PLLSRC_HXTAL_IRC48M | RCU_CFG0_PREDV0); /* CK_PLL = (CK_HXTAL/2) * 30 = 120 MHz */ RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4 | RCU_CFG0_PLLMF_5); RCU_CFG0 |= RCU_PLL_MUL30;
可以看出,8MHz的HXTAL經過預分頻器PREDV0分頻成4MHz,再通過鎖相環PLL倍頻30倍到了120MHz。
那么,當您選擇其他規格的外部晶振,比如12MHz,則可以先通過預分頻器PREDV0分頻成6MHz,再通過鎖相環PLL倍頻20倍即可,如代碼清單 0-4. 使用12MHz外部晶振配置120M系統時鐘所示。
/* select HXTAL/2 as clock source */ RCU_CFG0 &= ~(RCU_CFG0_PLLSEL | RCU_CFG0_PREDV0); RCU_CFG0 |= (RCU_PLLSRC_HXTAL_IRC48M | RCU_CFG0_PREDV0); /* CK_PLL = (CK_HXTAL/2) * 20 = 120 MHz */ RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4 | RCU_CFG0_PLLMF_5); RCU_CFG0 |= RCU_PLL_MUL20;
當然,在修改完配置函數后,別忘了將HXTAL_VALUE值改為12000000。
需要注意的是,在進行時鐘配置時,要嚴格按照Datasheet中規定的時鐘范圍進行配置,如GD32F303的 HXTAL的選 擇范 圍是4~32MHz, PLL的輸 入范 圍是 1~25MHz,輸出范圍是16~120Mhz,所以當使用32MHz的外部晶振時,不進行預分頻,而直接倍頻是不被允許的。
1.3.硬件連接說明
本章通過“輸出HXTAL時鐘信號”實驗來熟悉RCU的工作流程。
通過前面內容講解可知,本章實驗為“輸出HXTAL時鐘信號”,即通過PA8口將HXTAL輸出,我們使用示波器,將探頭連接到PA8口,從示波器上讀取PA8口波形即可。
1.4.軟件配置說明
本小節講解RCU_Example例程中RCU的配置說明,主要包括外設時鐘配置、GPIO引腳配置、主函數介紹以及運行結果。
軟件設計的流程如下:
(1)使能GPIOA時鐘
(2)初始化PA8,將此端口設置為備用功能模式(AFIO)
(3)通過調用庫函數選擇HXTAL作為PA8時鐘信號源
外設時鐘配置
void rcu_config(void) { /* enable the GPIOA clock */ rcu_periph_clock_enable(RCU_GPIOA); }
GPIO 引腳配置
代碼清單 0-6. RCU 例程引腳配置
void gpio_config(void) { /* configure PA8 port */ #if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_8); #elif GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E23X gpio_mode_set(GPIOA,GPIO_MODE_AF,GPIO_PUPD_NONE,GPIO_PIN_8); gpio_af_set(GPIOA,GPIO_AF_0,GPIO_PIN_8); #endif }
GPIO的配置說明,請參考GPIO章節。
主函數說明
代碼清單 0-7 . RCU 例程主函數
int main(void) { rcu_config(); gpio_config(); #if defined GD32F10X_HD || GD32F30X_HD || GD32E10X rcu_ckout0_config(RCU_CKOUT0SRC_HXTAL); #elif defined GD32F20X_CL || GD32F4XX rcu_ckout0_config(RCU_CKOUT0SRC_HXTAL,RCU_CKOUT0_DIV1); #elif GD32F1X0 || GD32F3X0 || GD32E23X rcu_ckout_config(RCU_CKOUTSRC_HXTAL,RCU_CKOUT_DIV1); #endif while(1){ } }
如代碼清單RCU例程主函數,該主函數主要分成四部分,RCU時鐘配置、GPIO配置、RCU輸出相關庫函數調用和while(1)主循環,其中RCU輸出相關庫函數請讀者結合各系列MCU Datasheet、User Manual進行RCU例程的分析。
注意:因為是輸出HXTAL,所以必須要使能HXTAL,否則PA8將無波形輸出。一個簡單的辦法是將HXTAL作為CK_SYS時鐘源,請參考本章第一節內容。
1.5.運行結果
如圖所示 RCU 例程運行結果為 RCU 例程運行結果,可看出,PA8 口正確輸出了 HXTAL 波形。

-
單片機
+關注
關注
6063文章
44923瀏覽量
646978 -
mcu
+關注
關注
146文章
17839瀏覽量
360459 -
嵌入式
+關注
關注
5141文章
19537瀏覽量
315016 -
時鐘樹
+關注
關注
0文章
56瀏覽量
10964 -
rcu
+關注
關注
0文章
21瀏覽量
5578
發布評論請先 登錄
GD32 MCU 入門教程】GD32 MCU 常見外設介紹(12)FMC 模塊介紹

《GD32 MCU原理及固件庫開發指南》 + 初讀感悟
《GD32 MCU原理及固件庫開發指南》+讀后感
兆易創新GD32 MCU選型手冊,適用于GD32全系列MCU
【GD32 MCU 入門教程】一、GD32 MCU 開發環境搭建(1)使用Keil開發GD32

【GD32 MCU 入門教程】一、GD32 MCU 開發環境搭建(2)使用 IAR 開發 GD32

【GD32 MCU 入門教程】一、GD32 MCU 開發環境搭建(3)使用 Embedded Builder 開發 GD32

【GD32 MCU 入門教程】二、GD32 MCU 燒錄說明(1)ISP 燒錄

【GD32 MCU 入門教程】GD32 MCU 常見外設介紹(14)RTC 模塊介紹

【GD32 MCU入門教程】GD32 MCU GPIO 結構與使用注意事項

評論