Dies ist für die Erfahreneren da draußen.
Ich bin derzeit an einem großen AVR-Projekt beteiligt (mit ATMega328) und es wird in Bezug auf Interrupts verwirrend.
Das Projekt beinhaltet Interrupts aus den folgenden Quellen
Bei so vielen Interrupt-Quellen und der Tatsache, dass globale Interrupts deaktiviert werden, wenn ein ISR ausgeführt wird, habe ich Angst, Interrupts zu verpassen, die ausgelöst werden könnten, wenn mein Code einen anderen Interrupt bedient.
Gibt es also eine strukturiertere Methode zur Verwaltung von Interrupts in einem großen Projekt?
Die erste Regel bei der Verwendung von Interrupts: Halte sie sehr kurz.
Wenn ein Interrupt auftritt, wird unabhängig davon, ob er aktiviert ist oder nicht und ob er gerade einen Interrupt bedient oder nicht, ein Interrupt Fired-Flag gesetzt. Jedem Interrupt ist eines dieser Flags zugeordnet (z. B. SPSR.SPIF). Das wird immer gesetzt, sobald der Interrupt feuert.
Das Interrupt-System durchläuft dann zyklisch die Interrupts und sucht nach gesetzten Interrupt-Flags, und wenn der Interrupt freigegeben ist, springt es dann zur ISR.
Dies geschieht unabhängig davon, wie lange der Interrupt zurückliegt.
Die Frage ist also nicht "werde ich einen Interrupt verpassen, weil ich in einer ISR bin", sondern "werde ich aufeinanderfolgende Interrupts verpassen, weil ich in einer ISR bin".
Zuerst müssen Sie also die maximale Rate berechnen, mit der ein Interrupt von einer Quelle auftreten kann.
Dann überprüfen Sie Ihre ISR-Routinen und stellen sicher, dass sie diese minimale Interrupt-Periode nie überschreiten. Erwägen Sie, Code aus einer ISR zu verschieben und stattdessen Flags zu setzen, damit Ihre Hauptschleife stattdessen Operationen ausführt.
In einer komplexeren Umgebung (5 Interrupts sind NICHT viel!) können Sie, wenn die Ressourcen dies zulassen, die Erstellung einer Interrupt-Ereigniswarteschlange in Betracht ziehen, in der ein Ereignis zu einer Liste eingehender Ereignisse hinzugefügt wird, wenn der Interrupt auftritt, und Ihre Hauptschleife ist dann frei um diese Ereignisse der Reihe nach zu verarbeiten. Möglicherweise müssen Sie Warteschlangen mit unterschiedlichen Prioritäten für unterschiedliche Interrupts verwenden.
Das ist auf einer kleinen MCU wie der '328P nicht wirklich machbar, da ihr die Ressourcen fehlen, um diese Art von Warteschlangen effektiv zu verwalten.
Ich habe Angst, Interrupts zu verpassen, die ausgelöst werden könnten, wenn mein Code einen anderen Interrupt bedient.
Majenko erklärte: "Das Interrupt-System durchläuft dann die Interrupts und sucht nach gesetzten Interrupt-Flags, und wenn der Interrupt aktiviert ist, springt es zur ISR." Das ist nicht ganz richtig, denn:
Die Interrupts haben entsprechend ihrer Interrupt-Vektorposition Priorität. Je niedriger die Interrupt-Vektoradresse, desto höher die Priorität.
Dies bedeutet, dass eine Unterbrechungsquelle "aushungern" kann. Nachdem eine ISR abgeschlossen ist, bevorzugt der Controller Interrupts mit hoher Priorität. Abhängig von der Interrupt-Frequenz kann es vorkommen, dass immer ein High-Level-Interrupt-Flag gesetzt ist, das im Wesentlichen ein niedrigeres Prio-Flag dauerhaft blockiert.
Es ist ein guter Rat, ISRs kurz zu halten und ihre Ausführungszeit zu kennen.
5 Interrupts sind wirklich nicht viel, erfordern aber dennoch Vorsicht auf einem einfachen System mit fester Priorität.
AVR XMEGA zum Beispiel bringt es auf eine andere Ebene. Ich habe ein XMEGA-Projekt, das 22 verschiedene Interrupt-Quellen verarbeiten muss (4xUART tx/rx = 8 + 4 Timer + 8 ADC komplett + 2 andere). Der XMEGA verfügt jedoch über einen "programmierbaren Multilevel-Interrupt-Controller". Dadurch können Sie jedem Interrupt manuell eine von drei Interrupt-Ebenen zuweisen (innerhalb dieser zählt weiterhin die Priorität der Interrupt-Vektornummer). Außerdem können Sie ein Round-Robin-Prioritätsschema aktivieren, das das zuvor erwähnte "Hunger"-Problem angeht.
Um das mögliche Hungerproblem für Low-Level-Interrupts mit statischer Priorität zu vermeiden, bei denen einige Interrupts möglicherweise nie bedient werden, bietet der PMIC eine Round-Robin-Planung
Also zu deiner ursprünglichen Frage:
Gibt es also eine strukturiertere Methode zur Verwaltung von Interrupts in einem großen Projekt?
Es hängt von den Fähigkeiten Ihres Systems ab. Stellen Sie bei einem Controller wie dem ATMega328 mit einfacher statischer prioritätsgesteuerter Interrupt-Verwaltung sicher, dass kein Interrupt verhungert, und halten Sie an "short" fest und "kennen Sie Ihre Ausführungszeit". Bei einem Controller wie dem XMEGA ist mehr Planung erforderlich, weil Sie einfach mehr Kontrolle haben. Sie müssen die Prioritäten sorgfältig verteilen und die Verwendung von Funktionen wie "Round Robin" berücksichtigen.
Ankit
sherrelbc
Majenko