发新帖本帖赏金 30.00元(功能说明)我要提问
返回列表
[STM32]

KEIL调试程序进入HardFault_Handler异常处理总结

[复制链接]
1297|5
手机看帖
扫描二维码
随时随地手机跟帖
forgot|  楼主 | 2022-11-15 09:55 | 显示全部楼层 |阅读模式
本帖最后由 forgot 于 2022-11-15 09:58 编辑

#申请原创#
在做CORTEX-M3单片机开发的时候,如STM32,可能会遇到设备跑着跑着程序死机的情况,往往调试起来很多时候发现是程序进入HardFault_Handler系统异常,根据相关资料和M3权威指南是可以通过调试查找出程序的问题点和解决问题的。

根据CM3指南中的 Faults 可分为4类:总线 faults、存储器管理 faults、用法 faults、硬 fault

以下是具体说明:
1、总线 Faults是当 AHB 接口上正在传送数据时,如果回复了一个错误信号,则会产生总线 faultsCM3有一个名为“总线 fault 状态寄存器”(BFSR)的。通过它,总线 fault 服务程序可以确定产生 fault 的场合是在数据访问时、在取指时、还是在中断的堆栈操作时。这个不展开细说

2、存储器管理faults多与MPU有关,其诱因常常是某次访问触犯了MPU设置的保护策略。另外,某些非法访问,例如,在不可执行的存储器区域试图取指,也会触发一个 MemManagefault,而且即使没有 MPU 也会触发。

3用法 faults 发生的场合可以是:执行了未定义的指令;无效的中断返回(LR 中包含了无效/错误的值);使用多重加载/存储指令时,地址没有对齐;除数为零;任何未对齐的访问等等

3、重点讲的就是HardFault_Handler,如果以上3fault 的服务例程无法执行,它们就会成为HardFault_Handler。在NVIC 中有一个硬 fault 状态寄存器(HFSR),它指出产生硬 fault 的原因。

具体调试流程:
3.1首先在将程序进入debug进入调试模式,在void HardFault_Handler(void)函数中打1个断点;如下,以STM32为例,程序在stm32f10x_it.c中;
void HardFault_Handler(void)
{
    /* Go to infinite loop when Hard Fault exception occurs */
    while (1) {
        //SoftReset();
    }
}

3.2等到软件运行到此处,查看(R14LR寄存器的值;如果看到LR寄存器中的值是0xFFFFFFF9,就去看MSP的地址;如果看到LR寄存器中的值是0xFFFFFFFD,就去看PSP的地址;

3.3然后在Keil菜单栏“View”——“Memory Windows”——“Memory”,在“Address”地址栏中输入MSPPSP的值,然后找到对应的地址。地址是以0x08开头的int位数,一般是第六个int数据;
3.4再到Keil菜单栏点击“View”——“Disassembly Window”,在“Disassembly”窗口中右击,选择“Show Disassemblyat Address...”。在弹出框“Show Code atAdress”的地址框中输入地址对应的code地址就可以转到对应代码的位置,通过检查分析或者改写代码前后的语句就可以判断问题的主要原因。

3.5 另外还有通过在调试状态下,进入HardFault断点后,通过菜单栏Peripherals >Core Peripherals >FaultReports打开异常发生的报告,然后通过Call Stack查看发生异常的原因,也是可以的。

3.6 如果不是函数语句的问题,可以通过查看编译后的.map的文件中heapSTACK所占用的地址,通过Memory内存窗口来观察堆栈的使用情况,来看是不是堆栈内存有溢出导致的。
    __heap_base                              0x2000d020   Data           0  startup_stm32f10x_hd.o(HEAP)
    __heap_limit                             0x20016420   Data           0  startup_stm32f10x_hd.o(HEAP)
    __initial_sp                             0x20017420   Data           0  startup_stm32f10x_hd.o(STACK)

分析说明:由于CM3在进入异常服务程序后,LR的值被自动更新为特殊的EXC_RETURN(附图),按照文件说明这是一个高28位全为1的值,只有[3:0]的值有特殊含义,如果主程序在线程模式下运行,并且在使用MSP时被中断,则在服务例程中LR=0xFFFF_FFF9(主程序被打断前的LR已被自动入栈)。如果主程序在线程模式下运行,并且在使用PSP时被中断,则在服务例程中LR=0xFFFF_FFFD(主程序被打断前的LR已被自动入栈)。

总结:根据个人的一些经验,大部分时候是由于以下两种情况导致,
1内存溢出或则访问越界,比方说数组的访问。
2堆栈分配问题,堆栈不够导致堆栈溢出。
根本解决问题肯定是优化代码,但是为了保险起见,可以在HardFault_Handler程序中加入复位命令来保障设备的持续运行,

//系统复位
void SoftReset(void)
{
#if !IS_DEBUG
    __set_FAULTMASK(1);
    NVIC_SystemReset();
#endif
}

/**************************************************************/
CM3指南截图
2.jpg
1.jpg
堆栈大小分配:
3.jpg


使用特权

评论回复

打赏榜单

21ic小管家 打赏了 30.00 元 2022-11-16
理由:签约作者奖励

相关帖子

xdqfc| | 2022-11-15 15:29 | 显示全部楼层
点赞一个。

使用特权

评论回复
WoodData| | 2022-11-16 09:06 | 显示全部楼层
赞一个

使用特权

评论回复
ayb_ice| | 2022-11-16 13:23 | 显示全部楼层
我没有实际这样分析过,出现时一般从上次正常的代码中恢复

使用特权

评论回复
玥月| | 2022-11-21 08:07 | 显示全部楼层
厉害厉害

使用特权

评论回复
dami| | 2022-12-3 10:55 | 显示全部楼层
赞一个

使用特权

评论回复
发新帖 本帖赏金 30.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1244

主题

10779

帖子

49

粉丝