配置GD32和STM32的时钟树是硬件初始化的核心步骤,直接影响系统主频、外设工作频率及稳定性。两者均基于Cortex-M内核,但时钟管理模块(GD32的RCU vs STM32的RCC)的寄存器定义、分频逻辑和配置流程存在差异。以下分别说明两者的配置方法及核心注意事项。
一、时钟树基本组成(共性)
无论是GD32还是STM32,时钟树的核心组成部分一致,包括:
高速时钟源:HSE(外部高速晶振,通常8MHz/12MHz)、HSI(内部高速时钟,通常8MHz);
PLL锁相环:将输入时钟倍频后作为系统主时钟(如72MHz/108MHz/168MHz);
低速时钟源:LSE(外部低速晶振,32.768kHz,用于RTC)、LSI(内部低速时钟,约40kHz,备用);
时钟分配:通过AHB分频器、APB1/APB2分频器将主时钟分配到外设(如GPIO、UART、SPI等)。
二、GD32时钟树配置(以GD32F1x0系列为例,基于标准库)
GD32的时钟管理由RCU(Reset and Clock Unit) 模块负责,配置步骤如下:
1. 明确目标时钟需求
以“使用HSE(8MHz)作为PLL输入,配置系统主频为72MHz”为例:
系统时钟(SYSCLK)= 72MHz;
AHB时钟(HCLK)= SYSCLK(不分频)= 72MHz;
APB1时钟(PCLK1)= HCLK/2 = 36MHz(APB1外设最大支持36MHz);
APB2时钟(PCLK2)= HCLK(不分频)= 72MHz(APB2外设支持72MHz)。
2. 配置步骤(代码示例)
#include "gd32f1x0.h"
void rcu_config(void) {
// 步骤1:使能HSE并等待稳定
rcu_osci_on(RCU_HSE); // 使能HSE
while(rcu_osci_stab_wait(RCU_HSE) == ERROR); // 等待HSE稳定(超时返回ERROR)
// 步骤2:配置PLL(输入源为HSE,倍频系数9 → 8MHz × 9 = 72MHz)
rcu_pll_config(RCU_PLLSOURCE_HSE_DIV1, RCU_PLL_MUL9); // HSE不分频作为PLL输入,倍频9
rcu_osci_on(RCU_PLL); // 使能PLL
while(rcu_osci_stab_wait(RCU_PLL) == ERROR); // 等待PLL稳定
// 步骤3:配置AHB/APB1/APB2分频
rcu_hclk_div_config(RCU_SYSCLK_DIV1); // AHB = SYSCLK / 1 → 72MHz
rcu_ppre1_div_config(RCU_HCLK_DIV2); // APB1 = HCLK / 2 → 36MHz
rcu_ppre2_div_config(RCU_HCLK_DIV1); // APB2 = HCLK / 1 → 72MHz
// 步骤4:选择系统时钟源为PLL
rcu_system_clock_source_config(RCU_CKSYSSOURCE_PLLCLK); // SYSCLK = PLL输出(72MHz)
// 步骤5:验证系统时钟频率(可选)
while(rcu_system_clock_source_get() != RCU_CKSYSSOURCE_PLLCLK); // 等待时钟源切换完成
}
3. 关键函数说明
rcu_osci_on(RCU_HSE):使能指定时钟源(HSE/HSI/PLL/LSE/LSI);
rcu_pll_config():配置PLL输入源(HSE分频后或HSI分频后)和倍频系数(如RCU_PLL_MUL9表示×9);
分频配置函数:rcu_hclk_div_config()(AHB分频)、rcu_ppre1_div_config()(APB1分频)、rcu_ppre2_div_config()(APB2分频);
时钟源切换:rcu_system_clock_source_config()需在PLL稳定后调用。
三、STM32时钟树配置(以STM32F103系列为例,基于标准外设库SPL)
STM32的时钟管理由RCC(Reset and Clock Control) 模块负责,配置步骤与GD32类似,但函数接口不同。
1. 目标时钟需求(同GD32)
系统时钟(SYSCLK)= 72MHz(HSE 8MHz → PLL ×9);
HCLK = 72MHz,PCLK1=36MHz,PCLK2=72MHz。
2. 配置步骤(代码示例)
#include "stm32f10x.h"
void RCC_Configuration(void) {
// 步骤1:使能HSE并等待稳定
RCC_HSEConfig(RCC_HSE_ON); // 使能HSE
ErrorStatus HSEStartUpStatus = RCC_WaitForHSEStartUp(); // 等待HSE稳定
if(HSEStartUpStatus != SUCCESS) {
// HSE启动失败,可切换到HSI处理
}
// 步骤2:配置PLL(HSE作为输入,不分频,倍频9 → 8MHz ×9=72MHz)
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); // 配置PLL源和倍频
// 步骤3:配置AHB/APB1/APB2分频
RCC_HCLKConfig(RCC_SYSCLK_Div1); // AHB = SYSCLK /1 →72MHz
RCC_PCLK1Config(RCC_HCLK_Div2); // APB1 = HCLK /2 →36MHz
RCC_PCLK2Config(RCC_HCLK_Div1); // APB2 = HCLK /1 →72MHz
// 步骤4:使能PLL并等待稳定,切换系统时钟源为PLL
RCC_PLLCmd(ENABLE); // 使能PLL
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); // 等待PLL稳定
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); // SYSCLK = PLL输出(72MHz)
// 步骤5:验证时钟频率(可选)
while(RCC_GetSYSCLKSource() != 0x08); // 0x08表示PLL作为系统时钟源
}
3. 关键函数说明
RCC_HSEConfig():使能/关闭HSE;
RCC_PLLConfig():配置PLL输入源(RCC_PLLSource_HSE_Div1表示HSE不分频)和倍频系数(RCC_PLLMul_9表示×9);
分频配置:RCC_HCLKConfig()(AHB)、RCC_PCLK1Config()(APB1)、RCC_PCLK2Config()(APB2);
时钟源切换:RCC_SYSCLKConfig()需在PLL稳定后调用,通过RCC_GetSYSCLKSource()验证。
四、STM32 HAL库配置(以STM32F103为例)
HAL库封装了更简洁的接口,通过HAL_RCC_OscConfig()和HAL_RCC_ClockConfig()完成配置:
#include "stm32f1xx_hal.h"
void SystemClock_Config(void) {
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
// 配置HSE和PLL
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; // 8MHz ×9=72MHz
if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
Error_Handler();
}
// 配置系统时钟、AHB、APB1、APB2
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) {
Error_Handler();
}
}
注意:HAL库需配置Flash等待周期(FLASH_LATENCY_2),因72MHz主频下需2个等待周期。
五、核心差异与注意事项
PLL输入源选择
GD32:部分型号支持HSE分频(如RCU_PLLSOURCE_HSE_DIV2)或HSI分频作为PLL输入;
STM32F1:PLL输入源可为HSE(分频或不分频)或HSI/2,需根据手册确认。
外设时钟限制
APB1外设(如UART2、I2C)最大频率:GD32和STM32均为36MHz,需确保PCLK1 ≤36MHz;
APB2外设(如GPIO、SPI1)最大频率:通常为72MHz(GD32F1x0/STM32F103),部分高性能型号支持更高频率(如STM32F4支持168MHz)。
低速时钟配置
LSE(32.768kHz)用于RTC,配置时需使能对应引脚(如STM32的PC14/PC15);
若无需RTC,可跳过LSE配置,使用LSI作为备用。
时钟稳定等待
必须等待HSE/PLL稳定后再切换时钟源(通过rcu_osci_stab_wait或RCC_GetFlagStatus验证),否则可能导致系统异常。
Flash等待周期
当系统主频超过一定值(如STM32F1在48~72MHz时需2个等待周期),需配置Flash latency,否则CPU无法正确读取Flash数据(GD32同样需配置)。
六、调试建议
配置完成后,通过库函数获取实际时钟频率(如GD32的rcu_system_clock_freq_get(),STM32的RCC_GetClocksFreq()),验证是否与预期一致;
若外设工作异常(如UART波特率错误),优先检查对应外设的时钟源(如UART1挂在APB2,时钟为PCLK2);
参考芯片参考手册(RM) 的“时钟树”章节,明确外设与APB1/APB2的映射关系(如SPI1在APB2,SPI2在APB1)。
通过以上步骤,可正确配置GD32和STM32的时钟树,确保系统和外设稳定工作。实际配置时需根据具体芯片型号(如GD32F4xx、STM32L0系列)的手册调整参数,因不同系列的时钟树细节可能存在差异。
————————————————
版权声明:本文为CSDN博主「Shylock_Mister」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Shylock_Mister/article/details/153481184
|
|