STM32 USB与GCC不可靠编译'-操作系统&x27;

STM32 USB与GCC不可靠编译'-操作系统&x27;,gcc,arm,usb,volatile,stm32,Gcc,Arm,Usb,Volatile,Stm32,我注意到我的软件中有一些非常奇怪的行为。事实上花了好几个月才找到 我正在使用ST的USB虚拟COM端口示例代码作为我项目的一部分,有时生成的二进制文件在使用-Os编译时完全无法工作。如果我改变了一些不相关的东西,那么它会突然恢复生机——在没有-Os的情况下编译,一切都会完美地工作 我追踪到USB初始化代码,该代码导致中断处理程序被反复调用。代码如下: #define __IO volatile #define RegBase (0x40005C00L) /* USB_IP

我注意到我的软件中有一些非常奇怪的行为。事实上花了好几个月才找到

我正在使用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)
我明白了:

   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

那么-为什么GCC会这样做,我能做些什么来避免它?显然,在嵌入式系统上任意重新排序寄存器写入是一个非常坏的消息。在这种情况下,是否有一种很好的方法来修复它,是否有一种方法可以确保它不会在其他任何地方重新排序写入


谢谢

我知道这是一个老帖子,但我想知道wInterrupt\u面具是怎么宣布的?是否也被宣布为不稳定?如果没有,GCC是否可以随意重新排序?

我知道这是一篇老文章,但我想知道wInterrupt\u Mask是如何声明的?是否也被宣布为不稳定?如果没有,这会允许GCC任意地对其重新排序吗?

Ok,那么您似乎可以添加
asm volatile(“:”内存”)写之间,但我还是不明白。另一个post声明“禁止GCC对易失性负载进行重新排序,并禁止存储相互之间的内存访问”,所以这可能是一个编译器错误吗?请参阅。就我个人而言,我真的不确定“C”标准狂热者会怎么说。也许他们会争论几天,而你却没有明确的答案。注意:
volatile unsigned*
unsigned*volatile
不同。如果能看到那篇关于恶魔般细节的帖子,那就太好了。为什么不设置障碍并继续前进?您确定您的代码中没有类似于
#define volatile/*nothing*/
的内容吗?在使用GCC和操作系统优化的最后几年中,我从未经历过您描述的这种行为。ST的代码通常都是一派胡言,所以如果他们在他们的魔法宏中弄错了什么,我也不会感到惊讶。我甚至把你的代码拿去测试了,很明显,它完全按照预期工作,0的所有存储都在7168(优化操作系统)的存储之前。别误会,我通常每个月都会看到有人声称在编译器中发现了几次bug,而在过去的几年里,这些发现中的每一个都是“PEBKAC”,而不是GCC的错。。。永远。进一步注意(我并不是故意刁难):这就是为什么这个问题很重要。它将一个特定的构建环境置于上下文之外,如果无法生成一个环境,那么罪魁祸首就已经被找到了……好吧,看来您可以添加
asm volatile(“:”内存”)写之间,但我还是不明白。另一个post声明“禁止GCC对易失性负载进行重新排序,并禁止存储相互之间的内存访问”,所以这可能是一个编译器错误吗?请参阅。就我个人而言,我真的不确定“C”标准狂热者会怎么说。也许他们会争论几天,而你却没有明确的答案。注意:
volatile unsigned*
unsigned*volatile
不同。如果能看到那篇关于恶魔般细节的帖子,那就太好了。为什么不设置障碍并继续前进?您确定您的代码中没有类似于
#define volatile/*nothing*/
的内容吗?在使用GCC和操作系统优化的最后几年中,我从未经历过您描述的这种行为。ST的代码通常都是一派胡言,所以如果他们在他们的魔法宏中弄错了什么,我也不会感到惊讶。我甚至把你的代码拿去测试了,很明显,它完全按照预期工作,0的所有存储都在7168(优化操作系统)的存储之前。别误会,我通常每个月都会看到有人声称在编译器中发现了几次bug,而在过去的几年里,这些发现中的每一个都是“PEBKAC”,而不是GCC的错。。。永远。进一步注意(我并不是故意刁难):这就是为什么这个问题很重要。它会断章取义地使用特定的构建环境,如果未能生成环境,那么罪魁祸首刚刚被发现……这不是答案。这不是答案。
   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]