1.时钟树

        

STM32的时钟树大致可分为3部分:

*  陶瓷晶振输入,进入预分频器
* 预分频器输出信号给到PLL倍频器
* 最终AHB桥总线速度,以及各总线的速度
       
晶振信号输入到芯片后有两条支路可以走,第一条是直接以原始频率不经过PLL倍频器,直接作为系统时钟(SYSCLK)。第二条是从预分频器流入,随后将输出信号输入PLL倍频器,
最终得到X*HSE的SYSCLK(X为倍频倍率)。假如输入为8MHz,那么X为9时才能达到最大频率72MHz。

        1.1 PLLXTPRE   

        PLLXTPRE(预分频器)的作用是为了将大于16Mhz的信号进行"/2"操作,因为在STM32中晶振的输入频率最大不超过16MHz
,所以当大于16MHz时需要进行分频操作。在市面上可以有些最小系统板用的是24MHz晶振,这是因为他们为了从成本考虑,24MHz的晶振比常用8MHz要便宜。当使用24MHz时,经过的路径是这样的,所以信号进过预分频器最终输出频率是
12MHz。

 

        8MHz时路径是这样的,所以信号进过预分频器最终输出频率是8MHz。

        1.2 PLLSRC         

        PLLSRC
的作用是选择系统时钟源,从图中可以看到有两条输入支路,一条是HSI经过"/2"的预分频后信号输入PLLSRC,一条是HSE经过预分频后输出的信号。

        

        1.3 PLLMUL       

        PLLMUL 的作用是将PLLSRC的输出信号进行x倍的倍频,x可以为1-16。

        经过被倍频的信号仍未作为SYSCLK,它还需要进过一个选择器,该选择器从图中可以看到有多条输入支路

        一条是HSI(8MHz)原始信号直接输入作为SYSCLK,HSI拥有一个很大的缺陷,那就是无论进过如何校准信号质量依然很差。

        一条是HSE原始信号直接输入作为SYSCLK,HSE信号一般都为陶瓷晶振信号。

        一条是PLLMUL倍频后信号作为SYSCLK。

       
除却上文所说的三条输入支路,还有两个旁路,一个SW,一个是CSS。其中前者的作用是开关,意义就在于选择SYSCLK的最终信号源。后者的作用是时钟安全系统,作用是当HSE时钟源出现问题后,强制将SYSCLK的信号源切换为HSI。

        1.4 总线桥       

        

       
只要理解了SYSCLK的时钟频率是如何产生的,那么关于总线桥的频率就不难理解了。STM32F103的常用频率是72MHz,所以这里就以72MHz为例。在得到SYSCLK信号后会优先经过AHB桥进行预分频,此处默认为1,即不分频,随后流入APB桥、滴答定时器(SYSTICK)以及DMA总线。APB桥又分为APB1和APB2,同时还可以进行一个预分频。APB1在32中的定义是
低速总线桥,从图中可以看到它的最大支持频率是36MHz,所以在流入APB1时需要进行一个"/2"
的预分频。在APB1桥下控制着TIM2,3,4子对象。APB2在32中的定义是高速总线桥,从图中可以看到它的最大支持频率是72MHz,所以在流入APB2时不需要进行预分频,即分频系数为1。在其下面拥有TIM1以及ADC子对象,也就是这两者的最大速度为72MHz。

        除却各总线桥预分频器,图中还有多个与门,与门的作用就是是否输出该总线的信号。

        2. 系统时钟配置

        2.1 直接上代码
void SystemInit (void) { /* 启动HSI时钟 */ RCC->CR |= (uint32_t)0x00000001; /* 复位
SW, AHB, APB1, APB2, ADCPRE and MCO bits */ RCC->CFGR &= (uint32_t)0xF8FF0000;
/* 复位 HSEON, CSSON and PLLON bits */ RCC->CR &= (uint32_t)0xFEF6FFFF; /* 复位
HSEBYP bit */ RCC->CR &= (uint32_t)0xFFFBFFFF; /* 复位 PLLSRC, PLLXTPRE, PLLMUL
and USBPRE/OTGFSPRE bits */ RCC->CFGR &= (uint32_t)0xFF80FFFF; /* 清除所有时钟中断标志位
*/ RCC->CIR = 0x009F0000; /* 配置系统时钟频率、AHB、APB2和APB1预分频器 */ /* 配置闪存延迟周期并启用预取缓冲区
*/ SetSysClockTo72(); } static void SetSysClockTo72(void) { uint32_t
StartUpCounter = 0, HSEStatus = 0; /* 配置 SYSCLK, HCLK, PCLK2 and PCLK1
---------------------------*/ /* 使能 HSE */ RCC->CR |= ((uint32_t)RCC_CR_HSEON);
/* 等待HSE晶振就绪 */ do { HSEStatus = RCC->CR & RCC_CR_HSERDY; //读CR寄存器中就绪位
StartUpCounter++; //超时计数 } while((HSEStatus == 0) && (StartUpCounter !=
0x0500)); //等待超时,以及标志位置位 if ((RCC->CR & RCC_CR_HSERDY) != RESET)
//此处语句的作用是检测HSE是否就绪 { HSEStatus = (uint32_t)0x01; //就绪标志 1 } else { HSEStatus =
(uint32_t)0x00; //不就绪标志 0 } if (HSEStatus == (uint32_t)0x01) //HSE就绪 { /*
SYSCLK预分频系数为1,即不分频 */ RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; /*
APB2预分频系数为1,即不分频 =SYSCLK */ RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; /*
APB1预分频系数为2,即 APB2 = SYSCLK/2 */ RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2; /*
初始化HSE预分频器,时钟源选择器,PLL倍频器 */ RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC
| RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL)); /*时钟源选择为 HSE,进行9倍频 SYSCLK = HSE*9 =
8MHz*9 = 72MHz */ RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE |
RCC_CFGR_PLLMULL9); /* 使能PLL倍频器 */ RCC->CR |= RCC_CR_PLLON; /* Wait till PLL is
ready */ while((RCC->CR & RCC_CR_PLLRDY) == 0) //等待PLL倍频器就绪 { } /*
复位时钟源选择,并将时钟源选择为PLL */ RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; /* 等待时钟源选择完成置位 */ while ((RCC->CFGR &
(uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08) { } } }
        2.2 代码解析

        RCC->CR |= (uint32_t)0x00000001

         此处代码的作用是启动芯片内置HSI时钟源,确保芯片能正常运行,以及触发CSS时钟安全警报后能正常切换。

        RCC->CFGR &= (uint32_t)0xF8FF0000

        将RCC->CFGR寄存器内的值复位为初始状态,即复位

SW:系统时钟切换 -> HSI作为系统时钟
HPRE: AHB 预分频 -> SYSCLK不分频 PPRE1:低速 APB1预分频 -> HCLK 不分频 PPRE2:高速 APB2预分频 ->
HCLK不分频 ADCPRE:ADC 预分频 -> PCLK2 2分频后作为 ADC 时钟 MCO 微控制器时钟输出:没有时钟输出
        RCC->CR &= (uint32_t)0xFEF6FFFF

       将 HSEON, CSSON and PLLON 复位为初始状态,即
HSEON :外部高速时钟使能 -> HSE振荡器关闭 CSSON:时钟安全系统使能 -> 时钟监测器关闭 PLLON:PLL 使能 -> PLL关闭
        RCC->CR &= (uint32_t)0xFFFBFFFF;

        复位 HSEBYP 状态。为什么这里是复位不与上面的复位一次进行呢,是因为在官方文档中写明了,在复位HSEBYP前需要先只有在外部1-
25MHz振荡器关闭的情况下,该位才可以写入。在上文我们将HSE时钟关闭了。此处复位是为了告诉芯片外部1-25MHz振荡器没有旁路。
所谓HSE旁路模式,是指无需陶瓷晶振作为系统时钟,直接从外界导入时钟信号。犹如芯片内部的驱动组件被旁路了。

        RCC->CFGR &= (uint32_t)0xFF80FFFF

        复位 PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE 状态
PLLSRC:PLL输入时钟源 -> HSI 时钟 2 分频后作为 PLL 输入时钟 PLLXTPRE: HSE 分频器作为 PLL输入 -> HSE
不分频 PLLMUL: PLL倍频系数 -> PLL 2 倍频输出 USBPRE: USB预分频 -> PLL 时钟 1.5 倍分频作为 USB 时钟
        此处的复位配置为什么不能与 RCC->CFGR &= (uint32_t)0xF8FF0000 
一起写入寄存器呢,同样的此处复位的值在写入对应寄存器之前必须要先关闭PLL倍频器,在复位CR寄存器是我们才将PLL关闭。

        RCC->CIR = 0x009F0000

        此处语句的作用就单纯的是复位所有中断标志位。从寄存器名字也可以体现出"IR",全英文不就是interrupt
。为什么要清除中断标志位,是因为在RCC系统时钟初始化时都会产生大量的中断,例如
HSE就绪就会将对应标志位置1,PLL就绪也同样,想要清楚就绪标志位,就只能通过该寄存器清除。

        RCC->CR |= ((uint32_t)RCC_CR_HSEON)

        使能HSE外部时钟源,这里的使能作用就跟配置GPIO一样,在配置每一个外设时应当先将其使能。

  do

  {

    HSEStatus = RCC->CR & RCC_CR_HSERDY;    //读CR寄存器中就绪位

    StartUpCounter++;                       //超时计数

  } while((HSEStatus == 0) && (StartUpCounter != 0x0500));     //等待超时,以及标志位置位

        此处代码的作用就是等待HSE就绪, StartUpCounter++这里能够完成自增的原因就是最前面 RCC->CR |=
(uint32_t)0x00000001 
使能了HSI时钟,保证了系统能正常运作,如果前面没有使能HSI则此处不能完成自增操作。如果迟迟都等不到HSE就绪,那么系统就会以HSI时钟作为SYSCLK运作。

        RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1

        此处就是配置AHB桥预分频器,此处不分频

        RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1

        此处就是配置APB2桥预分频器,此处不分频

        RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2

        
此处就是配置APB1桥预分频器,此处2分频,在官方文档的时钟树中标明了该APB1总线最高只支持到36MHZ,而我们的AHB桥有72MHz,所以要达到官方限制需进行2分频。

        

        RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC |
RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL))

        此处语句初始化PLL时钟源选择器,HSE预分频器,PLL倍频器

PLLSRC:PLL输入时钟源 -> HSI时钟2分频后作为PLL输入时钟

PLLXTPRE:HSE分频器作为PLL输入 -> HSE不分频

PLLMUL:PLL倍频系数 -> PLL 2倍频输出

        RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9) 

        此处语句将时钟源选择为 HSE,进行9倍频 SYSCLK = HSE*9 = 8MHz*9 = 72MHz

        RCC->CR |= RCC_CR_PLLON

        使能PLL倍频器。

        RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW))

        RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL

        此处两个语句是为了先复位系统时钟源并将系统时钟源选择为PLL。

        剩下的两个 while() 都是为了检测对应配置是否配置完成,如果配置完成硬件会将对应为置1。

 

技术
下载桌面版
GitHub
Gitee
SourceForge
百度网盘(提取码:draw)
云服务器优惠
华为云优惠券
腾讯云优惠券
阿里云优惠券
Vultr优惠券
站点信息
问题反馈
邮箱:[email protected]
吐槽一下
QQ群:766591547
关注微信