开发环境
- MCU:STM32F407ZET6
- IDE:MDK V5.14.0.0
- 软件包:uCOS-II V2.19
- 软件包:LUA
异常现象
正在进行的工作是一份代码的移植,原本在STM32F1处理器上稳定运行的代码移植到STM32F407上,不需要什么改动,功能本身也并不复杂,但是在移植GNSS部分的时候遇到了问题,程序进入HardFault
解决过程
首先交代一下两份程序。
- 需要移植的STM32F1程序是一份已经在产品上使用的程序,代码运行稳定没有问题。
- 被移植的STM32F4的工程我使用了之前调试的另一个项目的工程,没有使用一个新的工程模板,也没有对这个工程内不使用的代码进行清理。因为这个工程内有我准备使用的uCOS和LUA的代码(当时也调了很久,这是另一个坑)
遇到HardFault首先怀疑是数组下标越接导致,经过定位后发现居然是一条if判断语句
当执行这条简单的数值判断时,触发了HardFault,很明显不是数组下标越接或者是指针非法访问导致。在排除堆栈溢出、中断异常、编译器抽风等问题后,发现出现问题的变量数据类型为float
并且对float类型的读写访问都会出错,通过反汇编窗口发现是VLDR这条语句引起
这时我想起之前在使用这个工程时,为了同时使用uCOS-II和LUA,关闭了FPU,勾选了use microLIB选项(当时uCOS-II使用FPU有些问题,相关的教程也没有现在这么多),找到FPU的设置,果然被关闭了
将__FPU_PRESENT
设置为1,重新编译下载,恢复正常。现在uCOS-II应该是无法正常运行了,后续再进行调试或者更换系统。
问题重现
为了重现这个问题,我在探索者的F4资料中拿出了一个新的LED流水灯的工程。在main函数加入简单的测试代码
int i;
float f;
double d;
i=0;
f=0;
d=0;
i=d;
d=i;
i=f;
f=i;
- 打开FPU功能,不勾选Use MicroLIB,一切正常
- 关闭FPU功能,main函数无法进入,直接触发HardFault_Handler
- 关闭FPU功能,勾选Use MicroLIB,可以进入main函数了,对float和double类型的读写访问都会触发HardFault_Handler
- 打开FPU功能,勾选Use Micro LIB,一切正常
结论
- 在使用STM32F4时,必须使用FPU,即定义stm32f4xx.h文件种166行
#define __FPU_PRESENT 1
,否则在进入main函数时候会触发HardFault - 如果因为某些原因不能使用FPU,定义
#define __FPU_PRESENT 0
,那么必须在使用微库,在设置中勾选Use MicroLIB
,这时对float类型和double类型读写操作会导致HardFault,暂时没有找到解决办法。如果一定要使用浮点运算,可以考虑使用Q格式
致谢
最后感谢小麦大叔(一名被技术耽误的文坛巨匠)深夜提供帮助,向大家推荐他的博客和文章: