2012-11-28 29 views
7
static void RadioReleaseSPI(void) { 
    __disable_interrupt(); 
    spiTxRxByteCount &= ~0x0100; 
    __enable_interrupt(); 
} 

我知道多個任務可能會嘗試使用SPI資源。 spiTxRxByteCount是一個全局變量,用於跟蹤SPI當前是否正在被另一個任務使用。當任務需要SPI時,它可以檢查spiTxRxByteCount的狀態以查看是否正在使用SPI。當一個任務完成使用SPI時,它會調用該函數並清除該位,以表明SPI現在是空閒的。但爲什麼先禁用中斷,然後重新啓用它們呢?只是偏執狂?爲什麼要在這裏禁用中斷?

+0

如果你有一個RTOS,爲什麼不使用互斥鎖? –

+0

@ [在OS下以這種方式實現的信號量操作](http://www.mpi-sws.org/~druschel/courses/os/lectures/proc4.pdf) –

回答

14

& =將執行讀取 - 修改 - 寫入操作 - 它不是原子的。您不希望中斷在中間改變事物,導致寫入重寫的值不正確。

8

您需要禁用中斷以確保原子訪問。您不希望任何其他進程在您閱讀時訪問並可能修改該變量。

Introduction to Embedded Computing

原子訪問的需要

想象一下這樣的情景:前臺程序,在8位UC, 需要運行檢查一個16位的變量,稱之爲X 。因此它加載高字節,然後加載低字節(或者反過來, 命令無關緊要),然後檢查16位值。現在想象一下帶有相關ISR的 中斷,該中斷修改了這個16位變量。 進一步想象一下,在程序執行過程中給定的時間,變量的值碰巧是0x1234的 。這裏是非常糟糕的事情 可能發生:

  • 前景負荷高字節(0×12)
  • ISR發生時,修改X到0xABCD
  • 前景負荷低字節(0XCD)
  • 前臺程序見一個16位的0x12CD值。

的問題是,一個所謂不可分割一塊數據,我們 變量X,在訪問它, 因爲CPU的指令來訪問變量是除盡的過程實際上修改。 因此我們的變量X的負載已被破壞。你可以看到 變量的讀取順序無關緊要。如果在我們的示例中,訂單爲 ,則該變量將被錯誤地讀爲0xAB34而不是0x12CD,因此將 錯誤地讀取。無論哪種方式,讀取的值既不是 舊的有效值(0x1234)也不是新的有效值(0xABCD)。

編寫ISR參考數據並不好。這次假定 前臺程序爲了ISR的利益編寫了 先前的值0x1234,然後需要寫入新的值0xABCD。在 這種情況下,VBT如下:

  • 前景存儲新高字節(是0xAB)
  • ISR發生時,讀出X作爲0xAB34
  • 前景存儲新低字節(0XCD)

代碼(這次是ISR)再次看到既沒有 有效值0x1234,也沒有看到新的有效值0xABCD,而是 的無效值0xAB34。

雖然spiTxRxByteCount &= ~0x0100;看起來像C中的單個指令,但它實際上是對CPU的幾條指令。在GCC編譯時,彙編列表看起來像這樣:

57:atomic.c  ****  spiTxRxByteCount &= ~0x0100; 
    68     .loc 1 57 0 
    69 004d A1000000  movl _spiTxRxByteCount, %eax 
    69  00 
    70 0052 80E4FE  andb $254, %ah 
    71 0055 A3000000  movl %eax, _spiTxRxByteCount 
    71  00 

如果中斷是在兩者之間的任何這些指令並修改數據時,你的第一個ISR可以潛在讀取錯誤的值。因此,在對其進行操作之前,需要禁用中斷,並聲明變量volatile