STM32-時鍾-時鍾樹-時鍾初始化配置


1.STM32時鍾

在這里插入圖片描述

在這里插入圖片描述

  • STM32有5個時鍾源:HSI、HSE、LSI、LSE、PLL

  • HSI是高速內部時鍾,RC振盪器,頻率為16MHz,精度不高。可以直接作為系統時鍾或者用作PLL時鍾輸入。

  • HSE是高速外部時鍾,可接石英/陶瓷諧振器,或者接外部時鍾源,頻率范圍為4MHz~26MHz。

  • LSI是低速內部時鍾,RC振盪器,頻率為32kHz,提供低功耗時鍾。主要供獨立看門狗和自動喚醒單元使用。

  • LSE是低速外部時鍾,接頻率為32.768kHz的石英晶體。RTC

  • PLL為鎖相環倍頻輸出。 STM32F4有三個PLL:

  • 主PLL(PLL)由HSE或者HSI提供時鍾信號,並具有兩個不同的輸出時鍾。

①第一個輸出PLLP用於生成高速的系統時鍾(最高180MHz)

②第二個輸出PLLQ為48M時鍾,用於USB OTG FS時鍾,隨機數發生器的時鍾和SDIO時鍾。

  • 第一個專用PLL(PLLI2S)生成精確時鍾,在I2S和SAI1上實現高品質音頻

    N是用於PLLI2S vco的倍頻系數,其取值范圍是:192~432;

    R是I2S時鍾的分頻系數,其取值范圍是:2~7;

    Q是SAI時鍾分頻系數,其取值范圍是:2~15;P沒用到。

  • 第二個專用PLL(PLLSAI)同樣用於生成精確時鍾,用於SAI1輸入時鍾,同時還為LCD_TFT接口提供精確時鍾。

    N是用於PLLSAI vco的倍頻系數,其取值范圍是:192~432;

    Q是SAI時鍾分頻系數,其取值范圍是:2~15;

    R是LTDC時鍾的分頻系數,其取值范圍是:2~7;P沒用到。

  • PLLCLK=HSE*N/(M * P),可以通過改變N、M、P改變PLLCLK的頻率

  • 系統時鍾SYSCLK可來源於三個時鍾源:

​ ①、HSI振盪器時鍾

​ ②、HSE振盪器時鍾

​ ③、PLL時鍾

  • 任何外設在使用之前,必須使能相應的時鍾

  • STM32F4時鍾信號輸出MCO1(PA8)和MCO2(PC9),MCO1:用戶可以配置預分頻器(1~ 5)向MCO1引腳PA8輸出4個不同的時鍾源:HIS、LSE、HSE、PLL。MCO2:用戶可以配置預分頻器(1~ 5)向MCO2引腳PC9輸出4個不同的時鍾源:HSE、PLL、SYSCLK、PLLI2S 。MCO最大輸出時鍾不超過100MHz。

  • RCC時鍾控制相關寄存器定義在stm32f429xx.h中。結構體: RCC_TypeDef;RCC時鍾相關定義和函數在文件stm32f4xx_hal_rcc.h、stm32f4xx_hal_rcc.c 。

2.Stm32_Clock_Init

在CORE-startup_stm32f429xx.s文件中找到Reset_Handler,這一部分代碼作用是引導程序,可以看到先執行SystemInit函數再執行main。

; Reset handler Reset_Handler PROC EXPORT Reset_Handler [WEAK] IMPORT SystemInit IMPORT __main LDR R0, =SystemInit BLX R0 LDR R0, =__main BX R0 ENDP ; Dummy Exception Handlers (infinite loops which can be modified) 

可以在USER-system_stm32f7xx.c文件中找到SystemInit函數。其中/* Set HSION bit */可以看出系統初始化之后默認使用HSI作為系統時鍾來源,因為不知道外部時鍾是否准備好。

void SystemInit(void) { /* FPU settings ------------------------------------------------------------*/ #if (__FPU_PRESENT == 1) && (__FPU_USED == 1) SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */ #endif /* Reset the RCC clock configuration to the default reset state ------------*/ /* 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; /* Configure the Vector Table location add offset address ------------------*/ #ifdef VECT_TAB_SRAM SCB->VTOR = RAMDTCM_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 } 

時鍾配置一般步驟:

  • 使能PWR時鍾:調用函數 _HAL_RCC_PWR_CLK_ENABLE()。
  • 設置調壓器輸出電壓級別:調用函數 _HAL_PWR_VOLTAGESCALING_CONFIG()。
  • 選擇是否開啟Over-Driver功能:調用函數HAL_PWREx_EnableOverDrive()。
  • 配置時鍾源相關參數:調用函數HAL_RCC_OscConfig()。
  • 配置系統時鍾源以及AHB,APB1和APB2的分頻系數:調用函數HAL_RCC_ClockConfig()。

在STSTEM-sys.c文件中找到Stm32_Clock_Init函數:

//時鍾設置函數 //Fvco=Fs*(plln/pllm); //Fsys=Fvco/pllp=Fs*(plln/(pllm*pllp)); //Fusb=Fvco/pllq=Fs*(plln/(pllm*pllq)); //Fvco:VCO頻率 //Fsys:系統時鍾頻率 //Fusb:USB,SDIO,RNG等的時鍾頻率 //Fs:PLL輸入時鍾頻率,可以是HSI,HSE等. //plln:主PLL倍頻系數(PLL倍頻),取值范圍:64~432. //pllm:主PLL和音頻PLL分頻系數(PLL之前的分頻),取值范圍:2~63. //pllp:系統時鍾的主PLL分頻系數(PLL之后的分頻),取值范圍:2,4,6,8.(僅限這4個值!) //pllq:USB/SDIO/隨機數產生器等的主PLL分頻系數(PLL之后的分頻),取值范圍:2~15. //外部晶振為25M的時候,推薦值:plln=432,pllm=25,pllp=2,pllq=9. //得到:Fvco=25*(432/25)=432Mhz // Fsys=432/2=216Mhz // Fusb=432/9=48Mhz //返回值:0,成功;1,失敗 void Stm32_Clock_Init(u32 plln,u32 pllm,u32 pllp,u32 pllq) { HAL_StatusTypeDef ret = HAL_OK; RCC_OscInitTypeDef RCC_OscInitStructure; RCC_ClkInitTypeDef RCC_ClkInitStructure; __HAL_RCC_PWR_CLK_ENABLE(); //使能PWR時鍾 __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);//設置調壓器輸出電壓級別,以便在器件未以最大頻率工作 RCC_OscInitStructure.OscillatorType=RCC_OSCILLATORTYPE_HSE; //時鍾源為HSE RCC_OscInitStructure.HSEState=RCC_HSE_ON; //打開HSE RCC_OscInitStructure.PLL.PLLState=RCC_PLL_ON; //打開PLL RCC_OscInitStructure.PLL.PLLSource=RCC_PLLSOURCE_HSE; //PLL時鍾源選擇HSE RCC_OscInitStructure.PLL.PLLM=pllm; //主PLL和音頻PLL分頻系數(PLL之前的分頻) RCC_OscInitStructure.PLL.PLLN=plln; //主PLL倍頻系數(PLL倍頻) RCC_OscInitStructure.PLL.PLLP=pllp; //系統時鍾的主PLL分頻系數(PLL之后的分頻) RCC_OscInitStructure.PLL.PLLQ=pllq; //USB/SDIO/隨機數產生器等的主PLL分頻系數(PLL之后的分頻) ret=HAL_RCC_OscConfig(&RCC_OscInitStructure);//初始化 if(ret!=HAL_OK) while(1); ret=HAL_PWREx_EnableOverDrive(); //開啟Over-Driver功能 if(ret!=HAL_OK) while(1); //選中PLL作為系統時鍾源並且配置HCLK,PCLK1和PCLK2 RCC_ClkInitStructure.ClockType=(RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2); RCC_ClkInitStructure.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK;//設置系統時鍾時鍾源為PLL RCC_ClkInitStructure.AHBCLKDivider=RCC_SYSCLK_DIV1;//AHB分頻系數為1 RCC_ClkInitStructure.APB1CLKDivider=RCC_HCLK_DIV4;//APB1分頻系數為4 RCC_ClkInitStructure.APB2CLKDivider=RCC_HCLK_DIV2;//APB2分頻系數為2 ret=HAL_RCC_ClockConfig(&RCC_ClkInitStructure,FLASH_LATENCY_7);//同時設置FLASH延時周期為7WS,也就是8個CPU周期。 if(ret!=HAL_OK) while(1); } 

對於 __HAL_RCC_PWR_CLK_ENABLE();可以在stm32fxx_hal_rcc.h中找到:

#define __HAL_RCC_PWR_CLK_ENABLE() do { \ __IO uint32_t tmpreg; \ SET_BIT(RCC->APB1ENR, RCC_APB1ENR_PWREN);\ /* Delay after an RCC peripheral clock enabling */ \ tmpreg = READ_BIT(RCC->APB1ENR, RCC_APB1ENR_PWREN);\ UNUSED(tmpreg); \ } while(0) 

因為后面設置調壓器輸出電壓級別和選擇是否開啟Over-Driver功能要用到PWR時鍾,所以先使能PWR時鍾。

對於以下兩函數頭文件,都位於HALLIB-stm32f7xx_hal_rcc.h文件中

  • 配置時鍾源相關參數:調用函數HAL_RCC_OscConfig()。
  • 配置系統時鍾源以及AHB,APB1和APB2的分頻系數:調用函數HAL_RCC_ClockConfig()。
HAL_StatusTypeDef HAL_RCC_OscConfig(RCC_OscInitTypeDef *RCC_OscInitStruct); HAL_StatusTypeDef HAL_RCC_ClockConfig(RCC_ClkInitTypeDef *RCC_ClkInitStruct, uint32_t FLatency); 

HAL_RCC_OscConfig函數配置時鍾源相關參數

選中RCC_OscInitTypeDef找到它的定義:

首先根據TYPE判斷操作的是哪個時鍾源,然后再對相應的時鍾源配置。

typedef struct { uint32_t OscillatorType; /*!< The oscillators to be configured. This parameter can be a value of @ref RCC_Oscillator_Type */ uint32_t HSEState; /*!< The new state of the HSE. This parameter can be a value of @ref RCC_HSE_Config */ uint32_t LSEState; /*!< The new state of the LSE. This parameter can be a value of @ref RCC_LSE_Config */ uint32_t HSIState; /*!< The new state of the HSI. This parameter can be a value of @ref RCC_HSI_Config */ uint32_t HSICalibrationValue; /*!< The HSI calibration trimming value (default is RCC_HSICALIBRATION_DEFAULT). This parameter must be a number between Min_Data = 0x00 and Max_Data = 0x1F */ uint32_t LSIState; /*!< The new state of the LSI. This parameter can be a value of @ref RCC_LSI_Config */ RCC_PLLInitTypeDef PLL; /*!< PLL structure parameters */ }RCC_OscInitTypeDef; 

其中的RCC_PLLInitTypeDef:可以看到里面有對PLL時鍾源等一系列配置。

typedef struct { uint32_t PLLState; /*!< The new state of the PLL. This parameter can be a value of @ref RCC_PLL_Config */ uint32_t PLLSource; /*!< RCC_PLLSource: PLL entry clock source. This parameter must be a value of @ref RCC_PLL_Clock_Source */ uint32_t PLLM; /*!< PLLM: Division factor for PLL VCO input clock. This parameter must be a number between Min_Data = 2 and Max_Data = 63 */ uint32_t PLLN; /*!< PLLN: Multiplication factor for PLL VCO output clock. This parameter must be a number between Min_Data = 50 and Max_Data = 432 */ uint32_t PLLP; /*!< PLLP: Division factor for main system clock (SYSCLK). This parameter must be a value of @ref RCC_PLLP_Clock_Divider */ uint32_t PLLQ; /*!< PLLQ: Division factor for OTG FS, SDMMC and RNG clocks. This parameter must be a number between Min_Data = 2 and Max_Data = 15 */ #if defined (STM32F765xx) || defined (STM32F767xx) || defined (STM32F769xx) || defined (STM32F777xx) || defined (STM32F779xx) uint32_t PLLR; /*!< PLLR: Division factor for DSI clock. This parameter must be a number between Min_Data = 2 and Max_Data = 7 */ #endif /* STM32F767xx || STM32F769xx || STM32F777xx || STM32F779xx */ }RCC_PLLInitTypeDef; 

調用HAL_RCC_OscConfig函數的方法如下:首先設置一下RCC_OscInitTypeDef類型的結構體。

    RCC_OscInitStructure.OscillatorType=RCC_OSCILLATORTYPE_HSE; //時鍾源為HSE RCC_OscInitStructure.HSEState=RCC_HSE_ON; //打開HSE RCC_OscInitStructure.PLL.PLLState=RCC_PLL_ON; //打開PLL RCC_OscInitStructure.PLL.PLLSource=RCC_PLLSOURCE_HSE; //PLL時鍾源選擇HSE RCC_OscInitStructure.PLL.PLLM=pllm; //主PLL和音頻PLL分頻系數(PLL之前的分頻) RCC_OscInitStructure.PLL.PLLN=plln; //主PLL倍頻系數(PLL倍頻) RCC_OscInitStructure.PLL.PLLP=pllp; //系統時鍾的主PLL分頻系數(PLL之后的分頻) RCC_OscInitStructure.PLL.PLLQ=pllq; //USB/SDIO/隨機數產生器等的主PLL分頻系數(PLL之后的分頻) ret=HAL_RCC_OscConfig(&RCC_OscInitStructure);//初始化 

如果要配置HSI:可以找到RCC_OSCILLATORTYPE_HSE的定義,然后發現如下代碼塊,在RCC_OscInitStructure.OscillatorType=RCC_OSCILLATORTYPE_HSE;代碼中,將RCC_OSCILLATORTYPE_HSE修改成RCC_OSCILLATORTYPE_HSI即可。

#define RCC_OSCILLATORTYPE_NONE ((uint32_t)0x00000000U) #define RCC_OSCILLATORTYPE_HSE ((uint32_t)0x00000001U) #define RCC_OSCILLATORTYPE_HSI ((uint32_t)0x00000002U) #define RCC_OSCILLATORTYPE_LSE ((uint32_t)0x00000004U) #define RCC_OSCILLATORTYPE_LSI ((uint32_t)0x00000008U) 

同樣的方法可以配置其他的成員變量。

可以理解main函數的Stm32_Clock_Init,可以找到:Stm32_Clock_Init(432,25,2,9); //設置時鍾,216Mhz

然后找到Stm32_Clock_Init的定義,void Stm32_Clock_Init(u32 plln,u32 pllm,u32 pllp,u32 pllq)

由於外部晶振是25M,現在Stm32_Clock_Init第二個參數pllm是25,因此外部晶振是25M經過/M后,變成1。然后*n再/p最后得到216M 。

在這里插入圖片描述

HAL_RCC_ClockConfig配置系統時鍾源以及AHB,APB1和APB2的分頻系數

然后再看一下HAL_RCC_ClockConfig函數,HAL_StatusTypeDef HAL_RCC_ClockConfig(RCC_ClkInitTypeDef *RCC_ClkInitStruct, uint32_t FLatency)

對於第一個參數RCC_ClkInitTypeDef 在HALLIB-stm32f7xx_hal_rcc.h文件中可找到:

/** * @brief RCC System, AHB and APB busses clock configuration structure definition */ typedef struct { uint32_t ClockType; /*!< The clock to be configured. This parameter can be a value of @ref RCC_System_Clock_Type */ uint32_t SYSCLKSource; /*!< The clock source (SYSCLKS) used as system clock. This parameter can be a value of @ref RCC_System_Clock_Source */ uint32_t AHBCLKDivider; /*!< The AHB clock (HCLK) divider. This clock is derived from the system clock (SYSCLK). This parameter can be a value of @ref RCC_AHB_Clock_Source */ uint32_t APB1CLKDivider; /*!< The APB1 clock (PCLK1) divider. This clock is derived from the AHB clock (HCLK). This parameter can be a value of @ref RCC_APB1_APB2_Clock_Source */ uint32_t APB2CLKDivider; /*!< The APB2 clock (PCLK2) divider. This clock is derived from the AHB clock (HCLK). This parameter can be a value of @ref RCC_APB1_APB2_Clock_Source */ }RCC_ClkInitTypeDef; 

對於第一個ClockType它可以選擇哪些值:也可以在HALLIB-stm32f7xx_hal_rcc.h文件找到

#define RCC_CLOCKTYPE_SYSCLK ((uint32_t)0x00000001U) #define RCC_CLOCKTYPE_HCLK ((uint32_t)0x00000002U) #define RCC_CLOCKTYPE_PCLK1 ((uint32_t)0x00000004U) #define RCC_CLOCKTYPE_PCLK2 ((uint32_t)0x00000008U) 

對應於時鍾系統:可以配置SYSCLK、HCLK、PCLK

在這里插入圖片描述

SYSCLK、HCLK、PCLK都是占用不同的位,而且HAL_RCC_ClockConfig里面是用if進行判斷而不是ifelse,所以可用或運算配置時鍾。

//選中PLL作為系統時鍾源並且配置HCLK,PCLK1和PCLK2 RCC_ClkInitStructure.ClockType=(RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2); RCC_ClkInitStructure.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK;//設置系統時鍾時鍾源為PLL RCC_ClkInitStructure.AHBCLKDivider=RCC_SYSCLK_DIV1;//AHB分頻系數為1 RCC_ClkInitStructure.APB1CLKDivider=RCC_HCLK_DIV4;//APB1分頻系數為4 RCC_ClkInitStructure.APB2CLKDivider=RCC_HCLK_DIV2;//APB2分頻系數為2 ret=HAL_RCC_ClockConfig(&RCC_ClkInitStructure,FLASH_LATENCY_7);//同時設置FLASH延時周期為7WS,也就是8個CPU周期。 

配置調壓器輸出級別:

__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);//設置調壓器輸出電壓級別,以便在器件未以最大頻率工作。

首先找到__HAL_PWR_VOLTAGESCALING_CONFIG的定義:可以發現是通過PWR->CR寄存器來配置的。

  • VOS[1:0] =“0x01”時,fHCLK 最大值為 144 MHz。

  • VOS[1:0] =“0x10”時,fHCLK 最大值為 168 MHz。激活過驅動模式可將其擴展到
    180 MHz。

  • VOS[1:0] =“0x11”時,fHCLK 最大值為 180 MHz。激活過驅動模式可將其擴展到
    216 MHz。

#define __HAL_PWR_VOLTAGESCALING_CONFIG(__REGULATOR__) do { \ __IO uint32_t tmpreg; \ MODIFY_REG(PWR->CR1, PWR_CR1_VOS, (__REGULATOR__)); \ /* Delay after an RCC peripheral clock enabling */ \ tmpreg = READ_BIT(PWR->CR1, PWR_CR1_VOS); \ UNUSED(tmpreg); \ } while(0) 

對於__HAL_PWR_VOLTAGESCALING_CONFIG的參數,可以找到:

#define PWR_REGULATOR_VOLTAGE_SCALE1 PWR_CR1_VOS #define PWR_REGULATOR_VOLTAGE_SCALE2 PWR_CR1_VOS_1 #define PWR_REGULATOR_VOLTAGE_SCALE3 PWR_CR1_VOS_0 

通過 ret=HAL_PWREx_EnableOverDrive(); //可以開啟Over-Driver功能

配置FLASH等待周期

HAL_RCC_ClockConfig還有一個參數uint32_t FLatency,可以找到:

/** @defgroup FLASH_Latency FLASH Latency * @{ */ #define FLASH_LATENCY_0 FLASH_ACR_LATENCY_0WS /*!< FLASH Zero Latency cycle */ #define FLASH_LATENCY_1 FLASH_ACR_LATENCY_1WS /*!< FLASH One Latency cycle */ #define FLASH_LATENCY_2 FLASH_ACR_LATENCY_2WS /*!< FLASH Two Latency cycles */ #define FLASH_LATENCY_3 FLASH_ACR_LATENCY_3WS /*!< FLASH Three Latency cycles */ #define FLASH_LATENCY_4 FLASH_ACR_LATENCY_4WS /*!< FLASH Four Latency cycles */ #define FLASH_LATENCY_5 FLASH_ACR_LATENCY_5WS /*!< FLASH Five Latency cycles */ #define FLASH_LATENCY_6 FLASH_ACR_LATENCY_6WS /*!< FLASH Six Latency cycles */ #define FLASH_LATENCY_7 FLASH_ACR_LATENCY_7WS /*!< FLASH Seven Latency cycles */ #define FLASH_LATENCY_8 FLASH_ACR_LATENCY_8WS /*!< FLASH Eight Latency cycles */ #define FLASH_LATENCY_9 FLASH_ACR_LATENCY_9WS /*!< FLASH Nine Latency cycles */ #define FLASH_LATENCY_10 FLASH_ACR_LATENCY_10WS /*!< FLASH Ten Latency cycles */ #define FLASH_LATENCY_11 FLASH_ACR_LATENCY_11WS /*!< FLASH Eleven Latency cycles */ #define FLASH_LATENCY_12 FLASH_ACR_LATENCY_12WS /*!< FLASH Twelve Latency cycles */ #define FLASH_LATENCY_13 FLASH_ACR_LATENCY_13WS /*!< FLASH Thirteen Latency cycles */ #define FLASH_LATENCY_14 FLASH_ACR_LATENCY_14WS /*!< FLASH Fourteen Latency cycles */ #define FLASH_LATENCY_15 FLASH_ACR_LATENCY_15WS /*!< FLASH Fifteen Latency cycles */ /** * @} */ 

CPU 時鍾 (HCLK) 頻率對應的等待周期數是通過一張表對應的:

在這里插入圖片描述

然后就可以寫:ret=HAL_RCC_ClockConfig(&RCC_ClkInitStructure,FLASH_LATENCY_7);//同時設置FLASH延時周期為7WS,也就是8個CPU周期。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM