打印
[信息]

【实战经验】鬼魅一样的 Hard Fault

[复制链接]
1686|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 香水城 于 2017-8-16 15:13 编辑

鬼魅一样的 Hard Fault

问题:
该问题由某客户提出,发生在 STM32F101C8T6 器件上。据其工程师讲述:其某型号产品的设计中用到了 STM32F101C8T6 器件。在软件调试过程中,遇到了一个棘手的问题:程序会莫名其妙的跳到 Hard Fault 中断。在程序中,产生该中断的位置不固定,忽而在这里,忽而在那里。发生的时间不确定,有时候程序运了很长时间才遇到,有时候开始运行后没一会就发生了。产生该问题的原因不明,不知如何进行排查。

调研:
观察其工程师现场演示,证实确有其所述现象存在。
检查硬件设计:
1. 每一路 VDD,匀为 3.3V 供电且同源,并有 0.1uF 的退耦电容。
2. VDDA 为 3.3V 供电,与 VDD 同源,且有 0.1uF 的退耦电容。
3. VBAT 为 3.3V 供电,与 VDD 同源,且有 0.1uF 的退耦电容。
4. 设有芯片整体退耦电容,容值为 10uF。
5. 每一路 VSS 匀与电源地连接。
6. VSSA 与电源地连接。
7. 实测硬件电路,证实与原理图一致。退耦电容临近管脚摆放,地平面较为完整。
8. 用示波器实测电源纹波,小于 50mV。

检查软件设计:
1. 通过打印跟踪程序中每个指针变量,发现有指针对存贮器范围之外的地址进行访问。核查相关代码,该指针的数值来自 I2C 接收的数据。
2. 通过打印跟踪对I2C 数据缓冲区的访问,发现有缓冲区溢出现象发生。
3. 修改代码,将缓冲区加大,重新测试,未发生 Hard Fault 中断现象。

结论:
基本可以认为是缓冲区溢出,而造成某些指针取值错误,从而对非法地址进行了访问,进而引发出错保护中断发生。但对于此类问题,仍需进行长时间测试,才能有最终结论。

处理:
修改代码,根据实际需求设定I2C数据缓冲区大小,保证其足够的空间而不发生溢出。

建议:
Hard Fault中断是Cortex-M处理器为应急处理严重出错而设定的中断,它与MemManage Fault 中断、Bus Fault 中断以及 Usage Fault 中断,共同构成了 Cortex-M 出错管理机制的硬件基础。其中 Hard Fault 中断是出错的最终管理者,其优先级为-1 级,不可更改,而其它三种出错中断分别处理某方面的出错,它们优先级是可以设定的。MemManage Fault 中断与 MPU 有关,负责管理存贮器访问方面的出错,例如:
1. 访问了 MPU 覆盖范围之外的地址;
2. 访问了没有存贮器的空地址;
3. 向只读的区域写数据;
4. 越级访问某些区域;

当发生了存贮器访问方面的出错,Cortex-M 将尝试产生一个 MemManage Fault 中断。如果出于某些原因,MemManage Fault 中断不能立即响应,则将出错升级为严重出错,尝试由 Hard Fault 中断接管该出错的处理。Usage Fault 中断负责管理指令系统方面的出错,例如:
1. 执行了协处理器指令;
2. 执行了未定义的指令;
3. 尝试进入 ARM 状态;
4. 无效的中断返加码;
5. 使用 LDM 或 STM 指令时地址没对齐;

当发生了指令使用方面的出错,Cortex-M 将尝试产生一个 Usage Fault 中断,如未能成功则同处理 MemManage Fault 中断一样,将出错提升为严重出错,从而转交给 Hard Fault 中断来处理。Bus Fault 中断负责总线访问管理,当总线的应答信号返回错误时Cortex-M 尝试产生一个 Bus Fault 中断来处理,未果则将出错提升为严重出错,转交给 Hard Fault 中断来处理。通常,总线应答信号返回错误的诱因有以下几种:
1. 企图访问无效的地址,该地址上没有任何的设备;
2. 设备还没有做好数据传输的准备,如尚未做初始化;
3. 传输数据的尺寸不为设备所支持;

Hard Fault 中断用于处理严重出错。其它三种出错中断未能及时处理的出错都由 Hard Fault 中断来处理,它是 Cortex-M 处理出错的最后的机会。如果在 Hard Fault 的中断服务程序中又发生新的出错,或 Hard Fault 中断不能及时响应,则硬件系统将进入死锁状态,以避免故障扩散。在 Cortex-M 复位之后,Hard Fault 中断是被允许的,而其它三种出错中断则被禁止。所以,在通常的应用中,无论出现哪种出错都表现为产生了Hard Fault 中断。
一般来说,由于大多数型号的 STM32 中都未包含有 MPU,或应用软件未使能 MPU,所以内存管理方面的出错不为多见。而对于使用 C 语言编程的软件来说,如果不考虑编译器出错,除了由于函数指针使用不当,而造成尝试进入 ARM 状态以外,其它的指令使用方而的出错也不会遇到。于是,只有总线访问方面的出错才是我们主要面对的问题。导致总线访问出错的原因,可能在硬件方面,也可能在软件方面。在硬件方面常见的原因有:
1. 电源设计有错误,造成器件供电不平衡;
2. 电源质量不好,纹波、噪声过大;
3. 器件接地不良;
4. 对于带有 Vcap 引脚的器件来说,Vcap 引脚处理不当;
5. 电路中有强干扰源,对器件造成了干扰;

软件方面的原因则是使用指针访问了非法地址。根据已往相关问题的调试的经验,造成指针取值出错的常见原因有:
1. 使用了空指针;
2. 对地址偏移量的计算有误;
3. 数组越界导致程序出错;
4. 动态内存用不当,导致访问了已释放的内存地址;
5. 通过地址访问了已失效的局部变量;
6. 对与中断服务程序共享的变量的进行“读修改写”操作而未加临界保护;
Cortex-M 为各种出错设计了状态寄存器,有时核查这些寄存器的取值,对定位问题原因有所帮助。附表如下:
Bus Fault 状态寄存器 BFSR,地址:0xE000ED29

MemManage Fault 状态寄存器 MFSR,地址:0xE000ED28

Usage Fault 状态寄存器 UFSR,地址:0xE000ED2A
Hard Fault 状态寄存器 HFSR,地址:0xE000ED2C

更多实战经验请看:【ST MCU实战经验汇总贴】

沙发
大道至简| | 2015-8-30 11:15 | 只看该作者
我也经常碰到这个问题,但是把软件烧录在flash里面后,
脱离仿真器让他单独运行,却从来不会死机,连续跑20天的都很多。
接入仿真器后也是经常进入这个莫名其妙的地方

有时候连接仿真器,却会发现一下就进入Hard Fault了,有时候重新刷机一次就不会有这个问题了,有时候要刷机好几次。

每次刷机都是同一个版本的软件,有时候甚至是需要重新编译然后刷机。
严重怀疑仿真器有问题,但是换了仿真器也差不多,差别只是发生的概率高低而已

使用特权

评论回复
板凳
大道至简| | 2015-8-30 11:17 | 只看该作者
以上问题,请ST注意一下
我们用了3个仿真器都有这个问题的

使用特权

评论回复
地板
追逐浪花| | 2015-8-30 16:06 | 只看该作者
对于程序中的变量的定义应该格外的小心

使用特权

评论回复
5
xia00| | 2015-8-31 08:16 | 只看该作者
楼主总结的真的很棒啊,学习了。

使用特权

评论回复
6
wangzhihai1986| | 2015-8-31 08:42 | 只看该作者
HARD FAULT多半是栈溢出。

使用特权

评论回复
7
大道至简| | 2015-9-1 07:27 | 只看该作者
如果是堆栈溢出,为啥我脱离仿真器从不死机呢?

使用特权

评论回复
8
hbzjt2011| | 2015-9-1 07:37 | 只看该作者
学习了,确实应该注意调试程序过程中的数据类型和数据长度。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:意法半导体(中国)投资有限公司
简介:STM32技术专家

596

主题

17108

帖子

288

粉丝