1、认识时钟
HXTAL:高速外部时钟;
LXTAL:低速外部时钟;
IRC8M:高速内部时钟;
IRC40K:低速内部时钟;
HXTAL高速外部时钟为板子焊接的外部晶振,精度高,但同时功耗相较内部时钟也较高;
IRC8M内部高速时钟为芯片内部自带的时钟,精度较低,可以应用在对时钟要求不高的场景中;
IRC40K低速内部时钟用于独立看门狗的计数。
2、芯片资源架构(GD32F103xx系列MCU数据手册)
同时也可以参考GD32F10x系列MCU用户手册的MD系列(根据芯片资源所属选择)
找到自身所需的资源(TIMx、CAN等等)挂在APB1、APB2。
AHB总线为系统时钟的1分频,即最高频率为108MHz;
APB1总线为系统时钟的2分频,即最高频率为54MHz;
APB2总线为系统时钟的1分频,即最高频率为108MHz;
固件库的system_gd32f10x.c中找到
/* 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;
3、时钟树
开始分析时钟树,要从左往右分析。左侧四个框为四种时钟源,选择某一时钟源。
沿线路往右分析,经过各种倍频之后得到CK_SYS即系统时钟。继续往右分析,找到标注有“TIMER1、2、3…’”之类的框,可以看出其时钟来源于CK_APB1(最大54MHz),注意 在这个框中可以看到如下内容:TIMER1,2,3,4,5,6, 11,12,13 i f(APB1prescale =1)x1 else x 2;
如果APB1的分频系数为1,那么TIMER2的时钟频率=APB1时钟频率 x 1;
如果APB1的分频系数为2,那么TIMER2的时钟频率=APB1时钟频率 x 2;
由此可以算出,在GD32F103RC芯片中如果配置系统时钟CK_SYS=108MHz,则CK_APB1=54MHz,APB1prescale =2,因此CK_TIMER2 = CK_APB1 *2=CK_SYS=108MHz;
同理,如果配置CK_SYS=72MHz,则CK_TIMER2=72MHz;
4、修改代码
我们使用8M晶振
4.1、设置外部晶振
打开gd32f10x.h文件,此处在62行(仅参考)
/* define value of high speed crystal oscillator (HXTAL) in Hz */
#if !defined HXTAL_VALUE
#ifdef GD32F10X_CL
#define HXTAL_VALUE ((uint32_t)25000000) /*!< value of the external oscillator in Hz */
#else
#define HXTAL_VALUE ((uint32_t)8000000) /* !< from 4M to 16M *!< value of the external oscillator in Hz*/
#endif /* HXTAL_VALUE */
#endif /* high speed crystal oscillator value */
HXTAL_VALUE即板子所焊接的外部晶振的宏定义,改为8M
4.2、选定外部晶振作为系统主时钟
打开system_gd32f10x.c文件,此处在45行(仅参考)
/* system frequency define */
/*HXTAL:高速外部时钟; LXTAL:低速外部时钟;
IRC8M:高速内部时钟; IRC40K:低速内部时钟;*/
#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 原始为__IRC8M*/
将#define __SYS_OSC_CLK (__IRC8M)改为#define __SYS_OSC_CLK (__HXTAL)
4.3、配置系统时钟大小
打开system_gd32f10x.c文件,此处在61行(仅参考)
/* select a system clock by uncommenting the following line */
/* use 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)
/* use HXTAL (XD series CK_HXTAL = 8M, CL series CK_HXTAL = 25M) */
//#define __SYSTEM_CLOCK_HXTAL (uint32_t)(__HXTAL)
//#define __SYSTEM_CLOCK_24M_PLL_HXTAL (uint32_t)(24000000)
//#define __SYSTEM_CLOCK_36M_PLL_HXTAL (uint32_t)(36000000)
//#define __SYSTEM_CLOCK_48M_PLL_HXTAL (uint32_t)(48000000)
//#define __SYSTEM_CLOCK_56M_PLL_HXTAL (uint32_t)(56000000)
#define __SYSTEM_CLOCK_72M_PLL_HXTAL (uint32_t)(72000000)
//#define __SYSTEM_CLOCK_96M_PLL_HXTAL (uint32_t)(96000000)
//#define __SYSTEM_CLOCK_108M_PLL_HXTAL (uint32_t)(108000000)
此处我设置为72M,根据需求自己选择
4.4、修改倍频系数
4.3操作选择了72MHz作为时钟频率,此处来对时钟源(高速外部时钟)倍频处理
打开system_gd32f10x.c文件,此处在571行(仅参考)
找到此函数
static void system_clock_72m_hxtal(void)
static void system_clock_72m_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){
}
}
/* 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(GD32F10X_MD) || defined(GD32F10X_HD) || defined(GD32F10X_XD))
/* select HXTAL/2 as clock source */
RCU_CFG0 &= ~(RCU_CFG0_PLLSEL | RCU_CFG0_PREDV0);
RCU_CFG0 |= (RCU_PLLSRC_HXTAL | RCU_CFG0_PREDV0);
/* CK_PLL = (CK_HXTAL/2) * 18 = 72 MHz */
RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
/*此处我们的外部时钟选择的8MhZ,在GD32f10x.h-62行*/
RCU_CFG0 |= RCU_PLL_MUL18;
#elif defined(GD32F10X_CL)
/* CK_PLL = (CK_PREDIV0) * 18 = 72 MHz */
RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
RCU_CFG0 |= (RCU_PLLSRC_HXTAL | RCU_PLL_MUL18);
/* CK_PREDIV0 = (CK_HXTAL)/5 *8 /10 = 4 MHz */
RCU_CFG1 &= ~(RCU_CFG1_PREDV0SEL | RCU_CFG1_PLL1MF | RCU_CFG1_PREDV1 | RCU_CFG1_PREDV0);
RCU_CFG1 |= (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 /* GD32F10X_MD and GD32F10X_HD and GD32F10X_XD */
/* enable PLL */
RCU_CTL |= RCU_CTL_PLLEN;
/* wait until PLL is stable */
while(0U == (RCU_CTL & RCU_CTL_PLLSTB)){
}
/* select PLL as system clock */
RCU_CFG0 &= ~RCU_CFG0_SCS;
RCU_CFG0 |= RCU_CKSYSSRC_PLL;
/* wait until PLL is selected as system clock */
while(RCU_SCSS_PLL != (RCU_CFG0 & RCU_CFG0_SCSS)){
}
}
修改此处代码
#if (defined(GD32F10X_MD) || defined(GD32F10X_HD) || defined(GD32F10X_XD))
/* select HXTAL/2 as clock source */
RCU_CFG0 &= ~(RCU_CFG0_PLLSEL | RCU_CFG0_PREDV0);
RCU_CFG0 |= (RCU_PLLSRC_HXTAL | RCU_CFG0_PREDV0);
/* CK_PLL = (CK_HXTAL/2) * 18 = 72 MHz */
RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
/*此处我们的外部时钟选择的8MhZ,在GD32f10x.h-62行*/
RCU_CFG0 |= RCU_PLL_MUL18;
代入公式:CK_PLL = (CK_HXTAL/2) * 18 = 72 MHz
CK_PLL = (8/2) * 18 = 72 MHz
此处的8即为4.2步骤选择的外部晶振8M
拓展举例:外部为10M,(10/2)*18=90MHZ
而倍频系数18则为我们要选择的倍频RCU_PLL_MUL18
GO TO RCU_PLL_MUL18可以看到,自行计算选择
#endif /* GD32F10X_MD and GD32F10X_HD and GD32F10X_XD */
#define RCU_PLL_MUL16 CFG0_PLLMF(14) /*!< PLL source clock multiply by 16 */
#define RCU_PLL_MUL17 (PLLMF_4 | CFG0_PLLMF(0)) /*!< PLL source clock multiply by 17 */
#define RCU_PLL_MUL18 (PLLMF_4 | CFG0_PLLMF(1)) /*!< PLL source clock multiply by 18 */
#define RCU_PLL_MUL19 (PLLMF_4 | CFG0_PLLMF(2)) /*!< PLL source clock multiply by 19 */
#define RCU_PLL_MUL20 (PLLMF_4 | CFG0_PLLMF(3)) /*!< PLL source clock multiply by 20 */
#define RCU_PLL_MUL21 (PLLMF_4 | CFG0_PLLMF(4)) /*!< PLL source clock multiply by 21 */
#define RCU_PLL_MUL22 (PLLMF_4 | CFG0_PLLMF(5)) /*!< PLL source clock multiply by 22 */
#define RCU_PLL_MUL23 (PLLMF_4 | CFG0_PLLMF(6)) /*!< PLL source clock multiply by 23 */
#define RCU_PLL_MUL24 (PLLMF_4 | CFG0_PLLMF(7)) /*!< PLL source clock multiply by 24 */
#define RCU_PLL_MUL25 (PLLMF_4 | CFG0_PLLMF(8)) /*!< PLL source clock multiply by 25 */
#define RCU_PLL_MUL26 (PLLMF_4 | CFG0_PLLMF(9)) /*!< PLL source clock multiply by 26 */
#define RCU_PLL_MUL27 (PLLMF_4 | CFG0_PLLMF(10)) /*!< PLL source clock multiply by 27 */
#define RCU_PLL_MUL28 (PLLMF_4 | CFG0_PLLMF(11)) /*!< PLL source clock multiply by 28 */
#define RCU_PLL_MUL29 (PLLMF_4 | CFG0_PLLMF(12)) /*!< PLL source clock multiply by 29 */
#define RCU_PLL_MUL30 (PLLMF_4 | CFG0_PLLMF(13)) /*!< PLL source clock multiply by 30 */
#define RCU_PLL_MUL31 (PLLMF_4 | CFG0_PLLMF(14)) /*!< PLL source clock multiply by 31 */
#define RCU_PLL_MUL32 (PLLMF_4 | CFG0_PLLMF(15)) /*!< PLL source clock multiply by 32 */
至此你获得了一个拥有72MHZ的GD32单片机,爆赞!
有漏洞欢迎指出。