STM32 USB使用GCC' -Os'进行不可靠的编译

时间:2014-11-28 15:43:41

标签: gcc arm usb volatile stm32

我注意到我的软件中有一些非常奇怪的行为。这几个月需要追踪。

我使用ST的USB虚拟COM端口示例代码作为我项目的一部分,偶尔生成的二进制文件在使用-Os进行编译时完全无法工作。如果我改变了一些不相关的东西,那么它会突然恢复生机 - 并且在没有-Os的情况下进行编译,一切都会完美无缺。

我将其跟踪到USB初始化代码,导致重复调用中断处理程序。代码是这样的:

#define     __IO    volatile  
#define RegBase  (0x40005C00L)  /* USB_IP Peripheral Registers base address */
#define CNTR    ((__IO unsigned *)(RegBase + 0x40))
#define ISTR    ((__IO unsigned *)(RegBase + 0x44))
#define _SetCNTR(wRegValue)  (*CNTR   = (uint16_t)wRegValue)
#define _SetISTR(wRegValue)  (*ISTR   = (uint16_t)wRegValue)

  _SetISTR(0); // Clear all pending interrupts
  wInterrupt_Mask = IMR_MSK; // 7168
  _SetCNTR(wInterrupt_Mask); // enable interrupts for WKUP/RESET/SUSP

这没关系,但是GCC(通过许多不同的版本,虽然目前是4.8.4)产生了这个代码:

r1 = 7168
r2 = 0x40005c44 (USB_ISTR)
r3 = 0x40005c40 (USB_CNTR)
r4 = 0
   14b42:   6019        str r1, [r3, #0]    ; USB_CNTR = 7168
   14b44:   490b        ldr r1, [pc, #44]   ; r1 = &wInterrupt_Mask
   14b46:   6014        str r4, [r2, #0]    <--------------- hangs here - USB_ISTR = 0 (USB_ISTR)

所以这些陈述是完全错误的顺序,它会搞砸一切。这两个寄存器甚至标记为易失!

即使我这样做了:

  _SetISTR(0); // Clear all pending interrupts
  _SetISTR(0);
  _SetISTR(0);
  _SetISTR(0);
  _SetISTR(0); // I really mean it GCC
  wInterrupt_Mask = IMR_MSK; // 7168
  _SetCNTR(wInterrupt_Mask); // enable interrupts for WKUP/RESET/SUSP

我明白了:

   12d60:   601c        str r4, [r3, #0]
   12d62:   6011        str r1, [r2, #0] ; CNTR
   12d64:   601c        str r4, [r3, #0]
   12d66:   601c        str r4, [r3, #0]
   12d68:   601c        str r4, [r3, #0]
   12d6a:   601c        str r4, [r3, #0]

因此,虽然它解决了这个问题,但GCC仍然以一种完全奇怪的方式重新排序写入(没有收益),而且我不能完全确定它不会决定先设置CNTR在未来的某个时刻。

那么 - 为什么海湾合作委员会这样做了,我该怎么做才能避免呢?显然,在嵌入式系统上任意重新排序寄存器写入是非常坏的消息。在这种情况下有没有一种很好的方法来修复它,有没有办法确保它不会在其他任何地方重新排序写入?

谢谢!

1 个答案:

答案 0 :(得分:-1)

我知道这是一篇老文章,但是我想知道wInterrupt_Mask是如何声明的?它也被声明为volatile吗?如果不能,那么这是否会使GCC对其进行重新排序?