当前位置:网站首页>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的时钟线路,如下图:
边栏推荐
- 9 Sequence container
- Category 7
- RT thread studio learning (x) mpu9250
- Thoroughly understand the "rotation matrix / Euler angle / quaternion" and let you experience the beauty of three-dimensional rotation
- Scons编译IMGUI
- Planning and design of 1000 person medium-sized campus / enterprise network based on ENSP and firewall (with all configuration commands)
- Detailed explanation of coordinate tracking of TF2 operation in ROS (example + code)
- Network packet loss troubleshooting
- [image detection] SAR image change detection based on depth difference and pcanet with matlab code
- Decoupling in D
猜你喜欢

Day 5 of pyhon

leetcode. 39 --- combined sum

CL210OpenStack操作的故障排除--章節實驗
![[image denoising] salt and pepper noise image denoising based on Gaussian filter, mean filter, median filter and bilateral filter with matlab code attached](/img/f2/16db0b11d4e69946ec45b67ab41b81.png)
[image denoising] salt and pepper noise image denoising based on Gaussian filter, mean filter, median filter and bilateral filter with matlab code attached

Jackson XML is directly converted to JSON without writing entity classes manually

Test left shift real introduction

Day 6 of pyhon

sql——课程实验考查

SQL Server 2019 installation error. How to solve it

Elegantly spliced XML
随机推荐
I met 15 people recently and found that I couldn't answer the basic question of this test
Descscheduler secondary scheduling makes kubernetes load more balanced
‘CMRESHandler‘ object has no attribute ‘_timer‘,socket.gaierror: [Errno 8] nodename nor servname pro
Noi openjudge computes the n-th power of 2
[Li Kou] curriculum series
Lambda function perfect use guide
d的扩大@nogc
报表工具的二次革命
LED lighting experiment with simulation software proteus
Demonstrate "topic communication, action communication, service communication and parameter server" with a small turtle case
Principle and application of PWM
RT thread studio learning (VII) using multiple serial ports
循环链表和双向链表—课上课后练
Circular linked list and bidirectional linked list - practice after class
postman拼接替换参数循环调用接口
d的自动无垃集代码.
Beginners can't tell the difference between framework and class library
libprint2
速度自关联函数—LAMMPS V.S MATALB
最近面了15个人,发现这个测试基础题都答不上来...