硬汉嵌入式论坛

 找回密码
 立即注册
查看: 766|回复: 9
收起左侧

[技术讨论] STM32使用不同的编译器版本会造成FLASH读写出现HardFault

[复制链接]
回帖奖励 5 个金币 回复本帖可获得 5 个金币奖励! 每人限 1 次

2

主题

6

回帖

12

积分

新手上路

积分
12
发表于 2023-7-27 21:41:50 | 显示全部楼层 |阅读模式
硬汉大哥以及论坛里的各位大佬,本人最近在用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[20480] = {1}, 此时Bootloader程序烧录后工作正常,APP也成功跳转;
记录bootloader程序编译结果:
11.png
记录buf数组地址大小以及堆栈指针:
12.png
现象2:采用AC6编译器,优化等级为-O1,但是此时将全局数组buf初始化设置为uint8 buf[20480] = {0} (!!!注意是0,因此将会归类到ZI-DATA中), 此时Bootloader程序烧录后工作不正常,程序卡死在FLASH读写中并跳转到HardFault中;
记录buf初始化操作(后面写法类似):
19.png
记录bootloader编译结果:
14.png
记录buf数组地址大小和堆栈指针:
15.png
记录Fault reports:
16.png
现象3:采用AC5编译器,优化等级为-O1,但是此时将全局数组buf初始化设置为uint8 buf[20480] = {1} (!!!注意改成1,因此将会归类到RW-DATA中), 此时Bootloader程序烧录后工作不正常,程序卡死在FLASH读写中并跳转到HardFault中;
记录bootloader编译结果:
17.png
记录buf数组地址大小和堆栈指针:
18.png
记录Fault reports:

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


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

13.png
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106739
QQ
发表于 2023-7-28 09:31:16 | 显示全部楼层

回帖奖励 +5 个金币

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

使用道具 举报

210

主题

1043

回帖

1683

积分

至尊会员

More we do, more we can do.

积分
1683
发表于 2023-7-28 09:45:42 | 显示全部楼层

回帖奖励 +5 个金币

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

使用道具 举报

2

主题

6

回帖

12

积分

新手上路

积分
12
 楼主| 发表于 2023-7-28 16:52:44 | 显示全部楼层
emwin 发表于 2023-7-28 09:45
看描述你已经找到问题函数了,进一步调试不行吗,全速才异常?

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

使用道具 举报

2

主题

6

回帖

12

积分

新手上路

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

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

使用道具 举报

2

主题

6

回帖

12

积分

新手上路

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

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

使用道具 举报

0

主题

26

回帖

26

积分

新手上路

积分
26
发表于 2023-7-28 21:36:14 | 显示全部楼层
JunSn 发表于 2023-7-28 16:55
嗯,谢谢硬汉哥,我试试。

先不优化试试。
回复

使用道具 举报

13

主题

52

回帖

91

积分

初级会员

积分
91
发表于 2023-8-4 16:54:16 | 显示全部楼层
JunSn 发表于 2023-7-28 21:20
感谢硬汉哥,经过检查,发现是编译器的字节对齐不同造成的,因为我定义的全局数组是unsigned char类型的 ...

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

使用道具 举报

0

主题

1

回帖

1

积分

新手上路

积分
1
发表于 2023-8-24 21:02:34 | 显示全部楼层
Hzzz 发表于 2023-8-4 16:54
我没看懂,为什么数组起始地址没有四字节对齐会导致flash写操作异常。没有对齐,无非是cpu在取数据时会增 ...

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

使用道具 举报

39

主题

196

回帖

323

积分

高级会员

积分
323
发表于 2023-8-25 15:55:44 | 显示全部楼层
Hzzz 发表于 2023-8-4 16:54
我没看懂,为什么数组起始地址没有四字节对齐会导致flash写操作异常。没有对齐,无非是cpu在取数据时会增 ...

我之前也遇到一个很奇怪的问题。
F103的 可以用
[C] 纯文本查看 复制代码
uint16_t id = *(uint16_t *)(&data[1]);

这种写法。。

但是到L051的时候,这个写法就会进入硬件错误。
只能这样写..
[C] 纯文本查看 复制代码
uint16_t id = (data[0] << 8)|(data[1]);
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-3 12:25 , Processed in 0.319260 second(s), 30 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表