加入星计划,您可以享受以下权益:

  • 创作内容快速变现
  • 行业影响力扩散
  • 作品版权保护
  • 300W+ 专业用户
  • 1.5W+ 优质创作者
  • 5000+ 长期合作伙伴
立即加入
  • 正文
  • 推荐器件
  • 相关推荐
  • 电子产业图谱
申请入驻 产业图谱

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

06/12 10:00
812
阅读需 3 分钟
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

来源:公众号【鱼鹰谈单片机】,作者:鱼鹰Osprey,ID   :emOsprey

最近在调试 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]

完结撒花!

推荐器件

更多器件
器件型号 数量 器件厂商 器件描述 数据手册 ECAD模型 风险等级 参考价格 更多信息
AT24C16D-SSHM-B 1 Atmel Corporation EEPROM, 2KX8, Serial, CMOS, PDSO8, 0.150 INCH, GREEN, PLASTIC, MS-012AA, SOIC-8
$0.3 查看
74LVTH125MTCX 1 Fairchild Semiconductor Corporation Bus Driver, LVT Series, 4-Func, 1-Bit, True Output, BICMOS, PDSO14, 4.40 MM, LEAD FREE, MO-153AB, TSSOP-14
$0.56 查看
ABS07-32.768KHZ-4-T 1 Abracon Corporation CRYSTAL 32.7680KHZ 12.5PF SMD

ECAD模型

下载ECAD模型
$1.36 查看

相关推荐

电子产业图谱

六年开发经验,丰富的KEIL调试经验,STM32使用经验,C语言运用经验。