专栏名称: 嵌入式微处理器
关注这个时代最火的嵌入式微处理器,你想知道的都在这里。
目录
相关文章推荐
汇易咨询  ·  JCI观察:2025年1月印度棕榈油进口创1 ... ·  2 天前  
BCG波士顿咨询  ·  借力AI,推动车企创造更多现实价值 ·  3 天前  
51好读  ›  专栏  ›  嵌入式微处理器

遇见一个编译优化导致的bug

嵌入式微处理器  · 公众号  ·  · 2024-06-24 14:47

正文

最近在调试 can 通信,因为 c8t6 flash 很小,而鱼鹰培训工程完成的驱动越来越多,导致 flash 不足,因此把 bsp 的优化级别设置成 -O2。然而,谁知道在串口输入数据时直接 hardfault 了:

进一步跟踪发现问题出在这条代码中:
uint32_t cnt = *(( uint32_t*)pinfo->pdma_cnt_rx); // 出错代码.....pinfo->last_dma_cnt = cnt;
这条代码最开始是这样:
uint16_t cnt = *(( uint16_t*)pinfo->pdma_cnt_rx);

因为我的 last_dma_cnt 变量是 16 bit,我想节省一下 ram 空间,因为实际上 DMA 的计数器也只使用了 16 bit。

uint16_t        last_dma_cnt;       // used in dma
但测试时发现出现 hardfault 了,通过汇编分析发现是非四字节对齐访问 dma 外设,后面通过修改代码,强制使用 32 bit 访问,就再也没出现问题了。
uint32_t cnt = *(( uint32_t*)pinfo->pdma_cnt_rx);

但昨天修改完编译优化级别后,又一次出现了,汇编分析发现还是对齐问题,因为 0x4002005c 这个地址确实是 DMA 的计数器地址。

只是再优化后,没按我的要求 32 bit 访问,而是自作主张使用 16 bit 访问,因为它发现 cnt 这个变量 操作 的地方都是 16 bit,想当然的给我在取值时也给我直接优化成 16 bit 访问。

这样一来,由于 DMA 不支持 2 字节访问指令,因此直接 hardfault 了。为了解决这个优化问题,可以直接使用 volatile 关键字,保证编译器在取值时按照 4 字节对齐访问,如下:
uint32_t cnt = *((volatile uint32_t*)pinfo->pdma_cnt_rx);  // must: volatile uint32_t汇编代码0x0800BCA6 6800      LDR      r0,[r0,#0x00]


完结撒花!

END

来源:鱼鹰谈单片机

版权归原作者所有,如有侵权,请联系删除

推荐阅读
一个风骚的C语言操作






请到「今天看啥」查看全文