STM32时钟树

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

STM32的时钟树

对于广大初次接触STM32的读者朋友(甚至是初次接触ARM器件的读者朋友)来说,在熟悉了开发环境的使用之后,往往“栽倒”在同一个问题上。这问题有个关键字叫:时钟树。

众所周知,微控制器(处理器)的运行必须要依赖周期性的时钟脉冲来驱动——往往由一个外部晶体振荡器提供时钟输入为始,最终转换为多个外部设备的周期性运作为末,这种时钟“能量”扩散流动的路径,犹如大树的养分通过主干流向各个分支,因此常称之为“时钟树”。在一些传统的低端8位单片机诸如51,AVR,PIC等单片机,其也具备自身的一个时钟树系统,但其中的绝大部分是不受用户控制的,亦即在单片机上电后,时钟树就固定在某种不可更改的状态(假设单片机处于正常工作的状态)。比如51单片机使用典型的12MHz 晶振作为时钟源,则外设如IO口、定时器、串口等设备的驱动时钟速率便已经是固定的,用户无法将此时钟速率更改,除非更换晶振。

而STM32微控制器的时钟树则是可配置的,其时钟输入源与最终达到外设处的时钟速率不再有固定的关系,本文将来详细解析STM32微控制器的时钟树。图1是STM32微控制器的时钟树,表1是图中各个标号所表示的部件。

表1 图1标号释义

图1 STM32的时钟树

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

}

以上是ST官方所提供的STM32时钟树配置函数,读者首先要知道3点

●ST所提供的库函数在函数和变量命名上有非常良好的规范性和易读性(虽然有点

冗长),即便没有注释,也可从函数名和变量名来大致判断该函数或变量所包含的

意义。

●其次,读者应从上图区分出各个总线和对应的时钟:其中PLLCLK表示PLL锁相环

的输出时钟,SYSCLK表示系统时钟,HCLK表示AHB总线的时钟,PCLK1表示APB1

总线的时钟,PCLK2则表示APB2总线的时钟。

●○9、○10两句代码的作用是设置STM32内部FLASH的等待周期。做如下解释:STM32

的内部用户FLASH用以存储代码指令供CPU存取以执行,STM32的CPU的最大速

率已知为72MHz,但FLASH无法达到这么高的速度,因此要在CPU存取FLASH的

过程中插入所谓的“等待周期”,显然CPU速度越快,所要插入的等待周期个数越

多,原则是

⏹当CPU速率为0 ~ 24MHz时,不需要插入等待周期,即等到周期个数为0;

⏹当CPU速率为24 ~ 48MHz时,插入1个等待周期;

⏹当CPU速率为48MHz ~ 72MHz时,插入2个等待周期;

有以上三点准备之后,开始解析这段程序:

(1)定义一个ErrorStatus类型的变量HSEStartUpStatus;

(2)将时钟树复位至默认设置;

(3)开启HSE晶振;

(4)等待HSE晶振起振稳定,并将起振结果保存至HSEStartUpStatus变量中;

(5)判断HSE晶振是否起振成功(假设成功了,进入if内部);

(6)设置HCLK时钟为SYSCLK的1分频;

(7)设置PLCK2时钟为SYSCLK的1分频;

(8)设置PLCK1时钟为SYSCLK的2分频;

(11)选择PLL输入源为HSE时钟经过1分频,并进行9倍频;

(12)使能PLL输出;

(13)等待PLL输出稳定;

(14)选择系统时钟源为PLL输出;

(15)等待系统时钟稳定;

上述代码中对时钟树的配置顺序为(对应图中标号):

○3——○11——○14——○15——○7——○21——○8——○9

通过对比发现,程序中对时钟树的配置顺序并不是依次从图中由左到右、由上到下配置的,这是为什么呢?事实上这个问题相信大部分读者都可以自己解释:电子设计世界的思维和操作方式,其顺序往往和日常生活是不一样的,比如人们经常先给电视机连接电源,再打开电视机开关;先把大水管的总闸打开,再打开小水龙头;总而言之是一种由“主”到“次”的顺序。转移到最常见的51单片机的开发平台,开发人员往往先把定时器的分频数,重载值等参数配置好,最后才启动定时器计数;先把各个外设的中断打开,最后再打开总中断;这

相关文档
最新文档