出现崩溃
当 ARM Cortex-M 系列芯片进入 HardFault 异常,可以查看寄存器去排查问题。
如下,PC寄存器指向的是当前执行的代码的位置。
定位堆栈指针
在进入hardfault之后,我们可以通过查看堆栈的内容去排查问题。
堆栈分为两种堆栈,一个是主堆栈MSP,另一个是线程堆栈PSP。
要确定当前堆栈指针是MSP还是PSP,我们需要去查看R14(LR)的值。
在Cortex_M3权威指南中可以看到如下图所示:
当LR = 0xFFFFFFF9时,表示异常发生前,处理器正在使用的是主堆栈(MSP);
当LR = 0xFFFFFFFD时,表示异常发生前,处理器正在使用进程栈(PSP)
Cortex-M 异常发生时,硬件会自动将核心寄存器 “压栈”(Push)到当前使用的栈,这个压栈的内容就是异常栈帧,也是 PSP 指向地址存储的核心内容。
PSP或MSP 指向的地址及下方 32 字节,存储了 R0-R3、R12、LR、PC、xPSR 共 8 个寄存器的异常前值,其中 PC 值是定位 HardFault 根因的核心。
在上图中,我们可以看到LR寄存器中的值是0xFFFFFFFD。次数PSP 寄存器指向的地址里具体存储了哪些内容。
因此我应该去看PSP的地址,找到该地址的地址然后如下图所示打开内存,输入上面找到的寄存器地址0x20003BA0,右键选择以long型查看地址如下所示:
然后查看这个地址向下数六个long地址,为什么是6个long地址呢,因为由于异常发生时,内核将R0~R3,R12,LR,PC,XPRS寄存器依次入栈
其中LR 的核心功能是保存函数的返回地址,PC的值是0,说明堆栈出现了异常,我们当前只能先通过LR来定位问题了。
我们在0x080042B2这里打断点,查看具体出错的原因
第一次进入这里是
发现在第二次进入 这里是如下,然后就跑0x0000000的地址了
我们在继续具体分析
pop命令的作用如下,即从SP指向的栈中弹出两个栈顶数据,并保存在PR,PC中。
查看SP执行的栈中的内容,可以看到等下PC是被赋值成0x080034AD
然后单步运行一下,看到程序跑到了0x080034AC(疑问:为什么不是0x080034AD)
接着第二次全速运行,再次到0x080042B2断点
查看SP指向的栈,果然,全部的数据都是0x00000000,这时就要分析为什么数据都是0
怀疑是堆栈的问题,但是经过检测,没有内存的错乱。
于是就还怀疑是系统的问题,就去查看了系统堆栈的初始函数,不看不知道一看就发现FPU开启后,系统堆栈的内容是不一样的。
百度内容如下,开启了FPU后,内核会额外保存浮点寄存器的状态
查询了一下是如何开启FPU的
结果一看,果然是开启了FPU。
解决方法
关闭FPU
改变ucosii的入栈,读栈方式