STM32F103 时钟

STM32F103 时钟

STM32 的时钟设计显得较为繁琐,时钟树如图所示:

    1. 系统上电时刻,默认使用内部 HSI (8M)作为时钟源。HSI时钟信号由内部 8MHz 的RC振荡器产生,可直接作为系统时钟或在2分频后作为PLL输入。HSI RC振荡器能够在不需要任何外部器件的条件下提供系统时钟。它的启动时间比HSE晶体振荡器短。然而,即使在校准之后它的时钟频率精度仍较差。
    1. 上电后,可以通过选择时钟源来切换时钟到HSE。
    1. 内部PLL可以用来倍频HSI RC的输出时钟或HSE晶体输出时钟。PLL的设置(选择HIS振荡器除2或HSE振荡器为PLL的输入时钟,和选择倍频因子)必须在其被激活前完成。一旦PLL被激活,这些参数就不能被改动。针对 USB 的时钟,必须提供有效稳定的48MHz时钟。
    1. 晶体是一个32.768kHz的低速外部晶体或陶瓷谐振器。它为实时时钟或者其他定时功能提供一个低功耗且精确的时钟源。
    1. LSI RC担当一个低功耗时钟源的角色,它可以在停机和待机模式下保持运行,为独立看门狗和自动唤醒单元提供时钟。LSI时钟频率大约40kHz(在30kHz和60kHz之间)。
    1. 时钟安全系统(CSS)。时钟安全系统可以通过软件被激活。一旦其被激活,时钟监测器将在HSE振荡器启动延迟后被使能,并在HSE时钟关闭后关闭。如果HSE时钟发生故障,HSE振荡器被自动关闭,时钟失效事件将被送到高级定时器(TIM1和TIM8)的刹车输入端,并产生时钟安全中断CSSI,允许软件完成营救操作。此CSSI中断连接到Cortex™-M3的NMI中断(不可屏蔽中断)。
    1. 时钟输出。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. (1) OSC_IN/OSC_OUT 上外接 8M 晶振。要使用外接晶振,上电后(默认使用 8M 的HSI),首先需要使能 HSE,位于RCC_CR寄存器的 bit16,即:
    1. /* Enable HSE */
    1. RCC->CR |= ((uint32_t)RCC_CR_HSEON);
    1. 接着需要等待外部时钟 HSE 稳定(轮询 RCC_CR寄存器的 bit17):
    1. /* Wait till HSE is ready and if Time out is reached exit */
    1. do
    1. {
    1. HSEStatus = RCC->CR & RCC_CR_HSERDY;
    1. StartUpCounter++;
    1. } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
    1. (2) 接着配置 AHB 时钟为 SYSCLK ,即 AHB 分频系数为1,不分频,SYSCLK直接供给SDIO, FSMC, AHB BUS, FCLK并直接作用于APB1/APB2的输入端:
    1. /* HCLK = SYSCLK */
    1. RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;

配置高速APB2 分频系数为1,即 SYSCLK ->AHB->APB2:

    1. /* PCLK2 = HCLK */
    1. RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;

由于APB1的时钟最大频率为 36MHz,当前希望输入的SYSCLK为72MHz(最大频率),故需要配置低速 APB1 分频系数为2,即两分频:

    1. /* PCLK1 = HCLK */
    1. 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 并等待稳定

    1. /* Enable PLL */
    1. RCC->CR |= RCC_CR_PLLON;
    1. /* Wait till PLL is ready */
    1. while((RCC->CR & RCC_CR_PLLRDY) == 0)
    1. {
    1. }

(5) 切换系统时钟源为 PLL 的输出:

    1. /* Select PLL as system clock source */
    1. RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    1. RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;

轮询等待生效:

    1. /* Wait till PLL is used as system clock source */
    1. while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
    1. {
    1. }

至此时钟配置完毕,本次配置是基于板载外接 8MHz 晶振进行的配置,若是板载其他的频率的晶振,只需改变 PLL 的倍频系数即可,此刻,系统运行在最大支持频率 72MHz 下。

完整的代码如下:

    1. static voidSetSysClockTo72(void)
    1. {
    1. __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
    1. /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/
    1. /* Enable HSE */
    1. RCC->CR |= ((uint32_t)RCC_CR_HSEON);
    1. /* Wait till HSE is ready and if Time out is reached exit */
    1. do
    1. {
    1. HSEStatus = RCC->CR & RCC_CR_HSERDY;
    1. StartUpCounter++;
    1. } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
    1. if ((RCC->CR & RCC_CR_HSERDY) != RESET)
    1. {
    1. HSEStatus = (uint32_t)0x01;
    1. }
    1. else
    1. {
    1. HSEStatus = (uint32_t)0x00;
    1. }
    1. if (HSEStatus == (uint32_t)0x01)
    1. {
    1. /* Enable Prefetch Buffer */
    1. FLASH->ACR |= FLASH_ACR_PRFTBE;
    1. /* Flash 2 wait state */
    1. FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    1. FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;
    1. /* HCLK = SYSCLK */
    1. RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
    1. /* PCLK2 = HCLK */
    1. RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
    1. /* PCLK1 = HCLK */
    1. RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
    1. /* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
    1. RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
    1. RCC_CFGR_PLLMULL));
    1. RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
    1. /* Enable PLL */
    1. RCC->CR |= RCC_CR_PLLON;
    1. /* Wait till PLL is ready */
    1. while((RCC->CR & RCC_CR_PLLRDY) == 0)
    1. {
    1. }
    1. /* Select PLL as system clock source */
    1. RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    1. RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
    1. /* Wait till PLL is used as system clock source */
    1. while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
    1. {
    1. }
    1. }
    1. else
    1. { /* If HSE fails to start-up, the application will have wrong clock
    1. configuration. User can add here some code to deal with this error */
    1. }
    1. }
posted @ 2025-11-06 11:23  张大帅哥  阅读(54)  评论(0)    收藏  举报