1 综述
1.1 时钟源
在STM32中,一共有5个时钟源,分别是HSI、HSE、LSI、LSE、PLL。
- HSI:高速内部时钟源,RC振荡器,频率为8MHz。
- HSE:高速外部时钟源,可接石英/陶瓷谐振器或外部时钟,频率范围为4~16MHz。
- LSI:低速内部时钟源,RC振荡器,频率为40KHz。
- LSE:低速外部时钟源,接频率为32.768KHz的石英晶体。
- PLL:锁相环倍频输出,严格来说它不是独立时钟源,需要外接时钟源,输入可接HSI/2,HSE或是HSE/2。PLL倍频范围为x2~x16,但最大输出频率不能超过72MHz。
其中,LSI供独立看门狗IWDG使用,也可以被选为实时时钟源,不过,实时时钟源还可以选择LSE或者是HSE的128分配。在STM32中,全速功能的USB模块,其串行接口引擎需要一个48MHz的时钟源,该时钟源只能从PLL端获取,可选择分频1分频或1.5分频,若使用USB模块则必须先使能PLL并且时钟配置为72MHz或48MHz。
此外,在STM32中,可以选择一个时钟信号从MCO(PA8)脚输出,可以选择时钟源为PLL输出的2分频、HSI、HSE或系统时钟。
系统时钟SYSCLK,他提供STM32中绝大部分不见的工作时钟,系统时钟可以选择PLL输出、HSE和HSI、系统时钟最大频率为72MHz,通过AHB分配器分频后送给各个模块使用,AHB分配器可选1、2、4、8、·6、64、128、256、512分频,AHB分配器输出时钟可以供5大模块使用:
- 送给AHB总线、内核、内存和DMA使用的HCLK时钟。
- 通过8分频后送个Cortex的系统定时器时钟STCLK。
- 直接送给Cortex的空闲运行时钟FCLK。
- 送个低速外设总线APB1分配器,APB1分配器可以选择1、2、4、8和16分频,其输出一路供APB1外设使用(PCLK1,最大频率36MHz);另一路送个定时器(TIM2~TIM7)倍频器使用,该定时器倍频器根据APB1分频值自动选择x1或x2倍频(APB1分频值为1时,定时器倍频器为1倍频,APB1分频值为其它值时,定时器倍频器采用2倍频)。
- 送给高速外设总线APB2分频器,APB2分配器可选择1、2、4、8和16分频,其输出一路供APB2外设使用(PLCK2,最大频率为72MHz);一路送给定时器(TIM1&TIM8)使用,该定时器倍频器根据APB2分频值自动选择x1或x2倍频(APB2分频值为1时,定时器倍频器为1倍频,APB2分频值为其它值时,定时器倍频器采用2倍频);此外,APB2分配器输出还有一路供给ADC分配器使用,ADC分配器分频后供ADC模块使用,ADC分频可选2、4、6和8分频,不过ADC模块最大输入时钟不错过14MHz。
1.2 时钟树
2. 时钟源
2.1 HSE时钟
高速外部时钟信号(HSE)可以有以下两种时钟源产生:
- HSE外部晶体/陶瓷谐振器
- HSE用户外部时钟
为了减少时钟输出的失真和缩短启动稳定时间,晶体/陶瓷谐振器和负载电容器必须尽可能地靠近振荡器引脚,负载电容值必须根据所选择的振荡器来调整。
外部时钟源(HSE旁路)
在这个模式里,必须提供外部时钟,它的频率最高可达25MHz,用户可通过设置在时钟控制寄存器中的HSEBYP和HSEON位来选择这一模式。外部时钟信号(50%占空比的方波、正弦波或三角波)必须连到SOC_IN引脚,同时保证OSC_OUT引脚悬空,见图2)。
外部晶体/陶瓷谐振器(HSE晶体)
4~16Mz外部振荡器可为系统提供更为精确的主时钟,相关的硬件配置可参考图1,进一步信息可参考数据手册的电气特性部分。在时钟控制寄存器RCC_CR中的HSERDY位用来指示高速外部振荡器是否稳定,在启动时,直到这一位被硬件置’1’,时钟才被释放出来。如果在时钟中断寄存器RCC_CIR中允许产生中断,将会产生相应中断,HSE晶体可以通过设置时钟控制寄存器里RCC_CR中的HSEON位被启动和关闭。
2.2 HSI时钟
HSI时钟信号由内部8MHz的RC振荡器产生,可直接作为系统时钟或在2分频后作为PLL输入。HSI RC振荡器能够在不需要任何外部器件的条件下提供系统时钟,它的启动时间比HSE晶体振荡器短,然而,即使在校准之后它的时钟频率精度仍较差。
校准:制造工艺决定了不同芯片的RC振荡器频率会不同,这就是为什么每个芯片的HSI时钟频率在出厂前已经被ST校准到1%(25°C)的原因。系统复位时,工厂校准值被装载到时钟控制寄存器的HSICAL[7:0]位,如果用户的应用基于不同的电压或环境温度,这将会影响RC振荡器的精度,这时用户可以通过时钟控制寄存器里的HSITRIM[4:0]位来调整HSI频率,时钟控制寄存器中的HSIRDY位用来指示HSI RC振荡器是否稳定,在时钟启动过程中,直到这一位被硬件置’1’, HSI RC输出时钟才被释放。 HSI RC可由时钟控制寄存器中的HSION位来启动和关闭。如果HSE晶体振荡器失效, HSI时钟会被作为备用时钟源。
2.3 PLL时钟
内部PLL可以用来倍频HSI RC的输出时钟或HSE晶体输出时钟。PLL的设置(选择HSI振荡器除2或HSE振荡器为PLL的输入时钟、配置倍频因子)必须在其被激活前完成,一旦PLL被激活,这些参数就不能被修改。如果PLL中断在时钟中断寄存器里被允许,当PLL准备就绪时,可产生中断申请。如果需要在应用中使用USB接口, PLL必须被设置为输出48或72MHZ时钟,用于提供48MHz的USBCLK时钟。
2.4 LSE时钟
LSE晶体是一个32.768kHz的低速外部晶体或陶瓷谐振器,它为实时时钟或者其他定时功能提供一个低功耗且精确的时钟源。LSE晶体通过在备份域控制寄存器(RCC_BDCR)里的LSEON位启动和关闭,在备份域控制寄存器(RCC_BDCR)里的LSERDY指示LSE晶体振荡是否稳定,在启动阶段,直到这个位被硬件置’1’后, LSE时钟信号才被释放出来。如果在时钟中断寄存器里被允许,可产生中断申请。
外部时钟源(LSE旁路)
在这个模式里必须提供一个32.768kHz频率的外部时钟源。你可以通过设置在备份域控制寄存器(RCC_BDCR)里的LSEBYP和LSEON位来选择这个模式。具有50%占空比的外部时钟信号(方波、正弦波或三角波)必须连到OSC32_IN引脚,同时保证OSC32_OUT引脚悬空,见图1。
2.5 LSI时钟
LSI RC担当一个低功耗时钟源的角色,它可以在停机和待机模式下保持运行,为独立看门狗和自动唤醒单元提供时钟。 LSI时钟频率大约40kHz(在30kHz和60kHz之间)。LSI RC可以通过控制/状态寄存器(RCC_CSR)里的LSION位来启动或关闭,在控制/状态寄存器(RCC_CSR)里的LSIRDY位指示低速内部振荡器是否稳定,在启动阶段,直到这个位被硬件设置为’1’后,此时钟才被释放。如果在时钟中断寄存器(RCC_CIR)里被允许,将产生LSI中断申请。
LSI校准
可以通过校准内部低速振荡器LSI来补偿其频率偏移,从而获得精度可接受的RTC时间基数,以及独立看门狗(IWDG)的超时时间(当这些外设以LSI为时钟源)。校准可以通过使用TIM5的输入时钟(TIM5_CLK)测量LSI时钟频率实现,测量以HSE的精度为保证,软件可以通过调整RTC的20位预分频器来获得精确的RTC时钟基数,以及通过计算得到精确的独立看门狗(IWDG)的超时时间。
LSI校准步骤如下:
1.打开TIM5,设置通道4为输入捕获模式;
2.设置AFIO_MAPR的TIM5_CH4_IREMAP位为’1’,在内部把LSI连接到TIM5的通道4;
3.通过TIM5的捕获/比较4事件或者中断来测量LSI时钟频率;
4.根据测量结果和期望的RTC时间基数和独立看门狗的超时时间,设置20位预分频器。
2.6 系统时钟
系统复位后, HSI振荡器被选为系统时钟,当时钟源被直接或通过PLL间接作为系统时钟时,它将不能被停止,只有当目标时钟源准备就绪了(经过启动稳定阶段的延迟或PLL稳定),从一个时钟源到另一个时钟源的切换才会发生,在被选择时钟源没有就绪时,系统时钟的切换不会发生,直至目标时钟源就绪,才发生切换。在时钟控制寄存器(RCC_CR)里的状态位指示哪个时钟已经准备好了,哪个时钟目前被用作系统时钟。
2.7 RTC时钟
通 过 设 置 备 份 域 控 制 寄 存 器 (RCC_BDCR) 里 的 RTCSEL[1:0] 位 , RTCCLK 时 钟 源 可 以 由HSE/128、 LSE或LSI时钟提供,除非备份域复位,此选择不能被改变,LSE时钟在备份域里,但HSE和LSI时钟不是,因此:
- 如果LSE被选为RTC时钟:只要VBAT维持供电,尽管VDD供电被切断, RTC仍继续工作。
- 如果LSI被选为自动唤醒单元(AWU)时钟:如果VDD供电被切断, AWU状态不能被保证。
- 如果HSE时钟128分频后作为RTC时钟:如果VDD供电被切断或内部电压调压器被关闭(1.8V域的供电被切断),则RTC状态不确定。必须设置电源控制寄存器(PWR_CR)的DPB位为’1’(取消后备区域的写保护)。
2.8 看门狗时钟
如果独立看门狗已经由硬件选择或软件启动, LSI振荡器将被强制在打开状态,并且不能被关闭,在LSI振荡器稳定后,时钟供应给IWDG。
2.9 时钟输出
STM32允许输出时钟信号到外部MCO引脚,不过相应的GPIO端口寄存器必须被配置为相应功能。以下8个时钟信号可被选作MCO时钟:
- SYSCLK
- HSI
- HSE
- 除2的PLL时钟
- PLL2时钟
- PLL3时钟除以2
- XT1外部3~25MHz振荡器(用于以太网)
- PLL3时钟(用于以太网)在MCO上输出的时钟必须小于50MHz(这是I/O端口的最大速度)。
时钟的选择由时钟配置寄存器(RCC_CFGR)中的MCO[3:0]位控制。
3 外设时钟系统
以下介绍不同总线上挂载各种外设,不同的芯片系列可能缺少某些外设,用户应根据自己的芯片型号确定。
1.AHB总线外设:DMA1、DMA2、SRAM、FLASH、CRC、FSMC、SDIO、OTG(互联型设备)、ETH(互联型设备)。
2.APB1(低速外设总线):TIM2TIM7、TIM12TIM14、WWDG、SPI2SPI3、USART2USART3、UART4UART5、I2C1I2C2、USB、CAN1~CAN2、BKP、DAC、CEC。
3.APB2(高速外设总线):AFIO、GPIOAGPIOG、ADC1ADC2、TIM1、TIM8、SPI1、USART1、ADC3、TIM15TIM17、TIM9TIM11。
4 RCC库函数
4.1 时钟频率
typedef struct
{
uint32_t SYSCLK_Frequency; /*!< 系统时钟频率,单位:Hz */
uint32_t HCLK_Frequency; /*!< AHB总线时钟频率,单位:Hz */
uint32_t PCLK1_Frequency; /*!< APB1总线时钟频率,单位:Hz */
uint32_t PCLK2_Frequency; /*!< APB2总线时钟频率,单位:Hz */
uint32_t ADCCLK_Frequency; /*!< ADC模块输入时钟频率,单位:Hz */
}RCC_ClocksTypeDef;
4.2 RCC库函数
RCC库函数原型及实现请详见stm32f10x_rcc模块,以下仅介绍各接口的作用。
函数名 | 描述 |
---|---|
RCC_DeInit | 将外设RCC寄存器重设为缺省值 |
RCC_HSEConfig | 设置外部高速晶振( HSE) |
RCC_WaitForHSEStartUp | 等待 HSE 起振 |
RCC_AdjustHSICalibrationValue | 调整内部高速晶振( HSI)校准值 |
RCC_HSICmd | 使能或者失能内部高速晶振( HSI) |
RCC_PLLConfig | 设置 PLL 时钟源及倍频系数 |
RCC_PLLCmd | 使能或者失能 |
PLLRCC_SYSCLKConfig | 设置系统时钟( SYSCLK) |
RCC_GetSYSCLKSource | 返回用作系统时钟的时钟源 |
RCC_HCLKConfig | 设置 AHB 时钟( HCLK) |
RCC_PCLK1Config | 设置低速 AHB 时钟( PCLK1) |
RCC_PCLK2Config | 设置高速 AHB 时钟( PCLK2) |
RCC_ITConfig | 使能或者失能指定的 RCC 中断 |
RCC_USBCLKConfig | 设置 USB 时钟( USBCLK) |
RCC_ADCCLKConfig | 设置 ADC 时钟( ADCCLK) |
RCC_LSEConfig | 设置外部低速晶振( LSE) |
RCC_LSICmd | 使能或者失能内部低速晶振( LSI) |
RCC_RTCCLKConfig | 设置 RTC 时钟( RTCCLK) |
RCC_RTCCLKCmd | 使能或者失能 RTC 时钟 |
RCC_GetClocksFreq | 返回不同片上时钟的频率 |
RCC_AHBPeriphClockCmd | 使能或者失能 AHB 外设时钟 |
RCC_APB2PeriphClockCmd | 使能或者失能 APB2 外设时钟 |
RCC_APB1PeriphClockCmd | 使能或者失能 APB1 外设时钟 |
RCC_APB2PeriphResetCmd | 强制或者释放高速 APB( APB2)外设复位 |
RCC_APB1PeriphResetCmd | 强制或者释放低速 APB( APB1)外设复位 |
RCC_BackupResetCmd | 强制或者释放后备域复位 |
RCC_ClockSecuritySystemCmd | 使能或者失能时钟安全系统 |
RCC_MCOConfig | 选择在 MCO 管脚上输出的时钟源 |
RCC_GetFlagStatus | 检查指定的 RCC 标志位设置与否 |
RCC_ClearFlag | 清除 RCC 的复位标志位 |
RCC_GetITStatus | 检查指定的 RCC 中断发生与否 |
RCC_ClearITPendingBit | 清除 RCC 的中断待处理位 |
5 时钟系统初始化
假设采用外部提供晶振(HSE)频率为8MHz,PLLCLK=SYSCLK=72MHz,PCLK2=72MHz,PCLK1=36MHz,则时钟系统初始化代码如下:
void RCC_config()
{
ErrorStatus HSEStartUpStatus; // 定义错误状态变量
/* 时钟系统初始化 */
RCC_DeInit();//将RCC寄存器重新设置为默认值
RCC_HSEConfig(RCC_HSE_ON); //打开外部高速时钟晶振
HSEStartUpStatus = RCC_WaitForHSEStartUp();// 等待外部高速时钟晶振工作
if(HSEStartUpStatus == SUCCESS)
{
RCC_HCLKConfig(RCC_SYSCLK_Div1);//设置AHB不分频,HCLK=SYSCLK
RCC_PCLK2Config(RCC_HCLK_Div1);//设置APB2不分频,P2CLK=HCLK
RCC_PCLK1Config(RCC_HCLK_Div2); //设置APB1 为2分频,P1CLK=HCLK/2
FLASH_SetLatency(FLASH_Latency_2);//设置FLASH代码延时
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);//使能预取指缓存
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, //设置PLL时钟源,
RCC_PLLMul_9);//外部时钟不分频,为HSE的9倍频8MHz * 9 = 72MHz
RCC_PLLCmd(ENABLE);//使能PLL
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);//等待PLL准备就绪
{
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);//设置PLL为系统时钟源
while(RCC_GetSYSCLKSource() != 0x08)//判断PLL是否是系统时钟
{
}
}
}
/* 以下示例部分外设时钟初始化 */
/* 使能DMA1时钟*/
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
/* 使能CAN1时钟*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
/* 使能GPIOD时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
}