后续的时间分割线 在对STM32有了更加了解的认识之后,通过查数据手册可以知道当时我使用的芯片内存是接近300K的,所以当时肯定不是SRAM爆掉了这样,肯定只是因为当时代码写的不够好存在了异常写入的情况了,在此谨记吧,
以下为当时的原文 题目起的非常的傻,可能是这几天为了把这个问题调出来把人都给调废了吧。。。反正现在找到了问题就特别的开心。
有时候我们在使用STM32进行开发的时候,有时会莫名其妙的进入hardfault,而有时又会出现明明寄存器配置完全一模一样,程序原来都是好好的能跑的,可是自己改了一点其他无关紧要的东西的时候,整个程序的运行逻辑就不一样的问题。。。当出现这种问题的时候,一般就属于C语言和嵌入式结合所带来的很难排查的问题了:
- 指针指飞了
- 栈空间堆爆了
- 堆空间堆爆了
- SRAM爆了
SRAM爆掉可能会有很多种非常莫名其妙的情况,在不同的工程上可能也会有不同的状况。在我使用的工程中,需要使用两个CAN外设:CAN1和CAN2接口来收发数据。这些数据的处理接口都是使用的非常成熟的库来管理,之前从来没有出现什么问题。然而某一天我在给自己的代码新增功能的时候,调试突然发现有一个CAN端口再也接收不到数据了,可是调试发现一切函数都在正常的执行,就算直接查寄存器也是完全的一模一样,可是CAN就是死活接收不到数据,把新加入的代码删了吧,就可以正常运行,可是新加入的代码和CAN真的是一毛钱关系都没有。
幸好我在干活的时候用上了GIT,使用GIT进行二分定位,找到了第一个引入问题的版本,可是查了一下第一个问题版本所做的修改,也是基本和CAN没有关系。在查了很久的BUG无果之后,我最终向BUG妥协,丢弃了新的改动,回退到了最后一个没有问题的版本继续开发。然而开发没过多久就再一次出现了同样的问题。再一次进行问题定位,引入问题的版本的修改仅仅修改了一个文件,加了几个函数和变量而已。这回问题范围大大缩小了,我试图把所有新加的函数都注释掉,无果。但是当我把所有的变量都取消之后问题就解决了!!然后继续缩小范围,最终的导火线竟然是一个float类型的全局变量的声明!如果变量声明了,CAN就借不到数据,如果变量没有声明,则CAN就能成功的接收到数据!确认了问题的产生的源头,再通过不断的实验,我发现,当出问题的时候,Keil编译器编译成功后的ZI-data永远保留在一个值,此时无论再声明多少全局变量,ZI-data都不再变化了。Keil的ZI-data是全局变量的大小,在运行的时候是占用SRAM的。作为全局变量,怎么可能这个时候申请多少float都不会增加ZI-data呢?这时候一个很合理的推理就出现了:SRAM不够用了。因为内存不够用了,所以全局变量就占不了ZI-data的位置了,同时还有内存之间混乱的问题,因此就不能保证在哪个莫名其妙的地方你的数据被莫名其妙的改掉了。。。。因此如果看到ZI-data占用的空间很大的时候而且不再随变量的增加而增加的时候,那基本就是爆SRAM没跑了。
不过我遇到的这个CAN2无法接收的这个问题是我的整个操作系统中一个比较小的位置。我觉得还有很多时候,SRAM已经爆掉了,但是系统还可以正常运行,这可能只是侥幸降临,但是你也不知道它会在什么时候,改掉你的什么数据,也许这些数据带来的损失是不可挽回的。。。。。。
【嵌入式|大战STM32奇怪的hardfault,各种无厘头的真凶!】本博客就当做一个日记的方式记录了。。因为这个问题能出现的情况很多,但是出现的原因又不一定是这个,可能也就只有我能遇到这种情况了,就算其他人遇到了这种情况,也不一定能找到这篇文章把。。。关键字如果能想到的话问题就很好解决了,关键字不知道的话根本无法形容这种问题
推荐阅读
- C语言学习|第十一届蓝桥杯省赛 大学B组 C/C++ 第一场
- 【C】题目|【C语言】题集 of ⑥
- 单片机|自学单片机好找工作吗(会单片机能找什么工作?)
- 单片机|keil把源代码生成lib的方法
- c语言|一文搞懂栈(stack)、堆(heap)、单片机裸机内存管理malloc
- c语言|C语言初期学习遇到的特殊点 【三子棋详解】【初学者福音,详细总结,复习能手】
- 笔记|C语言数据结构——二叉树的顺序存储和二叉树的遍历
- 嵌入式-外设|DDR3基础详解
- 个人理解|【C语言基础之类型转换】
- c语言|【C语言】自定义类型 结构体 枚举 联合