STM32F103 时钟
STM32F103 时钟
- 系统上电时刻,默认使用内部 HSI (8M)作为时钟源。HSI时钟信号由内部 8MHz 的RC振荡器产生,可直接作为系统时钟或在2分频后作为PLL输入。HSI RC振荡器能够在不需要任何外部器件的条件下提供系统时钟。它的启动时间比HSE晶体振荡器短。然而,即使在校准之后它的时钟频率精度仍较差。
- 上电后,可以通过选择时钟源来切换时钟到HSE。
- 内部PLL可以用来倍频HSI RC的输出时钟或HSE晶体输出时钟。PLL的设置(选择HIS振荡器除2或HSE振荡器为PLL的输入时钟,和选择倍频因子)必须在其被激活前完成。一旦PLL被激活,这些参数就不能被改动。针对 USB 的时钟,必须提供有效稳定的48MHz时钟。
- 晶体是一个32.768kHz的低速外部晶体或陶瓷谐振器。它为实时时钟或者其他定时功能提供一个低功耗且精确的时钟源。
- LSI RC担当一个低功耗时钟源的角色,它可以在停机和待机模式下保持运行,为独立看门狗和自动唤醒单元提供时钟。LSI时钟频率大约40kHz(在30kHz和60kHz之间)。
- 时钟安全系统(CSS)。时钟安全系统可以通过软件被激活。一旦其被激活,时钟监测器将在HSE振荡器启动延迟后被使能,并在HSE时钟关闭后关闭。如果HSE时钟发生故障,HSE振荡器被自动关闭,时钟失效事件将被送到高级定时器(TIM1和TIM8)的刹车输入端,并产生时钟安全中断CSSI,允许软件完成营救操作。此CSSI中断连接到Cortex™-M3的NMI中断(不可屏蔽中断)。
- 时钟输出。STM32 微控制器允许输出时钟信号到外部MCO引脚。SYSCLK/HSI/HSE/除2的PLL时钟
/********************************************************/
基于特定的开发板上的时钟策略:
倍频/分频系数需要在使能 PLL 之前进行配置,所以需要在 Open PLL 之前将所有系统的时钟分频器系数以及PLL的倍频系数配置好。整个时钟的配置流程如下所示:
(1) 开启HSE,等待HSE稳定
(2) 设置APB2、APB1、AHB分频系数
(3) 设置PLL的时钟来源和PLL的倍频系数
(4) 开启PLL,等待PLL稳定
(5) 设置SYSCLK源为 PLL 的输出,读取时钟切换状态,确保PLLCLK被选为系统时钟
- (1) OSC_IN/OSC_OUT 上外接 8M 晶振。要使用外接晶振,上电后(默认使用 8M 的HSI),首先需要使能 HSE,位于RCC_CR寄存器的 bit16,即:
- /* Enable HSE */
- RCC->CR |= ((uint32_t)RCC_CR_HSEON);
- 接着需要等待外部时钟 HSE 稳定(轮询 RCC_CR寄存器的 bit17):
- /* 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));
- (2) 接着配置 AHB 时钟为 SYSCLK ,即 AHB 分频系数为1,不分频,SYSCLK直接供给SDIO, FSMC, AHB BUS, FCLK并直接作用于APB1/APB2的输入端:
- /* HCLK = SYSCLK */
- RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
配置高速APB2 分频系数为1,即 SYSCLK ->AHB->APB2:
- /* PCLK2 = HCLK */
- RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
由于APB1的时钟最大频率为 36MHz,当前希望输入的SYSCLK为72MHz(最大频率),故需要配置低速 APB1 分频系数为2,即两分频:
- /* PCLK1 = HCLK */
- RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
(3) 继续,配置 PLL 时钟源,以及 PLL 的倍频系数:
首先将需要配置的 bit 先清零:
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
接着
A. 选择HSE 时钟为 PLL 的输入 ,RCC_CFGR 的 bit16.
B. 对HSE输入晶振频率不分频,直接供给 PLL 作为输入
C. 由于外部晶振时钟为 8M,得到 72MHz 最大时钟频率,故设置 PLL 倍频系数为 9:
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
至此,分频/倍频系数基本设置完毕(未设置的部分采取系统 Reset 后的默认值)
(4) 开启 PLL 并等待稳定
- /* Enable PLL */
- RCC->CR |= RCC_CR_PLLON;
- /* Wait till PLL is ready */
- while((RCC->CR & RCC_CR_PLLRDY) == 0)
- {
- }
(5) 切换系统时钟源为 PLL 的输出:
- /* 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)
- {
- }
至此时钟配置完毕,本次配置是基于板载外接 8MHz 晶振进行的配置,若是板载其他的频率的晶振,只需改变 PLL 的倍频系数即可,此刻,系统运行在最大支持频率 72MHz 下。
完整的代码如下:
- static voidSetSysClockTo72(void)
- {
- __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
- /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/
- /* 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;
- }
- if (HSEStatus == (uint32_t)0x01)
- {
- /* Enable Prefetch Buffer */
- FLASH->ACR |= FLASH_ACR_PRFTBE;
- /* Flash 2 wait state */
- FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
- FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;
- /* 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 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)
- {
- }
- }
- else
- { /* If HSE fails to start-up, the application will have wrong clock
- configuration. User can add here some code to deal with this error */
- }
- }


浙公网安备 33010602011771号