教大家如何写出一个现场保存函数以及如何调用该函数

电子说

1.3w人已加入

描述

在进行CortexM系列MCU开发时,大家应该都或多或少触发过不可屏蔽中断,例如人见人爱的Hardfault。

对于嵌入式工程师来说,能够稳定复现的Bug最好解决,再不济挨个打断点也能定位到问题代码位置。

可是异常如果是不定时,无规律的发生在日常的运行中,那打断点的方式无异于守株待兔。

本篇将提供小技巧简述CortexM的异常压栈机制,教大家如何写出一个现场保存函数以及如何调用该函数。

如下图所示,触发中断的时候,CortexM​系列芯片会按照该排列将相关现场数据进行地址偏移压栈,N即此时的SP数值,通过SP中存放的地址,我们可以获取到如图所示的数据。

而要知道触发异常的地址则需要关注LR(Link Register)的数值,它存放着异常触发点的函数地址。

Flash单片机

那么按照压栈的排列,我们可以编写一个结构体以及相关的记录现场函数,如下图所示,结构体的成员完全是按照上图的压栈顺序排列,那下一步就是在哪里调用这个接口来获取到案发时的第一手资料

Flash单片机

​要想获得第一手数据,就要去中断函数的执行处,很多厂商的SDK都会在名为XXX_it.c文件里为开发者们写好各个中断的Handler,由于S文件中都是弱定义(弱定义即在C文件中有同名的函数,则以C文件中的函数优先编译,则可能造成触发中断时并不会运行S文件处的函数)所以建议可以将其屏蔽或者自己重新编写一个新的函数名。

由下图可见,通过IMPORT的形式调用外部现场保存函数,将SP寄存器赋值给R0寄存器是因为R0通常时作为函数的第一个参数进行调用的,可看作是将SP数值作为参数传入StackSave函数,BL的意思是带返回的跳转,即使跳转运行完成StackSave函数后还返回此处。

Flash单片机

完成上述函数编写以及调用后,即可进行测试了。本次范例通过SPI初始化时传入错误的外设寄存器地址来触发HardFault中断,由下图可看出,此时记录到的LR数值为0x8000e83

Flash单片机

​查询后可知,0x8000e83的位置为SPI初始化函数中,符合预设的异常触发位置。在非仿真环境下可通过map文件找到大致的函数地址。

Flash单片机

综上,我们就知道了如何获取到触发异常中断时的程序运行地址,通过将获取到的信息存入到片上Flash指定地址的形式将此时的现场信息进行保存,并通过固件和map一一对应管控。

这样在漫长运行过程中,如果不慎触发异常异常中断,通过对应的map文件即可迅速定位BUG所在大致位置​

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分