HardFault 在实际工作中比较常见,遇到这样问题,重要的是定位问题,当然有比较好的开源工具(backtrace),但这就失去分析问题本质的机会。
一、原因分析
1、可能堆栈溢出。
2、数组越界或局部变量未初始化
二、解决办法
1、增加栈空间
将0x800增大看是否解决问题,大多数情况可以解决问题,如果没有效果就要定位是进入HardFault之前的情况。
三、定位HardFault之前的情况
1、首先产看LR寄存器的值为)0XFFFFFFF1.
2、定位到MSP的值(主堆栈指针)0X20001550.
3、通过memory 产看0X20001550的值。
4、HardFault原因一般以0x08开头,找到0x080023D2.
5、在汇编窗口右键打开Disassembly Window,输入刚才的地址.
6、定位到HardFault之前的函数。
7、分析是因为变量i未赋除值,那么i就是随机数,问题解决。
四、boot跳转APP进入hardfault
1、通过上诉方法定位到问题是APP触发了定时器中断,导致hardfault,通过Call Stack + Locals也可以看出HAL_TIM_IRQHandler完之后就进入hardfault了,而且定位的地址则和上诉方式定位结果一致。所以又多了一种定位方法,而且更快速准确。
2、最近现在调试说stm32 的iap程序时,每次跳转总是进入hardfault_handler,仔细检查跳转时的设置,
前面进行了两个操作关中断 __disable_irq()和把用户代码的栈顶地址设置为栈顶指针__set_MSP(),
首先用户代码的栈顶地址是正确的,看了下__disable_irq()使用的“cpsid i”只是简单的禁止CPU去响应中断,
没有真正的去屏蔽中断的触发,中断发生后,相应的寄存器会将中断标志置位,在__enable_irq()后,
由于中断标志位没请空,还会触发中断,因此禁止中断需要逐个对模块进行Disable操作。进行修改后程序正常运行。
SysTick->CTRL = 0; /*关键代码*/
HAL_DeInit(); /*可选*/
HAL_NVIC_DisableIRQ(SysTick_IRQn); /*可选*/
HAL_NVIC_ClearPendingIRQ(SysTick_IRQn); /*可选*/