Im Treiber habe ich eine Funktion zum Kopieren der Daten aus der internen Struktur in eine Struktur aus der Anwendung.
Kann dieser Prozess durch einen Mikrocontroller-Interrupt-Trigger unterbrochen werden?
uint16_t getRawData(struct Data *Data_external)
{
if(Data_external == NULL)
{
return ERR_PARA;
}
else
{
*Data_external = Data_internal; // the copy process. Could this be interrupted?
}
return ERR_NONE;
}
microcontroller
c
embedded
interrupts
Stani
quelle
quelle
Antworten:
Ja. So ziemlich alles in einer MCU kann durch eine Interrupt-Anfrage unterbrochen werden. Wenn der Interrupt-Handler abgeschlossen ist, wird der vorherige Code einfach fortgesetzt, sodass dies normalerweise kein Problem darstellt.
In einem speziellen Fall können die Interrupt-Handler selbst durch Interrupts höherer Priorität (verschachtelte Interrupts) unterbrochen werden.
Wenn eine Reihe von Anweisungen nicht unterbrochen werden darf, müssen Sie einen kritischen Abschnitt implementieren (Interrupts grundsätzlich global deaktivieren, den Job ausführen, erneut aktivieren).
Denken Sie daran, dass abhängig von der Architektur der Ziel-CPU eine einzelne Zeile von C zu vielen Montageanweisungen kompiliert werden kann. Ein einfacher
i++
auf einem AVR ist mit mehreren Anweisungen kompiliert , wenni
beispielsweise istuint32_t
.quelle
Jede Operation, die nicht atomar ist, kann durch einen Interrupt gestört werden. Diese Art der Programmierung unterscheidet sich häufig stark von den meisten anderen Programmen und kann für Personen verwirrend sein, die weder Prozessordesign noch Computerarchitektur studiert haben.
Sie denken sich vielleicht: "Dies wird eigentlich nie passieren, wie lange dauert das Kopieren dieses Codes und wie wahrscheinlich ist eine Unterbrechung?" Bei den meisten Embedded-Anwendungen für die Produktion ist dies jedoch der Fall, da das Produkt jahrelang ohne Updates läuft.
Das andere Problem bei solchen Strukturkopien ist, dass sie außerordentlich schwer zu debuggen sind, wenn sie auftreten, da sie nur dann auftreten, wenn der Interrupt genau zum richtigen Zeitpunkt auftritt (der nur einen Zyklus betragen kann).
quelle
Der springende Punkt bei Interrupts ist, dass sie jederzeit auftreten können (und dies auch tun) und so konzipiert sind, dass sie keinen Einfluss auf Code haben, der gerade ausgeführt wird, wenn sie auftreten. Alle Register werden gespeichert, und abhängig von der CPU-Architektur kann ein völlig anderer Registersatz ausgetauscht werden, der Interrupt erledigt seine Aufgabe, und dann werden die ursprünglichen Register wiederhergestellt und der Code läuft wie gewohnt weiter.
Probleme können auftreten, wenn die Interrupt-Serviceroutine selbst versucht, auf den Speicher zuzugreifen, auf den der laufende, unterbrochene Code zugreift. Noch subtilere Fehler können auftreten, wenn ein zeitkritischer E / A-Prozess unterbrochen wird. Diese Probleme treten häufig bei älteren, einfacheren und weniger sicheren Architekturen auf, bei denen möglicherweise nur eine geringe Trennung zwischen dem Moduscode "Benutzer" und "Supervisor / Kernel" besteht.
Diese Art von Problem kann schwer zu identifizieren und oft schwer zu reproduzieren sein, aber wenn sie einmal identifiziert sind, sind sie oft ziemlich trivial, um sie mit defensiver Programmierung, Mutexen / Semaphoren oder einfach durch Deaktivieren von Interrupts in kritischen Codeabschnitten zu beheben.
Die allgemeine Klasse von Problemen wurde ausführlich untersucht, und moderne Mehrkern-CPUs und sogar Multitasking-Betriebssysteme wären nicht möglich, wenn nicht bereits mehrere Lösungen erprobt und getestet worden wären.
quelle
Ich gehe einfach davon aus, dass Sie dies aus einem sehr guten Grund gefragt haben.
Kann aufgeteilt werden (mit Ausnahme einiger Randfälle, die hier wahrscheinlich nicht im Spiel sind).
Ich kenne Ihre CPU nicht, aber ich habe noch keine CPU gesehen, die nicht das moralische Äquivalent von:
Jetzt kann es nicht auf eine einzelne Kern-CPU aufgeteilt werden, da nichts unterbrochen werden kann, während die Interrupts ausgeschaltet sind. Ob dies eine gute Idee ist oder nicht, hängt von vielen Dingen ab, für deren Bewertung ich einfach nicht qualifiziert bin.
Wenn Sie Multi-Core sind (und ich erinnerte mich schließlich, dass es eine Multi-Core-Embedded-CPU auf dem Markt gibt), tun Sie dies nicht. Es ist wertlos. Sie müssten eine ordnungsgemäße Verriegelung entwickeln.
quelle
Der Code, wie Sie ihn präsentiert haben, kann tatsächlich unterbrochen werden. Bevor Sie jedoch anfangen, überall kritische Abschnitte zu erstellen, sollten Sie einige Dinge überprüfen:
Sie sagen, diese Funktion befindet sich "in einem Treiber". Sind Interrupts bereits deaktiviert, wenn diese Funktion aufgerufen wird? Oder wird es in einem Interrupt-Handler aufgerufen, der verhindert, dass andere Interrupts ausgelöst werden? Wenn ja, kann der Vorgang tatsächlich nicht unterbrochen werden.
Wird
Data_internal
jemals in einem Interrupt-Handler zugegriffen? Wenn nicht, liegt kein Schaden vor, auch wenn der Betrieb unterbrochen werden kann.quelle
[Nicht genug Vertreter, um einen Kommentar abzugeben]
Ein weiteres Problem mit dieser Art von Strukturkopie ist, dass es sich um eine flache Kopie handelt . Möglicherweise benötigen Sie stattdessen eine tiefe Kopie.
Eine flache Kopie kann je nach Maschinenarchitektur möglicherweise, aber wahrscheinlich nicht atomar sein. Eine tiefe Kopie ist mit ziemlicher Sicherheit in keiner Architektur atomar.
quelle
Eine Qualitätsimplementierung, die für die Verwendung eingebetteter Systeme geeignet ist, dokumentiert, wie qualifizierte
volatile
Lese- oder Schreibvorgänge verschiedener Typen ausreichend detailliert ausgeführt werden, um anzugeben, ob und wie sie durch Interrupts "aufgeteilt" werden können und ob flüchtige Lese- und Schreibvorgänge sind oder nicht sequenziert in Bezug auf nicht qualifizierte Lese- und Schreibvorgänge. Während sich einige Implementierungen möglicherweise so verhalten, als wären allevolatile
Lese- und Schreibvorgänge qualifiziert, wird von Implementierungen im Allgemeinen erwartet, dass sie Sequenzen nicht qualifizierter Lese- und Schreibvorgänge auf die Weise verarbeiten können, die am effizientesten wäre, wenn keine dazwischenliegendenvolatile
Zugriffe vorliegen.Liest und schreibt auf einem typischen 32-Bit-Mikrocontroller von
volatile
qualifizierten Ganzzahltypen, die 32 Bit und kleiner sind; Eine Zuweisung besteht aus einem atomaren Lesen, gefolgt von einem atomaren Schreiben. Wenn Sie sicherstellen möchten, dass eine 32-Bit-Struktur atomar kopiert wird, platzieren Sie sie in einer Vereinigung mit auint32_t
und lesen oder schreiben Sie dieses Element, um die Struktur als Ganzes zu lesen oder zu schreiben. Qualitätsimplementierungen, die so konfiguriert sind, dass sie für die Verwendung eingebetteter Systeme geeignet sind, ermöglichen es Gewerkschaften, auf diese Weise eingesetzt zu werden, ohne zu berücksichtigen, ob der Standard Implementierungen erfordern würde, die nicht für eine solche Verwendung vorgesehen sind. Beachten Sie, dass sich gcc und clang nicht zuverlässig als Qualitätsimplementierungen verhalten, die für die Verwendung eingebetteter Systeme geeignet sind, es sei denn, verschiedene Optimierungen sind deaktiviert.quelle