一、STM32出现HardFault_Handler故障的原因主要有两个方面:
- 内存溢出或者访问越界。这个需要自己写程序的时候规范代码,遇到了需要慢慢排查。
- 堆栈溢出。增加堆栈的大小。
二、查找手册资料
排查方法:
发生异常之后可首先查看LR寄存器中的值,确定进入异常前一刻使用的堆栈为MSP或PSP,然后找到相应堆栈的指针?
注:在HandFault_Handler(void)中断里第一条语句打断点,进入中断后,查看LR寄存器的值,如果是0XFFFFFFF9,那么中断前使用的是MSP,如果是0XFFFFFFFD,那么中断前使用的是PSP:
参考“Cortex-M3 权威指南” 第九章 中断的具体行为 (P135)
中断/异常的响应序列
当CM3开始响应一个中断时,会在它看不见的体内奔涌起三股暗流:
- 入栈: 把8个寄存器的值压入栈
- 取向量:从向量表中找出对应的服务程序入口地址
- 选择堆栈指针MSP/PSP,更新堆栈指针SP,更新连接寄存器LR,更新程序计数器PC
(1)入栈
响应异常的第一个行动,就是自动保存现场的必要部分:依次把xPSR, PC, LR, R12以及R3‐R0由硬件自动压入适当的堆栈中:如果当响应异常时,当前的代码正在使用PSP,则压入PSP,即使用线程堆栈;否则压入MSP,使用主堆栈。一旦进入了服务例程,就将一直使用。
()主堆栈。
假设入栈开始时, SP的值为N,则在入栈后,堆栈内部的变化如表9.1表示。又因为AHB接口上的流水线操作本质,地址和数据都在经过一个流水线周期之后才进入。另外,这种入栈在机器的内部,并不是严格按堆栈操作的顺序的——但是机器会保证:正确的寄存器将被保存到正确的位置,如图9.1和表9.1的第3列所示。
由此可知,入栈顺序:R0~R3、R12、Return address、PSR、LR。(注意:被保存的顺序不是入栈的顺序)
因此,栈内地址为:
N-32 N-28 N-24 N-20 N-16 N-12 N-8 N-4 N-0
R0 R1 R2 R3 R12 LR PC xPSR 原先已入栈的内容
三、查找入栈的PC地址
在HardFault异常中断服务函数中添加一下代码:
void BusFault_Handler(void)
{
u8 i;
u32 Msp_Addr;
//程序入口地址错误会执行此异常处理
USART1_SendDataString("BusFaultrn");//通过串口打印上电信息
Msp_Addr=__get_MSP();//用于输出MSP地址,调用于文件core_cm3.c。
for(i=0;i<32;i++)
{
USART_SendData(USART1,*(u8*)(Msp_Addr++));
}
USART1_SendDataString("BusFault endrn");//通过串口打印上电信息
while(1);
}
串口输出结果为:48 61 72 64 46 61 75 6C 74 0D 0A 30 78 32 30 30 30 42 46 38 38 0D 0A 00 00 00 00 54 1E 00 A0 14 28 00 20 94 28 00 20 08 00 00 00 9B 20 02 08 06 75 01 08 00 00 00 21 48 61 72 64 46 61 75 6C 74 20 65 6E 64 0D 0A
从数据中取出寄存器数据:
00 00 00 00 54 1E 00 A0 14 28 00 20 94 28 00 20 08 00 00 00 9B 20 02 08 06 75 01 08 00 00 00 21
R0 R1 R2 R3 R12 LR PC xPSR
由此得出入栈的PC地址为:0x08017506
四、定位PC对应的代码行位置
打开CMD工具,使用DS5的arm-linux-gnueabihf-addr2line.exe工具从 .axf文件中查找指定地址对应的代码行位置。
命令和结果如下:
从图中可以看到PC地址:0x08017506,定位的代码位置为:FAT32_sys.c文件的第1767行。
说明:
arm-linux-gnueabihf-addr2line.exe工具的路径:D:DS-5bin>
MS36_2D_BT_APP.axf:为DS5生成Bin文件的过程中产生的中间文件。
-e:为cmd的命令。
|