读取了错误数据导致STM32 单片机Hard Fault
RT,程序本来能运行,然后代码几乎没改,突然就卡死在Hard Fault 里了。 用调试器跟踪了半天,发现是在调用屏幕库函数显示某个字符串时挂掉的。
第一步怀疑是指针指向的地址没有对齐,导致Hard Fault,于是来回试,更改字符串的定义方式,无果,开始怀疑是不是掉进编译的坑里了,或者是屏幕库有BUG。
第二步,程序启动时把要显示的指针数值从串口打印出去,发现无论我怎么改字符串定义,指针指向的地址始终不变。
第三步,突然想起来,这个指针的值会保存到Flash 里,复位后加载,所以值才一直不变。
所以问题就是之前的程序存储的数据有误,或者之前程序里指针指向的字符串地址在重新编译后发生变化,导致用读取出来旧的指针地址无法取得有效数据,结果可能是Hard Fault,也可能是显示出乱码。
解决方案是尽量不把指针直接存下来,可以把要指向的所有字符串或其他对象先放到一个数组里,然后存储数组下标,这样就算下标发生错误,也很容易检查出来,不会触发Hard Fault,让人一头雾水。
而对于我的代码,要存储的东西实际是一个结构体数组,结构体里面又放了指针,就算不把指针存进Flash,要是结构体数组的定义有点改变,读取的旧数据也是无效的,跟新的定义对不上了。需要个办法让程序在Flash 数据失效后不读取数据:
- 固件里硬编码个版本号,Flash 里也存储个版本号。数据定义变更后,手动改变固件里的版本号,于是旧的Flash 数据就可以被识别出来;
- 计算出默认状态结构体数组的CRC 校验码,并存储到Flash 中。变更定义后,校验码相应的会改变,就能自动识别出失效的Flash 数据;
- 每次烧录程序后把存储的数据清空;
我选了方案一,简单,不会出意外。