3. G4时钟系统:HSI/HSE/PLL配置、时钟树分析、SysTick定时器
时钟,说白了就是MCU的心脏。没有它,芯片就是一坨硅。我刚开始做数字电源那会儿,总觉得时钟配置嘛,无非就是改几个寄存器,能有多难?直到有一次,我做的图腾柱PFC在满载测试时突然炸管,查了三天才发现是时钟抖动导致PWM相位错位。嗯,从那以后,我再也不敢小看时钟树了。
今天咱们就好好捋一捋STM32G4的时钟系统。G4系列在数字电源领域这么火,很大程度上得益于它那颗灵活又精准的“心脏”。
3.1 时钟源概览:你有哪些选择?
G4的时钟源,说白了就四种:
- HSI16:内部16MHz高速振荡器。上电默认就用它,精度一般,胜在即开即用。
- HSE:外部高速晶振,通常接4-26MHz的晶振。精度高,适合对频率敏感的应用。
- PLL:锁相环,可以把低频时钟倍频到高频。G4的PLL最高能跑到170MHz。
- LSI/LSE:低速时钟,主要给RTC和独立看门狗用,咱们做电源主控一般不太关心。
3.2 时钟树分析:信号是怎么流到你手里的?
时钟树,你可以想象成城市的水管网络。水源(时钟源)经过泵站(PLL)增压,再通过阀门(分频器)分配到各个水龙头(外设)。
G4的时钟树有几个关键节点:
- SYSCLK:系统时钟,CPU和AHB总线的主时钟。最高170MHz。
- HCLK:AHB总线时钟,由SYSCLK分频得到。给Flash、DMA、GPIO这些高速外设用。
- PCLK1/PCLK2:APB外设时钟。PCLK1最高170MHz,PCLK2最高170MHz。注意,定时器的时钟可能比PCLK更高,因为有个倍频器。
- ADC时钟:G4的ADC很特殊,它有自己的独立时钟源,最高60MHz。这一点在做电源采样时特别重要。
为什么会强调这个?我在做一款LLC谐振变换器时,发现ADC采样值总是跳变。查到最后,发现是ADC时钟配置过高,超过了60MHz的限制。你想想看,采样值不准,环路控制能稳吗?
3.3 PLL配置:把频率“拧”上去
PLL的配置公式其实很简单:
VCO频率 = 输入时钟 / M * N
系统时钟 = VCO频率 / P / R
其中M、N、P、R都是分频/倍频系数。G4的PLL有多个输出分支,可以同时产生不同频率的时钟。
我常用的配置套路是这样的:
- 先用HSE 8MHz作为输入源
- M设为2,得到4MHz的PLL输入
- N设为85,VCO频率 = 4MHz * 85 = 340MHz
- P设为2,得到170MHz的系统时钟
- R设为2,给ADC提供170MHz/2 = 85MHz?不对,ADC最高60MHz,所以R要再分频。
3.4 SysTick定时器:系统的心跳
SysTick,说白了就是一个24位的递减计数器。它挂在系统时钟上,每来一个时钟脉冲就减1,减到0就触发中断。
在数字电源里,SysTick的用途很广:
- 任务调度:比如每1ms执行一次慢速环路,每100us执行一次快速保护。
- 软件延时:虽然我不推荐在电源控制中用软件延时,但调试时偶尔用用还行。
- 时间基准:给RTOS提供心跳,或者给状态机提供计时。
配置SysTick的代码很简单:
// 配置SysTick为1ms中断
// 假设系统时钟为170MHz
// 重装载值 = 170000000 / 1000 = 170000
SysTick_Config(170000);
注意,SysTick的时钟源可以选择系统时钟或者系统时钟的8分频。我建议用系统时钟直接驱动,这样精度更高。但如果你需要低功耗模式,可以考虑用8分频。
3.5 实战配置:从HSI到PLL的完整切换
下面我给出一段完整的时钟初始化代码。这段代码我在多个项目中验证过,你可以直接拿来用:
void SystemClock_Config(void)
{
// 1. 开启HSE
RCC->CR |= RCC_CR_HSEON;
while(!(RCC->CR & RCC_CR_HSERDY));
// 2. 配置PLL
RCC->PLLCFGR = 0;
RCC->PLLCFGR |= (2 << RCC_PLLCFGR_PLLM_Pos); // M=2
RCC->PLLCFGR |= (85 << RCC_PLLCFGR_PLLN_Pos); // N=85
RCC->PLLCFGR |= (1 << RCC_PLLCFGR_PLLP_Pos); // P=2
RCC->PLLCFGR |= (2 << RCC_PLLCFGR_PLLR_Pos); // R=2
RCC->PLLCFGR |= RCC_PLLCFGR_PLLSRC_HSE; // 时钟源为HSE
// 3. 开启PLL
RCC->CR |= RCC_CR_PLLON;
while(!(RCC->CR & RCC_CR_PLLRDY));
// 4. 配置Flash等待周期
// 170MHz需要5个等待周期
FLASH->ACR = FLASH_ACR_LATENCY_5WS;
// 5. 切换系统时钟到PLL
RCC->CFGR |= RCC_CFGR_SW_PLL;
while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);
// 6. 配置AHB/APB分频
RCC->CFGR |= RCC_CFGR_HPRE_DIV1; // HCLK = SYSCLK
RCC->CFGR |= RCC_CFGR_PPRE1_DIV1; // PCLK1 = HCLK
RCC->CFGR |= RCC_CFGR_PPRE2_DIV1; // PCLK2 = HCLK
// 7. 配置SysTick
SysTick_Config(SystemCoreClock / 1000);
}
3.6 避坑指南:时钟配置的常见问题
做数字电源这么多年,我总结了几条时钟相关的血泪教训:
- Flash等待周期:系统频率越高,Flash读取越慢。170MHz下必须配5个等待周期,否则程序会随机崩溃。
- ADC时钟独立:G4的ADC有自己的时钟树,别跟系统时钟混为一谈。ADC时钟超过60MHz,采样精度会急剧下降。
- PLL锁定时间:PLL从开启到稳定需要几十微秒。如果你在中断里切换时钟源,一定要考虑这个延时。
- 时钟输出监测:G4的MCO引脚可以把内部时钟输出到示波器。我调试时经常用这个功能来确认时钟频率是否准确。
嗯,时钟系统这块儿就先聊到这儿。下一章咱们会深入PWM定时器的配置,那才是数字电源控制的核心。到时候你会发现,时钟配置的每一个细节,都会直接影响PWM的精度和稳定性。