赞
踩
STM32时钟的配置主要是通过配置RCC相关的寄存器,限于篇幅,相关寄存器的表格和功能可到芯片手册上查知。意法半导体公司对于提供了STM32的固件库,通过调用固件库中的库函数,可以避免直接对于寄存器进行操作,方便我们对于STM32的寄存器进行配置。这些固件库函数其实是对于STM32中时钟树系统的一个刻画,STM32时钟的具体配置还是要落实到寄存器的配置上去,固件库函数只是提供了一个方便我们配置各寄存器的接口。
本文以void RCC_PLLConfig(uint32_t RCC_PLLSource, uint32_t RCC_PLLMul)函数为例,对这种封装进行简要介绍。
void RCC_PLLConfig(uint32_t RCC_PLLSource, uint32_t RCC_PLLMul);
其主要功能是选择进入PLL锁相环的时钟信号源,并选择对于时钟信号的倍频系数。
打开函数的具体实现,阅读其函数的具体介绍:
- /**
- * @brief Configures the PLL clock source and multiplication factor.
- * @note This function must be used only when the PLL is disabled.
- * @param RCC_PLLSource: specifies the PLL entry clock source.
- * For @b STM32_Connectivity_line_devices or @b STM32_Value_line_devices,
- * this parameter can be one of the following values:
- * @arg RCC_PLLSource_HSI_Div2: HSI oscillator clock divided by 2 selected as PLL clock entry
- * @arg RCC_PLLSource_PREDIV1: PREDIV1 clock selected as PLL clock entry
- * For @b other_STM32_devices, this parameter can be one of the following values:
- * @arg RCC_PLLSource_HSI_Div2: HSI oscillator clock divided by 2 selected as PLL clock entry
- * @arg RCC_PLLSource_HSE_Div1: HSE oscillator clock selected as PLL clock entry
- * @arg RCC_PLLSource_HSE_Div2: HSE oscillator clock divided by 2 selected as PLL clock entry
- * @param RCC_PLLMul: specifies the PLL multiplication factor.
- * For @b STM32_Connectivity_line_devices, this parameter can be RCC_PLLMul_x where x:{[4,9], 6_5}
- * For @b other_STM32_devices, this parameter can be RCC_PLLMul_x where x:[2,16]
- * @retval None
- */
可知其参数定义分为互联形产品和非互联形产品,我们看非互联形产品:
第一个参数选择PLL锁相环时钟信号来源uint32_t RCC_PLLSource,其值可以选择为:
- 高速内部时钟2分频RCC_PLLSource_HSI_Div2
- 高速外部时钟1分频RCC_PLLSource_HSE_Div1
- 高速外部时钟2分频RCC_PLLSource_HSE_Div2
跳转其定义位置找到:
- /** @defgroup PLL_entry_clock_source
- * @{
- */
- #define RCC_PLLSource_HSI_Div2 ((uint32_t)0x00000000)
- #if !defined (STM32F10X_LD_VL) && !defined (STM32F10X_MD_VL) && !defined (STM32F10X_HD_VL) && !defined (STM32F10X_CL)
- #define RCC_PLLSource_HSE_Div1 ((uint32_t)0x00010000)
- #define RCC_PLLSource_HSE_Div2 ((uint32_t)0x00030000)
- #define IS_RCC_PLL_SOURCE(SOURCE) (((SOURCE) == RCC_PLLSource_HSI_Div2) || \
- ((SOURCE) == RCC_PLLSource_HSE_Div1) || \
- ((SOURCE) == RCC_PLLSource_HSE_Div2))
- #else
- #define RCC_PLLSource_PREDIV1 ((uint32_t)0x00010000)
- #define IS_RCC_PLL_SOURCE(SOURCE) (((SOURCE) == RCC_PLLSource_HSI_Div2) || \
- ((SOURCE) == RCC_PLLSource_PREDIV1))
- #endif /* STM32F10X_CL */
- /**
- * @}
- */
这部分的意思是:
对于非互联形产品,定义如下:
- 高速内部时钟2分频RCC_PLLSource_HSI_Div2 ((uint32_t)0x00000000)
- 高速外部时钟1分频RCC_PLLSource_HSE_Div1 ((uint32_t)0x00010000)
- 高速外部时钟2分频RCC_PLLSource_HSE_Div2 ((uint32_t)0x00030000)
对于互联形产品,定义如下:(具体要看互联形的时钟树图)
- 高速内部时钟2分频RCC_PLLSource_HSI_Div2 ((uint32_t)0x00000000)
- 第一次分频选择的信号RCC_PLLSource_PREDIV1 ((uint32_t)0x00010000)
可是为什么要这样定义呢?着就和控制相关的寄存器有关了。查看非互联形产品芯片手册,找到时钟配置寄存器RCC_CFGR。
找到位16和位17:
可知,位16和位17所控制的相关逻辑为:
位16:PLLSRC | 位17:PLLTPRE | 功能 |
0 | 0 | 选择HSI2分频信号 |
0 | / | 选择HSI2分频信号 |
1 | 0 | 选择HSE1分频信号 |
1 | 1 | 选择HSE2分频信号 |
再看上面宏定义的配置,为什么这么定义就非常清晰了。
第二个参数选择PLL锁相环倍频系数uint32_t RCC_PLLMul,对于非互联形产品,其值可以选择为:
RCC_PLLMul_X X取值可以为2-16
跳转其指定位置:
- /**
- * @}
- */
-
- /** @defgroup PLL_multiplication_factor
- * @{
- */
-
- #ifndef STM32F10X_CL
-
- #define RCC_PLLMul_2 ((uint32_t)0x00000000)
-
- #define RCC_PLLMul_3 ((uint32_t)0x00040000)
-
- #define RCC_PLLMul_4 ((uint32_t)0x00080000)
-
- #define RCC_PLLMul_5 ((uint32_t)0x000C0000)
-
- #define RCC_PLLMul_6 ((uint32_t)0x00100000)
-
- #define RCC_PLLMul_7 ((uint32_t)0x00140000)
-
- #define RCC_PLLMul_8 ((uint32_t)0x00180000)
-
- #define RCC_PLLMul_9 ((uint32_t)0x001C0000)
-
- #define RCC_PLLMul_10 ((uint32_t)0x00200000)
-
- #define RCC_PLLMul_11 ((uint32_t)0x00240000)
-
- #define RCC_PLLMul_12 ((uint32_t)0x00280000)
-
- #define RCC_PLLMul_13 ((uint32_t)0x002C0000)
-
- #define RCC_PLLMul_14 ((uint32_t)0x00300000)
-
- #define RCC_PLLMul_15 ((uint32_t)0x00340000)
-
- #define RCC_PLLMul_16 ((uint32_t)0x00380000)
-
- #define IS_RCC_PLL_MUL(MUL) (((MUL) == RCC_PLLMul_2) || ((MUL) == RCC_PLLMul_3) || \
- ((MUL) == RCC_PLLMul_4) || ((MUL) == RCC_PLLMul_5) || \
-
- ((MUL) == RCC_PLLMul_6) || ((MUL) == RCC_PLLMul_7) || \
-
- ((MUL) == RCC_PLLMul_8) || ((MUL) == RCC_PLLMul_9) || \
-
- ((MUL) == RCC_PLLMul_10) || ((MUL) == RCC_PLLMul_11) || \
-
- ((MUL) == RCC_PLLMul_12) || ((MUL) == RCC_PLLMul_13) || \
-
- ((MUL) == RCC_PLLMul_14) || ((MUL) == RCC_PLLMul_15) || \
-
- ((MUL) == RCC_PLLMul_16))
-
- #else
-
- #define RCC_PLLMul_4 ((uint32_t)0x00080000)
-
- #define RCC_PLLMul_5 ((uint32_t)0x000C0000)
-
- #define RCC_PLLMul_6 ((uint32_t)0x00100000)
-
- #define RCC_PLLMul_7 ((uint32_t)0x00140000)
-
- #define RCC_PLLMul_8 ((uint32_t)0x00180000)
-
- #define RCC_PLLMul_9 ((uint32_t)0x001C0000)
-
- #define RCC_PLLMul_6_5 ((uint32_t)0x00340000)
-
-
-
- #define IS_RCC_PLL_MUL(MUL) (((MUL) == RCC_PLLMul_4) || ((MUL) == RCC_PLLMul_5) || \
- ((MUL) == RCC_PLLMul_6) || ((MUL) == RCC_PLLMul_7) || \
-
- ((MUL) == RCC_PLLMul_8) || ((MUL) == RCC_PLLMul_9) || \
-
- ((MUL) == RCC_PLLMul_6_5))
-
- #endif /* STM32F10X_CL */
-
- /**
- * @}
- */
其具体意思为,对于非互联形产品,其有定义:
- #define RCC_PLLMul_2 ((uint32_t)0x00000000)
- #define RCC_PLLMul_3 ((uint32_t)0x00040000)
- #define RCC_PLLMul_4 ((uint32_t)0x00080000)
- #define RCC_PLLMul_5 ((uint32_t)0x000C0000)
- #define RCC_PLLMul_6 ((uint32_t)0x00100000)
- #define RCC_PLLMul_7 ((uint32_t)0x00140000)
- #define RCC_PLLMul_8 ((uint32_t)0x00180000)
- #define RCC_PLLMul_9 ((uint32_t)0x001C0000)
- #define RCC_PLLMul_10 ((uint32_t)0x00200000)
- #define RCC_PLLMul_11 ((uint32_t)0x00240000)
- #define RCC_PLLMul_12 ((uint32_t)0x00280000)
- #define RCC_PLLMul_13 ((uint32_t)0x002C0000)
- #define RCC_PLLMul_14 ((uint32_t)0x00300000)
- #define RCC_PLLMul_15 ((uint32_t)0x00340000)
- #define RCC_PLLMul_16 ((uint32_t)0x00380000)
对于互联形产品:(具体看互联形产品手册)
- #define RCC_PLLMul_4 ((uint32_t)0x00080000)
- #define RCC_PLLMul_5 ((uint32_t)0x000C0000)
- #define RCC_PLLMul_6 ((uint32_t)0x00100000)
- #define RCC_PLLMul_7 ((uint32_t)0x00140000)
- #define RCC_PLLMul_8 ((uint32_t)0x00180000)
- #define RCC_PLLMul_9 ((uint32_t)0x001C0000)
- #define RCC_PLLMul_6_5 ((uint32_t)0x00340000)
查看非互联形产品芯片手册,找到时钟配置寄存器RCC_CFGR。
查看位21:18,了解其定义之后,就弄懂了RCC_PLLMul_X的定义。
void RCC_PLLConfig(uint32_t RCC_PLLSource, uint32_t RCC_PLLMul)函数的函数体为:
- void RCC_PLLConfig(uint32_t RCC_PLLSource, uint32_t RCC_PLLMul)
-
- {
-
- uint32_t tmpreg = 0;
-
- /* Check the parameters */
-
- assert_param(IS_RCC_PLL_SOURCE(RCC_PLLSource));
-
- assert_param(IS_RCC_PLL_MUL(RCC_PLLMul));
-
- tmpreg = RCC->CFGR;
-
- /* Clear PLLSRC, PLLXTPRE and PLLMUL[3:0] bits */
-
- tmpreg &= CFGR_PLL_Mask;
-
- /* Set the PLL configuration bits */
-
- tmpreg |= RCC_PLLSource | RCC_PLLMul;
-
- /* Store the new value */
-
- RCC->CFGR = tmpreg;
-
- }
函数具体实现逻辑为:
1、将CFGR的其他配置通过tmpreg先保存起来;
2、再将PLLSRC, PLLXTPRE,PLLMUL[3:0] bits清零;
3、再通过或等于将新的配置写入;
4、最后将新的配置赋回CFGR。
RCC在stm32f10x.h中被定义,是一个存放在特定地址的一个结构体,这个地址就是STM32中分配给相关寄存器的空间位置,结构体中存放着10个uint32_t类型的成员,分别对应着与RCC相关的是个寄存器。
#define RCC ((RCC_TypeDef *) RCC_BASE)
结构体所在地址偏移:
#define RCC_BASE (AHBPERIPH_BASE + 0x1000)
RCC结构体类型:
- /**
- * @brief Reset and Clock Control
- */
-
- typedef struct
- {
- __IO uint32_t CR;
- __IO uint32_t CFGR;
- __IO uint32_t CIR;
- __IO uint32_t APB2RSTR;
- __IO uint32_t APB1RSTR;
- __IO uint32_t AHBENR;
- __IO uint32_t APB2ENR;
- __IO uint32_t APB1ENR;
- __IO uint32_t BDCR;
- __IO uint32_t CSR;
-
- #ifdef STM32F10X_CL
- __IO uint32_t AHBRSTR;
- __IO uint32_t CFGR2;
- #endif /* STM32F10X_CL */
-
- #if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD_VL)
- uint32_t RESERVED0;
- __IO uint32_t CFGR2;
- #endif /* STM32F10X_LD_VL || STM32F10X_MD_VL || STM32F10X_HD_VL */
- } RCC_TypeDef;
-
- /**
- * @brief Real-Time Clock
- */
此结构体的第二个成员就是CFGR,这样函数执行完后就将新的配置字写入了相关寄存器中,使得配置生效。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。