STM32 系统复杂,外设非常多,并不是所有外设都需要系统时钟的高频率,比如看门狗以及 RTC 只需要几十k的时钟即可。同一个电路,时钟越快功耗越大,同时抗电磁干扰能力也会越弱,所以较为复杂的 MCU一般都是采取多时钟源。
一、STM32 的时钟系统图
二、STM32的5个时钟源
- HSI 是高速内部时钟,RC 振荡器,频率为 8MHz。
- HSE 是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为 4MHz~16MHz。我的开发板接的是 8M 的晶振。
- LSI 是低速内部时钟,RC 振荡器,频率为 40kHz。独立看门狗的时钟源只能是 LSI,同时 LSI 还可以作为 RTC 的时钟源。
- LSE 是低速外部时钟,接频率为32.768kHz 的石英晶体。这个主要是 RTC 的时钟源。
- PLL 为锁相环倍频输出,其时钟输入源可选择为 HSI/2、HSE 或者 HSE/2。倍频可选择为2~16 倍,但是其输出频率最大不得超过 72MHz。
三、时钟系统说明:
1.MCO 是 STM32 的一个时钟输出 IO(PA8),它可以选择一个时钟信号输出,可以选择为 PLL 输出的 2 分频、HSI、HSE、或者系统时钟。这个时钟可以用来给外部其他系统提供时钟源。
2.RTC 时钟源可以选择 LSI,LSE,以及 HSE 的 128 分频。
3.USB 的时钟是来自 PLL 时钟源。STM32 中有一个全速功能的 USB 模块,其串行接口引擎需要一个频率为 48MHz 的时钟源。该时钟源只能 从 PLL 输出端获取,可以选择为 1.5 分频或者 1 分频;当需要使用 USB 模块时,PLL 必须使能,并且时钟频率配置为 48MHz 或 72MHz。
4.系统时钟 SYSCLK是供 STM32 中绝大部分部件工作的时钟源。系统时钟可选择为 PLL 输出、HSI 或者 HSE。系统时钟最大频率为 72MHz,也可以超频,不过为了系统稳定性没有必要冒风险超频。从时钟图上可以看出,其他所有外设的时钟最终来源都是 SYSCLK。SYSCLK 通过 AHB 分频器分频后送给各模块使用。
这些模块包括:
- AHB 总线、内核、内存和 DMA 使用的 HCLK 时钟。
- 通过 8 分频后送给 Cortex 的系统定时器时钟,也就是 systick 。
- 直接送给 Cortex 的空闲运行时钟 FCLK。
- 送给 APB1 分频器。APB1 分频器输出一路供 APB1 外设使用(PCLK1,最大 频率 36MHz),另一路送给定时器(Timer)2、3、4 倍频器使用。
- 送给 APB2 分频器。APB2 分频器分频输出一路供 APB2 外设使用(PCLK2, 最大频率 72MHz),另一路送给定时器(Timer)1 倍频器使用。
- 其中需要理解的是 APB1 和 APB2 的区别,APB1 连接的是低速外设,包括电源接口、 备份接口、CAN、USB、I2C1、I2C2、UART2、UART3 等,APB2 连接的是高速外设包括 UART1、SPI1、Timer1、ADC1、ADC2、所有普通 IO 口(PA~PE)、第二功能 IO 口等
5.任何一个外设在使用之前都必须使能相应的时钟
四、系统时钟初始化函数
void SystemInit (void)
{
/* Reset the RCC clock configuration to the default reset state(for debug purpose) */
/* Set HSION bit */
RCC->CR |= (uint32_t)0x00000001;
/* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
#ifndef STM32F10X_CL
RCC->CFGR &= (uint32_t)0xF8FF0000;
#else
RCC->CFGR &= (uint32_t)0xF0FF0000;
#endif /* STM32F10X_CL */
/* Reset HSEON, CSSON and PLLON bits */
RCC->CR &= (uint32_t)0xFEF6FFFF;
/* Reset HSEBYP bit */
RCC->CR &= (uint32_t)0xFFFBFFFF;
/* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
RCC->CFGR &= (uint32_t)0xFF80FFFF;
#ifdef STM32F10X_CL
/* Reset PLL2ON and PLL3ON bits */
RCC->CR &= (uint32_t)0xEBFFFFFF;
/* Disable all interrupts and clear pending bits */
RCC->CIR = 0x00FF0000;
/* Reset CFGR2 register */
RCC->CFGR2 = 0x00000000;
#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
/* Disable all interrupts and clear pending bits */
RCC->CIR = 0x009F0000;
/* Reset CFGR2 register */
RCC->CFGR2 = 0x00000000;
#else
/* Disable all interrupts and clear pending bits */
RCC->CIR = 0x009F0000;
#endif /* STM32F10X_CL */
#if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)
#ifdef DATA_IN_ExtSRAM
SystemInit_ExtMemCtl();
#endif /* DATA_IN_ExtSRAM */
#endif
/* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */
/* Configure the Flash Latency cycles and enable prefetch buffer */
SetSysClock();
#ifdef VECT_TAB_SRAM
SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
#else
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
#endif
}
#define SYSCLK_FREQ_72MHz 72000000
如果要设置为 36MHz,只需要注释掉上面代码,然后加入下面代码即可:
#define SYSCLK_FREQ_36MHz 36000000
初始化之后的状态:
SYSCLK 72MHz
AHB 72MHz
PCLK1 36MHz
PCLK2 72MHz
PLL 72MHz
初始化之后可以通过变量SystemCoreClock获取系统变量。如果SYSCLK=72MHz,那么变量SystemCoreClock=72000000。
五、RCC相关配置寄存器
STM32 时钟系统的配置除了初始化的时候在 system_stm32f10x.c 中的 SystemInit()函数中外,其他的配置主要在 stm32f10x_rcc.c 文件中,里面有很多时钟设置函数,打开文件浏览基本上看函数的名称就知道函数的作用。在设置时钟时,一定要仔细参考 STM32 的时钟图
typedef struct
{
__IO uint32_t CR; //HSI,HSE,CSS,PLL等的使能和就绪标志位
__IO uint32_t CFGR; //PLL等的时钟源选择,分频系数设定
__IO uint32_t CIR; // 清除/使能 时钟就绪中断
__IO uint32_t APB2RSTR; //APB2线上外设复位寄存器
__IO uint32_t APB1RSTR; //APB1线上外设复位寄存器
__IO uint32_t AHBENR; //DMA,SDIO等时钟使能
__IO uint32_t APB2ENR; //APB2线上外设时钟使能
__IO uint32_t APB1ENR; //APB1线上外设时钟使能
__IO uint32_t BDCR; //备份域控制寄存器
__IO uint32_t CSR; //控制状态寄存器
} RCC_TypeDef;