JunSn 发表于 2023-7-27 21:41:50

STM32使用不同的编译器版本会造成FLASH读写出现HardFault

硬汉大哥以及论坛里的各位大佬,本人最近在用STM32G31RBT6这款芯片设计一个简单Bootloader程序时,发现了一个费解的现象,即FLASH的读写居然会因为编译器以及全局变量的初始化不同而出现HardFault的现象。

首先介绍一下思路,G431RBT6有一个64Kb的FLASH和32Kb的SRAM,因此程序的设计思路大致为
1.创建一个20kb的全局数组buf,然后用DMA+串口空闲中断接受BIN文件并存储到该数组中;
2.传输完毕后,状态变量更改,利用FLASH读写操作将该数组内容写到0x08010000中;
3.执行正常的bootloader程序跳转;
这是一个普通的Bootloader程序,但实际测试中发现了自己很难理解的现象,一共分为四种情况:
现象1:采用AC6编译器,优化等级为-O1,将全局数组buf初始化设置为uint8 buf = {1}, 此时Bootloader程序烧录后工作正常,APP也成功跳转;
记录bootloader程序编译结果:

记录buf数组地址大小以及堆栈指针:

现象2:采用AC6编译器,优化等级为-O1,但是此时将全局数组buf初始化设置为uint8 buf = {0} (!!!注意是0,因此将会归类到ZI-DATA中), 此时Bootloader程序烧录后工作不正常,程序卡死在FLASH读写中并跳转到HardFault中;
记录buf初始化操作(后面写法类似):

记录bootloader编译结果:

记录buf数组地址大小和堆栈指针:

记录Fault reports:

现象3:采用AC5编译器,优化等级为-O1,但是此时将全局数组buf初始化设置为uint8 buf = {1} (!!!注意改成1,因此将会归类到RW-DATA中), 此时Bootloader程序烧录后工作不正常,程序卡死在FLASH读写中并跳转到HardFault中;
记录bootloader编译结果:

记录buf数组地址大小和堆栈指针:

记录Fault reports:

现象4:采用AC5编译器,优化等级为-O1,但是此时将全局数组buf初始化设置为uint8 buf = {0} (!!!注意改成0,因此将会归类到ZI-DATA中), 此时Bootloader程序烧录后工作正常,APP可以正常跳转;
记录bootloader编译结果:

记录buf数组地址大小和堆栈指针:



总结:当编译器选择为AC6,优化等级为O1时,如果将全局数组buf初始化为{1}(就只写一个1,不是20480个1),程序就正常工作,但是当其他程序完全不动,仅仅将buf初始化改成{0},程序就不能正常工作,会卡死在flash读写中并进入Hardfault;当编译器选择为AC5,优化等级为O1,现象则是将全局数组buf修改为{0},就正常工作,修改为{1}就卡死在flash中;
堆栈总大小设置的是0X600,下载的APP都是一样的,大小为8.9Kb左右,我大致计算了一下,应该不会发生数组越界的现象,并且上面的比较其他的代码未动,仅仅修改了编译器以及全局数组的初始化方式,学识浅薄,苦思不解,希望有大佬能翻牌解惑,万分感谢!!!

eric2013 发表于 2023-7-28 09:31:16

这个确实有点诡异,用此贴的方法,分组设置优化等级锁定下问题试试,感觉你的程序中,估计有隐含的问题没有找到。
https://www.armbbs.cn/forum.php?mod=viewthread&tid=98479

emwin 发表于 2023-7-28 09:45:42

看描述你已经找到问题函数了,进一步调试不行吗,全速才异常?

JunSn 发表于 2023-7-28 16:52:44

emwin 发表于 2023-7-28 09:45
看描述你已经找到问题函数了,进一步调试不行吗,全速才异常?

想尝试通过逐步调试来定位,但是当设置错误现象时,debug进入flash读写函数后,第一次flash读写就直接运行到Hardfault中,但是观察数组以及读写的地址应该都在用户区,且没有冲突,所以很难理解。。

JunSn 发表于 2023-7-28 16:55:48

eric2013 发表于 2023-7-28 09:31
这个确实有点诡异,用此贴的方法,分组设置优化等级锁定下问题试试,感觉你的程序中,估计有隐含的问题没有 ...

嗯,谢谢硬汉哥,我试试。

JunSn 发表于 2023-7-28 21:20:32

eric2013 发表于 2023-7-28 09:31
这个确实有点诡异,用此贴的方法,分组设置优化等级锁定下问题试试,感觉你的程序中,估计有隐含的问题没有 ...

感谢硬汉哥,经过检查,发现是编译器的字节对齐不同造成的,因为我定义的全局数组是unsigned char类型的,因此当我使用不同的初始化方式时,编译器有可能会把地址按照1字节对齐,导致数组的起始地址不为4的整数倍,从而导致falsh写操作进入HardFault,两种编译器出现不同现象的根源也是基于此产生的。因此在强制性更改该数组的对齐方式后,问题得到了解决,希望此次分享能够给各位坛友一点帮助,再次感谢硬汉论坛。

Leo20201027 发表于 2023-7-28 21:36:14

JunSn 发表于 2023-7-28 16:55
嗯,谢谢硬汉哥,我试试。

先不优化试试。

Hzzz 发表于 2023-8-4 16:54:16

JunSn 发表于 2023-7-28 21:20
感谢硬汉哥,经过检查,发现是编译器的字节对齐不同造成的,因为我定义的全局数组是unsigned char类型的 ...

我没看懂,为什么数组起始地址没有四字节对齐会导致flash写操作异常。没有对齐,无非是cpu在取数据时会增加取数据时间啊。求解答

WuDiJiaYu 发表于 2023-8-24 21:02:34

Hzzz 发表于 2023-8-4 16:54
我没看懂,为什么数组起始地址没有四字节对齐会导致flash写操作异常。没有对齐,无非是cpu在取数据时会增 ...

我个人猜测哈 不一定对 STM32的一个地址对应的数据长度是32位的 所以有这个问题

会飞的猪_2020 发表于 2023-8-25 15:55:44

Hzzz 发表于 2023-8-4 16:54
我没看懂,为什么数组起始地址没有四字节对齐会导致flash写操作异常。没有对齐,无非是cpu在取数据时会增 ...

我之前也遇到一个很奇怪的问题。
F103的 可以用
uint16_t id = *(uint16_t *)(&data);
这种写法。。

但是到L051的时候,这个写法就会进入硬件错误。
只能这样写..
uint16_t id = (data << 8)|(data);
页: [1]
查看完整版本: STM32使用不同的编译器版本会造成FLASH读写出现HardFault