本帖最后由 forgot 于 2022-11-15 09:58 编辑
#申请原创# 在做CORTEX-M3单片机开发的时候,如STM32,可能会遇到设备跑着跑着程序死机的情况,往往调试起来很多时候发现是程序进入HardFault_Handler系统异常,根据相关资料和M3权威指南是可以通过调试查找出程序的问题点和解决问题的。
根据CM3指南中的 Faults 可分为4类:总线 faults、存储器管理 faults、用法 faults、硬 fault;
以下是具体说明: 1、总线 Faults是当 AHB 接口上正在传送数据时,如果回复了一个错误信号,则会产生总线 faults,CM3有一个名为“总线 fault 状态寄存器”(BFSR)的。通过它,总线 fault 服务程序可以确定产生 fault 的场合是在数据访问时、在取指时、还是在中断的堆栈操作时。这个不展开细说
2、存储器管理faults多与MPU有关,其诱因常常是某次访问触犯了MPU设置的保护策略。另外,某些非法访问,例如,在不可执行的存储器区域试图取指,也会触发一个 MemManagefault,而且即使没有 MPU 也会触发。
3、用法 faults 发生的场合可以是:执行了未定义的指令;无效的中断返回(LR 中包含了无效/错误的值);使用多重加载/存储指令时,地址没有对齐;除数为零;任何未对齐的访问等等
3、重点讲的就是HardFault_Handler,如果以上3个 fault 的服务例程无法执行,它们就会成为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等到软件运行到此处,查看(R14)LR寄存器的值;如果看到LR寄存器中的值是0xFFFFFFF9,就去看MSP的地址;如果看到LR寄存器中的值是0xFFFFFFFD,就去看PSP的地址;
3.3然后在Keil菜单栏“View”——“Memory Windows”——“Memory”,在“Address”地址栏中输入MSP或PSP的值,然后找到对应的地址。地址是以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的文件中heap与STACK所占用的地址,通过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指南截图 堆栈大小分配:
|