寄存器除了可以被配置成某种功能和模式之外。还有一大作用就是提供当前系统的配置情况,通过读寄存器的方法来获取这些配置情况。
根据“时钟树图”,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时钟频率。
(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; |
(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时钟。
3 RCC_GetClocksFreq()地位
RCC_GetClocksFreq(RCC_ClocksTypeDef* RCC_Clocks);根据“时钟树图”中的时钟关系将SYSCLK,HCLK,PCLKx,ADCCLK保存在RCC_Clocks结构体参数的对应元素之上。在需要利用当前模块时钟频率时可利用此函数求得,比如USARTx在配置BRR寄存器时就需要USARTx模块的时钟频率。Learning Note Over.