- #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 波形。
教程由GD32 MCU方案商聚沃科技原创发布,了解更多GD32 MCU教程,关注聚沃科技官网,GD32MCU技术交流群:859440462