[ M3 LN ] FW(固件)库函数RCC_GetClocksFreq()

时间:2021-12-10 17:27:31

寄存器除了可以被配置成某种功能和模式之外。还有一大作用就是提供当前系统的配置情况,通过读寄存器的方法来获取这些配置情况。


根据“时钟树图”,HCLK,PCLKx,ADCCLK等时钟都是SYSCLK经AHB预分频器分频出去后的时钟信号。在SYSCLK经AHB预分频器输出后直接得到HCLK,要得到PCLKx,还要经过一个预分频器,ADCCLK在APB2下, PCLK2时钟输出到ADC预分频器得到ADCCLK。而SYSCLK可由HSE,HSI, PLL提供。


1 RCC_GetClocksFreq()原型

RCC_GetClocksFreq()函数被定义在stm32f10x_rcc.c文件内,其原型为,

void  RCC_GetClocksFreq(RCC_ClocksTypeDef*  RCC_Clocks);


(1) 功能

将芯片内各模块的时钟频率保存在参数RCC_Clocks中,包含SYSCLK、HCLK、PCLKx、ADCCLK时钟频率值。


(2) 参数

RCC_Clocks为RCC_ClocksTypeDef类型指针变量,RCC_ClocksTypeDef结构体在<stm32f10x_rcc.h>文件中声明,

typedef struct
{
        uint32_t  SYSCLK_Frequency;  /*!< returns SYSCLK clock frequency expressed in Hz */
        uint32_t  HCLK_Frequency;    /*!< returns HCLK clock frequency expressed in Hz */
        uint32_t  PCLK1_Frequency;   /*!< returns PCLK1 clock frequency expressed in Hz */
        uint32_t  PCLK2_Frequency;   /*!< returns PCLK2 clock frequency expressed in Hz */
        uint32_t  ADCCLK_Frequency;  /*!< returns ADCCLK clock frequency expressed in Hz */
}RCC_ClocksTypeDef;


2 RCC_GetClocksFreq()源码

(1) SYSCLK频率

根据“读时钟树图”可知,SYSCLK时钟来源源可为HSE,HSI,PLL提供。SYSCLK不同的来源对应着不同的频率。根据“时钟配置寄存器”得知SYSCLK时钟来源才能确定SYSCLK的频率值。

1.        tmp = RCC->CFGR &CFGR_SWS_Mask;

2.         

3.        switch (tmp){

4.                 case 0x00:

5.                           RCC_Clocks->SYSCLK_Frequency    = HSI_Value;

6.                           break;

7.                 case 0x04:

8.                           RCC_Clocks->SYSCLK_Frequency    = HSE_Value;

9.                           break;

10.             case 0x08:

11.                       pllmull                =RCC->CFGR & CFGR_PLLMull_Mask;

12.                       pllsource     = RCC->CFGR & CFGR_PLLSRC_Mask;

13.                       pllmull                =( pllmull >> 18) + 2;

14.         

15.                       if (pllsource == 0x00){

16.                                RCC_Clocks->SYSCLK_Frequency =(HSI_Value >> 1) * pllmull;

17.                       }else{

18.                                if ((RCC->CFGR &CFGR_PLLXTPRE_Mask) != (uint32_t)RESET){

19.                                         RCC_Clocks->SYSCLK_Frequency    = (HSE_Value >> 1) * pllmull;

20.                                }else{

21.                                         RCC_Clocks->SYSCLK_Frequency    = HSE_Value * pllmull;

22.                                }

23.                       }

24.                       break;

25.             default:

26.                       RCC_Clocks->SYSCLK_Frequency    = HSI_Value;

27.                       break;

}

1. CFGR_SWS_Mask的值为 ((uint32_t)0x0000000C),tmp保存了CFGR寄存器的bit[3:2]( SWS,表示当前SYSCLK时钟来源 )两个位的状态。

4~6. tem的值为0x00时,则表明当前SYSCLK的时钟源为HSI,则SYSCLK频率大小为HSI_Value ( 8MHz )。

7~9. tem的值为0x04时,SYSCLK的时钟源为HSE,SYSCLK的频率大小为HSE_Value。如果芯片为STM32F105(7)XX互联系列处理器,则HSE_Value为25MHz。否则HSE_Value为8MHz。( PS: 在MDK中,Debug下选择的芯片要与开发板的信号保持一致。)

10. tem的值为0x08时,SYSCLK的时钟频率由PLL提供。

11. CFGR_PLLMull_Mask的值为((uint32_t)0x003C0000),pllmull保存了CFGR的bit[21:18]( PULLMUL,表PLL的倍频系数)的状态。

12.  CFGR_PLLSRC_Mask的值为((uint32_t)0x00010000),pllsource保存了CFGR bit[16](PLLSRC,表PLL时钟来源)的状态。

13.  pllmull保存了由CFGR bit[21:18]状态计算得到的PLL倍频系数。

15~16. 若pllsource为00,则表示PLL由HSI 2分频后提供,再经PLL倍频系数后作为SYSCLK时钟,计算得到SYSCLK频率大小。

17.  PLL由HSE提供。

18~19. CFGR_PLLXTPRE_Mask的值为((uint32_t)0x00020000),RESET的值为0.如果CFGR bit[17]状态不为0,则HSE 2分频后作为PLL时钟源,再经PLL倍频系数输出后作为SYSCLK时钟,并计算得到SYSCLK时钟频率。

20~21. 若CFGR bit[17]状态值为0,则HSE直接作为PLL的时钟源,并经PLL倍频后输出作为SYSCLK时钟,计算得到SYSCLK时钟频率。


根据CFGR时钟配置寄存器bit[3:2]( SWS,表示当前SYSCLK时钟来源 )位的状态得出SYSCLK频率并将其保存在RCC_Clocks->SYSCLK_Frequency参数中


(2) HCLK频率

1. tmp= RCC->CFGR & CFGR_HPRE_Set_Mask;
2. tmp = tmp >> 4;
3. presc = APBAHBPrescTable[tmp];
4. RCC_Clocks->HCLK_Frequency    = RCC_Clocks->SYSCLK_Frequency >> presc;

1. CFGR_HPRE_Set_Mask的值为((uint32_t)0x000000F0),tmp保存了CFGR bit[7:4](HPRE, AHB时钟的预分频系数 )的状态。

2. tmp向右移位4,得到CFGR bit[7:4]的值。

3. APBAHBPrescTable在”stm32f10x_rcc.c”中被定义,

static __I uint8_t APBAHBPrescTable[16] = {0, 0, 0, 0, 1, 2, 3, 4, 1, 2, 3, 4, 6, 7, 8, 9};

APBAHBPrescTable保存了每个以bit[7:4]状态值tmp为下标所对应的分频系数。

4. 因为SYSCLK时钟经AHB预分频器后直接作为HCLK,所以HCLK的频率为SYSCLK经AHB分频后的频率值( 分频系数为2^n )。


根据CFGR 的bit[7:4]( HPRE, AHB时钟的预分频系数),得到SYSLCK分频后的HCLK时钟频率并将其保存在RCC_Clocks->HCLK_Frequency参数中


(3) PCLKx频率

PCLKx由HCLK进入APBx预分频器后得到。

[1] PCLK1频率

1. tmp= RCC->CFGR & CFGR_PPRE1_Set_Mask;
2. tmp = tmp >> 8;
3. presc = APBAHBPrescTable[tmp];
4. RCC_Clocks->PCLK1_Frequency    = RCC_Clocks->HCLK_Frequency >> presc;

1. CFGR_PPRE1_Set_Mask的值为((uint32_t)0x00000700),tmp保存了CFGR bit[10:8]( PPRE1,低速APB1时钟PCLK1的预分频系数)状态值。

2. tmp得到CFGR bit[10:8]的值。

3. APBAHBPrescTable保存了以tmp为小标的分频系数。

4. 因为PCLK1是HCLK进入APB1预分频器后的时钟,所以根据APB1的预分频系数就得到了PCLK1的频率。


根据CFGR bit[10:8](PPRE1, 低速APB1时钟PCLK1的预分频系数)依HCLK时钟可计算得到PCLK1的时钟频率并将其保存在RCC_Clocks->PCLK1_Frequency参数中。PCLK1时钟频率最大为36MHZ.


[2] PCLK2频率

1. tmp= RCC->CFGR & CFGR_PPRE2_Set_Mask;
2. tmp = tmp >> 11;
3. presc = APBAHBPrescTable[tmp];
4. RCC_Clocks->PCLK2_Frequency    = RCC_Clocks->HCLK_Frequency >> presc;
同PCLK1,PCLK2的预分频系数在CFGR 的bit[13:11]( PPRE2, 高速APB2时钟(PCLK2)的预分频系数 )状态得到分频系数,再有HCLK时钟频率计算得到PCLK2并将其保存在RCC_Clocks->PCLK2_Frequency参数中PCLK2时钟频率最大为72MHZ.


(4) ADCCLK频率

ADCCLK时钟由PCLK2经ADC预分频器输出得到。

1. tmp= RCC->CFGR & CFGR_ADCPRE_Set_Mask;
2. tmp = tmp >> 14;
3. presc = ADCPrescTable[tmp];
4. RCC_Clocks->ADCCLK_Frequency    = RCC_Clocks->PCLK2_Frequency / presc;

1. CFGR_ADCPRE_Set_Mask的值为((uint32_t)0x0000C000),tmp保存了CFGR bit[15:14]( ADCPRE, ADC预分频 )的状态值。

2.tmp保存了CFGR bit[15:14]位的值。

3. ADCPrescTable的定义为,

static__I uint8_t ADCPrescTable[4] = {2, 4, 6, 8};

ADCPrescTable[tmp]就是ADC的分频值。

4. 由于ADCPrescTable[tmp]不满足2^n故而这里直接采取除法的方式来获取到ADCCLK时钟。


根据CFGR bit[15:14]( ADCPRE, ADC预分频 )状态得到的值依PCLK2时钟计算得到ADCCLK的频率并将其保存在RCC_Clocks ->ADCCLK_Frequency参数中


3 RCC_GetClocksFreq()地位

RCC_GetClocksFreq(RCC_ClocksTypeDef* RCC_Clocks);根据“时钟树图”中的时钟关系将SYSCLK,HCLK,PCLKx,ADCCLK保存在RCC_Clocks结构体参数的对应元素之上。在需要利用当前模块时钟频率时可利用此函数求得,比如USARTx在配置BRR寄存器时就需要USARTx模块的时钟频率。


Learning  Note Over.