在认识这颗时钟树之前,首先要明确“主干”和最终的“分支”。假设使用外部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_Configura
tion(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)
}
}