2024-07-02
GR5526 GUI专题(4) - Lvgl字体的位图数组合并转换为bin文件的说明
写技术文章
精选推荐
Ping
Cortex-M3/4的Fault异常是由于非法的存储器访问(比如访问0地址、写只读存储位置等)和非法的程序行为(比如除以0等)等造成的。常见的4种异常及产生异常的情况如下:
在默认复位初始化时Hard Fault使能,其它三者不使能,因此当程序中出现不合法内存访问(一般是指针错误引起)或非法的程序行为(一般就是数学里面常见的除0)时都将产生Hard Fault中断。
当系统死机或者出现异常时,首先需要判断是否为 HardFault,然后再判断是哪种 Fault,Goodix BLE芯片默认支持 SWD 协议,因此只要支持 SWD 的仿真器理论上都可以对其进行调试,硬件连接示意图如下。
1. J-Link获取现场信息
J-Link 硬件连接完成后,打开 J-Link Commander,然后键入“connect”, 根据芯片类型进行后续选择,最后成功连接,键入“h”,即可得下图所示信息。
可以看到 IPSR=3, 同时参看下图信息,可知当前进入 Hard Fault 异常处理模式。
2. 线索分析
A. 获取现场信息后,根据LR 寄存器中读到的值,确认当前使用 MSP 还是 PSP,上图示例R14(LR) = 0xFFFFFFE9,根据下图可知,使用的是 MSP。
B. 明确stack 为 MSP 后,读取MSP = 0x0083FF98 地址处最近的 8 个 word(32 Byte)。Cortex-M4在中断发生时的压栈顺序为:xPSR, PC, LR, R12, R3, R2, R1, R0,则读取到的8个word的含义是反过来的,其中第6个word为异常前的 LR,第7个word为异常前的 PC,通过这两个值就可以反推出异常发生前的位置。
按照如下顺序,即可得知: LR=0x01003FEB, PC=0xFFFFFFFE
3. 原因定位分析
通过上述步骤已获取到有效的现场信息,也分析到真实异常的 LR 以及 PC 值,下一步需要结合反汇编文件进行定位,找到大概的出错代码位置。显然地PC=0xFFFFFFFE是一个非法地址,此时 ARM 陷入了访问非法地址的异常,因此只能先看 LR指令,在反汇编文件中搜索 0x01003FE*,如下图所示:
可知具体指令为红框处,因为出问题时指令是 thumb 状态,因此最后一个 bit 是 1,此处要-1。既然是 LR 指令就需要看上一条指令。可以看到具体是BLX r0 这一条命令执行后出的问题,再观察此时 R0 为 0xFFFFFFFF, 然后 PC 跳到一个非法地址,故导致 HardFault。
Fault Trace模块是GR5xx SDK提供用于辅助开发调试阶段定位系统异常问题的模块,该模块支持以下实用功能:
如果使用了看门狗,则很有可能因为看门狗复位导致第一现场丢失,此时就需要借助Fault Trace模块的异常记录功能来判断。在出现Hard Fault后,Fault Trace模块会自动将异常信息存入NVDS中。 Fault Trace模块的具体使用方法请参考 GR5xx Fault Trace Module应用说明 和 GR551x Fault Trace Module流程 。
1. Fault Trace模块使用注意事项
(1) Fault Trace模块依赖APP LOG模块,Assert模块与Error模块,使用时需要确保下面的文件加入到 了工程中,并将它们的所在目录加入到Include Path中:
components\libraries\app_assert\app_assert.c
components\libraries\app_error\app_error.c
components\libraries\app_log\app_log.c
(2) Fault Trace模块不止支持记录HardFault异常信息,也支持记录使用宏 APP_ERROR_CHECK , APP_BOOL_CHECK 与 APP_ASSERT_CHECK 产生的错误信息。
(3) Fault Trace模块默认支持16条错误信息存储,该上限可通过 components\libraries\fault_trace\fault_trace.h 中的宏 FAULT_INFO_RECORDS_MAX 进行 调整,超出上限条数的错误信息会循环覆盖最老的错误信息。
(4) 如果要使用Cortex Backtrace的扩展功能,在 custom_config.h 中将宏 ENABLE_BACKTRACE_FEA 的值置为 1 。
2. Hardfault信息分析
在使用了Fault Trace模块的cortex-backtrace组件的情况下,HardFault时会 自动反推调用栈信息。下面是使用了cortex-backtrace组件后HardFault时的信息输出:
Fault on interrupt or bare metal(no OS) environment
==== Main stack information ====
addr: 2007fe28 data: 00000000
addr: 2007fe2c data: 00207379
addr: 2007fe30 data: 00000301
......
addr: 2007fffc data: 0020b8c5
=========
==== Registers information =====
R0 : 00123456 R1 : deadbeef
R2 : 00000000 R3 : 00000000
R12: 00000000 LR : 00077ded
PC : 00203ca8 PSR: 61000011
=========
Fault reason:
Bus fault: imprecise data access violation
Call stack info : 00203ca8<--00077de9<--00207375<--000002fd<--00207479<-
-00000003<--002073b1<--00000dfd<--002098fd<--0020988d<--00000dfd<--00040edf<-
-0004020f<--0020b8c1<--0020b8c1<--
cortex-backtrace主要打印了4个信息:栈数据,关键寄存器,异常类型和调用栈。其中栈数据可以结合汇编进行场景重现,对于某些由数据错误引起的HardFault调试有帮助(例如除0,空指针等等),关键寄存器包括:
A. 用于传参,存储返回值和临时数据的 R0-R3 寄存器
B. 用于过程间临时传参的 R12 (IP) 寄存器
C. 用于存储返回地址的 LR 寄存器
D. 用于存储当前运行地址的 PC 寄存器
E. 用于存储运算标志位,中断号及运行状态的 PSR 寄存器
通过 PC 寄存器可以知道异常具体发生在哪一个位置,可以通过汇编文件( .s 文件或是 .asm 文件)去查对应地址的汇编指令,也可以使用GCC工具链提供的 addr2line 工具来获取地址对应到哪个源文件中的哪一行。有时候可以看到 PC 的值是一个奇数,这是Cortex-M4核心的Thumb模式导致的,此时把地址值-1即是正确的地址。
异常类型是对Cortex-M4核心的 CFSR (Congifurable Fault Status Register) 寄存器的解析。该寄存器是Cortex-M4核心用于指示HardFault产生原因的寄存器。HardFault又被细分为3种类型:Usage Fault, Bus Fault, Memory Management Fault。具体不同类型以及指示内容的具体含义请参考Cortex-M4 Devices Generic User Guide - 4.3.10 Configurable Fault Status Register。
调用栈是Cortex Backtrace模块通过对寄存器,运行程序以及栈数据的分析和反推得到的调用关系链,和 PC 寄存器的值一样,结合汇编文件或者 addr2line 工具可以对整个调用链条进行定位。
1. J-link读取信息如下,错误信息为0xFFFFFFFD—Retuen to Thread mode and use the Process Stack for return,使用PSP。
2. 读取PSP地址附近10 Byte内容,LR=0x0100C385,PC=0x12345678。
3. MAP文件定位0x0100C384位置。
4. 0x12345678地址超过了内存范围。
Q:反汇编定位不准确
A:如果通过上述方法定位到的函数,发现程序不可能调用到,那么可能是上述方法的过程中有误,比如当前主栈用的是 PSP,但是误认为 MSP,也有可能是将 LR 和 PC 值相反了。
Q:MSP/PSP 不正常
A:如果发现 MSP/PSP 不正常时,则不可再继续用上述方法,一般这种错误是 ARM 上电异常导致的,重点怀疑的还是时钟、晶振、 PLL 等相关参数异常导致。
Q:得到的PC指向了一个莫名其妙的地方是怎么回事?
A: 有以下几种可能:
Q: 读取不了栈上的数据怎么办?
HARDFAULT CALLSTACK INFO: R0-00123456 R1-DEADBEEF R2-00000000 R3-00000000 R12-
00000000 LR-00077DED PC-00203C00 XPSR-61000011
A: 首先请确保芯片已经被Halt住,即在J-Link连上后需要先输入 h 让芯片停止运行;其次检查所读取的栈指针和所要读取的长度是否在正确的RAM范围内;最后如果上述步骤都不能解决问题,则有可能是芯片存在硬件异常,请检查供电及各个关键电源信号是否符合要求。
参考资料
1. 如何监控内存越界/踩踏的问题--基于GR5515移植DWT_Point
打开微信,使用“扫一扫”即可关注