FreeRTOS中如何定位HardFault?

嵌入式ARM 2023-04-24 13:00

大家好,我是鱼鹰。今天我们聊一聊开发中常见的 HardFault,这个问题应该从学习 STM32 开发以来就一直伴随着我们,很多人遇到这种问题也是不知道该如何定位。

如果只是独立开发,遇到这种问题,一般都是看代码、修改代码等等这些常规手段,因为自己写的代码最熟悉,改动一般也不会太大,容易缩小范围,也更容易定位。

但现在的产品越来越复杂,目前的开发模式都是合作开发,每个人负责各自的模块,这样的项目代码量大、复杂度高,也就更难定位问题。

而有的时候,刚入职一家公司,什么代码都不熟悉,又出现了 HardFault,更是让人崩溃,分分钟有跑路的冲动(你和代码,有一个能跑就行)。

此时,有一个能解决这种疑难杂症的大牛是能大大节省时间的,而我在公司也解决不少类似的问题,所以经验也算丰富,充当的也是这一类角色。

而定位 Hardfault 的方法一般是靠 KEIL在线调试+C语言+权威指南 中的知识搞定。

目前鱼鹰的解 BUG 差不多是这样的:

1、必现,代码熟悉的情况下,几个小时内搞定。

2、偶现,根据出现情况决定解决问题的时间,一般出现个四五次,基本就能定位。

3、难现,这种一般要挂一个记录仪实时记录运行情况。

经历了这么多,已经很少有能让鱼鹰需要花费几天时间才能解决的 Hardfault 问题了(犹记得刚来深圳时,因为别人写的一个 BUG 导致的 Hardfault,不得已加了几天通宵,要不是偶然机会还不一定能搞定)。

这里打个小广告,如果难解决,可以有偿请鱼鹰解决 Hardfault 问题哦。

不过最近工作上因为用了 C++,这个基础不是很熟悉,解决 Hardfault 的速度又下降了。而工程编译优化等级 -O2 也加大了不少调试难度,因此掌握下面的方法是很重要的:

总结 MDK 几种编译优化设置的方法

关于 Hardfault,鱼鹰以前也是分享了不少笔记的,不知道有多少人认真看过。

HardFault 之 INVSTAE 错误定位(一)

见鬼,过年回来后板子就 hardfault 了?

今天将继续分享关于在 FreeRTOS 定位 Hardfault 方法。

这里需要一个大佬写的组件 :CmBacktrace(事实上,如果能在线调试,鱼鹰是不需要借助这个组件的,但是难复现的情况下用这个组件还是比较香的)

gitee 仓库:https://gitee.com/Armink/CmBacktrace

这个组件估计很多道友都听说过,也用过,但鱼鹰想说的是,有些道友在用的组件可能比较老,没有下面这种追踪功能,建议大家更新一下。

上面可以看到出错时,函数的调用栈(有时可能是错误的,需要实际分析,仅做参考)

_call_main ->  main -> fult_test_by_div0
相当实用。
同时,本篇笔记不仅适用于在 FreeRTOS 定位 Hardfault,实际上uCOS、rt-thread 等其它 RTOS 照样可以修改后使用(裸机更不用说了)。 
仓库例子支持的平台:裸机、rt-thread、ucoss-ii、freertos。
这里重点在如何移植这个组件到 freertos 中(实际上,仓库的说明文档也非常详细,可以参考)。由于 freertos  也是不断更新中,所以这个组件的例子不能完全适用于新版本,而鱼鹰刚好移植好了,在此记录一下,方便大家移植。
1、将仓库中的 cm_backtrace(源码文件) 整个文件夹拷贝到自己的工程文件夹下。
2、在自己的工程中添加这些文件(我们可以打开 demos -> os -> freertos 工程查看)
只有两个文件,相当简单。
一个是核心源码,另外一个则是汇编代码,代码执行入口。
注意,根据 IDE 不同,选择的汇编文件也不同:
其实就是将 startup_stm32f10x_hd.s 中的hardfault 默认处理函数重定位到 cmb_fault.S 中了。
注意这里有一个weak,这样链接的时候就不会链接这个,而是 cmb_fault.S 这个:
为了更方便的定位问题,我们后面还需要修改一下这个代码才行。
注意,如果你的启动文件内的 hardfault 代码被修改了,而你不懂汇编,建议恢复成上面那种,不然可能运行不正常。
3、主函数中初始化代码。
这里的字符串需要和这个一样(根据自己的工程名修改):
所以,建议用英文建工程。这个在输出错误信息的时候用的上,否则每次查看调用栈都需要修改一下,比较麻烦。
如果开启了内部看门狗,建议关闭一下:
// HAL 库__HAL_DBGMCU_FREEZE_IWDG1();// 标准库DBGMCU_Config(DBGMCU_IWDG_STOP, ENABLE);

在断言失败的位置添加该函数 cm_backtrace_assert:

这样断言失败了也能看到调用栈了。
4、FreeROTS 内核文件修改(内核版本 V10.2.1)
为了分析出错的代码,必须知道每个任务的栈信息,而 FreeRTOS 可能没有这些信息,因此,我们需要添加进去。
task.c
FreeRTOS.h
注意,老版本freertos 是只要修改一处的,但新版本需要修改两处,否则会断言失败,运行不下去。
建议把注释也一起添加进去。
UBaseType_t     uxSizeOfStack;      /*< Support For CmBacktrace >*/


相关函数修改  task.c    prvInitialiseNewTask() :

task.c 文件最后添加如下代码用于获取栈地址、大小、名字:

为方便复制,在此贴代码:

/*-----------------------------------------------------------*//*< Support For CmBacktrace >*/uint32_t * vTaskStackAddr(){    return pxCurrentTCB->pxStack;}
uint32_t vTaskStackSize(){ #if ( portSTACK_GROWTH > 0 )
return (pxNewTCB->pxEndOfStack - pxNewTCB->pxStack + 1);
#else /* ( portSTACK_GROWTH > 0 )*/
return pxCurrentTCB->uxSizeOfStack;
#endif /* ( portSTACK_GROWTH > 0 )*/}
char * vTaskName(){ return pxCurrentTCB->pcTaskName;}/*-----------------------------------------------------------*/
5、根据所属 RTOS 平台和芯片内核修改组件配置信息

cmb_cfg.h

1)需要定义打印输出函数,一般用 printf 打印,也可以用你自定义的一些打印函数,功能和 printf 类似即可。

#define cmb_println(...)               printf(__VA_ARGS__);printf("\r\n")

2)使能 RTOS 支持

#define CMB_USING_OS_PLATFORM
3)具体 RTOS 选择 FreeRTOS
#define CMB_OS_PLATFORM_TYPE           CMB_OS_PLATFORM_FREERTOS
4)芯片内核根据实际选择,目前支持 M0、M3、M4、M7。
#define CMB_CPU_PLATFORM_TYPE          CMB_CPU_ARM_CORTEX_M3

5)打印虚拟栈,可以将出错时的原始栈信息打印出来,可能对分析有些帮助

#define CMB_USING_DUMP_STACK_INFO
6)语言支持:英语。实际也支持中文,但建议使用英语(不配置,默认就是英语)
#define CMB_PRINT_LANGUAGE             CMB_PRINT_LANGUAGE_ENGLISH

7) 如果是 C++ 编译的,有可能出错,可以在开头定义这个:

#define __CLANG_ARM


7、根据需要修改组件,方便使用(这些看看能不能有机会合并到大佬的分支里面)
1)因为功能涉及范围小,因此可以将相关头文件包含形式改成这种,这样就不需要改头文件路径了,移植更方便:
#include -->>#include "./cm_backtrace.h"
#include -->>#include "./cmb_cfg.h"
#include "cmb_def.h"-->>#include "./cmb_def.h"
main 中也不需要包含头文件,而是在需要位置直接声明这个函数即可,因为外部只需要调用这个函数。
#include -->void cm_backtrace_init(const char *firmware_name, const char *hardware_ver, const char *software_ver);
这样一来,就不需要添加头文件的路径了。

或者使用相对路径的方式添加头文件:

#include "../../driver/cm_backtrace/cm_backtrace.h"


另外,我们可以让程序进入 Hardfault 前,让代码自动停止,这样我们能更好的利用在线调试代码,《 传说中的软件断点到底是什么?

HardFault_Handler    PROC    LDR     r0, =0xE000EDF0; DEMCR    LDR     r0,[r0,#0x00]    AND     r0,r0,#0x00000001    CBZ     r0,not_in_debug    BKPT    0not_in_debug    MOV     r0, lr                  ; get lr    MOV     r1, sp                  ; get stack pointer (current is MSP)    BL      cm_backtrace_fault
因为刚进入 Hardfault 时的信息最全,又不想每次打断点,上面的代码很好的实现了功能,同时也不会影响程序的正常运行(会自动判断是否处于调试模式)。

8、实验。

上面都搞定了,就可以验证一下效果了。这里我们我们可以模拟仿真看看情况(修改工程配置,这些内容鱼鹰以前分享过,不多说)。

运行仓库例子后,应该能打印下面的信息,告诉我们出现了 div 0 错误。

而你移植好的工程也应该打印类似的信息(加入测试代码 :fault_test_by_div0();)如果打印不出来,有两种可能:

1、打印函数没初始化好就进入了Hardfault

2、打印函数有问题

之后我们复制最后一行,然后运行仓库 tools 里面的 add2line 工具看看调用栈信息:

在 git bash 中可能会执行失败,可以加入程序路径,当然也可以将该工具路径加入到Windows 环境变量中。有可能提示找不到 axf 文件,把这个文件拷贝到工具下即可。

正确的做法是,将该工具放到 C 盘目录下,同时添加环境变量,之后就可以在 axf 目录下打开 gitbash 或者 cmd 窗口执行命令即可。

这里只作为演示,就不多介绍这些了。

最后再简单介绍一下这个组件的实现原理:

如果出现hardfault, 首先进入汇编文件的 HardFault_Handler 处理,这里会得到当前的栈指针和 LR,并且根据 LR 确定出错的栈是哪个《STM32 两个栈,你用哪一个?》(这里是 PSP 栈)

根据错误寄存器信息,确定哪种错误(这里为 除 0 错误

然后对栈信息 和 LR 、PC 进行 FLASH 上的汇编代码分析,找出可能的跳转指令,这里找到的两个跳转地址为 0x08001f96 0x08000368,进而得到调用栈。

因此要能准确的得到调用栈,有两点重要前提条件(建议优化等级 -O0):

1、栈未被破坏

2、芯片运行代码和 axf 文件保持一致

即使如此,你也不能保证找出的调用栈就是正确的,比如你使用 fault_test_by_unalign() 测试,得到的结果如下: 

中间多了一个 fputc。

因此,这些打印信息只能作为参考使用。

但在线调试不同,它更专业,不容易出现错误调用关系。

今天分享的内容到此就结束了,希望这篇文章能对大家有所帮助!

END

来源:鱼鹰谈单片机


版权归原作者所有,如有侵权,请联系删除。

推荐阅读
瑞萨MCU上手有多难?
用C语言实现状态机(实用篇)
编码风格:µCOS vs FreeRTOS

→点关注,不迷路←

嵌入式ARM 关注这个时代最火的嵌入式ARM,你想知道的都在这里。
评论 (0)
  • UNISOC Miracle Gaming奇迹手游引擎亮点:• 高帧稳帧:支持《王者荣耀》等主流手游90帧高画质模式,连续丢帧率最高降低85%;• 丝滑操控:游戏冷启动速度提升50%,《和平精英》开镜开枪操作延迟降低80%;• 极速网络:专属游戏网络引擎,使《王者荣耀》平均延迟降低80%;• 智感语音:与腾讯GVoice联合,弱网环境仍能保持清晰通话;• 超高画质:游戏画质增强、超级HDR画质、游戏超分技术,优化游戏视效。全球手游市场规模日益壮大,游戏玩家对极致体验的追求愈发苛刻。紫光展锐全新U
    紫光展锐 2025-05-07 17:07 60浏览
  • 随着智能驾驶时代到来,汽车正转变为移动计算平台。车载AI技术对存储器提出新挑战:既要高性能,又需低功耗和车规级可靠性。贞光科技代理的紫光国芯车规级LPDDR4存储器,以其卓越性能成为国产芯片产业链中的关键一环,为智能汽车提供坚实的"记忆力"支持。作为官方授权代理商,贞光科技通过专业技术团队和完善供应链,让这款国产存储器更好地服务国内汽车厂商。本文将探讨车载AI算力需求现状及贞光科技如何通过紫光国芯LPDDR4产品满足市场需求。 车载AI算力需求激增的背景与挑战智能驾驶推动算力需求爆发式
    贞光科技 2025-05-07 16:54 57浏览
  • 多功能电锅长什么样子,主视图如下图所示。侧视图如下图所示。型号JZ-18A,额定功率600W,额定电压220V,产自潮州市潮安区彩塘镇精致电子配件厂,铭牌如下图所示。有两颗螺丝固定底盖,找到合适的工具,拆开底盖如下图所示。可见和大部分市场的加热锅一样的工作原理,手绘原理图,根据原理图进一步理解和分析。F1为保险,250V/10A,185℃,CPGXLD 250V10A TF185℃ RY 是一款温度保险丝,额定电压是250V,额定电流是10A,动作温度是185℃。CPGXLD是温度保险丝电器元件
    liweicheng 2025-05-05 18:36 190浏览
  • 想不到短短几年时间,华为就从“技术封锁”的持久战中突围,成功将“被卡脖子”困境扭转为科技主权的主动争夺战。众所周知,前几年技术霸权国家突然对华为发难,导致芯片供应链被强行掐断,海外市场阵地接连失守,恶意舆论如汹涌潮水,让其瞬间陷入了前所未有的困境。而最近财报显示,华为已经渡过危险期,甚至开始反击。2024年财报数据显示,华为实现全球销售收入8621亿元人民币,净利润626亿元人民币;经营活动现金流为884.17亿元,同比增长26.7%。对比来看,2024年营收同比增长22.42%,2023年为7
    用户1742991715177 2025-05-02 18:40 177浏览
  • 某国产固态电解的2次和3次谐波失真相当好,值得一试。(仅供参考)现在国产固态电解的性能跟上来了,值得一试。当然不是随便搞低端的那种。电容器对音质的影响_电子基础-面包板社区  https://mbb.eet-china.com/forum/topic/150182_1_1.html (右键复制链接打开)电容器对音质的影响相当大。电容器在音频系统中的角色不可忽视,它们能够调整系统增益、提供合适的偏置、抑制电源噪声并隔离直流成分。然而,在便携式设备中,由于空间、成本的限
    bruce小肥羊 2025-05-04 18:14 132浏览
  • 这款无线入耳式蓝牙耳机是长这个样子的,如下图。侧面特写,如下图。充电接口来个特写,用的是卡座卡在PCB板子上的,上下夹紧PCB的正负极,如下图。撬开耳机喇叭盖子,如下图。精致的喇叭(HY),如下图。喇叭是由电学产生声学的,具体结构如下图。电池包(AFS 451012  21 12),用黄色耐高温胶带进行包裹(安规需求),加强隔离绝缘的,如下图。451012是电池包的型号,聚合物锂电池+3.7V 35mAh,详细如下图。电路板是怎么拿出来的呢,剪断喇叭和电池包的连接线,底部抽出PCB板子
    liweicheng 2025-05-06 22:58 175浏览
  • 一、gao效冷却与控温机制‌1、‌冷媒流动设计‌采用低压液氮(或液氦)通过毛细管路导入蒸发器,蒸汽喷射至样品腔实现快速冷却,冷却效率高(室温至80K约20分钟,至4.2K约30分钟)。通过控温仪动态调节蒸发器加热功率,结合温度传感器(如PT100铂电阻或Cernox磁场不敏感传感器),实现±0.01K的高精度温度稳定性。2、‌宽温区覆盖与扩展性‌标准温区为80K-325K,通过降压选件可将下限延伸至65K(液氮模式)或4K(液氦模式)。可选配475K高温模块,满足材料在ji端温度下的性能测试需求
    锦正茂科技 2025-04-30 13:08 507浏览
  • 浪潮之上:智能时代的觉醒    近日参加了一场课题的答辩,这是医疗人工智能揭榜挂帅的国家项目的地区考场,参与者众多,围绕着医疗健康的主题,八仙过海各显神通,百花齐放。   中国大地正在发生着激动人心的场景:深圳前海深港人工智能算力中心高速运转的液冷服务器,武汉马路上自动驾驶出租车穿行的智慧道路,机器人参与北京的马拉松竞赛。从中央到地方,人工智能相关政策和消息如雨后春笋般不断出台,数字中国的建设图景正在智能浪潮中徐徐展开,战略布局如同围棋
    广州铁金刚 2025-04-30 15:24 334浏览
  • 你是不是也有在公共场合被偷看手机或笔电的经验呢?科技时代下,不少现代人的各式机密数据都在手机、平板或是笔电等可携式的3C产品上处理,若是经常性地需要在公共场合使用,不管是工作上的机密文件,或是重要的个人信息等,民众都有防窃防盗意识,为了避免他人窥探内容,都会选择使用「防窥保护贴片」,以防止数据外泄。现今市面上「防窥保护贴」、「防窥片」、「屏幕防窥膜」等产品就是这种目的下产物 (以下简称防窥片)!防窥片功能与常见问题解析首先,防窥片最主要的功能就是用来防止他人窥视屏幕上的隐私信息,它是利用百叶窗的
    百佳泰测试实验室 2025-04-30 13:28 617浏览
  • 二位半 5线数码管的驱动方法这个2位半的7段数码管只用5个管脚驱动。如果用常规的7段+共阳/阴则需要用10个管脚。如果把每个段看成独立的灯。5个管脚来点亮,任选其中一个作为COM端时,另外4条线可以单独各控制一个灯。所以实际上最多能驱动5*4 = 20个段。但是这里会有一个小问题。如果想点亮B1,可以让第3条线(P3)置高,P4 置低,其它阳极连P3的灯对应阴极P2 P1都应置高,此时会发现C1也会点亮。实际操作时,可以把COM端线P3设置为PP输出,其它线为OD输出。就可以单独控制了。实际的驱
    southcreek 2025-05-07 15:06 54浏览
  • 5小时自学修好BIOS卡住问题  更换硬盘故障现象:f2、f12均失效,只有ESC和开关机键可用。错误页面:经过AI的故障截图询问,确定是机体内灰尘太多,和硬盘损坏造成,开机卡在BIOS。经过亲手拆螺丝和壳体、排线,跟换了新的2.5寸硬盘,故障排除。理论依据:以下是针对“5小时自学修好BIOS卡住问题+更换硬盘”的综合性解决方案,结合硬件操作和BIOS设置调整,分步骤说明:一、判断BIOS卡住的原因1. 初步排查     拔掉多余硬件:断开所有外接设备(如
    丙丁先生 2025-05-04 09:14 73浏览
  • ‌一、高斯计的正确选择‌1、‌明确测量需求‌‌磁场类型‌:区分直流或交流磁场,选择对应仪器(如交流高斯计需支持交变磁场测量)。‌量程范围‌:根据被测磁场强度选择覆盖范围,例如地球磁场(0.3–0.5 G)或工业磁体(数百至数千高斯)。‌精度与分辨率‌:高精度场景(如科研)需选择误差低于1%的仪器,分辨率需匹配微小磁场变化检测需求。2、‌仪器类型选择‌‌手持式‌:便携性强,适合现场快速检测;‌台式‌:精度更高,适用于实验室或工业环境。‌探头类型‌:‌横向/轴向探头‌:根据磁场方向选择,轴向探头适合
    锦正茂科技 2025-05-06 11:36 290浏览
我要评论
0
1
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦