STM32之RCC系统时钟控制(芯片的心脏控制器)

参考资料:

野火STM32F407_霸天虎V2开发板原理图2025.pdf

1-STM32F4xx中文参考手册1.pdf

什么是RCC?

RCC即Reset Clock Control,也叫复位和时钟控制器。

时钟树

要想弄明白系统时钟是怎么回事,时钟树是逃避不了的一个话题。如下图:

接下来的内容我会尽量用最朴实的语言描述好时钟树,助于咱们理解它。

系统时钟

黄色区域:这段内容是重中之重,重点讲解。也就是我们常说的系统时钟。

①高速的外部时钟信号--HSE,可以由有源晶振和无源晶振提供,频率从4~26MHz不等。当使用有源晶振时,时钟从OSC_IN引脚进入,OSC_OUT引脚悬空;当用无源晶振时,时钟从OSC_IN和OSC_OUT进入,并且要配谐振电容。本开发板HSE使用25MHz的无源晶振,如下图

②主要内容--PLL锁相环。它的主要作用就是对时钟进行倍频,然后将它输出到各功能部件。PLL的时钟输入来自HSE(为主)或者HSI经过PLL时钟输入分频因子M(2~63)的分频,也就是VCO的时钟输入,VCO的时钟必须在1M~2M之间,当我们选择HSE=25M为PLL的时钟输入,M应设置为25,得到VCO的时钟就是1M;VCO的时钟经过倍频因子N倍频之后,即为VCO的时钟输出,VCO时钟输出必须在192~432之间,这里N配置为336,也就是VCO的时钟输出是336M,经后面的PLLCLK分频因子P(P可以取2,4,6,8,这里取最小值为2)后系统时钟为336/2=168M(当然VCO时钟输出取最大值432M时N为432,即为超频,此时系统时钟为216M,不建议);还有两个分频因子Q和R,其中经分频因子Q提供USB_OTGFS要求的48M,则Q=336/48=7。(详细内容可查看参考手册中6.3.2 RCC_PLLCFGR寄存器描述)

简言之:

VCOCLK_IN=PLLCLK_IN/M=HSE/25=25M/25=1M

VCOCLK_OUT=VCOCLK_IN*N=1M*336=336M

PLLCLK_OUT=VCOCLK_OUT/P=336M/2=168M

USBCLK=VCOCLK_OUT/Q=336M/7=48M

③SYSCLK就是系统时钟,它的来源有3种即HSI、HSE和PLLCLK。由RCC_CFGR

的SW位配置。我们选择PLLCLK作为SYSCLK的时钟源即SYSCLK=PLLCLK=168M。(如果HSE出现故障,SYSCLK会自动切换成HSI=16M,直到HSE恢复正常)

④这部分是SYSCLK经AHB预分频器(AHBPRESC)得到的AHB总线时钟,也就是HCLK。分频因子可以是1,2,4,8,16,64,128,256,512,由RCC_CFGR的HPRE位设置。片上的外设大部分都是经HCLK分频得到,具体多少具体设置。这里我们设置1分频,得到HCLK=SYSCLK=168M。

⑤⑥接下来就是APBx的总线时钟(x可以是1或2)。

其中APB2的总线时钟PCLK2由HCLK经高速APB2预分频器 得到,分频因子可以是1,2,4,8,16,由RCC_CFGR的PPRE2位设置。APB2属于高速时钟总线,片上的高速外设 挂载在它这里,如USART1、SPI1等,具体多少具体设置。这里我们设置2分频,得到PCLK2=HCLK/2=84M。

其中APB2的总线时钟PCLK1由HCLK经低速APB1预分频器 得到,分频因子可以是1,2,4,8,16,由RCC_CFGR的PPRE1位设置。APB1属于低速时钟总线,片上的低速外设 挂载在它这里,如USART2/3/4/5、SPI2/3、I2C1等,具体多少具体设置。这里我们设置4分频,得到PCLK1=HCLK/4=42M。

RTC时钟电路

A区域:RTC时钟电路,由时钟树可知,RTC时钟源可选3路中任意一路,分别是LSI、LSE和HSE。由RCC备份域控制器(RCC_BDCR)的RTCSEL1:0选择RTC时钟源(选择 RTC 时钟源后,除非备份域复位,否则其不可再更改。可使用 BDRST 位对其进行复位),其中HSE的时钟由RCC_CFGR的RTCPRE位设置HSE 分频系数得到1MHz。通常由LSE为RTC提供时钟,大小是32.768KHz,LSE由外接的晶体谐振器产生,谐振电容精度要求高,否则不容易起振。

独立看门狗时钟电路

B区域:独立看门狗时钟电路,由内部低速时钟LSI提供,大小为32KHz。

I2S时钟电路

C区域:I2S时钟电路,可选两路时钟源任意一路,即外部时钟引脚I2S_CKIN和专用PLLI2SCLK提供。由RCC_CFGR的I2SSRC位配置。

PHY以太网时钟电路

D区域:PHY以太网时钟电路,本开发板选择的PHY芯片是LAN8720A,使用RMII接口,此时PHY芯片只需提供一路时钟给MCU即可。

USB2.0 PHY时钟电路

E区域:USB2.0 PHY时钟电路,F407的USB没有集成PHY,要想实现USB高速传输,必须外置USB PHY芯片,常用芯片是USB3300,当外接USB PHY芯片时,PHY芯片需要给MCU提供一个时钟。

微控制器时钟输出引脚(MCO)

F区域:微控制器时钟输出引脚(MCO),即对外提供时钟,相当于一个有源晶振。F407有2个MCO,由PA8/9复用得到。MCO1的时钟源由RCC_CFGR的MCO1位选择时钟源(LSE、HSE、HSI、PLLCLK),由RCC_CFGR的MCO1PRE位选择几分频(无,2,3,4,5);MCO2的时钟源由RCC_CFGR的MCO2位选择时钟源(SYSCLK、PLLI2SCLK、HSE、PLLCLK),由RCC_CFGR的MCO2PRE位选择几分频(无,2,3,4,5);MCO1和MCO2的最大输出速率是100M。如图:

库函数是怎么设置系统时钟的?

我们找到库函数是怎么设置系统时钟的,找它的方法:在启动文件里找到SystemInit,F12定位位置,转到system_stm32f4xx.c的SystemInit函数,函数体内找到SetSysClock(),F12定位位置,该函数就是我们要找的配置系统时钟的函数。

以下内容是配置系统时钟的函数经过裁剪后的程序(将不是F407的程序已经删掉了,这是精简F407专用版):

cpp 复制代码
static void SetSysClock(void)
{
/******************************************************************************/
/*            PLL (clocked by HSE) used as System clock source                */
/******************************************************************************/
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
  
  /* 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;
  }

  //HSE启动成功
  if (HSEStatus == (uint32_t)0x01)
  {
    /* Select regulator voltage output Scale 1 mode */
    RCC->APB1ENR |= RCC_APB1ENR_PWREN;
    PWR->CR |= PWR_CR_VOS;

    /* HCLK = SYSCLK / 1*/
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
	/* PCLK2 = SYSCLK / 2*/
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;	  
	/* PCLK1 = SYSCLK / 4*/
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;

    /* Configure the main PLL */
    RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
                   (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
   
    /* Enable the main PLL */
    RCC->CR |= RCC_CR_PLLON;

    /* Wait till the main PLL is ready */
    while((RCC->CR & RCC_CR_PLLRDY) == 0)
    {
    }   

    /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
    FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;

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

    /* Wait till the main PLL is used as system clock source */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
    {
    }
  }
  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 */
	  //HSE启动出错处理
  }
}

总结下使用HSE设置系统时钟的步骤:

1.开启HSE并等待HSE稳定;

2.设置AHB(HCLK)、APB2、APB1的预分频因子;

3.设置PLL的时钟来源以及VCO输入时钟分频因子M、VCO输出时钟倍频因子N、PLLCLK时钟分频因子P、48MHz时钟(USB_OTGFS,SDIO,RNG)分频因子Q;

4.开启主PLL并等待其稳定;

5.将主PLLCLK设置为系统时钟SYSCLK并通过读取时钟切换状态位确保PLLCLK被选为系统时钟。

实验--实现HSE/HSI作为系统时钟并输出时钟

手搓一个使用HSE或HSI作为系统时钟的实验,并且使用MCO对外提供时钟输出

有一个小知识点:

当HSE直接或者间接(经过PLL倍频)作为系统时钟的时候,如果HSE发生故障,不仅HSE会关闭,PLL也会关闭,此时系统会将HSI设置为系统时钟,即SYSCLK=HSI=16M,如果没有开启CSS和CSS中断的话,整个系统只会在低速率下运行,相当于瘫痪。如果开启了CSS功能,此时在CSS中断里会执行补救措施,会将HSI重新设置系统时钟为168M,但只是权宜之计,因为HSI较于HSE精度低。

下面我们将手搓这个实验【程序源码放到附件了】

相关推荐
李永奉1 小时前
日常使用的锂电池上,新、旧锂电池的差异分析
单片机·嵌入式硬件·物联网·智能手机·电脑
额额额对了2 小时前
IMX6ULL 杂项设备 LED 驱动
stm32·单片机·嵌入式硬件
长春的KAKA3 小时前
Proxmark3 Iceman分支CLI命令总表
嵌入式硬件
半杯咖啡半行码3 小时前
STM32开发之IIC通信详解:从协议基础到FM24CL04实战
stm32·单片机·嵌入式硬件
硅基手札4 小时前
【I2C 技术系列 05】I2C 多主仲裁与时钟同步
驱动开发·stm32·单片机·嵌入式硬件·mcu·计算机外设
szxinmai主板定制专家4 小时前
面向虚拟电厂协调控制:RK3588+FPGA+AI边缘控制器设计思路与算力评估
人工智能·嵌入式硬件·fpga开发·机器人·jetson·zynq·振动采集
Zw-awa4 小时前
DO 和 AO 到底怎么选:比较器替你决定了什么
stm32
硅基手札4 小时前
【I2C 技术系列 01】I2C 电气特性与物理层
驱动开发·stm32·单片机·嵌入式硬件·mcu·计算机外设
comyccccc4 小时前
TB6612电机驱动板原理图与PCB设计学习笔记
单片机·嵌入式硬件