Mutex in Interrupts

7

Was ist für einen kleinen Mikrocontroller ohne Betriebssystem der richtige Weg, um Daten zwischen verschiedenen Interrupts und der Hauptschleife auszutauschen?

Mit einem Betriebssystem kann man einfach einen Mutex für jeden kritischen Teil erstellen und weitermachen, und der Scheduler wechselt beispielsweise zwischen Aufgaben.

Wenn ein Mutex in einem Interrupt verwendet wird, wird er nur für immer gesperrt, sodass dies offensichtlich nicht funktionieren kann.

Ein einfacher Ansatz, den ich mir vorstellen kann, besteht darin, Kopien der Variablen in einer Tabelle zu haben und beim Ändern ein Flag für jede geänderte Variable zu setzen. Kopieren Sie dann in der Hauptschleife durch Deaktivieren von Interrupts die Kopien in die Hauptvariablen und umgekehrt (mit einem Prioritätssystem für den Fall, dass zwei oder mehr geändert wurden). Dies würde einige Zeit dauern und sollte aber funktionieren.

Carlos
quelle

Antworten:

9

Es gibt verschiedene Möglichkeiten:

  1. Machen Sie jeden Status klein genug, um von der Hardware atomar aktualisiert zu werden. Wenn Sie sich beispielsweise auf einem 16-Bit-Computer befinden (z. B. einem Microchip-dsPIC), darf jeder gemeinsam genutzte Status nicht mehr als 16 Bit betragen.

  2. Verwenden Sie FIFOs zwischen Interrupt- und Vordergrundcode. Es gibt Möglichkeiten, FIFOs so zu gestalten, dass kein Mutex benötigt wird, aber Vordergrund- und Interrupt-Code können jederzeit auf ihre Enden zugreifen.

  3. Lassen Sie den Vordergrundcode Interrupts für den Zugriff auf wichtige gemeinsam genutzte Daten, die nicht atomar aktualisiert werden, vorübergehend ausschalten.

Olin Lathrop
quelle
8

In meinen MCU-Programmen (Atmel, PIC, ARM) verwende ich:

disable interrupts
critical action
enable interrupts

Meine kritischen Handlungen sind von sehr kurzer Dauer. Die meisten von ihnen sind vom Typ: var = var +/- 1;

Beachten Sie, dass Sie das oben beschriebene System verwenden können, um Ihre eigenen Mutexe zu erstellen.

Alter Furz
quelle
1
Ja, aber im Idealfall gibt es eine große Schleife, die Daten aus dem Interrupt verwendet, und der Interrupt, der die Daten im laufenden Betrieb ändert, sollte die Schleife erst bei der nächsten Iteration beeinflussen. Es ist zu verschwenderisch, die gesamte Schleife in den kritischen Bereich zu setzen.
Carlos
Ich würde mehr Details brauchen, aber es gibt normalerweise eine Lösung. Nur der Ort, an dem Sie allgemeine Variablen berühren, benötigt einen kritischen Abschnitt. Oder Sie können Puffer zur exklusiven Verwendung weitergeben. Wie gesagt, Sie können mit dieser Methode auch einen Mutex erstellen. Der Claim / Free Mutex-Code ist der einzige Ort, an dem Interrupts deaktiviert sind. Dies kann mit einer oder zwei Codezeilen erfolgen.
Oldfart
Ich denke allgemein. In diesem Fall gibt es eine Hauptschleife mit einer Reihe von Variablen, die groß ist und langsame Operationen ausführt. Es gibt n Interrupts, die eine beliebige Anzahl von Variablen haben, die von der Hauptschleife gemeinsam genutzt werden, und höchstwahrscheinlich kollidieren die Variablen nicht (zum Beispiel hat Interrupt 1 die Variablen a, b, c und Interrupt 2 d, e, f, aber nicht a, b, c auch). Ich denke, Interrupts können Elemente hinzufügen, die an einer Warteschlange geändert werden. Am Ende der Hauptschleifenaktualisierung werden zuerst die Hauptschleifenvariablen aus der Warteschlange und dann die Interruptkopien aus der Hauptschleife aktualisiert.
Carlos
Wenn die kritische Aktion wirklich nur das Inkrementieren oder Dekrementieren eines Zählers ist, müssen Sie auf den meisten Computern überhaupt keine Interrupts deaktivieren. Die meisten haben die Möglichkeit, ein atomares Inkrement oder Dekrement durchzuführen. Bei PIC 16 und PIC 18 würde dies beispielsweise mit den Anweisungen INCF und DECF erfolgen.
Olin Lathrop