stm32_Clock Init时钟系统初始化函数剖析
阿波罗STM32开发板:
《STM32FXX开发指南-HAL库版本》-4.3小节 STM32F4时钟系统
STM32FXxx官方资料:
《STM32F4xx中文参考手册》-第6章 复位和时钟控制
笔记基于正点原子官方视频
视频连接https://www.bilibili.com/video/BV1Wx411d7wT?p=71&spm_id_from=333.1007.top_right_bar_window_history.content.click
如有侵权,联系删除
一、STM32 有5个时钟源:HSI、HSE、LSI、LSE、PLL
-
HSI是高速内部时钟,RC振荡器,频率为16MHz,精度不高。可以直接作为系统时钟或者用作PLL时钟输入。
-
HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~26MHz。
-
LSI是低速内部时钟,RC振荡器,频率为32kHz,提供低功耗时钟。
-
LSE是低速外部时钟,接频率为32.768kHz的石英晶体。RTC
-
PLL为锁相环倍频输出。
-
系统时钟默认使用的是HSI时钟
1)STM32F4有三个PLL:
- 主PLL(PLL)由HSE或者HSI提供时钟信号,并具有两个不同的输出时钟。
①第一个输出PLLP用于生成高速的系统时钟
②第二个输出PLLQ为48M时钟,用于USB OTG FS时钟,随机数
发生器的时钟和SDIO时钟。 - 第一个专用PLL(PLLI2S)生成精确时钟,在I2S和SAI1上实现高品质音频
N是用于PLLI2S vco的倍频系数 ;
R是I2S时钟的分频系数 ;
Q是SAI时钟分频系数 ;P没用到。 - 第二个专用PLL(PLLSAI)同样用于生成精确时钟,用于SAI1输入时钟,同时还为LCD_TFT接口提供精确时钟。
N是用于PLLSAI vco的倍频系数 ;
Q是SAI时钟分频系数 ;
R是LTDC时钟的分频系数 。
2)主PLL时钟计算:
PLLCLK= HSE * N / (M*P)
二、系统初始化函数 SystemInit();
使用HAL库函数的时候,在系统启动之后会自动调用:
; Reset handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
三、时钟系统配置一般步骤:
- 使能PWR时钟:调用函数 __HAL_RCC_PWR_CLK_ENABLE()。
- 设置调压器输出电压级别:调用函数 __HAL_PWR_VOLTAGESCALING_CONFIG()。
- 选择是否开启Over-Driver功能:调用函数 HAL_PWREx_EnableOverDrive()。
- 配置时钟源相关参数:调用函数 HAL_RCC_OscConfig()。
- 配置系统时钟源以及AHB,APB1和APB2的分频系数:调用函数 HAL_RCC_ClockConfig()。
1.时钟源配置函数:HAL_RCC_OscConfig
在工程文件HALLIB-stm32f4xx_hal_rcc.h文件里
__weak HAL_StatusTypeDef HAL_RCC_OscConfig(RCC_OscInitTypeDef *RCC_OscInitStruct)
RCC_OscInitTypeDef定义如下
typedef struct
{
uint32_t OscillatorType;
uint32_t HSEState;
uint32_t LSEState;
uint32_t HSIState;
uint32_t HSICalibrationValue;
uint32_t LSIState;
RCC_PLLInitTypeDef PLL;
}RCC_OscInitTypeDef;
typedef struct
{
uint32_t PLLState;
uint32_t PLLSource;
uint32_t PLLM;
uint32_t PLLN;
uint32_t PLLP;
uint32_t PLLQ;
}RCC_PLLInitTypeDef;
HAL_RCC_OscConfig函数配置方法:
RCC_OscInitStructure.OscillatorType=RCC_OSCILLATORTYPE_HSE; //时钟源为HSE
RCC_OscInitStructure.HSEState=RCC_HSE_ON; //打开HSE
RCC_OscInitStructure.PLL.PLLState=RCC_PLL_ON; //打开PLL
RCC_OscInitStructure.PLL.PLLSource=RCC_PLLSOURCE_HSE; //PLL时钟源选择HSE
RCC_OscInitStructure.PLL.PLLM=pllm; //主PLL和音频PLL分频系数(PLL之前的分频)
RCC_OscInitStructure.PLL.PLLN=plln; //主PLL倍频系数(PLL倍频)
RCC_OscInitStructure.PLL.PLLP=pllp; //系统时钟的主PLL分频系数(PLL之后的分频)
RCC_OscInitStructure.PLL.PLLQ=pllq; //USB/SDIO/随机数产生器等的主PLL分频系数
HAL_RCC_OscConfig(&RCC_OscInitStructure); //初始化
后面我们在主函数里调用Stm32_Clock_Init(360,25,2,8); //设置时钟,180Mhz
查看Stm32_Clock_Init定义有:
可以看到Stm32_Clock_Init(360,25,2,8);中N=360;M=25;P=2;Q=8,对应时钟倍数关系如下图:
2.时钟配置函数:HAL_RCC_ClockConfig
HAL_StatusTypeDef HAL_RCC_ClockConfig(RCC_ClkInitTypeDef *RCC_ClkInitStruct, uint32_t FLatency)
在工程文件HALLIB-stm32f4xx_hal_rcc.h文件里
RCC_ClkInitTypeDef定义如下
typedef struct
{
uint32_t ClockType;
uint32_t SYSCLKSource;
uint32_t AHBCLKDivider;
uint32_t APB1CLKDivider;
uint32_t APB2CLKDivider;
}RCC_ClkInitTypeDef;
函数HAL_RCC_ClockConfig配置实例
//选中PLL作为系统时钟源并且配置HCLK,PCLK1和PCLK2
RCC_ClkInitStructure.ClockType=(RCC_CLOCKTYPE_SYSCLK|
RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2);
RCC_ClkInitStructure.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK; //系统时钟源
RCC_ClkInitStructure.AHBCLKDivider=RCC_SYSCLK_DIV1; //AHB分频系数为1
RCC_ClkInitStructure.APB1CLKDivider=RCC_HCLK_DIV4; //APB1分频系数为4
RCC_ClkInitStructure.APB2CLKDivider=RCC_HCLK_DIV2; //APB2分频系数为2
(&RCC_ClkInitStructure,FLASH_LATENCY_5);
//同时设置FLASH延时周期为5WS,也就是6个CPU周期。
配置系统时钟图如下:
3.FLASH等待周期表(STM32F429)
4.使能PWR时钟:
配置调压器输出级别和开启Over-driver功能需要开启PWR时钟。
5.配置调压器输出级别:
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
PWR_CR寄存器来配置:
位15:14 VOS[1:0]
00:保留(默认模式3选中)
01:级别3:HCLK最大频率120MHz
10:级别2:HCLK最大频率144MHz
11:级别1:HCLK最大频率168MHz,通过开启Over-drive模式可以达到180MHz。
6.开启Over-Driver功能:
HAL_StatusTypeDef HAL_PWREx_EnableOverDrive(void);
7.系统时钟配置完整代码
在工程文件SYSTEM-sys.c文件里
void Stm32_Clock_Init(u32 plln,u32 pllm,u32 pllp,u32 pllq)
{
HAL_StatusTypeDef ret = HAL_OK;
RCC_OscInitTypeDef RCC_OscInitStructure;
RCC_ClkInitTypeDef RCC_ClkInitStructure;
__HAL_RCC_PWR_CLK_ENABLE(); //使能PWR时钟
//下面这个设置用来设置调压器输出电压级别,以便在器件未以最大频率工作
//时使性能与功耗实现平衡,此功能只有STM32F42xx和STM32F43xx器件有,
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); //设置调压器输出电压级别1
RCC_OscInitStructure.OscillatorType=RCC_OSCILLATORTYPE_HSE; //时钟源为HSE
RCC_OscInitStructure.HSEState=RCC_HSE_ON; //打开HSE
RCC_OscInitStructure.PLL.PLLState=RCC_PLL_ON; //打开PLL
RCC_OscInitStructure.PLL.PLLSource=RCC_PLLSOURCE_HSE; //PLL时钟源选择HSE
RCC_OscInitStructure.PLL.PLLM=pllm; //主PLL和音频PLL分频系数(PLL之前的分频),取值范围:2~63.
RCC_OscInitStructure.PLL.PLLN=plln; //主PLL倍频系数(PLL倍频),取值范围:64~432.
RCC_OscInitStructure.PLL.PLLP=pllp; //系统时钟的主PLL分频系数(PLL之后的分频),取值范围:2,4,6,8.(仅限这4个值!)
RCC_OscInitStructure.PLL.PLLQ=pllq; //USB/SDIO/随机数产生器等的主PLL分频系数(PLL之后的分频),取值范围:2~15.
ret=HAL_RCC_OscConfig(&RCC_OscInitStructure);//初始化
if(ret!=HAL_OK) while(1);
ret=HAL_PWREx_EnableOverDrive(); //开启Over-Driver功能
if(ret!=HAL_OK) while(1);
//选中PLL作为系统时钟源并且配置HCLK,PCLK1和PCLK2
RCC_ClkInitStructure.ClockType=(RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2);
RCC_ClkInitStructure.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK; //设置系统时钟时钟源为PLL
RCC_ClkInitStructure.AHBCLKDivider=RCC_SYSCLK_DIV1; //AHB分频系数为1
RCC_ClkInitStructure.APB1CLKDivider=RCC_HCLK_DIV4; //APB1分频系数为4
RCC_ClkInitStructure.APB2CLKDivider=RCC_HCLK_DIV2; //APB2分频系数为2
ret=HAL_RCC_ClockConfig(&RCC_ClkInitStructure,FLASH_LATENCY_5); //同时设置FLASH延时周期为5WS,也就是6个CPU周期。
if(ret!=HAL_OK) while(1);
}