STM32 USB与GCC不可靠编译'-操作系统&x27;
我注意到我的软件中有一些非常奇怪的行为。事实上花了好几个月才找到 我正在使用ST的USB虚拟COM端口示例代码作为我项目的一部分,有时生成的二进制文件在使用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
-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]