单片机异常分析方法简介
什么是异常
程序运行输出不符合预期结果,我们就说程序产生了异常。
异常产生的原因有很多中,但大致可以分为两类软件异常和硬件异常。
软件异常
该类异常多出现在硬件初始化失败或者传入非法参数等场景,我们可以通过读取PC和LR寄存器数值定位软件异常点即异常前的调用关系。
硬件异常
该类异常触发的情况比较复杂,比如错误的指针操作、栈空间损坏、内存溢出、非法存储器映射等,但这类异常产生后触发hardfault中断,通过查看进入中断前压入栈中的寄存器的内容可以帮助我们定位引起硬件错误异常的指令的位置。
快速定位异常的方法
首先我们要区分当前异常属于哪种异常,再根据不同异常的特性找到异常发生时的有用的寄存器数值,这样就能定位到异常发生的指令位置。
区分当前异常是软件异常还是硬件中断异常
中断号PSR(IPSR)包含了当前正在执行的中断服务程序编号,若该寄存器为0表示不在中断中即当前异常为软件异常。
软件异常分析方法
软件异常发生后借助PC寄存器快速定位到异常发生的指令位置 。
注意:在 Cortex-M3/4 平台下,LR 寄存器保存的返回地址通常是奇数,这是因为 Cortex-M 平台有些跳转 / 调用操作需要将地址的第 0 位置 1 以表示操作模式为 Thumb 状态,因此在使用该地址的时候,请自动将基数地址减一。
硬件异常分析方法
硬件异常发生后系统会触发hardfault中断,由于当前程序已经运行到hardfault中断中,所以PC寄存器已经无法定位异常发生的指令位置,但是在进入中断前系统会将R0-R3,R12,LR,PC,XPSR压入栈中,这样就可以找到异常发生的指令对应的PC 寄存器。

注意:在进入中断后系统除了入栈上述8个寄存器外还会将R7和LR入栈,所以需要将当前SP地址加8*4方可获得PC值。
什么是栈
栈是一种先进后出的数据结构(类似于枪支的弹夹,先放入的子弹最后打出,后放入的子弹先打出)。对于cortex-M3内核使用了双堆栈,即MSP和PSP,这极大的方便了OS的设计。
MSP的含义是Main_Stack_Pointer,即主栈
PSP的含义是 Process_Stack_Pointer,即任务栈
SP:SP是堆栈指针,指向最后一个被压入元素的地址。
M3内核堆栈生长方向是向下的且出入栈的数据都是4字节对齐,所以入栈时SP先自减4,然后将待压入的数据存放到SP所指的地址,出栈时从SP指针所指的地址读出数据,然后SP指针自增4。
如何确定当前有效的栈
虽然对于cortex-M3有两个堆栈,但任何时刻只能使用其中之一,根据EXC_RETURN即可判断进入异常中断前程序的运行模式以及使用的栈类型。
运行模式,特权级别,栈三者关系
| 模式\级别 | 特权级 | 用户级 |
|---|---|---|
| Handler模式 | 中断-MSP | 错误用法 |
| 线程模式 | 非OS线程-MSP | OS线程-PSP |
断言定位异常利弊分析
也许有人说在STM32的库函数中有很多断言输出,通过__FILE__ ,__ LINE__这几种C标准用法可以快速定位到异常发生的文件及行号。但是该方法并不适用于硬件异常且会消耗较多的flash资源。
如何使用异常输出的信息快速定位异常点
通过上述分析可以在软件异常及硬件异常时快速定位到异常指令的位置,同时借助addr2line工具找到出问题的文件及对应的行号。
假设已知异常PC指针为0x08002234,并找到异常程序编译出的out文件,通过CMD命令行将当前目录切换到addr2line.exe所在的目录并执行如下命令(addr2line -e LR.out -a -f 08002234),在终端上即可看到异常指令对应的文件及行号。

本文介绍了单片机异常分析的基本方法,包括软件异常和硬件异常的区分及定位策略。在软件异常中,通过PC和LR寄存器可以定位异常点;而在硬件异常时,利用hardfault中断栈中的信息来定位错误源。栈的概念和其在异常处理中的作用也被阐述,以及如何确定当前有效的栈。此外,还讨论了断言定位的利弊以及如何使用addr2line工具快速定位异常点。

12万+

被折叠的 条评论
为什么被折叠?



