STM32学习笔记11——HardFault_Handler处理方法

时间:2024-05-19 18:56:35

根据网络资料及自己调试经验总结如下:

STM32 出现 HardFault_Handler 故障的原因主要有两个方面:
1、内存溢出或者访问越界。这个需要自己写程序的时候规范代码,遇到了需要慢慢排查。
2、堆栈溢出。增加堆栈的大小。

排查方法:

发生异常之后可首先查看 LR 寄存器中的值,确定进入异常前一刻使用的堆栈为 MSP 或 PSP,然后找到相应堆栈的指针?
注:在 HardFault_Handler(void)中断里第一条语句打断点,进入中断后,查看 LR 寄存器的值,如果是 0XFFFFFFF9,那么中断前使用的是 MSP,如果是 0XFFFFFFFD,那么中断前使用的是 PSP;
STM32学习笔记11——HardFault_Handler处理方法

根据找到的堆栈指针, 在内存中查看相应堆栈里的内容。由于异常发生时,内核将 R0~R3、 R12、 LR、 PC、 XPRS 寄存器依次入栈,其中 LR 即为发生异常前 PC 将要执行的下一条指令地址。
STM32学习笔记11——HardFault_Handler处理方法

中断/异常的响应序列

**当 CM3 开始响应一个中断时,会在它看不见的体内奔涌起三股暗流:

  1. 入栈: 把 8 个寄存器的值压入栈。
  2. 取向量:从向量表中找出对应的服务程序入口地址。
  3. 选择堆栈指针 MSP/PSP,更新堆栈指针 SP,更新连接寄存器 LR,更新程序计数器 PC。**

入栈

响应异常的第一个行动,就是自动保存现场的必要部分:依次把 xPSR, PC, LR, R12 以及 R3‐R0 由硬件自动压入适当的堆栈中:如果当响应异常时,
当前的代码正在使用 PSP,则压入 PSP,即使用线程堆栈;否则压入 MSP,使用主堆栈。一旦进入了服务例程,就将一直使用主堆栈。
假设入栈开始时, SP 的值为 N,则在入栈后,堆栈内部的变化如表 9.1 表示。又因为 AHB 接口上的流水线操作本质,地址和数据都在经过一个流水线周
期之后才进入。另外,这种入栈在机器的内部, 并不是严格按堆栈操作的顺序的——但是机器会保证: 正确的寄存器将被保存到正确的位置, 如表 9.1所示。

STM32学习笔记11——HardFault_Handler处理方法
测试: 在程序中调用如下函数,会进入异常故障中断。

void StackFlow(void)
{
int a[3],i;
for(i=0; i<10000; i++)
{
a[i]=1;
}
}

DEBUG 如下图
STM32学习笔记11——HardFault_Handler处理方法
SP 值为 0x20008d88,查看堆栈里面的值依次为 R0~R3、 R12、 LR、 PC、 XPRS, 例如 R0(00001C97), 根据表 9.1 里 LR 的位置, 得到地址 0x0800087D 即为异
常前 PC 将要执行的下一条指令地址(即 StackFlow()后面的语句处 RTC_Init().

另一种方法:

默认的 HardFault_Handler 处理方法不是死循环么? 将它改成 BX LR 直接返回的形式。然后在这条语句打个断点,一旦在断点中停下来,说明出错了,然后再返回,就可以返回到出错的位置的下一条语句那儿。

__asm void wait()
{
BX lr //BX 无条件转移指令,返回到发生错误的后面代码中
}
void HardFault_Handler(void)
{
/* Go to infinite loop when Hard Fault exception occurs */
wait();
}