当前位置:网站首页>GD32F4(5):GD32F450时钟配置为200M过程分析
GD32F4(5):GD32F450时钟配置为200M过程分析
2022-06-12 07:18:00 【Little Grey Bear】
GD32F450时钟树分析
文章目录
1. 系统环境
系统:win10
IDE:keil5
开发板:GD官方评估板GD32450Z_EVAL
用户手册版本:GD32F4xx_yonghushouce_Rev2.6.pdf
标准库版本:GD32F4xx_Demo_Suites_V2.5.0
2. 时钟树图
对于任何的一款MCU,熟悉它的时钟树,熟悉mcu时钟的配置过程,会修改时钟配置都是非常有必要的。
对于GD32F4来讲,它的时钟控制单元提供了一系列频率的时钟功能,包括:
- 一个外部高速晶体振荡器时钟(HXTAL)。
- 一个外部低速晶体振荡器时钟(LXTAL),一般接32.768K晶振。
- 一个内部48M RC振荡器时钟(IRC48M),这个48M时钟是专门为时钟校准控制器(CTC)和USB提供时钟的。
- 一个内部16M RC振荡器时钟(IRC16M。
- 一个内部32K RC振荡器时钟(IRC32K)。
- 三个锁相环(PLL)、一个HXTAL时钟监视器(CKM)、时钟预分频器、时钟多路复用器和时钟门控电路。
GD32F4系列MCU的时钟树如下图:
AHB、APB1、AHB2和Cortex-M4时钟都源自系统时钟(CK_SYS),系统时钟的时钟源可以选择IRC16M、 HXTAL或PLL。
系统时钟的最大运行时钟频率可以达到240MHz,但数据手册显示GD32F450最高可达到200M,GD32F470最高到达240M。
独立看门狗定时器有独立的时钟源(IRC32K),实时时钟(RTC)使用IRC32K、 LXTAL或HXTAL的分频(通过配置RCU_CFG0寄存器的RTCDIV位)作为时钟源。
3. GD32F450的时钟配置函数
首先我们先简要的叙述GD32F450的启动过程,关于GD32F450编译和启动过程的详细分析,我将另外写一篇文章,本文重点是记录官方带的demo程序是如何将GD32F450时钟配置到200M的。
在startup_gd32f450.s文件中,有如下一段汇编代码:
;/* reset Handler */
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit ;将SystemInit函数地址加载到R0寄存器
BLX R0 ;执行SystemInit进行时钟设置,执行完后返回
LDR R0, =__main ;将__main函数地址加载到R0寄存器
BX R0 ;执行__main函数,不再返回,__main会再调用用户的main函数,从此进入用户编写的程序
ENDP
和STM32的启动过程一样,芯片上电先调用Reset_Handler,Reset_Handler会调用两个函数,一个是SystemInit配置系统时钟,另一个是__main,本章重点介绍SystemInit函数;
时钟的配置,由3个函数来完成,SystemInit执行会调用system_clock_config,system_clock_config执行在调用system_clock_200m_25m_hxtal,最后完成200M时钟的配置,具体的时钟配置函数和内部代码逻辑如下:
3.1 SystemInit函数
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 */
//其实这个CP10、CP11并不是真正的寄存器,它其实是协处理器的名字,ARM拥有16个协处理器,常被命名为CP0—CP15,其中CP0—CP7由厂家定义协处理功能,而CP8—CP15预留给ARM使用,CP15提供一些系统控制功能,这包括体系结构和特征识别,以及控制、状态信息和配置支持,还提供了性能监视器寄存器。CP14主要提供debug系统的控制、Thumb执行环境、字节码执行。CP10、CP11 两个协处理器一起,提供了浮点运算和向量操作,以及高级的 SIMD 指令扩展。协处理器8、9、12和13预留给ARM将来使用。因为协处理器是协助内核的,16个协处理器共提供出16*32位,基本每个位都有其相应的功能(不使用的位除外),我们平时都接触不到,因此我们平时都忽略它。
#endif
/* Reset the RCU clock configuration to the default reset state ------------*/
/* Set IRC16MEN bit */
//选择内部16M时钟
RCU_CTL |= RCU_CTL_IRC16MEN;
//将时钟进行2分频,等待时钟稳定,这里会等待的久一点,
RCU_MODIFY
//上面程序的目的是设置当前系统内核的时钟,此时系统的时钟为8M
//下面的Reset都是关闭操作,将各种时钟模块的使能全部关闭,变成失能
/* Reset CFG0 register */
RCU_CFG0 = 0x00000000U;
/* Reset HXTALEN, CKMEN and PLLEN bits */
//关闭外部高速时钟、高速时钟时钟监视器(CKM)、PLL锁相环使能
RCU_CTL &= ~(RCU_CTL_PLLEN | RCU_CTL_CKMEN | RCU_CTL_HXTALEN);
/* Reset PLLCFGR register */
RCU_PLL = 0x24003010U;
/* Reset HSEBYP bit */
RCU_CTL &= ~(RCU_CTL_HXTALBPS);
/* Disable all interrupts */
RCU_INT = 0x00000000U;
/* Configure the System clock source, PLL Multiplier and Divider factors, AHB/APBx prescalers and Flash settings ----------------------------------*/
//进入时钟配置,重新配置系统相关时钟
system_clock_config();
}
3.2 system_clock_config函数
static void system_clock_config(void)
{
...
#elif defined (__SYSTEM_CLOCK_200M_PLL_25M_HXTAL)
//利用外部高速时钟(评估板带的是25M晶振),配置系统时钟为200M
system_clock_200m_25m_hxtal();
#endif
}
3.3 system_clock_200m_25m_hxtal函数
static void system_clock_200m_25m_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 */
//若外部高速时钟异常,上面等待超时,则进入这里永远等待,系统会卡在while(1)里面
if(0U == (RCU_CTL & RCU_CTL_HXTALSTB)){
while(1){
//我感觉这里不合理,按理说外部时钟异常,应该触发相应的中断,并自动切换到内部高速时钟运行,而不是卡在这里。以后我有时间会把这个函数改改,现在先这样用吧。
}
}
//运行到这里,说明外部高速时钟正常启动,下面就要按照时钟树,来配置系统和各个模块的时钟
RCU_APB1EN |= RCU_APB1EN_PMUEN;//使能APB1总线
PMU_CTL |= PMU_CTL_LDOVS;//配置使能内部电压调节器1.2V域供电
//时钟的配置原则应该是从内向外,对照时钟树图,就可以非常清楚的明白时钟配置过程
/* HXTAL is stable */
/* AHB = SYSCLK */
RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;//系统SYS时钟到AHB总线时钟不进行分频
/* APB2 = AHB/2 */
RCU_CFG0 |= RCU_APB2_CKAHB_DIV2;//APB2是AHB的2分频
/* APB1 = AHB/4 */
RCU_CFG0 |= RCU_APB1_CKAHB_DIV4;//APB1是AHB的4分频
//GD32F450有3个PLL(PLL、PLLI2S、PLLSAI),这里只配置了一个PLL,
//现在外部晶振时钟是25M,通过PSC的25分频,变成1M,然后再PLL内倍频400倍,变成400M,然后再经过P进行2分频,变成200M,传给系统时钟。同时400M还进行了Q的9分频,产生大约48M的CK48M给USB提供时钟去了。
//当更换外部晶振的频率后的时候,通过修改PSC就可以进行匹配了
/* Configure the main PLL, PSC = 25, PLL_N = 400, PLL_P = 2, PLL_Q = 9 */
RCU_PLL = (25U | (400U << 6U) | (((2U >> 1U) - 1U) << 16U) |
(RCU_PLLSRC_HXTAL) | (9U << 24U));
/* enable PLL */
RCU_CTL |= RCU_CTL_PLLEN;//上面配置完了,就要使能PLL
/* wait until PLL is stable */
//等待PLL配置时钟稳定下来
while(0U == (RCU_CTL & RCU_CTL_PLLSTB)){
}
//在用户手册3.3.4章节,说如果1.2V电源域工作在高频状态下,且打开了多种功能,建议进入高驱动模式。
/* Enable the high-drive to extend the clock frequency to 200 Mhz */
//使能高驱动模式
PMU_CTL |= PMU_CTL_HDEN;
//等待PMU_CS寄存器的HDRF被置位
while(0U == (PMU_CS & PMU_CS_HDRF)){
}
/* select the high-drive mode */
//将LDO切换到高驱动模式
PMU_CTL |= PMU_CTL_HDS;
//等待PMU_CS寄存器的HDSRF被置位。进入高驱动模式
while(0U == (PMU_CS & PMU_CS_HDSRF)){
}
/* select PLL as system clock */
//设置SCS[1:0],将时钟切换到刚配置好的PLL这条系统时钟线路
RCU_CFG0 &= ~RCU_CFG0_SCS;
RCU_CFG0 |= RCU_CKSYSSRC_PLLP;
/* wait until PLL is selected as system clock */
//等待PLL这条系统时钟配置能稳定给系统提供时钟
while(0U == (RCU_CFG0 & RCU_SCSS_PLLP)){
}
//到此处,系统完成了从8M到200M的切换
}
3.4 根据程序中的配置,绘制配置后的时钟路线图
最后,我们来绘制一下程序中配置的路径,其中绿色的是开始配置8M的时钟线路,红色的是配置200M的时钟线路,如下图:
边栏推荐
- RT thread studio learning summary
- LVDS drive adapter
- Kali与编程:如何快速搭建OWASP网站安全实验靶场?
- 推荐17个提升开发效率的“轮子”
- When SQL server2019 is installed, the next step cannot be performed. How to solve this problem?
- TypeScript基础知识全集
- Database syntax related problems, solve a correct syntax
- D
- NOI openjudge 计算2的N次方
- Embedded gd32 code read protection
猜你喜欢

Thoroughly understand the "rotation matrix / Euler angle / quaternion" and let you experience the beauty of three-dimensional rotation

esp32 hosted

lambda 函数完美使用指南

ROS dynamic parameter configuration: use of dynparam command line tool (example + code)

Embedded gd32 code read protection

【图像去噪】基于非局部欧几里德中值 (NLEM) 实现图像去噪附matlab代码

The second revolution of reporting tools

libprint2

Detailed explanation of addressing mode in 8086

Detailed explanation of memory addressing in 8086 real address mode
随机推荐
Can official account also bring goods?
i. Mx6ul porting openwrt
企业微信官方 加解密库 PHP7版本报错 mcrypt_module_open 未定义方法 并且被PHP抛弃 解决方法使用 openssl解决
[image denoising] image denoising based on partial differential equation (PDE) with matlab code
What is the difference between < t > and object?
Unity用Shader实现UGU i图片边缘选中高亮
Troubleshooting of cl210openstack operation -- Chapter experiment
Paddepaddl 28 supports the implementation of GHM loss, a gradient balancing mechanism for arbitrary dimensional data (supports ignore\u index, class\u weight, back propagation training, and multi clas
Explain in detail the use of dynamic parameter adjustment and topic communication in ROS (principle + code + example)
【高考那些事】准大学生看过来,选择方向和未来,自己把握
Nine project management issues that PM should understand
leetcode. 39 --- combined sum
libprint2
推荐17个提升开发效率的“轮子”
Summary of software testing tools in 2021 - unit testing tools
【图像去噪】基于偏微分方程(PDE)实现图像去噪附matlab代码
C language sizeof strlen
Test manager defines and implements test metrics
Day 6 of pyhon
sql server 2019安装出现错误,如何解决