在进行CortexM系列MCU开发时,大家应该都或多或少触发过不可屏蔽中断,例如人见人爱的Hardfault。
对于嵌入式工程师来说,能够稳定复现的Bug最好解决,再不济挨个打断点也能定位到问题代码位置。
可是异常如果是不定时,无规律的发生在日常的运行中,那打断点的方式无异于守株待兔。
本篇将提供小技巧简述CortexM的异常压栈机制,教大家如何写出一个现场保存函数以及如何调用该函数。
如下图所示,触发中断的时候,CortexM系列芯片会按照该排列将相关现场数据进行地址偏移压栈,N即此时的SP数值,通过SP中存放的地址,我们可以获取到如图所示的数据。
而要知道触发异常的地址则需要关注LR(Link Register)的数值,它存放着异常触发点的函数地址。
那么按照压栈的排列,我们可以编写一个结构体以及相关的记录现场函数,如下图所示,结构体的成员完全是按照上图的压栈顺序排列,那下一步就是在哪里调用这个接口来获取到案发时的第一手资料
要想获得第一手数据,就要去中断函数的执行处,很多厂商的SDK都会在名为XXX_it.c文件里为开发者们写好各个中断的Handler,由于S文件中都是弱定义(弱定义即在C文件中有同名的函数,则以C文件中的函数优先编译,则可能造成触发中断时并不会运行S文件处的函数)所以建议可以将其屏蔽或者自己重新编写一个新的函数名。
由下图可见,通过IMPORT的形式调用外部现场保存函数,将SP寄存器赋值给R0寄存器是因为R0通常时作为函数的第一个参数进行调用的,可看作是将SP数值作为参数传入StackSave函数,BL的意思是带返回的跳转,即使跳转运行完成StackSave函数后还返回此处。
完成上述函数编写以及调用后,即可进行测试了。本次范例通过SPI初始化时传入错误的外设寄存器地址来触发HardFault中断,由下图可看出,此时记录到的LR数值为0x8000e83
查询后可知,0x8000e83的位置为SPI初始化函数中,符合预设的异常触发位置。在非仿真环境下可通过map文件找到大致的函数地址。
综上,我们就知道了如何获取到触发异常中断时的程序运行地址,通过将获取到的信息存入到片上Flash指定地址的形式将此时的现场信息进行保存,并通过固件和map一一对应管控。
这样在漫长运行过程中,如果不慎触发异常异常中断,通过对应的map文件即可迅速定位BUG所在大致位置
-
寄存器
+关注
关注
31文章
5234浏览量
119000 -
仿真器
+关注
关注
14文章
1006浏览量
83400 -
串口中断
+关注
关注
0文章
64浏览量
13777 -
Flash单片机
+关注
关注
0文章
111浏览量
9334 -
MCU芯片
+关注
关注
3文章
241浏览量
11219
发布评论请先 登录
相关推荐
一文详解python调用函数
如何查看及更改函数/函数块的调用环境
![如何查看及更改<b class='flag-5'>函数</b>/<b class='flag-5'>函数</b>块的<b class='flag-5'>调用</b>环境](https://file1.elecfans.com/web2/M00/AE/C0/wKgaomVWvV2ANCozAAAzJenX8j8177.png)
传递函数是怎么定义的以及如何写出传递函数?
![传递<b class='flag-5'>函数</b>是怎么定义的<b class='flag-5'>以及</b><b class='flag-5'>如何写出</b>传递<b class='flag-5'>函数</b>?](https://file.elecfans.com/web2/M00/04/B9/pYYBAGDb5JaAVNXoAAATBvS4NjM804.png)
python函数与函数之间的调用
OP-TEE的内核初始化函数调用
![OP-TEE的内核初始化<b class='flag-5'>函数</b><b class='flag-5'>调用</b>](https://file1.elecfans.com/web2/M00/AC/27/wKgaomVDdK2AcJsKAARQFQOrVvs468.jpg)
评论