总结一下近段学习,便于以后查看。
1.时钟简介
手册上写到:
时钟控制单元提供了一系列频率的时钟功能,包括一个内部16M RC振荡器时钟(IRC16M)、 一个内部48M RC振荡器时钟(IRC48M)、一个外部高速晶体振荡器时钟(HXTAL)、一个内 部32K RC振荡器时钟(IRC32K)、一个外部低速晶体振荡器时钟(LXTAL)、三个锁相环(PLL)、 一个HXTAL时钟监视器、时钟预分频器、时钟多路复用器和时钟门控电路。 AHB、APB和Cortex®-M4时钟都源自系统时钟(CK_SYS),系统时钟的时钟源可以选择 IRC16M、HXTAL或PLL。系统时钟的最大运行时钟频率可以达到240MHz。具体的时钟配置可以参考数据手册上的时钟树。这里主要介绍一下系统时钟的配置。
重点是这句话
系统时钟的时钟源可以选择 IRC16M、HXTAL或PLL。
2.系统时钟配置
首先,在官方例程中的system_gd32f4xx.c文件里,有这样一段宏定义
/* system frequency define 具体数值修改在GD32F4xx.h里*/
#define __IRC16M (IRC16M_VALUE) /* internal 16 MHz RC oscillator frequency 内部部振荡器频率*/
#define __HXTAL (HXTAL_VALUE) /* high speed crystal oscillator frequency 高速外部振荡器频率*/
#define __SYS_OSC_CLK (__HXTAL) /* main oscillator frequency 主振荡器频率 选择外部晶振或内部晶振 */
这里主要是起提示作用,我是用外部晶振倍频,所以 __SYS_OSC_CLK (__HXTAL)。
确定好外部高速晶振的频率后,在gd32f4xx.h文件里修改HXTAL_VALUE的值。我用的8M晶振,所以修改如下
#define HXTAL_VALUE ((uint32_t)8000000)
主振荡器频率确定好后,再回到这句话“系统时钟的时钟源可以选择 IRC16M、HXTAL或PLL。”这里面pll是指将IRC16M或者HXTAL倍频到一定的频率。
/* select a system clock by uncommenting the following line 选择系统时钟 :直接使用内、外部晶振频率 or 将其倍频*/
//#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)
//#define __SYSTEM_CLOCK_240M_PLL_IRC16M (uint32_t)(240000000)
#define __SYSTEM_CLOCK_240M_PLL_8M_HXTAL (uint32_t)(240000000)//外部晶振8M 通过锁相环将系统时钟分、倍频到 240M
//#define __SYSTEM_CLOCK_240M_PLL_25M_HXTAL (uint32_t)(240000000)
在system_gd32f4xx.c文件中主要通过上面的宏定义,去选择相应的函数来确定系统时钟。
我这里选择将外部晶振8M通过锁相环将系统时钟倍频到 240M。具体的倍频代码如下
static void system_clock_240m_8m_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_CTL |= PMU_CTL_LDOVS;
/* HXTAL 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 = 8, PLL_N = 480, PLL_P = 2, PLL_Q = 10 */
RCU_PLL = (8U | (480U << 6U) | (((2U >> 1U) - 1U) << 16U) |
(RCU_PLLSRC_HXTAL) | (10U << 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 240 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)){
}
}
你也可以通过查看数据手册修改相应的倍频系数。
3.查看系统时钟
在gd32f4xx_rcu.c文件中有
uint32_t rcu_clock_freq_get(rcu_clock_freq_enum clock)
{
uint32_t sws, ck_freq = 0U;
uint32_t cksys_freq, ahb_freq, apb1_freq, apb2_freq;
uint32_t pllpsc, plln, pllsel, pllp, ck_src, idx, clk_exp;
/* exponent of AHB, APB1 and APB2 clock divider */
const uint8_t ahb_exp[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
const uint8_t apb1_exp[8] = {0, 0, 0, 0, 1, 2, 3, 4};
const uint8_t apb2_exp[8] = {0, 0, 0, 0, 1, 2, 3, 4};
sws = GET_BITS(RCU_CFG0, 2, 3);
switch(sws) {
/* IRC16M is selected as CK_SYS */
case SEL_IRC16M:
cksys_freq = IRC16M_VALUE;
break;
/* HXTAL is selected as CK_SYS */
case SEL_HXTAL:
cksys_freq = HXTAL_VALUE;
break;
/* PLLP is selected as CK_SYS */
case SEL_PLLP:
/* get the value of PLLPSC[5:0] */
pllpsc = GET_BITS(RCU_PLL, 0U, 5U);
plln = GET_BITS(RCU_PLL, 6U, 14U);
pllp = (GET_BITS(RCU_PLL, 16U, 17U) + 1U) * 2U;
/* PLL clock source selection, HXTAL or IRC16M/2 */
pllsel = (RCU_PLL & RCU_PLL_PLLSEL);
if(RCU_PLLSRC_HXTAL == pllsel) {
ck_src = HXTAL_VALUE;
} else {
ck_src = IRC16M_VALUE;
}
cksys_freq = ((ck_src / pllpsc) * plln) / pllp;
break;
/* IRC16M is selected as CK_SYS */
default:
cksys_freq = IRC16M_VALUE;
break;
}
/* calculate AHB clock frequency */
idx = GET_BITS(RCU_CFG0, 4, 7);
clk_exp = ahb_exp[idx];
ahb_freq = cksys_freq >> clk_exp;
/* calculate APB1 clock frequency */
idx = GET_BITS(RCU_CFG0, 10, 12);
clk_exp = apb1_exp[idx];
apb1_freq = ahb_freq >> clk_exp;
/* calculate APB2 clock frequency */
idx = GET_BITS(RCU_CFG0, 13, 15);
clk_exp = apb2_exp[idx];
apb2_freq = ahb_freq >> clk_exp;
/* return the clocks frequency */
switch(clock) {
case CK_SYS:
ck_freq = cksys_freq;
break;
case CK_AHB:
ck_freq = ahb_freq;
break;
case CK_APB1:
ck_freq = apb1_freq;
break;
case CK_APB2:
ck_freq = apb2_freq;
break;
default:
break;
}
return ck_freq;
}
可以通过调试信息来查看系统时钟频率

本文详细介绍了GD32F4xx微控制器中时钟控制单元的功能,特别是系统时钟的配置方法,包括使用不同时钟源(IRC16M、HXTAL和PLL)以及通过锁相环实现频率倍频。还提供了查看系统时钟频率的示例代码和调试方法。
1万+





