上一讲我们说了H7时钟树的一些基本概念,现在的话我们来用HAL库和CubeMx配置一下

再次说明,本文耗时较久,如果您想搞懂RCC初始化流程,请认真阅读,刚开始可能看不懂,但是仔细阅读之后绝对会有收获。

启动流程

H7的启动流程我们再说一下:

系统上电复位,进入启动文件 startup_stm32h743xx.s,在这个文件里面执行复位中断服务程序。

  • 在复位中断服务程序里面执行函数 SystemInit,此函数在文件 system_stm32h7xx.c 里面。
  • 之后是调用启动文件__main,最终进入到 main函数

进入到 main 函数就可以开始用户应用程序编程了。在程序运行之前需要:

  • MPU 初始化,需要用到库文件 stm32h7xx_hal_cortex.c 和 stm32h7xx_hal_cortex.h。
  • Cache 初始化,需要用到 core_cm7.h 文件。
  • HAL 库初始化函数 HAL_Init,对Systick滴答定时器初始化,需要用到文件 stm32h7xx_hal.c。
  • 系统时钟初始化,需要用到库文件 stm32h7xx_hal_rcc.c

要注意的是,Hal库的SystemInit函数对于时钟只做了:复位 RCC 时钟配置为默认复位值(默认开启 HSI) 并没有做其他的配置,所以时钟初始化还要用户自己配置。

我们今天关心的就是最后一步的系统时钟初始化

上面的四步,在执行完HAL_Init之后,系统还在用内部高速时钟 HSI,对于 H7 来说,HSI 主频是 64MHz

修改时钟配置

那么我们来看下如何修改时钟的配置:

第 1 步:在 stm32h7xx_hal_conf.h 文件配置 HSE_VALUE
配置的大小要跟板子的实际晶振大小匹配。

我使用的外部晶振是25Mhz的 所以配置为25000000

#if !defined (HSE_VALUE)
#define HSE_VALUE ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */

第 2 步:然后我们初始化时钟,最主要的就是两个结构体参数和两个函数:

RCC_ClkInitTypeDef RCC_ClkInitStruct;  // 配置时钟源相关参数
RCC_OscInitTypeDef RCC_OscInitStruct;  //配置系统时钟源及各个外设分频系数
 HAL_RCC_OscConfig()  //配置时钟源相关参数HAL_RCC_ClockConfig() //配置系统时钟源及各个外设分频系数

HAL_RCC_OscConfig()

HAL_RCC_OscConfig() , 该 函 数 在 HAL 库 关 键 头 文 件stm32h7xx_hal_rcc.h 中声明,在文件 stm32h7xx_hal_rcc.c 中定义。首先我们来看看该函数声明:

__weak HAL_StatusTypeDef HAL_RCC_OscConfig(RCC_OscInitTypeDef *RCC_OscInitStruct);

只有一个RCC_OscInitTypeDef 结构体参数,我们来看下这个结构体:

typedef struct
{uint32_t OscillatorType; //需要选择配置的振荡器类型 uint32_t HSEState; //HSE 状态 uint32_t LSEState; //LSE 状态 uint32_t HSIState; //HIS 状态 uint32_t HSICalibrationValue; //HIS 校准值uint32_t LSIState; //LSI 状态
uint32_t HSI48State //HSI48 的状态
uint32_t CSIState; //CSI 状态
uint32_t CSICalibrationValue; //CSI 校准值RCC_PLLInitTypeDef PLL; //PLL 配置
}RCC_OscInitTypeDef;

第一个就是选择振荡器的类型,比如我们要开启 HSE,那么我们会设置 OscillatorType 的值为 RCC_OSCILLATORTYPE_HSE,然后设置 HSEState 的值为 RCC_HSE_ON 开启 HSE。对于其他时钟源 HSI,LSI 和 LSE,配置方法类似

最后有一个 RCC_PLLInitTypeDef PLL; //PLL 配置

这个就是配置锁相环了,结构体参数如下

typedef struct
{uint32_t PLLState; //PLL 状态uint32_t PLLSource; //PLL 时钟源uint32_t PLLM; //PLL 分频系数 Muint32_t PLLN; //PLL 倍频系数 Nuint32_t PLLP; //PLL 分频系数 Puint32_t PLLQ; //PLL 分频系数 Q
uint32_t PLLR; //PLL 分频系数 R
uint32_t PLLRGE; //PLL1 时钟输入范围
uint32_t PLLVCOSEL; //PLL1 时钟输出范围
uint32_t PLLFRACN; //PLL1 VCO 乘数因子的小数部分
}RCC_PLLInitTypeDef;

这里的分频系数,全部都是PLL锁相环内部控制,我们要做的就是明白具体的公式就行

  • Fvco:VCO频率
  • Fsys:系统时钟频率,也是PLL1的p分频输出时钟频率 pll1_p_ck
  • Fpllq:PLL1的q分频输出时钟频率 pll1_q_ck
  • ref1_ck: PLL输入时钟频率,可以是HSI,CSI,HSE等.

  • plln:PLL1倍频系数(PLL倍频),取值范围:4~512.
  • pllm:PLL1预分频系数(进PLL之前的分频),取值范围:2~63.
  • pllp:PLL1的p分频系数(PLL之后的分频),分频后作为系统时钟,取值范围:2~128.(且必须是2的倍数)
  • pllq:PLL1的q分频系数(PLL之后的分频),取值范围:1~128.

VCO频率: Fvco= ref1_ck*(plln/pllm);
pll1_p_ck频率: Fsys=Fvco/pllp= ref1_ck*(plln/(pllm*pllp));
pll1_q_ck频率: Fpllq=Fvco/pllq= ref1_ck*(plln/(pllm*pllq));


具体的公式如下,上一篇也有讲解

HAL_RCC_ClockConfig()

接下来我们就要看 HAL_RCC_ClockConfig()函数,声明如下:

HAL_StatusTypeDef HAL_RCC_ClockConfig(RCC_ClkInitTypeDef *RCC_ClkInitStruct,
uint32_t FLatency);

一共有两个参数:第一个入口参数 RCC_ClkInitStruct 是结构体 RCC_ClkInitTypeDef
指针类型,用来设置 SYSCLK 时钟源以及 SYSCLK、AHB,APB1、APB2、APB3 和 APB4 的分
频系数。第二个入口参数 FLatency 用来设置 FLASH 延迟

我们开看下RCC_ClkInitTypeDef 具体位置在stm32h7xx_hal_rcc.h 中声明

typedef struct
{uint32_t ClockType;             /*!< 要配置的时钟。该参数可以是@ref RCC_System_Clock_Type 的值     */uint32_t SYSCLKSource;          /*!< 用作系统时钟的时钟源(SYSCLKS)*/uint32_t SYSCLKDivider;         /*!< 系统时钟分频    */uint32_t AHBCLKDivider;         /*!< AHB分频 */uint32_t APB3CLKDivider;        /*!APB3分频*/uint32_t APB1CLKDivider;        /*!APB1分频*/uint32_t APB2CLKDivider;        /*!APB2分频*/uint32_t APB4CLKDivider;      /*!APB4分频*/
}RCC_ClkInitTypeDef;

第一个参数 ClockType 配置说明我们要配置的是 SYSCLK,HCLK、D1PCLK1(PCLK3)、
PCLK1、PCLK2 和 D3PCLK1(PCLK4)六个时钟。
第二个参数 SYSCLKSource 配置选择系统时钟源为 PLL。
第三个参数 SYSCLKDivider 配置 SYSCLK 分频系数
第四个参数 AHBCLKDivider 配置 AHB 分频系数
第五个参数 APB1CLKDivider 配置 APB1 分频系数
第六个参数 APB2CLKDivider 配置 APB2 分频系数
第七个参数 APB3CLKDivider 配置 APB3 分频系数
第八个参数 APB4CLKDivider 配置 APB4 分频系数

这个在下面有详细的介绍

然后我们看第二个参数:FLatency 用来设置 FLASH 延迟和调压器VOS

那就需要知道Flash 读操作

Flash 读操作 是每次读取完Flash数据,需要延时一定时间,确保之后的数据传输正常

VOS:在STM32H7中,系统Flash的受到调压器输出电压级别选择(VOS)的影响(在电源控制寄存器中)

为了得到最高的FLASH读取速度,我们需要设置VOS级别为1 然后等待数设置为4 就可以得到最高的Flash读取速度,ST 官方例程使用的就是 4 个 等待状态数

STM32H7xx参考手册 112页

最终代码如下:

都做了注释

/*
*********************************************************************************************************
*   函 数 名: SystemClock_Config
*   功能说明: 初始化系统时钟
*               System Clock source            = PLL (HSE)
*               SYSCLK(Hz)                     = 400000000 (CPU Clock)
*               HCLK(Hz)                       = 200000000 (AXI and AHBs Clock)
*               AHB Prescaler                  = 2
*               D1 APB3 Prescaler              = 2 (APB3 Clock  100MHz)
*               D2 APB1 Prescaler              = 2 (APB1 Clock  100MHz)
*               D2 APB2 Prescaler              = 2 (APB2 Clock  100MHz)
*               D3 APB4 Prescaler              = 2 (APB4 Clock  100MHz)
*               HSE Frequency(Hz)              = 25000000
*               VDD(V)                         = 3.3
*               Flash Latency(WS)              = 4
*   形    参:
*           plln:PLL1倍频系数(PLL倍频),取值范围:4~512.
*           pllm:PLL1预分频系数(进PLL之前的分频),取值范围:2~63.
*           pllp:PLL1的p分频系数(PLL之后的分频),分频后作为系统时钟,取值范围:2~128.(且必须是2的倍数)
*           pllq:PLL1的q分频系数(PLL之后的分频),取值范围:1~128.
*
*
*            Fvco:VCO频率
*            Fsys:系统时钟频率,也是PLL1的p分频输出时钟频率 pll1_p_ck
*            Fpllq:PLL1的q分频输出时钟频率  pll1_q_ck
*            ref1_ck: PLL输入时钟频率,可以是HSI,CSI,HSE等.
*
*
*            plln:PLL1倍频系数(PLL倍频),取值范围:4~512.
*            pllm:PLL1预分频系数(进PLL之前的分频),取值范围:2~63.
*            pllp:PLL1的p分频系数(PLL之后的分频),分频后作为系统时钟,取值范围:2~128.(且必须是2的倍数)
*            pllq:PLL1的q分频系数(PLL之后的分频),取值范围:1~128.
*
*
*
*            VCO频率: Fvco= ref1_ck*(plln/pllm);
*            pll1_p_ck频率: Fsys=Fvco/pllp= ref1_ck*(plln/(pllm*pllp));
*            pll1_q_ck频率: Fpllq=Fvco/pllq= ref1_ck*(plln/(pllm*pllq));
*
*           CPU频率(rcc_c_ck)=pll1_p_ck频率=400Mhz
*           rcc_aclk=rcc_hclk3=200Mhz
*           AHB1/2/3/4(rcc_hclk1/2/3/4)=200Mhz
*           APB1/2/3/4(rcc_pclk1/2/3/4)=100Mhz
*           FMC时钟频率=pll2_r_ck=((25/25)*512/2)=256Mhz
*
*
*          外部晶振为25M的时候,推荐值:plln=160,pllm=5,pllp=2,pllq=2.
*          得到:Fvco=25*(160/5)=800Mhz
*          CPU频率Fsys= pll1_p_ck频率=800/2=400Mhz
*          pll1_q_ck频率=800/2=400Mhz
*   返 回 值: 无*********************************************************************************************************
*/
void SystemClock_Config(u32 plln,u32 pllm,u32 pllp,u32 pllq)
{HAL_StatusTypeDef ret=HAL_OK;RCC_ClkInitTypeDef RCC_ClkInitStruct;RCC_OscInitTypeDef RCC_OscInitStruct;/*使能供电配置更新 */MODIFY_REG(PWR->CR3,PWR_CR3_SCUEN, 0);/* 1、芯片内部的LDO稳压器输出的电压范围,可选VOS1,VOS2和VOS3,不同范围对应不同的Flash读速度,详情看参考手册的Table 12的表格。2、这里选择使用VOS1,电压范围1.15V - 1.26V。*/__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);while ((PWR->D3CR & (PWR_D3CR_VOSRDY)) != PWR_D3CR_VOSRDY) {}/* 使能HSE,并选择HSE作为PLL时钟源 */RCC_OscInitStruct.OscillatorType=RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState=RCC_HSE_ON;RCC_OscInitStruct.HSIState=RCC_HSI_OFF;RCC_OscInitStruct.CSIState=RCC_CSI_OFF;RCC_OscInitStruct.PLL.PLLState=RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource=RCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLN=plln;RCC_OscInitStruct.PLL.PLLM=pllm;RCC_OscInitStruct.PLL.PLLP=pllp;RCC_OscInitStruct.PLL.PLLQ=pllq;RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;ret=HAL_RCC_OscConfig(&RCC_OscInitStruct);if(ret!=HAL_OK) while(1);/* 选择PLL的输出作为系统时钟配置RCC_CLOCKTYPE_SYSCLK系统时钟配置RCC_CLOCKTYPE_HCLK 时钟,对应AHB1,AHB2,AHB3和AHB4总线配置RCC_CLOCKTYPE_PCLK1时钟,对应APB1总线配置RCC_CLOCKTYPE_PCLK2时钟,对应APB2总线配置RCC_CLOCKTYPE_D1PCLK1时钟,对应APB3总线配置RCC_CLOCKTYPE_D3PCLK1时钟,对应APB4总线     AHB 分频系数为 2,故其频率为HCLK=SYSCLK/2=200MHz。APB1 分频系数为 2,故其频率为 PCLK1=HCLK/2=100MHz。APB2分频系数为 2,故其频率为 PCLK2=HCLK/2=200/2=100MHz,APB3 分频系数为 2,故其频率PCLK3=HCLK/2=200/2=100MHz,APB4 的分频系数为 2,故其频率 PLCK4=HCLK/2=200/2=100MHz */RCC_ClkInitStruct.ClockType=(RCC_CLOCKTYPE_SYSCLK|\RCC_CLOCKTYPE_HCLK |\RCC_CLOCKTYPE_D1PCLK1 |\RCC_CLOCKTYPE_PCLK1 |\RCC_CLOCKTYPE_PCLK2 |\RCC_CLOCKTYPE_D3PCLK1);RCC_ClkInitStruct.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.SYSCLKDivider=RCC_SYSCLK_DIV1;RCC_ClkInitStruct.AHBCLKDivider=RCC_HCLK_DIV2;RCC_ClkInitStruct.APB1CLKDivider=RCC_APB1_DIV2; RCC_ClkInitStruct.APB2CLKDivider=RCC_APB2_DIV2; RCC_ClkInitStruct.APB3CLKDivider=RCC_APB3_DIV2;  RCC_ClkInitStruct.APB4CLKDivider=RCC_APB4_DIV2; /* 此函数会更新SystemCoreClock,并重新配置HAL_InitTick */ret=HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);if(ret!=HAL_OK) while(1);/*   使用IO的高速模式,要使能IO补偿,即调用下面三个函数 (1)使能CSI clock(2)使能SYSCFG clock(3)使能I/O补偿单元, 设置SYSCFG_CCCSR寄存器的bit0*/__HAL_RCC_CSI_ENABLE() ;__HAL_RCC_SYSCFG_CLK_ENABLE() ;HAL_EnableCompensationCell();}

主函数调用:

 SystemClock_Config(160,5,2,4);            //设置时钟400Mhz


STM32H7时钟树RCC分析--- HAL库配置(二)相关推荐

  1. STM32H7时钟树RCC分析--- CubeMx配置(三)

    前言: 之前我们说了H7的时钟原理,还有HAL库的时钟配置代码,下面我们来看下CubeMx怎么配置 STM32H7时钟树RCC分析-原理讲解(一) STM32H7时钟树RCC分析- HAL库配置(二) ...

  2. STM32H7时钟树RCC分析---原理讲解(一)

    STM32 有很多系列,可以满足市场的各种需求,从内核上分有 Cortex-M0.M3.M4和 M7 这几种,每个内核又大概分为主流.高性能和低功耗. 用HAL库配置请看:STM32H7时钟树分析- ...

  3. STM32F1系列HAL库配置系统时钟

    STM32F1系列HAL库配置系统时钟 其实一开始对于时钟我也是知之甚少,在MSP432中我就一直忽视时钟配置,其实也是在STM32学习时落下的病根,现在趁有空补一下. 时钟简单讲解 对于时钟系统,在 ...

  4. HAL库配置GPIO

    HAL库配置GPIO HAL库与标准库不同的特点: 使用`CubeMX`配置GPIO底层参数: 总结HAL库中GPIO的相关功能: GPIO的寄存器: 总结 HAL库与标准库不同的特点: 标准库中初始 ...

  5. STM32F4系列HAL库配置定时器实验——输入捕获

    STM32F4系列HAL库配置定时器实验--输入捕获 输入捕获简单讲解 输入捕获模式可以用来测量脉冲宽度或者测量频率.我们以测量周期和频率为例,用一个简图来说明输入捕获的原理 假定定时器工作在向上计数 ...

  6. HAL库配置FreeRTOS

    HAL库配置 配置时钟源 1:修改HAL库定时器时钟源. 由于HAL库内部会使用systick定时器用于系统延时功能,而FreeRTOS也需要一个定时器用于操作系统内核调度的使用,顾需修改HAL库的时 ...

  7. STM32F4xx系列使用HAL库配置SPI-读写FLASH

    SPI协议简介 SPI物理层特点    SPI协议层 QSPI协议简介 SPI框图 Flash写入与EEPROM有点相似,不同的是FLASH写入需要软件手动擦除,而EEPROM不用 SPI配置流程 1 ...

  8. stm32捕获占空比_【电机控制】六步法驱动BLDC电机,使用硬件COM事件,STM32+CUBEMX(HAL库)配置...

    现在我也只能说是电机入门,但是想要把电机作为终身事业,从有霍尔到无霍尔,从方波到正弦波,现在把其中的一些知识点分享出来,因为电机控制其实的资料比较难找的,前人栽树,后人乘凉,如果我有什么错误,在知乎上 ...

  9. 【电机控制】六步法驱动BLDC电机,使用硬件COM事件,STM32+CUBEMX(HAL库)配置

    已经做了半年的BLDC驱动器了,目前是做到了电流转速双闭环,期间遇到了很多很多问题,一个是资料难找,再加上公司要求使用CUBEMX,本身HAL库的资料也难找,难上加难啊,可能是用CUBEMX做出来的大 ...

最新文章

  1. Spring Cloud - Feign调用问题
  2. 重温目标检测--SSD
  3. linux command find
  4. 数据库开发——MySQL——存储引擎
  5. mysql添加索引造成的影响
  6. 2.3创建用户访问过滤器(安全性)
  7. MongoDB数据库读书笔记
  8. matlab的图像滤波,Matlab实现图像滤波
  9. 从官方例程深度学习海思SDK及API(2)
  10. 百度知道1000指数的关键词留链接排名到第一的实战案例
  11. lcd屏指针时钟画法
  12. Go中的SSRF攻防战
  13. android夜间模式监控
  14. windows下sass开发环境的搭建
  15. mac版本的visual studio的快捷键修改_几款高效率的mac软件
  16. 2019年全国大学生“TI杯”电子设计竞赛综合测评电路仿真
  17. 【经典贪心练习】金银岛
  18. java aio nio bio_3. 彤哥说netty系列之Java BIO NIO AIO进化史
  19. folx是什么软件?Mac上免费的网络下载管理器
  20. Android处理大图片

热门文章

  1. python创建线程在后台运行
  2. python使用xlwt创建与保存excel文件
  3. 以太坊geth节点各种报错(求助)
  4. java实现马尔科夫链_java – 马尔可夫链文本生成
  5. angular下拉框点击无反应_angular 实现 下拉菜单 的 点击其他区域关闭下拉菜单功能?...
  6. mysql在线增加字段_MySQL在线加字段实现原理
  7. mysql视图_MySQL视图详解
  8. android自动播放mp3,audio标签移动端(微信)实现自动播放
  9. 浅谈密码学中数论基础
  10. μC/OS-III---I笔记3---时间管理