Ich verstehe, dass mehrere Aufgaben möglicherweise versuchen, die SPI-Ressource zu verwenden. spiTxRxByteCount
ist eine globale Variable, die verfolgt, ob der SPI gerade von einer anderen Task verwendet wird. Wenn ein Task den SPI benötigt, kann er den Status von spiTxRxByteCount
prüfen, um zu sehen, ob der SPI verwendet wird. Wenn eine Task mit dem SPI ausgeführt wird, ruft sie diese Funktion auf und löscht das Bit, um anzuzeigen, dass der SPI nun frei ist. Aber warum zuerst die Interrupts deaktivieren und danach wieder aktivieren? Nur Paranoia?
Sie müssen Interrupts deaktivieren, um atomaren Zugriff zu gewährleisten. Sie möchten nicht, dass ein anderer Prozess auf diese Variable zugreift und sie möglicherweise ändert, während Sie sie lesen.
Aus Einführung in Embedded Computing :
Die Notwendigkeit für den atomaren Zugriff
Stellen Sie sich dieses Szenario vor: Vordergrundprogramm, das auf einem 8-Bit-μC läuft, muss eine 16-Bit-Variable untersuchen, nennen Sie es X. So lädt es das Hoch Byte und lädt dann das Low-Byte (oder umgekehrt, die Reihenfolge spielt keine Rolle) und untersucht dann den 16-Bit-Wert. Nun stell dir ein Interrupt mit einem zugeordneten ISR, der diese 16-Bit-Variable modifiziert. Stellen Sie sich vor, dass der Wert der Variablen 0x1234 bei ist eine bestimmte Zeit in der Programmausführung. Hier ist die sehr schlechte Sache das kann passieren:
- Vordergrund lädt hohes Byte (0x12)
- ISR tritt auf, ändert X zu 0xABCD
- Vordergrund lädt Low-Byte (0xCD)
- Vordergrundprogramm sieht einen 16-Bit-Wert von 0x12CD.
Das Problem ist, dass ein vermeintlich unteilbares Datenstück, unser Variable X, wurde tatsächlich in den Prozess des Zugriffs geändert, weil die CPU-Anweisungen für den Zugriff auf die Variable teilbar waren. Und so wurde unsere Ladung der Variablen X beschädigt. Sie können sehen, dass Die Reihenfolge der gelesenen Variablen spielt keine Rolle. Wenn die Bestellung war Umgekehrt in unserem Beispiel wäre die Variable falsch gelesen worden als 0xAB34 anstelle von 0x12CD. In beiden Fällen ist der gelesene Wert keines der alte gültige Wert (0x1234) noch der neue gültige Wert (0xABCD).
Das Schreiben von ISR-referenzierten Daten ist nicht besser. Diesmal nehmen wir an, dass Im Vordergrund des Programms steht für die ISR die vorheriger Wert 0x1234 und muss dann einen neuen Wert 0xABCD schreiben. Im In diesem Fall ist die VBT wie folgt:
- Vordergrund speichert neues High-Byte (0xAB)
- ISR tritt auf, liest X als 0xAB34
- Vordergrund speichert neues Low-Byte (0xCD)
Noch einmal sieht der Code (diesmal die ISR) weder das vorherige noch gültiger Wert von 0x1234, noch der neue gültige Wert von 0xABCD, sondern der ungültige Wert von 0xAB34.
Während spiTxRxByteCount &= ~0x0100;
in C wie eine einzelne Anweisung aussehen kann, sind es tatsächlich mehrere Anweisungen an die CPU. In GCC zusammengestellt, sieht das Assembly-Listing so aus:
Wenn zwischen diesen Anweisungen ein Interrupt auftritt und die Daten ändert, kann Ihr erster ISR möglicherweise den falschen Wert lesen. Daher müssen Sie Interrupts deaktivieren, bevor Sie daran arbeiten, und außerdem die Variable volatile
deklarieren.