单片机/MCU论坛
直播中

zzyzzf@126.com

12年用户 11经验值
擅长:模拟技术
私信 关注
[文章]

STM32 时钟树的学习

STM32的时钟树
         对于广大初次接触STM32的读者朋友(甚至是初次接触ARM器件的读者朋友)来说,在熟悉了开发环境的使用之后,往往“栽倒”在同一个问题上。这问题有个关键字叫:时钟树。
         众所周知,微控制器(处理器)的运行必须要依赖周期性的时钟脉冲来驱动——往往由一个外部晶体振荡器提供时钟输入为始,最终转换为多个外部设备的周期性运作为末,这种时钟“能量”扩散流动的路径,犹如大树的养分通过主干流向各个分支,因此常称之为“时钟树”。在一些传统的低端8位单片机诸如51,AVR,PIC等单片机,其也具备自身的一个时钟树系统,但其中的绝大部分是不受用户控制的,亦即在单片机上电后,时钟树就固定在某种不可更改的状态(假设单片机处于正常工作的状态)。比如51单片机使用典型的12MHz晶振作为时钟源,则外设如IO口、定时器、串口等设备的驱动时钟速率便已经是固定的,用户无法将此时钟速率更改,除非更换晶振。
         而STM32微控制器的时钟树则是可配置的,其时钟输入源与最终达到外设处的时钟速率不再有固定的关系,本文将来详细解析STM32微控制器的时钟树。图1是STM32微控制器的时钟树,表1是图中各个标号所表示的部件。
标号            图1标号释义
1     内部低速振荡器(LSI,40Khz)
2     外部低速振荡器(LSE,32.768Khz)
3    外部高速振荡器(HSE,3-25MHz)
4    内部高速振荡器(HIS,8MHz)
5    PLL输入选择位
6    RTC时钟选择位
7    PLL1分频数寄存器
8    PLL1倍频寄存器
9    系统时钟选择位
10            USB分频寄存器
11            AHB分频寄存器
12            APB1分频寄存器
13            AHB总线
14            APB1外设总线
15            APB2分频寄存器
16       APB2外设总线
17            ADC预分频寄存器
18            ADC外设
19            PLL2分频数寄存器
20            PLL2倍频寄存器
21            PLL时钟源选择寄存器
22            独立看门狗设备
23       RTC设备
  

       在认识这颗时钟树之前,首先要明确“主干”和最终的“分支”。假设使用外部8MHz晶振作为STM32的时钟输入源(这也是最常见的一种做法),则这个8MHz便是“主干”,而“分支”很显然是最终的外部设备比如通用输入输出设备(GPIO)。这样可以轻易找出第一条时钟的“脉络”:
3——5——7——21——8——9——11——13
对此条时钟路径做如下解析:
对于3,首先是外部的3-25MHz(前文已假设为8MHz)输入;
对于5,通过PLL选择位预先选择后续PLL分支的输入时钟(假设选择外部晶振);
对于7,设置外部晶振的分频数(假设1分频);
对于21,选择PLL倍频的时钟源(假设选择经过分频后的外部晶振时钟);
对于8,设置PLL倍频数(假设9倍频);
对于9,选择系统时钟源(假设选择经过PLL倍频所输出的时钟);
对于11,设置AHB总线分频数(假设1分频);
对于13,时钟到达AHB总线;
在上一章节中所介绍的GPIO外设属于APB2设备,即GPIO的时钟来源于APB2总线,同样在图1中也可以寻获GPIO外设的时钟轨迹:
3——5——7——21——8——9——11——15——16
对于3,首先是外部的3-25MHz(前文已假设为8MHz)输入;
对于5, 通过PLL选择位预先选择后续PLL分支的输入时钟(假设选择外部晶振);
对于7,设置外部晶振的分频数(假设1分频);
对于21,选择PLL倍频的时钟源(假设选择经过分频后的外部晶振时钟);
对于8,设置PLL倍频数(假设9倍频);
对于9,选择系统时钟源(假设选择经过PLL倍频所输出的时钟);
对于11,设置AHB总线分频数(假设1分频);
对于15,设置APB2总线分频数(假设1分频);
对于16,时钟到达APB2总线;
现在来计算一下GPIO设备的最大驱动时钟速率(各个条件已在上述要点中假设):
1)   由3所知晶振输入为8MHz,由5——21知PLL的时钟源为经过分频后的外部晶振时钟,并且此分频数为1分频,因此首先得出PLL的时钟源为:8MHz / 1 = 8MHz。
2)   由8、9知PLL倍频数为9,且将PLL倍频后的时钟输出选择为系统时钟,则得出系统时钟为 8MHz * 9 = 72MHz。
3)   时钟到达AHB预分频器,由11知时钟经过AHB预分频器之后的速率仍为72MHz。
4)   时钟到达APB2预分频器,由15经过APB2预分频器后速率仍为72MHz。
5)   时钟到达APB2总线外设。
因此STM32的APB2总线外设,所能达到的最大速率为72MHz。依据以上方法读者可以搜寻出APB1总线外设时钟、RTC外设时钟、独立看门狗等外设时钟的来龙去脉。接下来从程序的角度分析时钟树的设置,程序清单如下:
void RCC_Configuration(void)
{
        ErrorStatus HSEStartUpStatus;                                                                                                     (1)
        RCC_DeInit();                                                                                                                                (2)
        RCC_HSEConfig(RCC_HSE_ON);                                                                                                   (3)
        HSEStartUpStatus = RCC_WaitForHSEStartUp();                                                                           (4)
        if(HSEStartUpStatus == SUCCESS)                                                                                                (5)
        {
                   RCC_HCLKConfig(RCC_SYSCLK_Div1);                                                                               (6)
                     RCC_PCLK2Config(RCC_HCLK_Div1);                                                                               (7)
                     RCC_PCLK1Config(RCC_HCLK_Div2);                                                                               (8)
                    FLASH_SetLatency(FLASH_Latency_2);                                                                             (9)
                    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);                                                (10)
                  RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);                                             (11)
                  RCC_PLLCmd(ENABLE);                                                                                                       (12)
                  while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);                                                 (13)
                  RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);                                                             (14)
                  while(RCC_GetSYSCLKSource() != 0x08);                                                                             (15)
        }
}

回帖(1)

IT Fan

2018-3-11 22:05:47
学习了                          
举报

更多回帖

发帖
×
20
完善资料,
赚取积分