当前位置: 首页 > news >正文

STM32CubeMX 生成时钟获取函数的分析

关键字:STM32CubeMX, HAL 时钟获取函数

1. 问题

STM32CubeMX 升级到了 V6.13.0 ,与此同时 STM32Cube_FW_H7 也升级到了 V1.12.0 ,在时钟获取数组的定义中出现了问题,造成的问题现象是串口输出内容乱码,经过和 V6.12.1+ STM32Cube_FW_H7_V1.11.2 生成的代码对比,发现是时钟获取函数的数组出现的问题,修改之后即可正常。

2. 如何复现

在 ST 官网上下载 STM32CubeMX 6.13.0 链接:Here,选择器件型号为 STM32H743ZIT6,使能 USART3 这个外设,选择使用 STM32Cube_FW_H7_V1.12.0 库来生成代码之后,串口打印出来的内容就是乱码。

时钟配置如下图 1 所示。

图1. 默认时钟配置

2.1. 代码分析

首先,让我们看一下,不同的版本在生成代码中的主要区别,主要是 D1CorePrescTable 这个数组的内容有变化。

图2. 生成代码对比 

由上图可见,数组 D1CorePrescTable 的【4 : 7】内容由原来的{1,2,3,4}变成了 {0,0,0,0},那么这个数组是做什么用的,又为什么会对串口有影响呢?让我们来分析一下代码。

在串口初始化中有如下调用关系:

MX_USART3_UART_Init()àHAL_UART_Init()àUART_SetConfig()àHAL_RCC_GetPCLK1Freq()

图3. 代码内容

由图 3 中的代码,我们可以看到,这里引用了 D1CorePrescTable 的内容,这里是如何引用的呢?其实是比较巧妙的。

我们首先看寄存器中是如何配置的。

图4. 寄存器描述

寄存器中的 D2PPRE1[2:0]是配置 D2 域中 APB1 的分频系数,默认是 0xx,表示不分频;100 是 1/2 分频;101 是 1/4 分频 ; 以此类推。

在整个时钟树中的位置如图 5 所示

图5. 寄存器在时钟树中位置

回到代码,我们单独截取其中一句话。

图6. 代码详细内容

其中的数值定义如图 7 所示

图7. 代码定义内容

这个地方通过读取寄存器(RCC->D2CFGR 中的 D2PPRE1)的配置,就能得到 APB1总线上的时钟分频参数,其先通过函数 HAL_RCC_GetHCLKFreq()得到系统时钟的频率,再将其进行右移操作(右移 1 位代表除以 2)。具体右移多少位就是通过查找 D1CorePrescTable 这个表来决定的。

比如,这里如果是 1/2 分频,那么 RCC->D2CFGR & RCC_D2CFGR_D2PPRE1) >> RCC_D2CFGR_D2PPRE1_Pos 得到的结果就是 0b100,再和 0x1FU 进行“与操作”得到也是 0b100,即十进制的 4。通过正确的 D1CorePrescTable 表格,即可得到 D1CorePrescTable【4】=1,(注意数组是从 0 开始的)那么就是系统时钟进行右移 1 位的操作,得到除以 2 的效果。

正确数组:const uint8_t D1CorePrescTable[16] = {0, 0, 0, 0, 1, 2, 3, 4, 1, 2, 3, 4, 6, 7, 8, 9};

错误数组:const uint8_t D1CorePrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};

但是如果是错误的数组,查到的就是 D1CorePrescTable【4】=0,这是不需要右移的,就是没有经过 1/2 分频,显然是不对正确的。

这里还有个小问题:如果在 APB1 的时钟是没有经过分频的,那么 RCC->D2CFGR & RCC_D2CFGR_D2PPRE1) >> RCC_D2CFGR_D2PPRE1_Pos 得到的结果就总是小于 4 的(即 0xx,具体参见图 4),查表得到的结果就都是 0,也是没有问题的。但是1/2,1/4,1/8,1/16 这些分频系数都会出现计算错误,所以正确的方式就是手动修改这个参数即可解决问题。

3. 解决问题

手动修改 system_stm32h7xx.c 中的数组 D1CorePrescTable 中的【4 :7】中数据即可。

正确:const uint8_t D1CorePrescTable[16] = {0, 0, 0, 0, 1, 2, 3, 4, 1, 2, 3, 4, 6, 7, 8, 9};

同时,提交 bugzilla :197431 (此号码为 ST 内部使用,外部用户无法访问)。

4. 小结

这个问题,主要是来自时钟计算所需要的表格出错,造成串口波特率计算出来的结果错误。本文简要分析了数组在查表的方式进行的对应运算关系,并对错误范围做出了解释,未来遇到类似的问题都可以使用此方式进行分析。
 

http://www.dtcms.com/a/305868.html

相关文章:

  • OmniParser:提升工作效率的视觉界面解析工具
  • react+ant design怎么样式穿透-tooltip怎么去掉箭头
  • 地下停车场照明节能:技术方案与价值重构
  • day7 替换数字那道题需要多写几次
  • 容器与虚拟机的本质差异:从资源隔离到网络存储机制
  • InfluxDB 3 数据库命名与创建全攻略:规范、限制与实战指南
  • Linux 进程管理与计划任务详解
  • 在 CentOS 系统上安装 Docker
  • ComfyUI自定义图片导出路径
  • SpringBoot 2.7.18 升级 3.4.6
  • PHP语法高级篇(七):MySQL数据库
  • 具身智能 自动驾驶相关岗位的技术栈与能力地图
  • 微信小程序中实现页面跳转的方法
  • 爬虫验证码处理:ddddocr 的详细使用(通用验证码识别OCR pypi版)
  • 第2章 cmd命令基础:常用基础命令(2)
  • 数据驱动的自动驾驶虚拟测试方法
  • 【同济大学】双速率自动驾驶架构LeAD:端到端+LLM,CARLA实测93%路线完成率,性能SOTA!
  • 深入浅出设计模式——创建型模式之原型模式 Prototype
  • 【MySQL 数据库】MySQL索引特性(二)页目录(B和B+树)(非)聚簇索引 索引操作
  • 李宏毅2025《机器学习》-第九讲:大型语言模型评测的困境与“古德哈特定律”**
  • java面向对象高级02——单例类(设计模式)
  • 数据分析师进阶——95页零售相关数据分析【附全文阅读】
  • 【NLP舆情分析】基于python微博舆情分析可视化系统(flask+pandas+echarts) 视频教程 - 微博评论IP地图可视化分析实现
  • 语言模型的评估指标整理
  • Python设计模式详解:策略模式(Strategy Pattern)实战指南
  • LRU (Least Recently Used) 缓存实现及原理讲解
  • Ubuntu22.04中搭建GN编译环境
  • 深入理解缓存淘汰策略:LRU vs LFU 完全解析
  • 2025 年 NOI 最后一题题解
  • LoongCollector 安全日志接入实践:企业级防火墙场景的日志标准化采集