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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章