文章目录
一.概要
GD32单片机的时钟源包括多种选项,时钟控制单元提供了一系列频率的时钟功能,包括一个内部16M RC振荡器时钟(IRC16M)、一个内部48M RC振荡器时钟(IRC48M)、一个外部高速晶体振荡器时钟(HXTAL)、一个内部32K RC振荡器时钟(IRC32K)、一个外部低速晶体振荡器时钟(LXTAL)、三个锁相环(PLL)、一个HXTAL时钟监视器、时钟预分频器、时钟多路复用器和时钟门控电路。
二.GD32F407VET6单片机时钟源介绍
IRC32K:低速内部时钟,IRC32K RC振荡器时钟担当一个低功耗时钟源的角色,它的时钟频率大约32 kHz,为独立看门狗定时器和实时时钟电路提供时钟。
IRC16M:高速内部16MHz时钟,内部16MHz RC振荡器时钟,简称IRC16M时钟,拥有16MHz的固定频率,设备上电后CPU默认选择的时钟源就是IRC16M时钟。他精度比较低,容易受温度影响,在CAN,USART等对时钟精度要求高的场合不适用。
IRC48M:内部48MHz RC振荡器时钟,简称IRC48M时钟,拥有48MHz的固定频率,当使用USBFS/USBHS/TRNG/SDIO模块时,IRC48M振荡器在不需要任何外部器件的条件下为用户提供了一种成本更低的时钟源选择。
HXTAL:高速外部时钟,4到32MHz的外部振荡器可为系统提供更为精确的主时钟。
PLL(Phase Locked Loop)锁相环时钟:
PLL时钟的源可以是IRC8M或HXTAL。PLL可以对输入的时钟信号进行倍频,以产生更高频率的时钟信号,从而提高系统的性能。
LXTAL:低速外部时钟,LXTAL晶体一般是一个32.768kHz的低速外部晶体或陶瓷谐振器。它为实时时钟电路提供一个低功耗且精确的时钟源。
AHB、APB和Cortex®-M4时钟都源自系统时钟(CK_SYS),系统时钟的时钟源可以选择
IRC16M、HXTAL或PLL。系统时钟的最大运行时钟频率可以达到240MHz。独立看门狗定时器有独立的时钟源(IRC32K),实时时钟(RTC)使用IRC32K、LXTAL或HXTAL的分频(通过配置RCU_CFG0寄存器的RTCDIV位)作为时钟源。
二.GD32F407VET6单片机外部高频晶振配置
4到32M的外部高速晶体振荡器可为系统时钟提供更为精确时钟源。带有特定频率的晶体必须靠近两个HXTAL的引脚连接。和晶体连接的外部电阻和电容必须根据所选择的振荡器来调整。 比如外部8M晶振,通过示波器可以量外部晶振的震荡波形,OSCIN脚与OSCOUT引脚都可以,如果单片机程序没跑起来,外部的8M晶振波形是没有的。
HXTAL晶体振荡器可以通过设置控制寄存器RCU_CTL的HXTALEN位来启动或关闭,在控制寄存器RCU_CTL中的HXTALSTB位用来指示外部高速振荡器是否已稳定。在启动时,直到这一位被硬件置‘1’,时钟才被释放出来。这个特定的延迟时间被称为振荡器的启动时间。
配置外部高频晶振参考代码如下:
/* enable HXTAL */
RCU_CTL |= RCU_CTL_HXTALEN;
/* wait until HXTAL is stable or the startup time is longer than HXTAL_STARTUP_TIMEOUT */
do{
timeout++;
stab_flag = (RCU_CTL & RCU_CTL_HXTALSTB);
}while((0U == stab_flag) && (HXTAL_STARTUP_TIMEOUT != timeout));
三.GD32F407VET6单片机内部高频晶振配置
内部16MHz RC振荡器时钟,简称IRC16M时钟,拥有16MHz的固定频率,设备上电后CPU默认选择其做为系统时钟源。IRC16M RC振荡器能够在不需要任何外部器件的条件下为用户提供更低成本类型的时钟源。IRC16M RC振荡器可以通过设置控制寄存器(RCU_CTL)中的IRC8MEN位被启动和关闭。控制寄存器RCU_CTL中的IRC16MSTB位用来指示IRC16M内部RC振荡器是否稳定。IRC16M振荡器的启动时间比HXTAL晶体振荡器要更短。
工厂会校准IRC16M时钟频率的精度,但是它的精度仍然比HXTAL时钟要差。用户可以根据需求、环境条件和成本决定选择哪个时钟作为系统时钟源。
配置内部高频晶振参考代码如下:
/* enable IRC16M */
RCU_CTL |= RCU_CTL_IRC16MEN;
/* wait until IRC16M is stable or the startup time is longer than IRC16M_STARTUP_TIMEOUT */
do{
timeout++;
stab_flag = (RCU_CTL & RCU_CTL_IRC16MSTB);
}while((0U == stab_flag) && (IRC16M_STARTUP_TIMEOUT != timeout));
四.GD32F407VET6单片机使用内部16M晶振实验
STLINK接GD32F407VET6开发板,STLINK接电脑USB口。
主要代码:
#include "gd32f4xx.h"
#include "gd32f4xx_libopt.h"
#include "systick.h"
int main(void)
{
systick_config();//配置系统主频168M,内部16M晶振,配置在#define __SYSTEM_CLOCK_168M_PLL_IRC16M (uint32_t)(168000000)
rcu_periph_clock_enable(RCU_GPIOB);//使能GPIOB时钟
gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_4);//PB4配置成输出
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4);//PB4配置成推挽输出,50M速度
while(1)
{
gpio_bit_set(GPIOB, GPIO_PIN_4);//PB4输出高电平
delay_1ms(100);//等待100ms
gpio_bit_reset(GPIOB, GPIO_PIN_4);//PB4输出低电平
delay_1ms(100);
}
}
/* select a system clock by uncommenting the following line */
//#define __SYSTEM_CLOCK_IRC16M (uint32_t)(__IRC16M)
//#define __SYSTEM_CLOCK_HXTAL (uint32_t)(__HXTAL)
//#define __SYSTEM_CLOCK_120M_PLL_IRC16M (uint32_t)(120000000)
//#define __SYSTEM_CLOCK_120M_PLL_8M_HXTAL (uint32_t)(120000000)
//#define __SYSTEM_CLOCK_120M_PLL_25M_HXTAL (uint32_t)(120000000)
#define __SYSTEM_CLOCK_168M_PLL_IRC16M (uint32_t)(168000000)
//#define __SYSTEM_CLOCK_168M_PLL_8M_HXTAL (uint32_t)(168000000)
//#define __SYSTEM_CLOCK_168M_PLL_25M_HXTAL (uint32_t)(168000000)
// #define __SYSTEM_CLOCK_200M_PLL_IRC16M (uint32_t)(200000000)
//#define __SYSTEM_CLOCK_200M_PLL_8M_HXTAL (uint32_t)(200000000)
//#define __SYSTEM_CLOCK_200M_PLL_25M_HXTAL (uint32_t)(200000000)
#elif defined (__SYSTEM_CLOCK_168M_PLL_IRC16M)
system_clock_168m_irc16m();
static void system_clock_168m_irc16m(void)
{
uint32_t timeout = 0U;
uint32_t stab_flag = 0U;
/* enable IRC16M */
RCU_CTL |= RCU_CTL_IRC16MEN;
/* wait until IRC16M is stable or the startup time is longer than IRC16M_STARTUP_TIMEOUT */
do{
timeout++;
stab_flag = (RCU_CTL & RCU_CTL_IRC16MSTB);
}while((0U == stab_flag) && (IRC16M_STARTUP_TIMEOUT != timeout));
/* if fail */
if(0U == (RCU_CTL & RCU_CTL_IRC16MSTB)){
while(1){
}
}
RCU_APB1EN |= RCU_APB1EN_PMUEN;
PMU_CTL |= PMU_CTL_LDOVS;
/* IRC16M is stable */
/* AHB = SYSCLK */
RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
/* APB2 = AHB/2 */
RCU_CFG0 |= RCU_APB2_CKAHB_DIV2;
/* APB1 = AHB/4 */
RCU_CFG0 |= RCU_APB1_CKAHB_DIV4;
/* Configure the main PLL, PSC = 16, PLL_N = 336, PLL_P = 2, PLL_Q = 7 */
RCU_PLL = (16U | (336U << 6U) | (((2U >> 1U) - 1U) << 16U) |
(RCU_PLLSRC_IRC16M) | (7U << 24U));
/* enable PLL */
RCU_CTL |= RCU_CTL_PLLEN;
/* wait until PLL is stable */
while(0U == (RCU_CTL & RCU_CTL_PLLSTB)){
}
/* Enable the high-drive to extend the clock frequency to 168 Mhz */
PMU_CTL |= PMU_CTL_HDEN;
while(0U == (PMU_CS & PMU_CS_HDRF)){
}
/* select the high-drive mode */
PMU_CTL |= PMU_CTL_HDS;
while(0U == (PMU_CS & PMU_CS_HDSRF)){
}
/* select PLL as system clock */
RCU_CFG0 &= ~RCU_CFG0_SCS;
RCU_CFG0 |= RCU_CKSYSSRC_PLLP;
/* wait until PLL is selected as system clock */
while(0U == (RCU_CFG0 & RCU_SCSS_PLLP)){
}
}
实验结果:
可以看到LED D1灯(PB4引脚驱动)能间隔闪烁,间隔时间200ms。
查看寄存器,可以看到内部16M晶振使能,系统主频通过PLL倍频到168MHz。
晶振以及系统主频选择函数如下图所示:
五.工程源代码下载
源码下载链接如下:
CSDN
六.小结
一般我们在实际产品开发中,都会使用外部晶振,但有时候会遇到降低BOM成本,减少板子空间,增加单片机的GPIO利用率的场合,就可能会使用内部晶振。