STM32F429--RCC时钟树

STM32F429–RCC时钟树简介

  • RCC全称:reset clock config ,复位和时钟控制,在中文参考手册的第六章
  • 系统时钟: SYSCLK,首选PPL为系统时钟,可达180MHZ
  • 时钟树 :单片机所有的时钟

学前概念须知
STM32F429有5条总线 越高时钟越快由低到高分别是 :
APB1 -->APB2–>AHB1–>AHB2–>AHB3

  • HSE: 高速的外部时钟,板子采用无源晶振,设置为25M,精度较高,一般配置为这个。

  • HSI: 高速的内部时钟,为16M,当HSE故障时,自动切换到HSI,直到HSE启动.

  • PLLCLK:锁相环时钟 HSE->PLL->倍频到180M M/N/P
    系统时钟:来源 HSI HSE PLLCLK 控制RCC_CFGR时钟配置寄存器的SW位 配置为10PLLCLK

  • HCLK:【 AHB高速总线时钟】,最高180M,为AHB总线外设提供 [important]

  • AHB: advanced high-performance bus 【高性能总线】

  • FCLK:free clock 内核CPU自由时钟

  • RTC: real time clock,实时时钟,为芯片内部的RTC提供时钟,具体看功能框图

下面都是由低到高速,对应5条总线的时钟 ,后面是分频因子

  • PCLK1: 为APB1总线提供45M时钟,APB1总线定时器2倍频后90M时钟 RCC_CFGR寄存器配置,PPRE1位
  • PCLK2: 为APB2总线提供90M时钟,APB2总线定时器2倍频后180M时钟 RCC_CFGR寄存器配置,PPRE2位
  • PPRE2: APB高速预分频器
  • PPRE1: APB地速预分频器
  • APB1一般设置为45M , APB2一般设置为 90M

STM32F429时钟树功能框图

在这里插入图片描述

说明:
1–6部分为主系统时钟,A~F为外设和其他时钟
图中最高为168MHZ有误,应改为180MHZ

系统时钟配置流程:
static void SetSysClock(void)
选择HSE打开,默认25M -->
进入锁相环/M=25 ,最终为1M–>
设置倍频因子xN = 360M,VCO默认1 最终为360M–>
/ P设置为2 最终360/2=180M–>
选择PLLCLK作为系统时钟,不选HSI/HSE–>
设置1倍分频,得HCLK 360M–>
设置倍频因子为8,360/8=45M,最后得到APB1 45MHZ
设置倍频因子为8,360/4=90M,最后得到APB2 90MHZ

其他外设的时钟需要用到的时候再进行配置,这里不作说明。
总结:
先配置好HSI/HSEPLL振荡器作为PLL时钟源,并配置分频系数M/N/P/Q
A,B,C,D,F时钟在需要的时候才需要配置。

可通过MCO时钟输出来检测自己配置的PLLCLK在示波器显示,来判断是否成功配置为180MHZ。

程序部分

1-使能HSE,并等待HSE稳定
2-配置 AHB APB2 APB1 总线的预分频因子
3-配置 PLL的各种分频因子,并使能PLL
4-选择系统时钟来源

想要配置自己想要的时钟,可以直接修改提供的SetSysClock函数,不过为了保证库函数的完整性,我们可以通过固件库来自己实现一个,一般不选用HSI,精确度没有HSE的高。下面程序采用条件编译的方式,#if 0#else #endif 部分是从系统自带的时钟配置函数裁剪下来的部分。

bsp_rccclkconfig.c

#include "bsp_rccclkconfig.h"

#if 0
static void SetSysClock(void)
{
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;

/*-------------------------1-使能HSE,并等待HSE稳定----------------------------------------*/  
  /* 使能 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启动成功 */
	if (HSEStatus == (uint32_t)0x01)
  {
/*----------------------------------------------------------------------------------------*/
    /* 选择电压调节器输出为模式1 */
		/* 使能电源接口时钟 */
    RCC->APB1ENR |= RCC_APB1ENR_PWREN;
    PWR->CR |= PWR_CR_VOS;
/*----------------------------2-配置 AHB APB2 APB1 总线的预分频因子-----------------------*/
    /* HCLK = SYSCLK / 1*/
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1;    
    /* PCLK2 = HCLK / 2*/
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;    
    /* PCLK1 = HCLK / 4*/
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;

/*----------------------------3-配置 PLL的各种分频因子,并使能PLL-----------------------*/  
    /* 配置 主 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)
    {
    }
    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;
		
/*----------------------------4-选择系统时钟来源-----------------------------------------*/

    /* 选择主锁相环时钟作为系统时钟 */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= RCC_CFGR_SW_PLL;

    /* 等待PLLCLH切换称系统时钟 */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
    {
    }
  }
  else
  { /* HSE启动失败后,用户纠错的代码 */
  } 
}

#endif

取值范围:
// m : 2~63
// n :192~432
// p :2、4、6、8
// q :2~15
// SYSCLK = (HSE/m) * n /p = 25/25 * 432 / 2 = 216M 
// HSE_SetSysClk(25,432,2,7)
void HSE_SetSysClk(uint32_t m,uint32_t n,uint32_t p,uint32_t q)
{
	__IO uint32_t HSEStartUpStatus = 0;
	
	/* 使能HSE 并等待HSE稳定*/
	RCC_HSEConfig(RCC_HSE_ON);	
	HSEStartUpStatus = RCC_WaitForHSEStartUp();
	
	if( HSEStartUpStatus == SUCCESS )
  {
			/* 选择电压调节器输出为模式1 */
			/* 使能电源接口时钟 */
			RCC->APB1ENR |= RCC_APB1ENR_PWREN;
			PWR->CR |= PWR_CR_VOS;

			RCC_HCLKConfig(RCC_SYSCLK_Div1);
			RCC_PCLK2Config(RCC_HCLK_Div2);
			RCC_PCLK1Config(RCC_HCLK_Div4);

			RCC_PLLConfig(RCC_PLLSource_HSE, m, n, p, q);

			RCC_PLLCmd(ENABLE);
			while ( ( RCC_GetFlagStatus(RCC_FLAG_PLLRDY) ) == RESET )
			{
			}
			/* 打开OVER-Drive模式,为的是达到更高的频率 */
			PWR->CR |= PWR_CR_ODEN;
			while((PWR->CSR & PWR_CSR_ODRDY) == 0)
			{
			}
			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;


			RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
			while ( ( RCC_GetSYSCLKSource() ) != 0X08 )
			{
			}	  
  }
  else{ /* HSE启动识别,用户在这里添加纠错代码 */ }
}

/*
*以下部分是配置MCO引脚输出的配置函数
*/
// MCO1 PA8 GPIO 初始化
void MCO1_GPIO_Config(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
  
  // MCO1 GPIO 配置
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;  
  GPIO_Init(GPIOA, &GPIO_InitStructure); 
}

// MCO2 PC9 GPIO 初始化
void MCO2_GPIO_Config(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
  
  // MCO2 GPIO 配置
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;  
  GPIO_Init(GPIOC, &GPIO_InitStructure);
}

bsp_rccclkconfig.h

#ifndef  __BSP_RCCCLKCONFIG_H
#define  __BSP_RCCCLKCONFIG_H
#include "stm32f4xx_rcc.h"
void HSE_SetSysClk(uint32_t m,uint32_t n,uint32_t p,uint32_t q);
#endif  /*__BSP_RCCCLKCONFIG_H*/

main.c

#include "stm32f4xx.h"
#include "bsp_rccclkconfig.h"
int main(void)
{
// 程序来到main函数之前,启动文件已经调用SystemInit()函数把系统时钟初始化成180MHZ
// SystemInit()在system_stm32f4xx.c中定义,如果想修改系统时钟,可自行编写程序修改	
// 重新设置系统时钟,这时候可以选择使用HSE还是HSI	
	/* 把系统时钟初始化为216M */
	HSE_SetSysClk(25,432,2,9);	
	// MCO1 输出PLLCLK	
    RCC_MCO1Config(RCC_MCO1Source_PLLCLK, RCC_MCO1Div_1);
	while (1);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章