1.1 实验内容 通过本实验主要学习以下内容: • RCU时钟原理及配置; • RCU时钟输出验证。 1.2 实验原理 1.2.1 RCU时钟树原理 GD32F303系列MCU的时钟树如下图所示,由该图可知,GD32F303系列MCU的时钟树可大致分为三个部分:1、主系统时钟以及外设时钟配置,如下图所示,GD32F303系列MCU最高主频为120MHz(CK_SYS),该系统时钟根据SCS[1:0]控制位进行选择,可选择来源于HSI8M、PLL或者HXTAL,PLL时钟源可根据PLLSEL控制位选择来自于HSI8M/2或者HXTAL以及HSI48M,之后经过2-63倍频(PLLMF)得到PLL时钟,PLL时钟可以通过USB分频输出给USB模块,系统时钟会直接输出给IIS外设使用,AHB时钟可由系统时钟分频而来,AHB时钟最高120M,AHB时钟会输出给内核以及外设使用;2、RTC以及独立看门狗时钟配置,如图中2所示,RTC时钟可选择HXTAL/128分频、LXTAL或者IRC40K,独立看门狗仅可选择IRC40K使用;3、时钟输出配置,如图中3所示,内部系统时钟、IRC8M、HXTAL以及PLL/2可通过CKOUT0SEL控制位控制输出到CKOUT引脚。 1.2.2 外部高速晶振原理 外部高速晶振可选择4-32M时钟,若系统应用中有异步通信以及高精度定时等应用建议选择使用外部高速晶振,外部高速晶振具有更高的精度,在GD32F303应用系统中建议选择8M/16M/24M晶振,因为外部晶振输入给PLL的时钟源仅可进行1分频或者2分频,选择其他频率的晶振难以配置到最高120M系统时钟。 HXTAL具有时钟监测的功能,置位CKMEN控制位将会使能该功能,使能后一旦监测到HXTAL失效,HXTAL将自动被禁止,中断寄存器RCU_INT中的HXTAL时钟阻塞中断标志位CKMIF将被置‘1’,并产生NMI不可屏蔽中断,使用者可在NMI中断中切换到内部时钟并重新进行时钟配置,可用于HXTAL失效情况下的异常处理。 |
1.2.3 内部高速时钟原理 GD32F303系列MCU的内部高速时钟有IRC8M和IRC48M,IRC8M较为常用,且具有更高的精度,另外需注意内部高速时钟并非晶振,电路上为RC振荡器,因而比较容易受外部环境的影响,如下图所示,常温下IRC8M的精度约为1%。
1.2.4 内部低速时钟原理 GD32F303系列MCU内部有IRC40K低速时钟,该低速时钟可以为RTC或FWDG使用,如下图所示,据测试IRC40K精度较差,如果作为RTC时钟源可能存在较大偏差的情况,如果使用者使用RTC建议可以选择LXTAL外部低频晶振,或者使用内部高速时钟对IRC40K进行校准(校准方法为使用内部高速时钟对IRC40K进行捕获,然后调整IRC40K的trim值)。 1.2.5 外部低速晶振原理 外部低速晶振一般选择32.768KHZ的晶振,外部低速晶振可以选择作为RTC时钟,在这种情况下,RTC可以在VDD掉电以及VBAT不掉电的情况下工作。 1.2.6 时钟输出功能 时钟输出功能可以输出4-120MHz的时钟,具体通过配置CKOUT0SEL控制位进行实现,另外需要将CKOUT引脚(一般为PA8引脚)配置为推挽输出的模式,有关时钟输出选择配置如下表所示。
1.3 硬件设计 本节主要介绍开发板外挂高速晶振以及低速晶振电路。 1.3.1 外部高速晶振电路设计 外部高速晶振电路如下图所示,其中外部高速晶振选择8MHZ,匹配电容选择20pf,该匹配电容可以参考以下公式:C1=C2=2*(Cload-CS),其中Cload为晶体负载电容,Cs为PCB以及MCU引脚的杂散电容,典型值为10pf,因而可以选择负载电容约为20pf的晶振,匹配电容即可选择20pf,需要注意晶振尽量靠近MCU引脚摆放,且晶振引脚走线尽量等长,PCB区域尽量禁空,走线可以包地,另外若走线不等长,匹配电容可以适当选择不同的匹配电容以适配不同的杂散电容。R28的1M欧姆为晶振引脚的反馈电阻,该反馈电阻的作用为减少晶振输出波形的谐波分量,提高晶振稳定性,该电阻并非必须,MCU内部也有400K的反馈电阻,从笔者使用来看,并不影响晶振起振及使用,但建议电路上可以选择保留。R29的100R电阻为晶振引脚串联电阻,用于限流以及引脚保护。另外测量晶振引脚波形时可能存在OSC_IN脚波形为较好的正弦波,OSC_OUT引脚波形可能存在畸变,该现象为正常现象,不影响使用,MCU内部使用的为OSC_IN引脚的波形,并通过内部整形方波供给MCU使用。 1.3.2 外部低速晶振电路设计 外部低速晶振电路如下图所示,外部低速晶振选择32.768KHz,匹配电容选择10pf,C1 = C2 = 2*(CLOAD - CS),其中CS为PCB和MCU引脚的杂散电容, 经验值在2pF-7pF之间,建议以5pF为参考值计算。推荐选用外部晶体时,尽量选择晶体负载电容在10pF左右的,这样外部所接匹配电容C1和C2电容值为10pF即可,且PCB Layout时尽可能近地靠近晶振引脚。 1.4 代码解析 本节主要进行例程代码解析,主要分成两个部分:时钟配置以及CKOUT时钟输出验证。 1.4.1 时钟配置代码解析 时钟配置是一个MCU系统的基础,读者在开发MCU项目时需要首先明确当前系统所运行的主频具体是多少,这样才能够准确的进行外设时钟配置,定时器定时才会准确,ADC采样率才会准确,通信的速率才会准确等等,系统超频也会带来不可预料的风险,因而建议开发者在开发初期就需要明确系统主频配置,有条件的情况下可以通过定时或者时钟输出进行校验。 本例程中时钟配置函数代码如以下所示,该代码实现通过外部8M晶振进行PLL倍频,实现120MHz主系统时钟的功能。 C
void rcu_system_clk_config_120M(void)
{
uint32_t timeout = 0U;
uint32_t stab_flag = 0U;
/* 使能外部8M晶振 */
RCU_CTL |= RCU_CTL_HXTALEN;
/* 等待外部晶振ready,或者外部晶振未ready情况下超时退出 */
do{
timeout++;
stab_flag = (RCU_CTL & RCU_CTL_HXTALSTB);
}while((0U == stab_flag) && (HXTAL_STARTUP_TIMEOUT != timeout));
/* 如果外部晶振未ready,程序卡死进入while(1),读者若避免卡死可在此处切换到内部振荡器使用 */
if(0U == (RCU_CTL & RCU_CTL_HXTALSTB)){
while(1){
}
}
RCU_APB1EN |= RCU_APB1EN_PMUEN;
PMU_CTL |= PMU_CTL_LDOVS;
/* AHB一分频,系统时钟等于AHB时钟 */
RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
/* APB2一分频,APB2高速外设时钟等于AHB时钟 */
RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
/* APB1 二分频,APB1低速外设时钟等于AHB时钟/2 */
RCU_CFG0 |= RCU_APB1_CKAHB_DIV2;
/* 选择HXTAL/2作为PLL时钟源,开发板外部晶振为8M,即8/2=4M作为PLL时钟源*/
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_PLL_MUL30倍频因子即可 */
RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4 | RCU_CFG0_PLLMF_5);
RCU_CFG0 |= RCU_PLL_MUL30;
/* 使能 PLL */
RCU_CTL |= RCU_CTL_PLLEN;
/* 等待PLL Ready */
while(0U == (RCU_CTL & RCU_CTL_PLLSTB)){
}
/* 使能PLL高驱模式 */
PMU_CTL |= PMU_CTL_HDEN;
while(0U == (PMU_CS & PMU_CS_HDRF)){
}
/* 选择PLL高驱模式 */
PMU_CTL |= PMU_CTL_HDS;
while(0U == (PMU_CS & PMU_CS_HDSRF)){
}
/* 选择PLL作为系统时钟 */
RCU_CFG0 &= ~RCU_CFG0_SCS;
RCU_CFG0 |= RCU_CKSYSSRC_PLL;
/* 等待PLL被选择作为系统时钟 */
while(0U == (RCU_CFG0 & RCU_SCSS_PLL)){
}
} |
如果读者使用的是其他频率的晶振,可以选择修改PLL倍频因子以及HXTAL的宏定义即可,比如若读者选择16MHz晶振,可以将历程中RCU_PLL_MUL30的倍频因子修改为RCU_PLL_MUL15,且将HXTAL_VALUE宏定义修改为16000000。 |
1.4.2 CKOUT时钟输出代码解析 CKOUT时钟输出配置代码如下所示,该函数无形参输入,首先将PA8配置为推挽输出,然后将系统时钟配置为CKOUT输出。
C
void ckout_config(void)
{
/* 以下两句配置PA8作为推挽输出,即作为CKOUT功能输出 */
rcu_periph_clock_enable(RCU_GPIOA);
gpio_init(GPIOA,GPIO_MODE_AF_PP,GPIO_OSPEED_MAX,GPIO_PIN_8);
/* 以下语句为配置系统时钟输出到CKOUT引脚,若希望输出其他时钟可以修改该函数形参,
在GD32F303上仅可以输出以下时钟:RCU_CKOUT0SRC_CKSYS,RCU_CKOUT0SRC_IRC8M,RCU_CKOUT0SRC_HXTAL,RCU_CKOUT0SRC_CKPLL_DIV2*/
rcu_ckout0_config(RCU_CKOUT0SRC_CKSYS);
} |
1.4.3 主函数代码解析 本例程主函数如下所示,首先使用外部8M晶振倍频配置系统时钟为120MHZ,然后通过PA8将系统时钟输出。 C
int main(void)
{
bsp_uart_init(&BOARD_UART); /* 板载UART初始化 */
printf("Example ofClock configuration and output.\r\n");
rcu_system_clk_config_120M(); /*使用外部8M晶振进行倍频,将系统时钟配置为120M*/
ckout_config(); /*通过PA8(CKOUT)将系统时钟输出*/
while (1)
{}
} |
1.5 实验结果 首先将PA8外接示波器,然后将本例程编译通过后,烧录到红枫派开发板中,通过示波器可以观察到系统时钟输出,如下图所示,本例程中系统时钟输出为120MHz。
本教程由GD32 MCU方案商聚沃科技原创发布,了解更多GD32 MCU教程,关注聚沃科技官网,GD32MCU技术交流群:859440462
|