GD32_时钟配置解析

这篇具有很好参考价值的文章主要介绍了GD32_时钟配置解析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

GD32_时钟配置解析

本文以GD32F303型号为基础,依照标准库GD32F30x_Firmware_Library_V2.1.5为例,作为笔记简单记录个人对其时钟配置的理解,后续会持续更新本篇笔记内容。



前言

因为某些原因,国外半导体供应供应短缺,以STM32为例的系列芯片紧缺,价格跳水严重。技术群的部分码友们所在公司纷纷寻找替代产品,将头转向兆易创新的GD32,在将以前的STM32项目移植到国产GD32过程中,踩坑是在所难免,我也重新梳理了对GD32的理解。作为笔记加深理解。本篇主要是对时钟树的配置的一些理解和问题,欢迎各位码友指点!


一、时钟源简介

时钟控制单元提供有五个时钟源,见时钟树标记,包括:
1:内部8M RC振荡器时钟(IRC8M):高速内部8MHz时钟,拥有8MHz的固定频率,设备上电后CPU默认选择的时钟源就是IRC8M时钟
2:内部48M RC 振荡器时钟(IRC48): 有一个固定的频率48MHz,可用作USB时钟或者PLL时钟源
3:外部高速晶体振荡器时钟(HXTAL:4到32MHz的外部振荡器,可为系统提供精确的主时钟。带有特定频率的晶体必须靠近两个HXTAL的引脚。和晶体连接的外部电阻和电容必须根据所选择的振荡器来调整
4:内部40K RC振荡器时钟(IRC40K):它的时钟频率大约40 kHz,为独立看门狗定时器和实时时钟电路提供时钟。
5:外部低速晶体振荡器时钟(LXTA):一个32.768kHz的低速外部晶体或陶瓷谐振器。它为实时时钟电路提供一个低功耗且精确的时钟源。
内部锁相环(PLL):对输入参考频率为4到32MHz时钟进行分频操作,输出一个8-120 MHz的时钟输出
剩下就是HXTAL时钟监视器、时钟预分频器、时钟多路复用器和时钟门控电路等。
AHB、 APB和Cortex®-M4时钟都源自系统时钟(CK_SYS),系统时钟的时钟源可以选择IRC8M、HXTAL或PLL。系统时钟的最大运行时钟频率可以达到120MHz。
严格来说锁相环不算时钟源,它是其他时钟源头配置而来

二、时钟配置步骤

1.SystemInit (void)

此函数中主要操作为依内部8MHz时钟为时钟源,驱动时钟配置,线路为红色线路所示,步骤如下图:
GD32_时钟配置解析

GD32_时钟配置解析

代码如下(示例):

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 IRC8MEN bit */
    RCU_CTL |= RCU_CTL_IRC8MEN;						//打开内部8MHz RC振荡器
    while(0U == (RCU_CTL & RCU_CTL_IRC8MSTB)){  	//等待内部8MHz RC振荡器稳定
    }
    RCU_MODIFY(0x50);								//AHB时钟分频设置 先二分频再四分频
    
    RCU_CFG0 &= ~RCU_CFG0_SCS;						//00:选择 CK_IRC8M 时钟作为 CK_SYS 时钟源

#if (defined(GD32F30X_HD) || defined(GD32F30X_XD))
    /* reset HXTALEN, CKMEN and PLLEN bits */
	/*外部高速时钟使能位、HXTAL 时钟监视器使能位、PLL使能位 复位,方便后续操作*/
    RCU_CTL &= ~(RCU_CTL_PLLEN | RCU_CTL_CKMEN | RCU_CTL_HXTALEN);
    /* disable all interrupts */
    /*关闭中断位*/
    RCU_INT = 0x009f0000U;
#elif defined(GD32F30X_CL)
    /* Reset HXTALEN, CKMEN, PLLEN, PLL1EN and PLL2EN bits */
    RCU_CTL &= ~(RCU_CTL_PLLEN |RCU_CTL_PLL1EN | RCU_CTL_PLL2EN | RCU_CTL_CKMEN | RCU_CTL_HXTALEN);
    /* disable all interrupts */
    RCU_INT = 0x00ff0000U;
#endif

    /* reset HXTALBPS bit */
    RCU_CTL &= ~(RCU_CTL_HXTALBPS); //旁路模式位复位
    
    /* Reset CFG0 and CFG1 registers */
    RCU_CFG0 = 0x00000000U;
    RCU_CFG1 = 0x00000000U;
    /* configure the system clock source, PLL Multiplier, AHB/APBx prescalers and Flash settings */
    system_clock_config();
}

2.system_clock_config();

根据宏定义,选择相关的时钟频率配置函数,我的是高速外部时钟源配置108MHz系统时钟
配置函数为;system_clock_108m_hxtal();
代码如下(示例):

static void system_clock_config(void)
{
#ifdef __SYSTEM_CLOCK_IRC8M
    system_clock_8m_irc8m();
#elif defined (__SYSTEM_CLOCK_48M_PLL_IRC8M)
    system_clock_48m_irc8m();
#elif defined (__SYSTEM_CLOCK_72M_PLL_IRC8M)
    system_clock_72m_irc8m();
#elif defined (__SYSTEM_CLOCK_108M_PLL_IRC8M)
    system_clock_108m_irc8m();
#elif defined (__SYSTEM_CLOCK_120M_PLL_IRC8M)
    system_clock_120m_irc8m();
#elif defined (__SYSTEM_CLOCK_HXTAL)
    system_clock_hxtal();
#elif defined (__SYSTEM_CLOCK_48M_PLL_HXTAL)
    system_clock_48m_hxtal();
#elif defined (__SYSTEM_CLOCK_72M_PLL_HXTAL)
    system_clock_72m_hxtal();
#elif defined (__SYSTEM_CLOCK_108M_PLL_HXTAL)
    system_clock_108m_hxtal();
#elif defined (__SYSTEM_CLOCK_120M_PLL_HXTAL)
    system_clock_120m_hxtal();
#endif /* __SYSTEM_CLOCK_IRC8M */
}

3. system_clock_108m_hxtal();

该函数以外部时钟源配置108兆系统时钟步骤如图,时钟线路为绿色线路所示:
GD32_时钟配置解析

代码如下(示例):

static void system_clock_108m_hxtal(void)
{
    uint32_t timeout = 0U;
    uint32_t stab_flag = 0U;

    /* 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));

    /* if fail */
    if(0U == (RCU_CTL & RCU_CTL_HXTALSTB)){
        while(1){
        }
    }

    RCU_APB1EN |= RCU_APB1EN_PMUEN;   //PMU 时钟使能
    PMU_CTL |= PMU_CTL_LDOVS;		  //11: LDO 输出高电压模式

    /* HXTAL is stable */
    /* AHB = SYSCLK */
    RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
    /* APB2 = AHB/1 */
    RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
    /* APB1 = AHB/2 */
    RCU_CFG0 |= RCU_APB1_CKAHB_DIV2;

#if (defined(GD32F30X_HD) || defined(GD32F30X_XD))
    /* select HXTAL/2 as clock source */
    RCU_CFG0 &= ~(RCU_CFG0_PLLSEL | RCU_CFG0_PREDV0);
    RCU_CFG0 |= (RCU_PLLSRC_HXTAL_IRC48M | RCU_CFG0_PREDV0);//HXTAL 时钟或者 IRC48M 时钟(寄存器 RCU_CFG1 位 PLLPRESEL 决定)被选择为 PLL 时钟的时钟源

    /*CK_PLL = (CK_HXTAL/2) * 27 = 108 MHz*/
    RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4 | RCU_CFG0_PLLMF_5);
    RCU_CFG0 |= RCU_PLL_MUL27;			//30 27 21 20 19 18:011010

#elif defined(GD32F30X_CL)
    /* CK_PLL = (CK_PREDIV0) * 27 = 108 MHz */ 
    RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4 | RCU_CFG0_PLLMF_5);
    RCU_CFG0 |= (RCU_PLLSRC_HXTAL_IRC48M | RCU_PLL_MUL27);

    /* CK_PREDIV0 = (CK_HXTAL)/5 *8 /10 = 4 MHz */ 
    RCU_CFG1 &= ~(RCU_CFG1_PLLPRESEL | RCU_CFG1_PREDV0SEL | RCU_CFG1_PLL1MF | RCU_CFG1_PREDV1 | RCU_CFG1_PREDV0);
    RCU_CFG1 |= (RCU_PLLPRESRC_HXTAL | RCU_PREDV0SRC_CKPLL1 | RCU_PLL1_MUL8 | RCU_PREDV1_DIV5 | RCU_PREDV0_DIV10);

    /* enable PLL1 */
    RCU_CTL |= RCU_CTL_PLL1EN;
    /* wait till PLL1 is ready */
    while((RCU_CTL & RCU_CTL_PLL1STB) == 0){
    }
#endif /* GD32F30X_HD and GD32F30X_XD */

    /* enable PLL */
    RCU_CTL |= RCU_CTL_PLLEN;  //PLL 被打开

    /* wait until PLL is stable */
    while(0U == (RCU_CTL & RCU_CTL_PLLSTB)){
    }

    /* enable the high-drive to extend the clock frequency to 120 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_PLL; 	//10:选择 CK_PLL 时钟作为 CK_SYS 时钟源

    /* wait until PLL is selected as system clock */
    while(0U == (RCU_CFG0 & RCU_SCSS_PLL)){
    }
}

三、修改参数详解

1.外部晶振时钟频率,在gd32f30x.h文件中,根据实际外部晶振频率修改参数,我的板子是8兆晶振,选择:
#define HXTAL_VALUE ((uint32_t)8000000)

/* define value of high speed crystal oscillator (HXTAL) in Hz */
#if !defined  HXTAL_VALUE
#ifdef GD32F30X_CL
#define HXTAL_VALUE    ((uint32_t)25000000) /*!< value of the external oscillator in Hz */
#else
#define HXTAL_VALUE    ((uint32_t)8000000) /* !< from 4M to 32M *!< value of the external oscillator in Hz*/
#endif /* HXTAL_VALUE */
#endif /* high speed crystal oscillator value */

2.外部晶振时钟频率,在system_gd32f30x.c文件中,_SYS_OSC_CLK为系统时钟主频率选择宏定义,使用外部晶振选择__HXTAL
我需要的系统时钟配置函数为:__SYSTEM_CLOCK_108M_PLL_HXTAL()

/* 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     (__HXTAL)                /* 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)
  1. 在system_gd32f30x.c文件中修改PLL分频倍频系数,带入公式:CK_PLL = (CK_HXTAL/分频系数) * PLL倍频系数 = xx MHz
    CFG0寄存器的30 27 21 20 19 18位:011010即倍频为27,最终系统时钟频率:108MHz
#if (defined(GD32F30X_HD) || defined(GD32F30X_XD))
    /* select HXTAL/2 as clock source */
    RCU_CFG0 &= ~(RCU_CFG0_PLLSEL | RCU_CFG0_PREDV0);
    RCU_CFG0 |= (RCU_PLLSRC_HXTAL_IRC48M | RCU_CFG0_PREDV0);//HXTAL 时钟或者 IRC48M 时钟(寄存器 RCU_CFG1 位 PLLPRESEL 决定)被选择为 PLL 时钟的时钟源

    /*CK_PLL = (CK_HXTAL/2) * 27 = 108 MHz*/
    RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4 | RCU_CFG0_PLLMF_5);
    RCU_CFG0 |= RCU_PLL_MUL27;

四、测试方法及注意事项

系统时钟准确与否关系到整个工程的功能能否正常运行,拿到祖传代码或者移植新项目一定记得先测时钟,别问为什么,问就是教训!!!

1.测试方法

1.通过系统函数获取时钟配置,uint32_t rcu_clock_freq_get(rcu_clock_freq_enum clock)函数可用来获取时钟参数,
获取APB1时钟:uclk = rcu_clock_freq_get(CK_APB1);
获取APB2时钟:uclk = rcu_clock_freq_get(CK_APB2);
获取CK_AHB时钟:uclk = rcu_clock_freq_get(CK_AHB);
获取CK_SYS时钟:uclk = rcu_clock_freq_get(CK_SYS);
STM32中函数测试方法位:
RCC_ClocksTypeDef RCC_Clocks;
RCC_GetClocksFreq(&RCC_Clocks);
2.上述方法是配置参数,结果是跟着参数走的,有时候与实际情况不一样,一般情况是写一个简单的定时器或延时函数,周期性改变某个GPIO电平,通过示波器进行检测是最准的
3.如图,通过配置CK_OUTO时钟输出引脚,配置引脚位复用输出模式,使用void rcu_ckout0_config(uint32_t ckout0_src)进行配置,然后也是通过示波器看波形
GD32_时钟配置解析

2.注意事项

1.#define HXTAL_VALUE ((uint32_t)8000000)外部晶振时钟频率,这个时钟频率与实际晶振频率不一样可能导致串口输出异常
2.如果没有外部晶振,被迫使用内部时钟,记得一定要通过配置的到并测试,不要不管配置等待系统默认选择内部时钟。
3.后续跟进

总结

系统时钟非常重要,各个板子的支持时钟可能不同,但是配置方法大同小异
如有错误,欢迎指正,原创不易,转载留名!文章来源地址https://www.toymoban.com/news/detail-491567.html

到了这里,关于GD32_时钟配置解析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • GD32F303高级定时器输出互补PWM-开发笔记

    ◼ 总通道数:4; ◼ 计数器宽度:16位; ◼ 时钟源可选:内部时钟,内部触发,外部输入,外部触发; ◼ 多种计数模式:向上计数,向下计数和中央计数; ◼ 正交编码器接口:被用来追踪运动和分辨旋转方向和位置; ◼ 霍尔传感器接口:用来做三相电机控制; ◼ 可编程

    2024年02月09日
    浏览(61)
  • GD32F303基于USBD库的usb custom hid 双向通讯实现

    默认已经建立好需要移植的GD32F303空白工程 环境:keil   GD库版本: V2.1.4 通讯工具: 链接:https://pan.baidu.com/s/1Ukuy0u52C9ufPGz9QcHONA  提取码:d9rf 正文开始 USBD库植步骤: 找到GD官网的软件包 本文中用的是GD32F30x_Firmware_Library_V2.1.4 将FirmwareGD32F30x_usbd_library 文件夹全部拷贝至工程

    2023年04月09日
    浏览(42)
  • 单片机GD32F303RCT6 (Macos环境)开发 (二十)—— 光感芯片veml7700的使用

    1、veml有7个寄存器,每个十六位,见图。 00是config寄存器, 01 02 是中断设置的阈值 03是节能模式的设置 04 是得到的光的亮度值 05是得到的data of whole WHITE 06是中断设置值。 2、我们只测试得到光的亮度值,所以veml寄存器设置如下: 设置gain,integration time ,power save mode ,interrup

    2024年02月04日
    浏览(62)
  • STM32 时钟树解析

    从stm32数据手册中我们可以看到关于stm32的许多组成部分,RCC、GPIO、DMA、ADC、DAC和定时器等。而其中最重要的就是时钟系统,若将stm32比作人的话,时钟就是stm32的心脏,GPIO是它的四肢。时钟系统为stm32提供能量,stm32能否正常的运行的核心就要时钟系统的正常运行。 stm32时钟

    2024年02月08日
    浏览(29)
  • GD32F30x系列---CAN通信收发配置

    GD32F30x系列CAN通信配置: 先找到CAN模块时钟时挂载在APB1总线上的,如下图所示: APB1总线的最大频率为60MHz,如下图所示: 根据总线频率可以计算出对应波特率的配置BS1,BS2等; 如果不会计算的话也可以直接使用工具,如下图所示: 这里工具会直接帮你你计算好BS1、BS2、P

    2024年01月19日
    浏览(98)
  • STM32/GD32学习指南-踩坑之(一)外部晶振配置,初始化失败,不起振

    GD32使用外部有源晶振和无源晶振的问题,型号为GD32 F450 一、GD32配置使用外部晶振 1.使用外部无源晶振 找到startup_gd32f450_470.s汇编文件,找到SystemInit()函数跳转进去 在底部找到system_clock_config()函数,再次跳转进去 选中宏定义:__SYSTEM_CLOCK_200M_PLL_IRC16M,跳转,如图 将内部时钟

    2024年02月13日
    浏览(50)
  • GD32F30x系列---串口通信(USART)基础配置(中断接收模式)

    GD32F30x系列USART数据帧可以通过全双工或半双工、同步或异步进行传输,且支持DMA功能,目前我们这里先不使用DMA,下一节再使用DMA与其对比。 其他的原理与解析就不再赘述,大家可以自行搜索相关资料,要多看数据手册。 1、创建一个usart.c文件和usart.h文件到对应的文件夹中

    2024年02月12日
    浏览(35)
  • GD32F470之网络lwip+UDP配置+lan8720芯片

    先申明,本栏目用的都是GD32F470芯片240M,软件用的是keil,编写用的是C++(其实和C没有区别). 和STM32的lwip配置大致一样,主要不一样的地方在于 PHY的配置顺序问题,下面会讲到. 我用的是lan8720,所以头文件要修改一下,在gd32f4xx_enet.h中。 把PHY_TYPE改为LAN8700, PHY_ADDRESS改为0, 这是

    2023年04月09日
    浏览(46)
  • STM32——STM32F103时钟解析(正点原子资料+HAL库代码分析)

    上次写系统时钟解析的时候说出一篇103的时钟解析,我就整理HAL库开发的正点的资料,给小白梳理,我也是小白,不做权威使用。 在 STM32 中,有五个时钟源,为 HSI、HSE、LSI、LSE、PLL。从时钟频率来分可以分为高速时钟源和低速时钟源,在这 5 个中 HIS,HSE 以及 PLL 是高速时钟

    2024年02月19日
    浏览(48)
  • 【STM32时钟配置】

    使用内部高速时钟时,工作频率最大为64Mhz,且不稳定,因此需要外接时钟源一般8MHZ。8MHZ经过PLL后SYSCLK为72Mhz;APB1预分频后为36MHZ,APB2预分频后为72MHZ,定时器1~8时钟频率为72MHZ,ADC经过6分频后为12MHZ 比F1系列多一个PLL;最大频率为168MHZ;APB1预分频为42MHZ;APB2预分频为84MHZ;

    2024年02月16日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包