STM32系统时钟配置及时钟树

版权声明:均是学习笔记、心得,如有冒犯,请指出,会及时处理。https://blog.csdn.net/qq_27485531 https://blog.csdn.net/qq_27485531/article/details/83715716

参考资料:《 STM32F4xx 中文参考手册》 RCC 章节。

STM32时钟可大致分为系统时钟和其它时钟两大类,总共包含5个时钟源 HSI(High Speed Internal Clock)HSE(High Speed External Clock)LSI(low Speed Internal Clock)LSE(Low Speed External Clock )PLL(Phase Locked Loop Clock)。

下图即为STM32时钟树,黄色标识部分即为系统时钟部分,橙色即为其它时钟部分。

一、系统时钟

①HSE(High Speed External Clock)高速外部时钟信号

 HSE 是高速的外部时钟信号,可以由有源晶振或者无源晶振提供,频率从 4-26MHZ不等。当使用有源晶振时,时钟从 OSC_IN

引脚进入,OSC_OUT 引脚悬空,当选用无源晶振时,时钟从 OSC_IN 和 OSC_OUT 进入,并且要配谐振电容。HSE 我们使用

25M 的无源晶振。如果我们使用 HSE 或者 HSE 经过 PLL倍频之后的时钟作为系统时钟 SYSCLK,当 HSE 故障时候,不仅

HSE 会被关闭,PLL也会被关闭,此时高速的内部时钟时钟信号HSI 会作为备用的系统时钟,直到 HSE 恢复正常,HSI=16M。

HSI(High Speed Internal Clock)高速内部时钟信号

由芯片内部RC振荡器提供,大小为16MHZ,当HSE故障时,系统时钟会自动切换到HSI,直到HSE 启动成功。

②锁相环 PLL(Phase Locked Loop )

PLL的主要作用是对时钟进行倍频,然后把时钟输出到各个功能部件。PLL有两个,一个是主 PLL(黄色部分,为系统时钟部

分),另外一个是专用的 PLLI2S(橙色部分),他们均由 HSE 或者 HSI 提供时钟输入信号。

主 PLL有两路的时钟输出,第一个输出时钟 PLLCLK用于系统时钟,第二个输出用于 USB OTG FS 的时钟、RNG 和 SDIO 时

钟。专用的 PLLI2S 用于生成精确时钟,给 I2S 提供时钟。

HSE 或者 HSI 经过 PLL 时钟输入分频因子 M分频后,成为 VCO 的时钟输入,VCO 的时钟必须在 1~2M 之间,我们选择

HSE=25M 作为 PLL 的时钟输入,M 设置为 25,那么 VCO输入时钟就等于 1M。VCO 输入时钟经过 VCO倍频因子 N 倍频之

后,成为 VCO时钟输出,VCO时钟必须在 192~432M 之间。我们配置 N 为 360,则 VCO的输出时钟等于 360M。VCO 输出时

钟之后有三个分频因子:PLLCLK分频因子 p,USB OTG FS/RNG/SDIO时钟分频因子 Q,分频因子R

具体公式如下

                                                             PLLCLK = HSE(HSI) / M *N /P 

                                                             PLL48CK =  HSE(HSI) / M *N /Q

③系统时钟 SYSCLK

系统时钟来源可以是:HSI、PLLCLK、HSE,具体的由时钟配置寄存器 RCC_CFGR的 SW位配置。如果系统时钟是由HSE 经

过 PLL倍频之后的 PLLCLK 得到,当 HSE 出现故障的时候,系统时钟会切换为HSI=16M,直到 HSE 恢复正常为止。

④AHB 总线时钟 HCLK

系统时钟 SYSCLK 经过 AHB 预分频器分频之后得到时钟叫 AHB 总线时钟,即 HCLK,分频因子可以是:[1,2,4,8,16,64,

128,256,512],具体的由时钟配置寄存器RCC_CFGR 的 HPRE 位设置。片上大部分外设的时钟都是经过 HCLK 分频得到,

至于 AHB总线上的外设的时钟设置为多少,得等到我们使用该外设的时候才设置。这里只需粗线条的设置好AHB的时钟即可。

⑤APB2总线时钟 PCLK2

APB2总线时钟 PCLK2 由 HCLK经过高速 APB2预分频器得到,分频因子可以是:[1,2,4,8,16],具体由时钟配置寄存器

RCC_CFGR 的 PPRE2位设置。HCLK2属于高速的总线时钟,片上高速的外设就挂载到这条总线上,比如全部的 GPIO、

USART1、SPI等。至于 APB2总线上的外设的时钟设置为多少,得等到我们使用该外设的时候才设置。这里只需粗线条的设置好

APB2的时钟即可。

⑥APB1总线时钟 PCLK1

APB1 总线时钟 PCLK1 由 HCLK经过低速 APB预分频器得到,分频因子可以是:[1,2,4,8,16],具体由时钟配置寄存器

RCC_CFGR的 PPRE1位设置。HCLK1属于低速的总线时钟,最高为 45M,片上低速的外设就挂载到这条总线上,比如

USART2/3/4/5、SPI2/3,I2C1/2等。至于 APB1总线上的外设的时钟设置为多少,得等到我们使用该外设的时候才设置。

这里只需粗线条的设置好APB的时钟即可。

系统初始化时钟过程如下

Reset_Handler    PROC
                 EXPORT  Reset_Handler             [WEAK]
        IMPORT  SystemInit
        IMPORT  __main

                 LDR     R0, =SystemInit
                 BLX     R0
                 LDR     R0, =__main
                 BX      R0
                 ENDP

这是一个启动文件,当我们单片机上电后,首先执行的启动文件,会进入SystemInit函数

void SystemInit(void)
{
  /* FPU设置 ------------------------------------------------------------*/
  #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
    SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));  /* set CP10 and CP11 Full Access */
  #endif
  /* 复位RCC时钟配置到默认的初始化状态 ------------*/
  /* Set HSION bit */
  RCC->CR |= (uint32_t)0x00000001;

  /* Reset CFGR register */
  RCC->CFGR = 0x00000000;

  /* Reset HSEON, CSSON and PLLON bits */
  RCC->CR &= (uint32_t)0xFEF6FFFF;

  /* Reset PLLCFGR register */
  RCC->PLLCFGR = 0x24003010;

  /* Reset HSEBYP bit */
  RCC->CR &= (uint32_t)0xFFFBFFFF;

  /* Disable all interrupts */
  RCC->CIR = 0x00000000;

#if defined(DATA_IN_ExtSRAM) || defined(DATA_IN_ExtSDRAM)
  SystemInit_ExtMemCtl(); 
#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */
         
  /* 配置系统时钟 ----------------------------------*/
  SetSysClock();

  /* Configure the Vector Table location add offset address ------------------*/
#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
}

在SystemInit中会配置系统时钟

配置系统时钟的代码如下

下面是CMSIS Cortex-M4设备外围设备访问层系统源文件中的设置系统时钟函数SetSysClock(void)

static void SetSysClock(void)
{

/******************************************************************************/
/*            使用HSE作为PLL的输入来配置系统时钟                                */
/******************************************************************************/
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
  
  /* 一、使能HSE */
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);
 
  /* 等待HSE使能稳定,如果时间超时,则跳出 */
  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稳定后,开始配置HCLK、PCLK2、PCLK1、PLL各自的预分频因子与倍频因子 */
  if (HSEStatus == (uint32_t)0x01)
  {
	
	
		 /* 配置HCLK为1分频,即HCLK = 系统时钟 HCLK = SYSCLK / 1 */
		RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
    
		/*配置APB2总线时钟为2分频  PCLK2 = HCLK / 2 */
		RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
				
		/*配置APB1总线时钟为4分频PCLK1 = HCLK / 4 */
		RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
   
		/* 配置主PLL */
		RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
										(RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
   
    /* 三、使能主PLL */
    RCC->CR |= RCC_CR_PLLON;

    /*等待主PLL稳定 */
    while((RCC->CR & RCC_CR_PLLRDY) == 0)
    {
    }
/*------------------------------------------------------------------------------------------*/		   
		/* 使能Over-drive 模式来达到更高的时钟频率 */
		PWR->CR |= PWR_CR_ODEN;
		while((PWR->CSR & PWR_CSR_ODRDY) == 0)        //判断Over-drive模式是否已经成功启动
		{
		}
		PWR->CR |= PWR_CR_ODSWEN;
		while((PWR->CSR & PWR_CSR_ODSWRDY) == 0)
		{
		}      
		/*选择FLASH预取指缓存的模式, 指令缓存, 数据缓存和等待缓存 */
		FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
/*------------------------------------------------------------------------------------------*/		
				
    /* 四、选择主PLL作为系统时钟源 */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= RCC_CFGR_SW_PLL;

    /*判断系统时钟是否已经稳定 */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
    {
    }
  }
  else
  { /* 如果HSE启动失败,那么时钟就会被错误的配置,用户可以在这里添加一些代码来处理错误 */
  }
 
}

系统时钟配置主要就是以上部分,系统时钟初始化就进行的是上述操作.

二、其它时钟

A、RTC时钟

RTCCLK 时钟源可以是 HSE 1 MHz( HSE 由一个可编程的预分频器分频)、 LSE 或者 LSI 时钟。选择方式是编程 RCC 备份

域控制寄存器 (RCC_BDCR) 中的 RTCSEL[1:0] 位和 RCC时钟配置寄存器 (RCC_CFGR) 中的 RTCPRE[4:0] 位。所做的选择只

能通过复位备份域的方式修改。我们通常的做法是由 LSE 给 RTC提供时钟,大小为 32.768KHZ。LSE由外接的晶体谐振器产生,

所配的谐振电容精度要求高,不然很容易不起震。

B、独立看门狗时钟

独立看门狗时钟由内部的低速时钟 LSI 提供,大小为 32KHZ。

C、I2S 时钟

I2S 时钟可由外部的时钟引脚 I2S_CKIN 输入,也可由专用的 PLLI2SCLK提供,具体的由 RCC 时钟配置寄存器 (RCC_CFGR)

的 I2SSCR位配置。

D、PHY以太网时钟

F429要想实现以太网功能,除了有本身内置的 MAC之外,还需要外接一个 PHY 芯片,常见的 PHY 芯片有 DP83848和

LAN8720,其中 DP83848支持 MII 和 RMII 接口,LAN8720只支持 RMII 接口。野火 F429 开发板用的是 RMII 接口,选择的

PHY 芯片是LAB8720。使用 RMII 接口的好处是使用的 IO 减少了一半,速度还是跟 MII 接口一样。当使用 RMII 接口时,PHY

芯片只需输出一路时钟给 MCU 即可,如果是 MII 接口,PHY 芯片则需要提供两路时钟给 MCU。

E、USB PHY 时钟

F429 的 USB 没有集成 PHY,要想实现 USB 高速传输的话,必须外置 USB PHY 芯片,常用的芯片是 USB3300。当外接 USB

PHY 芯片时,PHY 芯片需要给 MCU 提供一个时钟。

F、MCO时钟输出

MCO 是 microcontroller clock output 的缩写,是微控制器时钟输出引脚,主要作用是可以对外提供时钟,相当于一个有源晶振。

F429中有两个 MCO,由 PA8/PC9复用所得。MCO1所需的时钟源通过 RCC 时钟配置寄存器 (RCC_CFGR) 中MCO1PRE[2:0]

和MCO1[1:0]位选择。MCO2所需的时钟源通过 RCC 时钟配置寄存器 (RCC_CFGR) 中的MCO2PRE[2:0] 和 MCO2位选择。

以上就是STM32f429的时钟树讲解,理解之后,以此类推,对于学习STM32其它时钟树有很大的帮助。

猜你喜欢

转载自blog.csdn.net/qq_27485531/article/details/83715716