2014-10-20 55 views
6

我在AVR32上有一箇中斷服務路由。我需要從中斷狀態寄存器讀取以取消中斷。但是我不使用讀取的結果。我寧願不使用asm指令,但我擔心gcc會優化讀取虛擬變量。什麼是正確的方式?如何使用C/gcc從外設IO寄存器讀取數據?

目前我有:

uint32_t tmp = *(volatile uint32_t *)INTERRUPT_STATUS_REG_ADDRESS; 

也應該tmp下揮發?我擔心如果不使用tmp,gcc會跳過讀取。

+0

我不熟悉的AVR32,但是你確定你要讀中斷狀態寄存器?根據我的經驗,您只需清除相應寄存器中的單箇中斷標誌(通常通過向相應位寫入1來完成)。另外,你的用例是什麼? – 2014-10-21 08:13:48

+0

是的,它只是讀取PWM比較狀態寄存器以清除IRQ。 'uint32_t temp = AVR32_PWM.isr2;' – Robotbugs 2014-10-22 06:22:21

回答

6

讀取中斷狀態通過指針寄存器澆鑄到(易失性uint32_t的*)告訴編譯器,閱讀這個表達式(變量在指定的地址)產生的副作用,所以它總是需要評估這個表達式。

作爲你的TMP變量不揮發,編譯器就可以優化掉存儲你的寄存器變量的值。

我認爲C標準(see here)的章節5.1.2.3是不太相關。

此外章節6.7.3說明:

具有volatile限定類型的對象可以在方式未知的 實現或具有其他未知的副作用被修改。因此參照 於這樣的對象的任何表達式,應根據抽象機, 如5.1.2.3中描述的規則嚴格評價。此外,在每一個順序點的值最後存儲在 對象應與由抽象機規定的同意,除由前述的 未知因素修改。 116) 具有volatile限定類型的對象的訪問權限由實現定義。

實際上,你可以忽略tmp和只寫:

*(volatile uint32_t *)INTERRUPT_STATUS_REG_ADDRESS; 

這將簡單地讀取寄存器uint32_t的位於INTERRUPT_STATUS_REG_ADDRESS;

+0

謝謝,這看起來很奇怪,看起來像這樣的一段代碼。我真的不確定這樣的事情可以發揮作用。 – Robotbugs 2014-10-22 06:19:41

+1

是的,它看起來很奇怪,所以至少用一個具有解釋性名稱的宏或函數來讀取外設寄存器可能很好。 – dbrank0 2014-10-22 06:28:01