[英]STM32 USB Unreliable compilation with GCC '-Os'
我注意到我的軟件中有一些非常奇怪的行為。 實際上花了幾個月的時間來追蹤。
我使用 ST 的 USB 虛擬 COM 端口示例代碼作為我項目的一部分,偶爾生成的二進制文件在使用-Os
編譯時完全無法工作。 如果我改變了一些不相關的東西,那么它會突然恢復生機——並且在沒有-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。
那么 - 為什么 GCC 這樣做了,我該怎么做才能避免它呢? 顯然,在嵌入式系統上任意重新排序寄存器寫入是非常糟糕的消息。 在這種情況下,有沒有一種很好的方法可以解決它,有沒有辦法確保它不會在其他任何地方重新排序寫入?
謝謝!
我知道這是一篇舊帖子,但我想知道 wInterrupt_Mask 是如何聲明的? 它也被宣布為 volatile 嗎? 如果沒有,那是否會允許 GCC 任意重新排序?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.