问题记录

在尝试使用Clion在STM32平台上开发调试时,需要通过OpenOCD结合ST-Link等调试器进行烧录和调试。但通过STM32CubeMX生成代码后,发现出现以下现象:

  1. 程序能够正常编译并下载到开发板上,且运行符合预期。
  2. 调试时GDB Server能够正常连接,可以正常查看函数调用栈。但却在SystemClock_Config函数配置参数时,调用的HAL_RCC_OscConfig等函数均返回为HAL_ERROR,而导致死循环在Error_Handler



  3. OpenOCD的重置reset选项配置的为初始化init。

既然问题在正常下载时没有复现(排除硬件问题),且这段CubeMX生成代码比较成熟,出问题的可能不大。所以主要查看为什么调试会导致时钟配置有误。

根因分析

首先,STM32使用手册提到,PLL使能后,主PLL的配置参数不可更改。也就是说,重复配置PLL是不允许的。

OpenOCD 的启动流程(/usr/share/openocd/scripts/target/stm32f4x.cfg)入手分析。首先,ARM Cortex 内核限制 SWD 时钟频率不能超过内核频率的 1/6,而单片机上电后如果不做任何配置,时钟来源为 HSI 的 16MHz,这样 SWD 频率就最高是 2.666MHz。因此,如果不做时钟上的更改,OpenOCD 默认只能使用 2000kHz 的 adapter speed。

adapter speed 2000
adapter srst delay 100
if {[using_jtag]} {
jtag_ntrst_delay 100
}
reset_config srst_nogate

由于选择的重置选项是reset-init,所以,下面这行配置脚本会执行。

而如果让 OpenOCD 启动调试,为了加快 SWD 时钟,OpenOCD 会把 MCU 里面的 PLL 打开并设置到 64MHz,然后将系统时钟来源切换为 PLL.

在复位时提高系统时钟(16MHz → 64MHz),以提升调试速度。

$_TARGETNAME configure -event reset-init {
mww 0x40023804 0x08012008 ;# 配置 PLL
mww 0x40023C00 0x00000102 ;# 设置 Flash 等待状态
mmw 0x40023800 0x01000000 0 ;# 启用 PLL
sleep 10
mmw 0x40023808 0x00001000 0 ;# 配置总线分频
mmw 0x40023808 0x00000002 0 ;# 切换到 PLL 时钟
adapter speed 8000
}

那么,为什么会出现时钟不正常呢?我们分析 HAL 库设置系统时钟的流程。按照正常流程,HAL 库会启动 HSE,然后配置 PLL 参数,并将 PLL 时钟源设为 HSE,最后将系统时钟来源设置为 PLL。如果单片机上电后不做任何额外的时钟配置,这部分程序是可以正常工作的,单片机能够在正确的时钟上运行。

然而,巧合的是,启用调试器后,在运行用户代码前,系统时钟就处于已经配置 PLL 的状态。HAL 库如果检测到这种状态,则不会对 PLL 配置进行更改,只会检测现有的 PLL 配置与欲应用的配置是否相符,如果不相符,则返回 HAL_ERROR。

__weak HAL_StatusTypeDef HAL_RCC_OscConfig(RCC_OscInitTypeDef  *RCC_OscInitStruct) {
... // 初始化 HSI,HSE 等,在此省略 if ((RCC_OscInitStruct->PLL.PLLState) != RCC_PLL_NONE) {
// 如果 PLL 当前不是系统时钟
if (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL) {
// 正常上电时,__HAL_RCC_GET_SYSCLK_SOURCE 应该返回 RCC_CFGR_SWS_HSI,从而进入这个分支
... // 对 PLL 进行配置
} else {
// 如果启动调试器,__HAL_RCC_GET_SYSCLK_SOURCE 应该返回 RCC_CFGR_SWS_PLL,就会进入这个分支
// 对 PLL 配置进行检查,如果与给定的配置不符,就返回 ERROR
pll_config = RCC->PLLCFGR;
if((READ_BIT(pll_config, RCC_PLLCFGR_PLLSRC) != RCC_OscInitStruct->PLL.PLLSource) ||
(READ_BIT(pll_config, RCC_PLLCFGR_PLLM) != RCC_OscInitStruct->PLL.PLLM) ||
(READ_BIT(pll_config, RCC_PLLCFGR_PLLN) != RCC_OscInitStruct->PLL.PLLN) ||
(READ_BIT(pll_config, RCC_PLLCFGR_PLLP) != RCC_OscInitStruct->PLL.PLLP) ||
(READ_BIT(pll_config, RCC_PLLCFGR_PLLQ) != RCC_OscInitStruct->PLL.PLLQ))
{
return HAL_ERROR;
}
}
}
}

后面的情况也正如开头所讲,返回错误值,卡死在错误处理函数内。

解决方法

  1. 调整OpenOCD的重置选项至Run,关于重置选项的用途,请参考:https://openocd.org/doc/html/Reset-Configuration.html
  • run Let the target run
  • halt Immediately halt the target
  • init Immediately halt the target, and execute the reset-init script
  1. main函数的 USER CODE 1 段内加入以下代码
int main(void)
{
/* USER CODE BEGIN 1 */
__HAL_RCC_HSI_ENABLE(); // 启用 HSI
__HAL_RCC_SYSCLK_CONFIG(RCC_SYSCLKSOURCE_HSI); // 切换系统时钟为 HSI
/* USER CODE END 1 */ HAL_Init();
SystemClock_Config();
// 进行其他初始化
}

参考文章

https://blog.vinkvin.com/post/96/

https://blog.t123yh.xyz:3/index.php/archives/922

STM32在使用Clion平台开发时调试失败 SystemClock_Config 返回 HAL_ERROR的更多相关文章

  1. 公众号第三方平台开发-aes解密失败

    公众号第三方平台开发-aes解密失败 问题:本地启动项目,配置域名,测试微信公众号,系统正常运行:将项目部署到测试环境执行同样的操作,系统报错,错误异常:aes解密失败..... 调试--寻找问题-- ...

  2. 用C++做微信公众平台开发的后台开发时,用sha1加密验证的方法

    微信公众平台开发时,须要验证消息是否来自微信server,这要用到sha1加密算法.官网上给的是php的sha函数,C++中要用到以下这个函数: 一.引入头文件: #include<openss ...

  3. Senparc.Weixin.MP SDK 微信公众平台开发教程(二十二):如何安装 Nuget(dll) 后使用项目源代码调试

    最近碰到开发者问:我使用 nuget 安装了 Senparc.Weixin SDK,但是有一些已经封装好的过程想要调试,我又不想直接附加源代码项目,这样就没有办法同步更新了,我应该怎么办? 这其实是一 ...

  4. 【夯实PHP基础】php开发时遇到白页的调试方法

    本文地址   分享提纲: 1. 设置报错报错级别,显示报错 2. 白页的可能原因     1.[设置报错报错级别,显示报错] php开发时,访问地址也对,但就是不出来页面,显示的是 白的页面,所以就可 ...

  5. NodeJs使用Express框架开发时的快速调试方法

    习惯了php开发,可以直接使用echo或者var_dump()将想要查看的变量结果输出到网页查看,非常的方便.但是使用express开发时,每次修改文件后,都需要使用npm start命令重启服务,然 ...

  6. Senparc.Weixin.MP SDK 微信公众平台开发教程(十八):Web代理功能

    在Senparc.Weixin.dll v4.5.7版本开始,我们提供了Web代理功能,以方便在受限制的局域网内的应用可以顺利调用接口. 有关的修改都在Senparc.Weixin/Utilities ...

  7. Senparc.Weixin.MP SDK 微信公众平台开发教程(十七):个性化菜单接口说明

    前不久微信上线了个性化菜单接口,Senparc.Weixin SDK也已经同步更新. 本次更新升级Senparc.Weixin.MP版本到v13.5.2,依赖Senparc.Weixin版本4.5.4 ...

  8. Senparc.Weixin.MP SDK 微信公众平台开发教程(三):微信公众平台开发验证

    要对接微信公众平台的"开发模式",即对接到自己的网站程序,必须在注册成功之后(见Senparc.Weixin.MP SDK 微信公众平台开发教程(一):微信公众平台注册),等待官方 ...

  9. Senparc.Weixin.MP SDK 微信公众平台开发教程(七):解决用户上下文(Session)问题

    从这篇文章中我们已经了解了微信公众平台消息传递的方式,这种方式有一个先天的缺陷:不同用户的请求都来自同一个微信服务器,这使得常规的Session无法使用(始终面对同一个请求对象,况且还有对方服务器Co ...

  10. Senparc.Weixin.MP SDK 微信公众平台开发教程(九):自定义菜单接口说明

    上一篇<Senparc.Weixin.MP SDK 微信公众平台开发教程(八):通用接口说明>介绍了如何通过通用接口获取AccessToken,有了AccessToken,我们就可以来操作 ...

随机推荐

  1. clickhouse--数据类型

    数据类型 整型 固定长度的整型,包括有符号整型或无符号整型. 整型范围(-2n-1~2n-1-1): Int8 - [-128 : 127] Int16 - [-32768 : 32767] Int3 ...

  2. script crossorigin 属性

    来源:https://juejin.cn/post/6969825311361859598 <script src="xxxx" crossorigin="anon ...

  3. C++中线程同步与互斥的四种方式介绍及对比详解

    引言 在C++中,当两个或更多的线程需要访问共享数据时,就会出现线程安全问题.这是因为,如果没有适当的同步机制,一个线程可能在另一个线程还没有完成对数据的修改就开始访问数据,这将导致数据的不一致性和程 ...

  4. nuxt.js 使用 Typescript 在 VSCode 报错: File 'xxx/components/Logo.vue' is not a module. Vetur(2306)

    nuxt.js 生成的默认文件 components/Logo.vue 源码大概如下: 1 <template> 2 <svg 3 class="NuxtLogo" ...

  5. 给react native 添加transform translateY动画报错:Transform with key of "translateY" must be a number:{translateY“:0}

    初学react native,想实现一个相机扫描功能时,报错,报错描述如标题 这是我的主要逻辑代码 const fadeAnim = useRef(new Animated.Value(0)).cur ...

  6. 工作必会的Nginx的启动安装和常用配置例子

    概述 由于自己的之前学习 nginx 只会简单使用,然后每次配置 nginx 都要找文档去了解怎么配置,有点麻烦,所以这里记录下一些常用的nginx 配置和配置的例子,到时候直接 copy 修改即可. ...

  7. css px em rem % vw vh vm 区别

    前言 在传统项目开发中,我们只会用到 px.%.em 这几个单位长度,它们可以适用大部分项目的开发,并且拥有较好的兼容性. 而从 css3 开始,浏览器对逻辑单位的支持又提升了新的境界,增加了 rem ...

  8. 数据、信息、知识、智慧:AI时代我们该如何思考?

    时代的浪潮滚滚向前,AI技术的演进正悄然改变着我们认知世界和创造价值的方式.从数据.信息到知识.智慧,从大数据到大模型,从单一智能体到多智能体协作,这是一场深刻的认知革命,也是生产力解放的新纪元. A ...

  9. Delphi 检测鼠标键盘多久没有活动

    function GetInputAwayTime():DWORD; var lpi:TLastInputInfo; begin lpi.cbSize := sizeof(lpi); GetLastI ...

  10. Ubuntu截屏工具推荐

    Ubuntu截屏工具推荐 本篇博文推荐Ubuntu下的截屏工具Flameshot,可以作为Windows下Snipaste截图工具的平替. GitHub地址:https://github.com/fl ...