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

Comprendo che più attività possono tentare di utilizzare la risorsa SPI. spiTxRxByteCount è una variabile globale utilizzata per tenere traccia di se l'SPI è attualmente in uso da un'altra attività. Quando un'attività richiede lo SPI, è possibile controllare lo stato di spiTxRxByteCount per verificare se viene utilizzato SPI. Quando un'operazione viene eseguita utilizzando l'SPI, chiama questa funzione e cancella il bit, per indicare che l'SPI è ora libero. Ma perché disabilitare prima gli interrupt e poi riattivarli dopo? Solo paranoia?Perché la disattivazione degli interrupt è necessaria qui?

+0

Se si dispone di un RTOS, perché non utilizzare un mutex? –

+0

@ [Operazione di semaforo implementata in questo modo in ambiente operativo] (http://www.mpi-sws.org/~druschel/courses/os/lectures/proc4.pdf) –

risposta

14

Il & = eseguirà un'operazione di lettura-modifica-scrittura, non è atomico. Non si desidera che un interrupt modifichi le cose nel mezzo, causando la sovrascrittura della scrittura con un valore errato.

8

È necessario disattivare gli interrupt per garantire l'accesso atomico. Non vuoi che nessun altro processo acceda e potenzialmente modifichi quella variabile mentre la stai leggendo.

Da Introduction to Embedded Computing:

la necessità di accesso atomica

Immaginate questo scenario: programma in primo piano, in esecuzione su un 8-bit uC, necessità di esaminare una variabile a 16 bit, lo chiamano X Quindi carica il byte alto e quindi carica il byte basso (o viceversa, l'ordine non ha importanza), quindi esamina il valore a 16 bit. Ora immagina un interrupt con un ISR associato che modifica quella variabile a 16 bit. Inoltre, immagina che il valore della variabile sia 0x1234 a in un dato momento nell'esecuzione del programma. Qui è la cosa molto brutta che può accadere:

  • carichi in primo piano byte alto (0x12)
  • ISR si verifica, modifica X per 0xABCD
  • carichi di primo piano byte basso (0xCD)
  • programma in primo piano vede un valore a 16 bit di 0x12CD.

Il problema è che un pezzo apparentemente inscindibile di dati, il nostro variabili X, è stato effettivamente modificato nel processo di accedervi, perché le istruzioni della CPU di accedere alla variabile erano divisibili. E quindi il nostro carico della variabile X è stato corrotto. Puoi vedere che l'ordine della variabile letto non ha importanza. Se l'ordine fosse invertito nel nostro esempio, la variabile sarebbe stata erroneamente letta come 0xAB34 invece di 0x12CD. In entrambi i casi, il valore letto non è né il vecchio valore valido (0x1234) né il nuovo valore valido (0xABCD).

La scrittura di dati con riferimento ISR non è migliore. Questa volta supponiamo che il programma in primo piano abbia scritto, a beneficio dell'ISR, il valore precedente 0x1234 , e quindi debba scrivere un nuovo valore 0xABCD.In questo caso, la VBT è la seguente:

  • negozi di primo piano nuovo massimo di byte (0xAB)
  • ISR si verifica, si legge X come 0xAB34
  • negozi in primo piano nuovo byte basso (0xCD)

Ancora una volta il codice (questa volta l'ISR) non visualizza né il valore valido di 0x1234, né il nuovo valore valido di 0xABCD, ma piuttosto il valore non valido di 0xAB34.

Mentre spiTxRxByteCount &= ~0x0100; può sembrare una singola istruzione in C, in realtà sono diverse istruzioni per la CPU. Compilato nel GCC, la quotazione di montaggio si presenta in questo modo:

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 

Se un interrupt arriva nel mezzo di dette istruzioni e modifica dei dati, il vostro primo ISR può potenzialmente leggere il valore errato. Quindi è necessario disabilitare gli interrupt prima di operare su di esso e dichiarare anche la variabile volatile.

Problemi correlati