【12】STM32·HAL库开发 | 您所在的位置:网站首页 › STM32时钟树结构 › 【12】STM32·HAL库开发 |
目录
1.认识时钟树(掌握)1.1什么是时钟?1.2认识时钟树(F1)1.2.1STM32F103时钟树简图1.2.2STM32CubeMX时钟树(F103)
1.3认识时钟树(F4)1.3.1F407时钟树1.3.2F429时钟树1.3.3STM32F4时钟树简图1.3.4STM32CubeMX时钟树(F407)1.3.5STM32CubeMX时钟树(F429)
2,配置系统时钟(掌握)2.1外设时钟使能和失能2.2`sys_stm32_clock_init` 函数(F1)2.2.1`HAL_RCC_OscConfig()`函数(F1)2.2.2` HAL_RCC_ClockConfig()`函数(F1)2.2.3实际配置步骤2.3.1.1.配置HSE_VALUE2.3.2,调用SystemInit()函数(可选)2.3.2,调用sys_stm32_clock_init()函数
2.4`sys_stm32_clock_init` 函数(F4/F7)2.4.1 HAL_RCC_OscConfig()函数2.4.2HAL_RCC_ClockConfig()函数2.4.3Stm32_Clock_Init()函数
3,总结(了解)
1.认识时钟树(掌握)
1.1什么是时钟?
下图的clk是clock(时钟)的缩写,下面的波形可以理解为脉冲信号或者方波。简单来说,时钟是具有周期性的脉冲信号,最常用的是占空比50%的方波。时钟是单片机的脉搏,搞懂时钟走向及关系,对单片机使用至关重要! 下图是F1系列的时钟树,从左侧竖线开始,OSC_OUT与OSC_IN是外部高速晶振所连接的引脚,OSC32_IN与OSC32_OUT是外部低速晶振所连接的引脚,这两个是外部时钟源。STM32还有内部时钟源HSI与LSI。HSE经过PLLXTPRE选择器可以进行1分频或者2分频,PLLSRC用于选择内部还是外部时钟,经过PLL锁相环倍频得到PLLCLK,选择器控制位SW选择SYSCLK的时钟来源。Cortex系统时钟是滴答定时器SysTick,定时器时钟频率都为72Mhz,TIM1和TIM8位高级定时器。 STM32是向外部输出时钟通道,MCO是引脚PA8复用得到此项功能,时钟来源有四个。 STM32F103最大系统时钟为72MHz,HSE与HSI想要得到72MHz需要经过PLL锁相环进行倍频,进入PLL之前也需要进行分频,HSI只有2分频,HSE可以选择1分频或者2分频。HSI经过2分频为4MHz经过16倍频,最大是64MHz,即用内部高速时钟最大可达64MHz,显然用内部是不满足的,基本是不使用。F1系列最常用HSE为8MHz,与HSI时钟一致,一分频后为8MHz,经过9倍频,可以得到72MHz。 经过系统时钟来到HCLK(也就是AHB总线,AHB总线时钟用名字HCLK来表示),从SYSCLK到HCLK需要进行分频(分频系数不用关心,具体的分频系数需要查看寄存器,事实上该分频系数一般设置为1);HCLK经过两个桥分为APB1和APB2总线,分频系数份别为2和1,AHB除了能分出APB1和APB2,AHB总线上还会挂载外设,并且内核时钟也是来自AHB。 低速有LSI与LSE,LSI可以作为IWDG独立看门狗、RTC实时时钟外设的时钟来源,LSE只能作为RTC的时钟源。 时钟源(振荡器)、锁相环:HAL_RCC_OscConfig(),控制时钟源是否打开、锁相环PLL的倍频系数 系统时钟、总线:HAL_RCC_ClockConfig(),配置系统时钟的来源,SYSCLK->HCLK->APB1/APB2的分频器。 使能外设时钟:__HAL_RCC_PPP_CLK_ENABLE(),__HAL_RCC_PPP_CLK_ENABLE()并不是函数是宏,PPP代表任意外设,例如GPIO、ADC等,STM32为了低功耗,将所有外设时钟默认是关闭的,想要使用哪一个外设就要使能哪一个宏。 扩展外设时钟(RTC/ADC/USB):HAL_RCCEx_PeriphCLKConfig(),Ex是拓展Extend的缩写,不同系列,该函数配置的外设不同。 1.2.2STM32CubeMX时钟树(F103) 下图是F407时钟树图,与F429时钟树不同。图中VCO,V是电压,C是控制,O是振荡器,也就是压控振荡器。 HSE与HSI都无法直接达到SYSCLK的最大时钟频率,需要经过锁相环倍频,在此之前需要进行M倍分频,F1系列锁相环PLL只是倍频器,而F4系列锁相环是先倍频后分频,SYSCLK一般经过1分频到达HCLK也就是AHB总线,在F4系列中AHB分为AHB1和AHB2,甚至AHB3,APB1与APB2是AHB1总线经过桥达到的。。LSE是专门为RTC提供的,RTC对时钟的精准度要求较高,优先选择LSE,如果没有LSE则用LSI代替。 时钟源、PLL:HAL_RCC_OscConfig(),用于配置四个时钟源的开关,以及RTC振荡器校准系数的设置。 系统时钟、总线:HAL_RCC_ClockConfig(),配置系统时钟的来源, 使能外设时钟:__HAL_RCC_PPP_CLK_ENABLE(),PPP可以是任意外设,例如GPIO 扩展外设时钟(PLLI2S/ I2S/ LTDC /RTC等):HAL_RCCEx_PeriphCLKConfig() 1.3.4STM32CubeMX时钟树(F407) 48MHz clocks(MHz)可以作为全速USB(FSUSB)的时钟来源。
1.配置HSE_VALUE:告诉HAL库外部晶振频率,在stm32xxxx_hal_conf.h,定义; 2.调用SystemInit()函数(可选):在启动文件中调用, 在system_stm32xxxx.c定义; 3.选择时钟源,配置PLL:通过HAL_RCC_OscConfig()函数设置; 4.选择系统时钟源,配置总线分频器:通过HAL_RCC_ClockConfig()函数设置; 5.配置扩展外设时钟(可选):通过HAL_RCCEx_PeriphCLKConfig()函数设置,正点原子只在H7系列中设置此项。 3 +4 + 5 =正点原子自定义函数 sys_stm32_clock_init() 2.1外设时钟使能和失能我们要使用某个外设,必需先使能该外设时钟!!! HAL库使能某个外设时钟的方法,以使能GPIOA为例,如: __HAL_RCC_GPIOA_CLK_ENABLE(); /* 使能 GPIOA 时钟 */HAL库禁止某个外设时钟的方法,以使能GPIOA为例,如: __HAL_RCC_GPIOA_CLK_DISABLE(); /* 禁止 GPIOA 时钟 */ 2.2sys_stm32_clock_init 函数(F1) 2.2.1HAL_RCC_OscConfig()函数(F1)HAL_RCC_OscConfig()函数原型如下,函数返回值为HAL_StatusTypeDef类型。 HAL_StatusTypeDef HAL_RCC_OscConfig(RCC_OscInitTypeDef *RCC_OscInitStruct)`第一个参数OscillatorType是选择4个振荡器中的哪一个;HSEState配置HSE打开还是关闭;HSI是永远RC振荡器的,会随着温度、电压变化而变化,不稳定,需要有一个校验值。 typedef struct { uint32_t OscillatorType; /* 选择需要配置的振荡器 */ uint32_t HSEState; /* HSE 状态 */ uint32_t HSEPredivValue; /* HSE 预分频值 */ uint32_t LSEState; /* LSE 状态 */ uint32_t HSIState; /* HSI状态 */ uint32_t HSICalibrationValue; /* HSI 校准值 */ uint32_t LSIState; /* LSI 状态 */ RCC_PLLInitTypeDef PLL; /* PLL 结构体 */ }RCC_OscInitTypeDef;RCC_PLLInitTypeDef锁相环结构体如下所示,PLLState是配置打开锁相环还是关闭,倍频系数为2~16倍频。 typedef struct { uint32_t PLLState; /* PLL 状态 */ uint32_t PLLSource; /* PLL 时钟源 */ uint32_t PLLMUL; /* PLL 倍频系数 */ }RCC_PLLInitTypeDef; 2.2.2 HAL_RCC_ClockConfig()函数(F1) HAL_StatusTypeDef HAL_RCC_ClockConfig(RCC_ClkInitTypeDef *RCC_ClkInitStruct, uint32_t FLatency)HCLK是AHB总线时钟,PCLK1是APB1总线上时钟,PCLK2是APB2总线上时钟。 typedef struct { uint32_t ClockType; /* 要配置的时钟(SYSCLK/HCLK/PCLK1/PCLK2) */ uint32_t SYSCLKSource; /* 系统时钟源 */ uint32_t AHBCLKDivider; /* AHB 时钟预分频系数 */ uint32_t APB1CLKDivider; /* APB1 时钟预分频系数 */ uint32_t APB2CLKDivider; /* APB2 时钟预分频系数 */ }RCC_ClkInitTypeDef;F1系统时钟为72Mhz,FLASH时钟来源来自72Mhz,但是用72Mhz会超频,最大时钟频率为24Mhz,用72Mhz的时钟访问FLAH太快,需要等待几个周期。 uint32_t FLatency #define FLASH_LATENCY_0 0x00000000U /* FLASH 0个等待周期 */ #define FLASH_LATENCY_1 FLASH_ACR_LATENCY_0 /* FLASH 1个等待周期 */ #define FLASH_LATENCY_2 FLASH_ACR_LATENCY_1 /* FLASH 2个等待周期 */实际设置FLASH_ACR寄存器LATENCY位域,需要参考《 STM32F10xxx闪存编程参考手册.pdf 》3.1小节 在stm32f1xx_hal_conf.h中配置HSE_VALUE的值。 #if !defined (HSE_VALUE) #if defined(USE_STM3210C_EVAL) #define HSE_VALUE 25000000U /*!< Value of the External oscillator in Hz */ #else #define HSE_VALUE 8000000U /*!< Value of the External oscillator in Hz */ #endif #endif /* HSE_VALUE */ 2.3.2,调用SystemInit()函数(可选)如果不想调用SystemInit()函数,可以用分号“;”注释掉。SystemInit()函数在system_stm32f1xx.c中被定义,只配置了中断向量表所在的位置,并没有配置时钟相关。 ; Reset handler Reset_Handler PROC EXPORT Reset_Handler [WEAK] IMPORT __main IMPORT SystemInit LDR R0, =SystemInit BLX R0 LDR R0, =__main BX R0 ENDP 2.3.2,调用sys_stm32_clock_init()函数sys_stm32_clock_init()函数一般在main函数的前几行被调用,主要由函数HAL_RCC_OscConfig和HAL_RCC_ClockConfig组成。选择要配置的时钟时,可以用或“|”同时设置多个时钟,结构体rcc_osc_init在定义时给到0,如果其中结构体未被赋值,则默认为0,如果不定义可能为随机数,赋值为0是为了避免不必要的麻烦。 void sys_stm32_clock_init(uint32_t plln) { HAL_StatusTypeDef ret = HAL_ERROR; RCC_OscInitTypeDef rcc_osc_init = {0}; RCC_ClkInitTypeDef rcc_clk_init = {0}; rcc_osc_init.OscillatorType = RCC_OSCILLATORTYPE_HSE; /* 选择要配置HSE */ rcc_osc_init.HSEState = RCC_HSE_ON; /* 打开HSE */ rcc_osc_init.HSEPredivValue = RCC_HSE_PREDIV_DIV1; /* HSE预分频系数 */ rcc_osc_init.PLL.PLLState = RCC_PLL_ON; /* 打开PLL */ rcc_osc_init.PLL.PLLSource = RCC_PLLSOURCE_HSE; /* PLL时钟源选择HSE */ rcc_osc_init.PLL.PLLMUL = plln; /* PLL倍频系数 */ ret = HAL_RCC_OscConfig(&rcc_osc_init); /* 初始化 */ if (ret != HAL_OK) { while (1); /* 时钟初始化失败,之后的程序将可能无法正常执行,可以在这里加入自己的处理 */ } /* 选中PLL作为系统时钟源并且配置HCLK,PCLK1和PCLK2*/ rcc_clk_init.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2); rcc_clk_init.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; /* 设置系统时钟来自PLL */ rcc_clk_init.AHBCLKDivider = RCC_SYSCLK_DIV1; /* AHB分频系数为1 */ rcc_clk_init.APB1CLKDivider = RCC_HCLK_DIV2; /* APB1分频系数为2 */ rcc_clk_init.APB2CLKDivider = RCC_HCLK_DIV1; /* APB2分频系数为1 */ ret = HAL_RCC_ClockConfig(&rcc_clk_init, FLASH_LATENCY_2); /* 同时设置FLASH延时周期为2WS,也就是3个CPU周期。 */ if (ret != HAL_OK) { while (1); /* 时钟初始化失败,之后的程序将可能无法正常执行,可以在这里加入自己的处理 */ } } 2.4sys_stm32_clock_init 函数(F4/F7)STM32F4/F7系列的sys_stm32_clock_init 函数实现主要由HAL_RCC_OscConfig()函数和HAL_RCC_ClockConfig()函数实现。 2.4.1 HAL_RCC_OscConfig()函数HAL_RCC_OscConfig()函数的返回值数据类型为HAL_StatusTypeDef ,一般无需关心其返回值,除非函数在调用过程中出现了问题。 HAL_StatusTypeDef HAL_RCC_OscConfig(RCC_OscInitTypeDef *RCC_OscInitStruct)`OscillatorType是选择外部的哪个振荡器,如果要配置多个振荡器,则用竖线“|”隔开。 typedef struct { uint32_t OscillatorType; /* 选择需要配置的振荡器 */ uint32_t HSEState; /* HSE 状态 */ uint32_t LSEState; /* LSE 状态 */ uint32_t HSIState; /* HSI 状态 */ uint32_t HSICalibrationValue; /* HSI 校准微调值,范围0x0~0x1F */ uint32_t LSIState; /* LSI 状态 */ RCC_PLLInitTypeDef PLL; /* PLL 结构体 */ }RCC_OscInitTypeDef; typedef struct { uint32_t PLLState; /* PLL 状态 */ uint32_t PLLSource; /* PLL 时钟源 */ uint32_t PLLM; /* PLL 分频系数 M */ uint32_t PLLN; /* PLL 倍频系数 N */ uint32_t PLLP; /* PLL 分频系数 P */ uint32_t PLLQ; /* PLL 分频系数 Q */ }RCC_PLLInitTypeDef; 2.4.2HAL_RCC_ClockConfig()函数 HAL_StatusTypeDef HAL_RCC_ClockConfig(RCC_ClkInitTypeDef *RCC_ClkInitStruct, uint32_t FLatency) typedef struct { uint32_t ClockType; /* 要配置的时钟(SYSCLK/HCLK/PCLK1/PCLK2) */ uint32_t SYSCLKSource; /* 系统时钟源 */ uint32_t AHBCLKDivider; /* AHB 时钟预分频系数 */ uint32_t APB1CLKDivider; /* APB1 时钟预分频系数 */ uint32_t APB2CLKDivider; /* APB2 时钟预分频系数 */ }RCC_ClkInitTypeDef;配置FLASH的等待周期,由于F4/F7系列的系统时钟都比访问FLASH的时钟更快,如果要有系统时钟访问FLASH则需要进行等待,一共是有0~15,16个选择。但是在有些芯片中,可能是0~7,那么需要查询FLASH_ACR寄存器LATENCY位域 uint32_t FLatency #define FLASH_LATENCY_0 FLASH_ACR_LATENCY_0WS /* FLASH 0个等待周期 */ #define FLASH_LATENCY_1 FLASH_ACR_LATENCY_1WS /* FLASH 1个等待周期 */ #define FLASH_LATENCY_2 FLASH_ACR_LATENCY_2WS /* FLASH 2个等待周期 */ ... #define FLASH_LATENCY_15 FLASH_ACR_LATENCY_15WS /* FLASH 15个等待周期 */ 2.4.3Stm32_Clock_Init()函数 下面为F429时钟配置函数,__HAL_PWR_VOLTAGESCALING_CONFIG函数设置调压器输出电压,来控制最大可达到的时钟。其中等待周期FLASH_LATENCY_5可以根据STM32F4xx中文参考手册中的表7, CPU 时钟 (HCLK) 频率对应的等待周期数来进行配置。 |
CopyRight 2018-2019 实验室设备网 版权所有 |