前言
本系列文章统一围绕STM32F103C8T6最小系统开发板进行记录,如涉及其他开发板将会特别说明。
STM32时钟的概念
时钟对于STM32而言是驱动源,相当于人类的心脏。有了时钟,STM32才能运行,并给片上的所有外设模块提供时钟使其正常工作。
STM32中系统时钟为什么有这么多的时钟源?
- 提供STM32系统内核、各种总线和外设所需要的工作频率。
- 增加抗电磁干扰能力,提高稳定性。
- 考虑掉电情况(外部高/低速时钟无法正常供电时,内部高/低速时钟可以提供时钟源)。
时钟源
以stm32f1系列为例:
-
外部高速时钟(HSE)
- 来源:可接石英 / 陶瓷谐振器,或者接外部时钟源。
- 频率范围是 4MHz – 16MHz。
- 可以直接作为系统时钟或PLL输入。
-
内部高速时钟(HSI)
- 来源:内部RC振荡器。
- 频率为8MHz(用此时钟源,系统时钟SYSCLK的最大频率不超过64MHz,8/2*16 = 64MHz)。
- 可以直接作为系统时钟或PLL输入。
-
外部低速时钟(LSE)
- 来源:外接石英晶体。
- 频率为 32.768KHz。
- 主要是RTC的时钟源。
-
内部低速时钟(LSI)
- 来源:内部RC 振荡器。
- 频率为 40KHz左右(30K-60KHz)。
- 供独立看门狗和自动唤醒单元使用。
-
锁相环时钟(PLL):锁相环倍频输出,可作为系统的时钟源,严格的来说并不算一个独立的时钟源。
- 来源:HSI/2 、 HSE 或者 HSE/2 。
- PLL倍频因子:2 – 16 倍。
- 输出频率最大不得超过 72MHz。
-
系统时钟源(SYSTICK):
- 最大频率为72MHz。
- 来源:PLL倍频输出、HSI或者HSE。
- 输出:AHB分频器。
-
AHB总线时钟(HCLK):将系统时钟频率进行分频并提供给各模块使用。
- 分频因子:1、2、4、8、16、64、128、256、512。
- 主要输出:
- AHB总线、内核、内存和DMA使用的HCLK时钟。
- 通过8分频后送给Cortex的系统定时器时钟。
- Cortex的自由运行时钟FCLK。
- APB1预分频器。
- APB2预分频器 。
-
APB1总线时钟(PCLK1):低速总线时钟,最大为36MHz。
- 来源:由AHB分频而得。
- 分频因子:1、2、4、8、16。
- 输出:APB1外设、通用定时器2~7。
-
APB2总线时钟(PCLK2):高速总线时钟,最大为72MHz。
- 来源:由AHB分频而得。
- 分频因子:1、2、4、8、16。
- 输出:APB2外设、高级定时器1和定时器8。
RCC寄存器
-
RCC_CR 时钟控制寄存器
- 内外部高速时钟的使能和就绪标志(含内部高速时钟校准调整)。
- 外部高速时钟旁路。
- 时钟安全系统CSS使能。
- PLL使能和PLL就绪标志。
-
RCC_CFGR 时钟配置寄存器
- 系统时钟源切换及状态。
- AHB、APB1、APB2、ADC、USB预分频选择。
- PLL输入时钟源选择及HSE输入PLL分频选择,PLL倍频系数选择。
- MCO(PA8)引脚微控制器时钟输出。
-
RCC_APBxRSTR 外设复位寄存器
- LSI、LSE、HIS、HSE、PLL就绪中断标志。
- HSE时钟失效导致时钟安全系统中断标志。
- LSI、LSE、HIS、HSE、PLL就绪中断使能。
- 清除LSI、LSE、HIS、HSE、PLL就绪中断。
- 清除时钟安全系统中断。
-
RCC_AHBENR/APBxENR外设时钟使能寄存器
- 主要功能:使能AHB、APB1、APB2总线下的各外设
-
RCC_APBxRSTR 外设复位寄存器
- 主要功能:APB1、APB2总线下的各外设复位
系统时钟的配置
以stm32f1系列为例:官方提供的启动文件startup_stm32f10x_hd.s中,在执行main函数前会调用system_stm32f10x.c文件下的SystemInit函数对系统时钟进行配置。
在SystemInit函数下的SetSysClock函数,会对系统时钟频率、HCLK、PCLK等进行具体配置。
/**
* @brief Configures the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers.
* @param None
* @retval None
*/
static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSE
SetSysClockToHSE();
#elif defined SYSCLK_FREQ_24MHz
SetSysClockTo24();
#elif defined SYSCLK_FREQ_36MHz
SetSysClockTo36();
#elif defined SYSCLK_FREQ_48MHz
SetSysClockTo48();
#elif defined SYSCLK_FREQ_56MHz
SetSysClockTo56();
#elif defined SYSCLK_FREQ_72MHz
SetSysClockTo72();
#endif
设置系统时钟频率为72MHz的基本流程:
- 使能HSE时钟并等待完成。
/* Enable HSE */
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CR & RCC_CR_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
- 设置HCLK、PCLK1、PCLK2频率。
/* HCLK = SYSCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
- 使能PLL锁相环时钟并设置倍频因子为9(9*8MHz = 72MHz),使能并选择其为系统的时钟源。
/* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
/* Enable PLL */
RCC->CR |= RCC_CR_PLLON;
/* Wait till PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
{
}
至此,成功将系统时钟频率设置为72MHz,其中PCLK1为36MHz,PCLK2为72MHz。