前言
本文主要介绍STM32F429的HAL库中的RCC用法。本文主要参考资料:
- Description of STM32F4 HAL and low-layer drivers
更新顺序:
- 20201026——更新旁路电路使用注释,HSICalibrationValue的取值范围写错,已经更正。
综述
特性
复位之后,芯片的时钟源为HSI。Flash预取缓存,D缓存,I缓存和所有外设全部禁用。此时,只有内部SRAM,FLASH和JTAG还在工作。
- 在高速总线和低速总线上都没有预分频,这些总线上映射的设备全都以HSI速度在运行。
- 所有外设的时钟都关闭,除了SRAM和FLASH。
- 所有GPIO为浮空输入状态,除了JTAG,其用于特定的debug功能。
一旦设备复位,用户软件必须做以下工作:
- 配置时钟源来驱动系统时钟(SYSCLK)。
- 配置系统时钟频率和Flash设定。
- 配置AHB和APB的预分频。
- 使能将要使用的GPIO。
- 配置不是SYSCLK驱动的外设时钟源。
为了管理外设读写寄存器,应该考虑到:外设有效使能相比于RCC外设时钟使能有一个延时:
- 延时取决于外设映射
- 若外设映射在AHB总线上,延时为2个AHB时钟。
- 若外设映射在APB总线上,延时为2个APB时钟。
解决方案:
对于AHB和APB外设中,虚拟读取外设已经插入到每一个 __HAL_RCC_PPP_CLK_ENABLE() 宏中。
初始化和反初始化函数
这个模块的函数实现以下功能:
- 配置内部/外部振荡器:HSE,HSI,LSE,LSI,PLL,CSS,MCO
- 系统总线时钟:SYSCLK,AHB,APB1,APB2
内部/外部时钟和PLL配置:
- 高速内部时钟(HSI),16MHz,工厂校正RC振荡器,可以直接使用或者间接用作系统时钟(SYSCLK)源。
- 低速内部时钟(LSI),32kHz,低功耗RC振荡器,可以用于IWDG或者RTC时钟源。
- 高速外部时钟(HSE),4-26MHz晶振,可以直接使用或者间接作用系统时钟(SYSCLK)源。另外还可以作为RTC时钟源。
- 低速外部时钟(LSE),32kHz晶振,可以用用作RTC时钟源。
- PLL,具有两路不同的输出时钟:
- 第一路用于产生高速的系统时钟。
- 第二路用于产生USB OTG FS,RNG,和SDIO。
- 时钟安全系统(CSS),一旦通过宏 __HAL_RCC_CSS_ENABLE() 使能CSS,若HSE时钟发生故障且HSE直接或者间接用作SYSCLK时钟源,则SYSCLK源则自动切回HSI且产生一个中断。这个中断与Cortex-M4 NMI (不可屏蔽中断)异常向量相连。
- 时钟输出1(MCO1),在PA8引脚上输出,输出的时钟可以一下时钟源分频:HSI,LSE,HSE,PLL。
- 时钟输出2(MCO2),在PC9引脚上输出,输出的时钟可以一下时钟源分频:HSE,PLL,SYSCLK,PLLI2S。
系统,AHB,APB总线时钟配置:
- 可以作为SYSCLK时钟源的有:
- HSI
- HSE
- PLL
- AHB时钟(HCLK)从SYSCLK分频而来,可以用于驱动CPU,存储器和映射到AHB上的外设。
- APB1(PCLK1)和APB2(PCLK2)时钟从AHB时钟分频而来,且用于驱动映射到该总线的外设。
- 对于STM32F429来说,最高系统时钟频率为180MHz,PLCK2为90MHz,PLCK1为42MHz。
注意:
- 更多关于时钟树等更多的信息,可以参考博客<STM32F429第七篇之RCC(复位与时钟)>。
- 关于总线挂载外设的更多信息,可以参考博客<STM32F429第五篇之HAL库内存映射实现>
这部分对应的API有:
外设控制函数
这部分函数用于控制RCC时钟频率。
这部分包含以下API:
- HAL_RCC_MCOConfig
- HAL_RCC_EnableCSS
- HAL_RCC_DisableCSS
- HAL_RCC_GetSysClockFreq
- HAL_RCC_GetHCLKFreq
- HAL_RCC_GetPCLK1Freq
- HAL_RCC_GetPCLK2Freq
- HAL_RCC_GetOscConfig
- HAL_RCC_GetClockConfig
- HAL_RCC_NMI_IRQHandler
- HAL_RCC_CSSCallback
函数介绍
HAL_RCC_DeInit
函数原型
void HAL_RCC_DeInit(void)
复位RCC时钟到默认状态。
注意:
- 默认状态如下所示:
- HSI打开且用作系统时钟源。
- HSE和PLL关闭
- CSS,MCO1和MCO2关闭
- 所有中断关闭
- 这个函数并不修改以下配置
- 外设时钟
- LSI,LSE,和RTC时钟
HAL_RCC_OscConfig
函数原型
HAL_StatusTypeDef HAL_RCC_OscConfig (RCC_OscInitTypeDef * RCC_OscInitStruct)
通过RCC_OscInitStruct中的参数初始化RCC 晶振的特定参数
注意:
- 当PLL用作系统时钟的时候,不可以被禁用。
- 该API不适用于将LSE Bypass转换成LSE On或者将LSE On 转化成LSE Bypass。用户需要首先将转换成LSE OFF,然后在去转换LSE Bypass或者LSE On。
- 该API不适用于将HSE Bypass转换成HSE On或者将HSE On 转化成HSE Bypass。用户需要首先将转换成HSE OFF,然后在去转换HSE Bypass或者HSE On。
参数
- RCC_OscInitStruct:包含RCC振荡器配置信息的 RCC_OscInitTypeDef 指针。
返回值类型
例程
- 该函数的使用例程可以参考博客<STM32F429第四篇之跑马灯程序详解>
HAL_RCC_ClockConfig
函数原型
HAL_StatusTypeDef HAL_RCC_ClockConfig (RCC_ClkInitTypeDef * RCC_ClkInitStruct, uint32_t FLatency)
根据特定参数RCC_ClkInitStruct来初始化CPU,AHB,APB系统时钟。
注意:
- CMSIS变量用来存储系统时钟频率,且通过本函数调用的HAL_RCC_GetHCLKFreq()函数来更新数据。
- 硬件使能HSI用作系统时钟源有以下几种情况:
- 复位
- 从STOP或者STANDBY模式中恢复
- 当CCS使能时,HSE用作系统时钟源的时候出现故障
- 只有当目标时钟源准备好,才可切换时钟源。若目标时钟源没有准备好就发送切换指令,则实际切换会等到目标时钟源准备好才发生。
- 根据设备电压,软件正确设置HPRE[3:0]以保证HCLK不超过允许的最大频率。
参数
- RCC_ClkInitStruct:包含RCC外设配置信息的 RCC_ClkInitTypeDef指针。
- FLatency:闪存延时,该参数由设备决定。
例程
该函数的使用例程可以参考博客<STM32F429第四篇之跑马灯程序详解>
HAL_RCC_MCOConfig
函数原型
void HAL_RCC_MCOConfig (uint32_t RCC_MCOx, uint32_t RCC_MCOSource, uint32_t RCC_MCODiv)
选择MCO1或者MCO2的时钟源。
注意:
- PA8/PC9应该配置成复用功能。
参数:
- RCC_MCOx:选择配置的引脚。
- RCC_MCOSource:指定输出的时钟源。
- RCC_MCODiv:指定输出时钟的分频。
参数的具体定义在文档:stm32f4xx_hal_rcc.h中,具体源程序如下:
/** @defgroup RCC_MCO_Index MCO Index
* @{
*/
#define RCC_MCO1 ((uint32_t)0x00000000U)
#define RCC_MCO2 ((uint32_t)0x00000001U)
/**
* @}
*/
/** @defgroup RCC_MCO1_Clock_Source MCO1 Clock Source
* @{
*/
#define RCC_MCO1SOURCE_HSI ((uint32_t)0x00000000U)
#define RCC_MCO1SOURCE_LSE RCC_CFGR_MCO1_0
#define RCC_MCO1SOURCE_HSE RCC_CFGR_MCO1_1
#define RCC_MCO1SOURCE_PLLCLK RCC_CFGR_MCO1
/**
* @}
*/
/** @defgroup RCC_MCOx_Clock_Prescaler MCOx Clock Prescaler
* @{
*/
#define RCC_MCODIV_1 ((uint32_t)0x00000000U)
#define RCC_MCODIV_2 RCC_CFGR_MCO1PRE_2
#define RCC_MCODIV_3 ((uint32_t)RCC_CFGR_MCO1PRE_0 | RCC_CFGR_MCO1PRE_2)
#define RCC_MCODIV_4 ((uint32_t)RCC_CFGR_MCO1PRE_1 | RCC_CFGR_MCO1PRE_2)
#define RCC_MCODIV_5 RCC_CFGR_MCO1PRE
/**
* @}
*/
下方参数定义在stm32f4xx_hal_rcc_ex.h中。
#define RCC_MCO2SOURCE_SYSCLK ((uint32_t)0x00000000U)
#define RCC_MCO2SOURCE_PLLI2SCLK RCC_CFGR_MCO2_0
#define RCC_MCO2SOURCE_HSE RCC_CFGR_MCO2_1
#define RCC_MCO2SOURCE_PLLCLK RCC_CFGR_MCO2
HAL_RCC_EnableCSS
函数原型
void HAL_RCC_EnableCSS (void )
使能时钟安全系统(CSS)。
注意:
- 若捕捉到HSE时钟故障,则晶振会自动进制且产生一个中断通知软件该故障,让MCU采取应急措施。
HAL_RCC_DisableCSS
函数原型
void HAL_RCC_DisableCSS(void)
禁用时钟安全系统(CSS)。
HAL_RCC_GetSysClockFreq
函数原型
uint32_t HAL_RCC_GetSysClockFreq (void )
返回系统时钟(SYSCLK)频率。
注意:
- 该函数计算系统频率并非芯片的真实系统频率。它是根据预定义值以及所选的时钟源:
- 若系统时钟源为HSI,函数返回值是基于HSI_VALUE(),该常数预定义在stm32f4xx_hal_conf.h文件,默认值为16MHz,但是真实参数会随着电压和温度变化。
- 若系统时钟源为HSE,函数返回值是基于HSE_VALUE(),该常数预定义在stm32f4xx_hal_conf.h文件,默认25MHz,用户必须保证该值与实际使用晶振频率一致,否则该函数将计算出错。
- 若系统时钟源为PLL,函数返回值是基于HSE_VALUE(**)或者HSI_VALUE(*)和PLL配置参数。
- 当HSE晶体频率不是整数值时,该函数返回值不正确。
- 该函数可以用于计算外设通信的脉宽或者计算其他的参数。
- 每当系统时钟改变时,则需要重新调用该函数更新系统时钟值。否则,基于该函数配置将会出错。
HAL_RCC_GetHCLKFreq
函数原型
uint32_t HAL_RCC_GetHCLKFreq (void )
返回HCLK频率。
注意:
- 每当HCLK频率变化时,该函数需要被调用以更新HCLK值。否则,基于该函数的配置将会出错。
- 调用该函数时,用以存储系统时钟的CMSIS变量将会被更新。
HAL_RCC_GetPCLK1Freq
函数原型
uint32_t HAL_RCC_GetPCLK1Freq (void )
返回PCLK1的频率。
注意:
- 每当PCLK1频率变化时,该函数需要被调用以更新HCLK值。否则,基于该函数的配置将会出错。
HAL_RCC_GetPCLK2Freq
函数原型
uint32_t HAL_RCC_GetPCLK2Freq (void )
返回PCLK2的频率
注意:
- 每当PCLK2频率变化时,该函数需要被调用以更新HCLK值。否则,基于该函数的配置将会出错。
HAL_RCC_GetOscConfig
函数原型
void HAL_RCC_GetOscConfig (RCC_OscInitTypeDef * RCC_OscInitStruct)
根据 RCC配置寄存器获取RCC_OscInitStruct对应的参数。
参数
- RCC_OscInitStruct:包含RCC振荡器配置信息的 RCC_OscInitTypeDef 指针。
HAL_RCC_GetClockConfig
函数原型
void HAL_RCC_GetClockConfig (RCC_ClkInitTypeDef * RCC_ClkInitStruct, uint32_t * pFLatency)
根据内部RCC寄存器设置,配置RCC_ClkInitStruct的对应参数。
参数
- RCC_ClkInitStruct:包含RCC外设配置信息的 RCC_ClkInitTypeDef指针。
- FLatency:闪存延时,该参数由设备决定。
HAL_RCC_NMI_IRQHandler
函数原型
void HAL_RCC_NMI_IRQHandler (void )
该函数处理RCC CSS中断请求。
注意:
- 该函数应该在NUM_Handler()处调用。
HAL_RCC_CSSCallback
函数原型
void HAL_RCC_CSSCallback (void )
RCC时钟安全系统中断回调。
结构体
HAL_StatusTypeDef
这个枚举类型定义了HAL的状态。
/**
* @brief HAL Status structures definition
*/
typedef enum
{
HAL_OK = 0x00U,
HAL_ERROR = 0x01U,
HAL_BUSY = 0x02U,
HAL_TIMEOUT = 0x03U
} HAL_StatusTypeDef;
RCC_OscInitTypeDef
/**
* @brief RCC Internal/External Oscillator (HSE, HSI, LSE and LSI) configuration structure definition
*/
typedef struct
{
uint32_t OscillatorType; /*!< The oscillators to be configured.
This parameter can be a value of @ref RCC_Oscillator_Type */
uint32_t HSEState; /*!< The new state of the HSE.
This parameter can be a value of @ref RCC_HSE_Config */
uint32_t LSEState; /*!< The new state of the LSE.
This parameter can be a value of @ref RCC_LSE_Config */
uint32_t HSIState; /*!< The new state of the HSI.
This parameter can be a value of @ref RCC_HSI_Config */
uint32_t HSICalibrationValue; /*!< The HSI calibration trimming value (default is RCC_HSICALIBRATION_DEFAULT).
This parameter must be a number between Min_Data = 0x00 and Max_Data = 0x1F */
uint32_t LSIState; /*!< The new state of the LSI.
This parameter can be a value of @ref RCC_LSI_Config */
RCC_PLLInitTypeDef PLL; /*!< PLL structure parameters */
}RCC_OscInitTypeDef;
OscillatorType(振荡器类型)
/** @defgroup RCC_Oscillator_Type Oscillator Type
* @{
*/
#define RCC_OSCILLATORTYPE_NONE ((uint32_t)0x00000000U)
#define RCC_OSCILLATORTYPE_HSE ((uint32_t)0x00000001U)
#define RCC_OSCILLATORTYPE_HSI ((uint32_t)0x00000002U)
#define RCC_OSCILLATORTYPE_LSE ((uint32_t)0x00000004U)
#define RCC_OSCILLATORTYPE_LSI ((uint32_t)0x00000008U)
/**
* @}
*/
HSEState(HSE状态)
/** @defgroup RCC_HSE_Config HSE Config
* @{
*/
#define RCC_HSE_OFF ((uint8_t)0x00U)
#define RCC_HSE_ON ((uint8_t)0x01U)
#define RCC_HSE_BYPASS ((uint8_t)0x05U)//当使用有源晶振的时候,选择旁路模式。
/**
* @}
*/
LSEState(LSE状态)
/** @defgroup RCC_LSE_Config LSE Config
* @{
*/
#define RCC_LSE_OFF ((uint8_t)0x00U)
#define RCC_LSE_ON ((uint8_t)0x01U)
#define RCC_LSE_BYPASS ((uint8_t)0x05U)
/**
* @}
*/
HSIState(HSI状态)
/** @defgroup RCC_HSI_Config HSI Config
* @{
*/
#define RCC_HSI_OFF ((uint8_t)0x00U)
#define RCC_HSI_ON ((uint8_t)0x01U)
#define RCC_HSICALIBRATION_DEFAULT ((uint32_t)0x10U) /* Default HSI calibration trimming value */
/**
* @}
*/
HSICalibrationValue(HSI校正微调值)
该值的默认值为RCC_HSICALIBRATION_DEFAULT。该参数取值范围为:0x00~0x1F。
LSIState(LSI状态)
/** @defgroup RCC_LSI_Config LSI Config
* @{
*/
#define RCC_LSI_OFF ((uint8_t)0x00U)
#define RCC_LSI_ON ((uint8_t)0x01U)
/**
* @}
*/
PLL(PLL初始化)
/**
* @brief RCC PLL configuration structure definition
*/
typedef struct
{
uint32_t PLLState; /*!< The new state of the PLL.
This parameter can be a value of @ref RCC_PLL_Config */
uint32_t PLLSource; /*!< RCC_PLLSource: PLL entry clock source.
This parameter must be a value of @ref RCC_PLL_Clock_Source */
uint32_t PLLM; /*!< PLLM: Division factor for PLL VCO input clock.
This parameter must be a number between Min_Data = 0 and Max_Data = 63 */
uint32_t PLLN; /*!< PLLN: Multiplication factor for PLL VCO output clock.
This parameter must be a number between Min_Data = 50 and Max_Data = 432
except for STM32F411xE devices where the Min_Data = 192 */
uint32_t PLLP; /*!< PLLP: Division factor for main system clock (SYSCLK).
This parameter must be a value of @ref RCC_PLLP_Clock_Divider */
uint32_t PLLQ; /*!< PLLQ: Division factor for OTG FS, SDIO and RNG clocks.
This parameter must be a number between Min_Data = 4 and Max_Data = 15 */
}RCC_PLLInitTypeDef;
此定义见于<stm32f4xx_hal_rcc_ex.h>。
其中,PLLState 定义如下:
/** @defgroup RCC_PLL_Config PLL Config
* @{
*/
#define RCC_PLL_NONE ((uint8_t)0x00U)
#define RCC_PLL_OFF ((uint8_t)0x01U)
#define RCC_PLL_ON ((uint8_t)0x02U)
/**
* @}
*/
PLLSource 定义如下
/** @defgroup RCC_PLL_Clock_Source PLL Clock Source
* @{
*/
#define RCC_PLLSOURCE_HSI RCC_PLLCFGR_PLLSRC_HSI
#define RCC_PLLSOURCE_HSE RCC_PLLCFGR_PLLSRC_HSE
/**
* @}
*/
RCC_ClkInitTypeDef
/**
* @brief RCC System, AHB and APB busses clock configuration structure definition
*/
typedef struct
{
uint32_t ClockType; /*!< The clock to be configured.
This parameter can be a value of @ref RCC_System_Clock_Type */
uint32_t SYSCLKSource; /*!< The clock source (SYSCLKS) used as system clock.
This parameter can be a value of @ref RCC_System_Clock_Source */
uint32_t AHBCLKDivider; /*!< The AHB clock (HCLK) divider. This clock is derived from the system clock (SYSCLK).
This parameter can be a value of @ref RCC_AHB_Clock_Source */
uint32_t APB1CLKDivider; /*!< The APB1 clock (PCLK1) divider. This clock is derived from the AHB clock (HCLK).
This parameter can be a value of @ref RCC_APB1_APB2_Clock_Source */
uint32_t APB2CLKDivider; /*!< The APB2 clock (PCLK2) divider. This clock is derived from the AHB clock (HCLK).
This parameter can be a value of @ref RCC_APB1_APB2_Clock_Source */
}RCC_ClkInitTypeDef;
ClockType(时钟类型)
/** @defgroup RCC_System_Clock_Type System Clock Type
* @{
*/
#define RCC_CLOCKTYPE_SYSCLK ((uint32_t)0x00000001U)
#define RCC_CLOCKTYPE_HCLK ((uint32_t)0x00000002U)
#define RCC_CLOCKTYPE_PCLK1 ((uint32_t)0x00000004U)
#define RCC_CLOCKTYPE_PCLK2 ((uint32_t)0x00000008U)
/**
* @}
*/
SYSCLKSource(系统时钟源)
/** @defgroup RCC_System_Clock_Source System Clock Source
* @{
*/
#define RCC_SYSCLKSOURCE_HSI RCC_CFGR_SW_HSI
#define RCC_SYSCLKSOURCE_HSE RCC_CFGR_SW_HSE
#define RCC_SYSCLKSOURCE_PLLCLK RCC_CFGR_SW_PLL
#define RCC_SYSCLKSOURCE_PLLRCLK ((uint32_t)(RCC_CFGR_SW_0 | RCC_CFGR_SW_1))
/**
* @}
*/
AHBCLKDivider(AHB时钟预分频)
/** @defgroup RCC_AHB_Clock_Source AHB Clock Source
* @{
*/
#define RCC_SYSCLK_DIV1 RCC_CFGR_HPRE_DIV1
#define RCC_SYSCLK_DIV2 RCC_CFGR_HPRE_DIV2
#define RCC_SYSCLK_DIV4 RCC_CFGR_HPRE_DIV4
#define RCC_SYSCLK_DIV8 RCC_CFGR_HPRE_DIV8
#define RCC_SYSCLK_DIV16 RCC_CFGR_HPRE_DIV16
#define RCC_SYSCLK_DIV64 RCC_CFGR_HPRE_DIV64
#define RCC_SYSCLK_DIV128 RCC_CFGR_HPRE_DIV128
#define RCC_SYSCLK_DIV256 RCC_CFGR_HPRE_DIV256
#define RCC_SYSCLK_DIV512 RCC_CFGR_HPRE_DIV512
/**
* @}
*/
APBCLKDivider(APB1和APB2时钟预分频)
/** @defgroup RCC_APB1_APB2_Clock_Source APB1/APB2 Clock Source
* @{
*/
#define RCC_HCLK_DIV1 RCC_CFGR_PPRE1_DIV1
#define RCC_HCLK_DIV2 RCC_CFGR_PPRE1_DIV2
#define RCC_HCLK_DIV4 RCC_CFGR_PPRE1_DIV4
#define RCC_HCLK_DIV8 RCC_CFGR_PPRE1_DIV8
#define RCC_HCLK_DIV16 RCC_CFGR_PPRE1_DIV16
/**
* @}
*/