Aus RN-Wissen.de
Wechseln zu: Navigation, Suche
Balkonkraftwerk Speicher und Wechselrichter Tests und Tutorials

(Empfehlungen für Code in der ISR)
(Empfehlungen für Code in der ISR)
Zeile 10: Zeile 10:
 
==Empfehlungen für Code in der ISR==
 
==Empfehlungen für Code in der ISR==
  
In der ISR kann im Prinzip ein beliebiger Code stehen. Damit es nicht zu Störungen im Hauptprogramm kommt, sollte man aber ein paar Empfehlungen beachten:
+
In der ISR kann im Prinzip ein beliebiger Code stehen. Das kann im Extremfall so weit gehen, das fast der ganze Code in ISRs steht, und das Hauptprogramm nur die Initialisierung am Anfang macht und später nur noch den µC zwischen den Interrupts in einen Stromsparmode versetzt.
  
Die ISR sollte relativ schnell beendet werden. Entsprechend sollte man langsame Teile wie explizites warten oder das Warten auf externe Ereignisse vermeiden. Dazu gehört meist auch die Ausgabe auf ein LCD Display. Auch Rechnungen mit Fließkommazahlen brauchen relativ lange. Einfache Änderungen an IO-Registern sind dagegen relativ schnell, auch wenn man dafür relativ viele Zeilen schreibt.  
+
Die wesentliche Forderung an die ISR ist, dass genügend Rechenzeit für das Hauptprogramm übrig bleibt, und das weiter schnell genug auf ggf. weitere Interrupts reagiert werden kann.  Was das genau heißt hängt stark vom Einzelfall ab. Die ISR sollte daher relativ schnell beendet werden. Entsprechend sollte man langsame Teile wie explizites warten oder das Warten auf externe Ereignisse vermeiden. Dazu gehört meist auch die Ausgabe auf ein LCD Display. Auch Rechnungen mit Fließkommazahlen brauchen relativ lange, sind aber nicht absolut tabu. Einfache Änderungen an IO-Registern sind dagegen relativ schnell, auch wenn man dafür relativ viele Zeilen im Source-code schreibt.  
  
Wenn das Hauptprogramm und die ISR auf die gleiche Variable oder ein IO Register zugreifen, muss das Hauptprogramm aufpassen, das nicht zu einem ungeeigneten Zeitpunkt die ISR dazwischen kommt. Die Zugriffe sollten "atomar" gestaltet sein, z.B. durch ein CLI() und SEI(), wenn der Zugriff nicht von sich aus schon Atomar ist, z.B. durch einen einzigen ASM Befehl. Je nach µC ist der schreibende Zugriff auf einzelne Bits nicht atomar möglich: erst wird das ganze Byte gelesen, dann das gewünschte Bit manipuliert und dann das ganze Byte zurück geschrieben.  
+
Wenn das Hauptprogramm und die ISR auf die gleiche Variable oder ein IO Register zugreifen, muss das Hauptprogramm aufpassen, das nicht zu einem ungeeigneten Zeitpunkt die ISR dazwischen kommt. Die Zugriffe sollten "atomar" gestaltet sein, z.B. durch ein CLI() und SEI(), wenn der Zugriff nicht von sich aus schon atomar ist, z.B. durch einen einzigen ASM Befehl. Je nach µC ist der schreibende Zugriff auf einzelne Bits von sich aus atomar möglich: erst wird das ganze Byte gelesen, dann das gewünschte Bit manipuliert und dann das ganze Byte zurück geschrieben.  
  
 
Damit es mit der Optimierung keine Probleme gibt, müssen in C die gemeinsam genutzten Variablen, die in einer ISR verändert werden als volatile gekennzeichnet werden. Bei einer volatilen Variable lohnt es sich ggf. in der ISR eine lokale nicht volatile Kopie anzulegen.  
 
Damit es mit der Optimierung keine Probleme gibt, müssen in C die gemeinsam genutzten Variablen, die in einer ISR verändert werden als volatile gekennzeichnet werden. Bei einer volatilen Variable lohnt es sich ggf. in der ISR eine lokale nicht volatile Kopie anzulegen.  
Zeile 22: Zeile 22:
 
Der oft genannte Hinweis in der ISR nur ein Flag zu setzen, und dann die ganze Rechnung im Hauptprogramm zu machen hilft oft auch nicht weiter. Zum einen setzt die Hardware schon von sich aus meistens ein Flag in einem IO-Register, wenn ein Interrupt ausgelöst werden könnte. Nur um ein Flag zu setzen braucht man also den Interrupt meist gar nicht, ein Flag hat die Hardware schon gesetzt. Es geht dann also besser ganz ohne Interrupt. Wenn eine andere ISR zeitkritisch ist, kann man ggf. in der ISR Interrupts freigeben und so geschachtelte Interrupts erlauben. Der Code kann dann weiter in der logischen Reihenfolge bleiben und man spart sich die dauernde Abfrage des Flags im Hauptprogramm. Wenn der selbe Interrupt noch mal kommt, hat man mit dem Flag im Hauptprogramm auch ein Problem.
 
Der oft genannte Hinweis in der ISR nur ein Flag zu setzen, und dann die ganze Rechnung im Hauptprogramm zu machen hilft oft auch nicht weiter. Zum einen setzt die Hardware schon von sich aus meistens ein Flag in einem IO-Register, wenn ein Interrupt ausgelöst werden könnte. Nur um ein Flag zu setzen braucht man also den Interrupt meist gar nicht, ein Flag hat die Hardware schon gesetzt. Es geht dann also besser ganz ohne Interrupt. Wenn eine andere ISR zeitkritisch ist, kann man ggf. in der ISR Interrupts freigeben und so geschachtelte Interrupts erlauben. Der Code kann dann weiter in der logischen Reihenfolge bleiben und man spart sich die dauernde Abfrage des Flags im Hauptprogramm. Wenn der selbe Interrupt noch mal kommt, hat man mit dem Flag im Hauptprogramm auch ein Problem.
  
Aufgaben wie die Ausgabe mehrerer Bytes per UART oder an ein ähnliches langsames Gerät wie ein LCD löst man da besser, indem man die Ausgabe Puffert und in einen extra Interrupt verlagert, die dann jeweils 1 Byte ohne Wartezeiten ausgibt. Viele kurze Interrupts sind meist das kleinere Problem als eine langsame ISR. Die Koordination mit ggf. vorhanden Ausgaben des Hauptprogramms ist dabei noch eine andere Baustelle.
+
Aufgaben wie die Ausgabe mehrerer Bytes per UART oder an ein ähnliches langsames Gerät wie ein LCD löst man besser, indem man die Ausgabe puffert. Die eigentliche Ausgabe erledigt eine andere ISR, die dann jeweils 1 Byte ohne Wartezeiten ausgibt. Viele kurze Interrupts sind meist das kleinere Problem als eine langsame ISR. Die Koordination mit ggf. vorhanden Ausgaben des Hauptprogramms ist dabei noch eine andere Baustelle.
  
 
==Siehe auch==
 
==Siehe auch==

Version vom 10. Juli 2011, 09:07 Uhr

Programm-Code, der beim Auftreten einer freigeschalteten Interrupt-Anforderung (IRQ) ausgeführt wird. Dazu wird der normale Programmfluss unterbrochen, die Interrupt Service Routine (ISR) ausgeführt, und danach das Programm an der unterbrochenen Stelle fortgeführt.

Je nach Hardware bzw. deren Konfiguration wird die ISR direkt betreten oder indirekt über eine Interrupt-Vektor-Tabelle, welche nur die Startadressen der unterschiedlichen ISRs enthält bzw. Sprunganweisungen zum Start der jeweiligen ISR.

Empfehlungen für Code in der ISR

In der ISR kann im Prinzip ein beliebiger Code stehen. Das kann im Extremfall so weit gehen, das fast der ganze Code in ISRs steht, und das Hauptprogramm nur die Initialisierung am Anfang macht und später nur noch den µC zwischen den Interrupts in einen Stromsparmode versetzt.

Die wesentliche Forderung an die ISR ist, dass genügend Rechenzeit für das Hauptprogramm übrig bleibt, und das weiter schnell genug auf ggf. weitere Interrupts reagiert werden kann. Was das genau heißt hängt stark vom Einzelfall ab. Die ISR sollte daher relativ schnell beendet werden. Entsprechend sollte man langsame Teile wie explizites warten oder das Warten auf externe Ereignisse vermeiden. Dazu gehört meist auch die Ausgabe auf ein LCD Display. Auch Rechnungen mit Fließkommazahlen brauchen relativ lange, sind aber nicht absolut tabu. Einfache Änderungen an IO-Registern sind dagegen relativ schnell, auch wenn man dafür relativ viele Zeilen im Source-code schreibt.

Wenn das Hauptprogramm und die ISR auf die gleiche Variable oder ein IO Register zugreifen, muss das Hauptprogramm aufpassen, das nicht zu einem ungeeigneten Zeitpunkt die ISR dazwischen kommt. Die Zugriffe sollten "atomar" gestaltet sein, z.B. durch ein CLI() und SEI(), wenn der Zugriff nicht von sich aus schon atomar ist, z.B. durch einen einzigen ASM Befehl. Je nach µC ist der schreibende Zugriff auf einzelne Bits von sich aus atomar möglich: erst wird das ganze Byte gelesen, dann das gewünschte Bit manipuliert und dann das ganze Byte zurück geschrieben.

Damit es mit der Optimierung keine Probleme gibt, müssen in C die gemeinsam genutzten Variablen, die in einer ISR verändert werden als volatile gekennzeichnet werden. Bei einer volatilen Variable lohnt es sich ggf. in der ISR eine lokale nicht volatile Kopie anzulegen.

Um Platz auf dem Stack zu sparen, sollte man Funktionsaufrufe in der ISR vermeiden, also besser den Code direkt einfügen. Einige Unterprogramme sind ggf. nicht "reentrant", dürfen also nicht 2 mal gleichzeitig aufgerufen werden - eventuell aus dem Hauptprogramm und dann noch mal aus der ISR. Dies passiert z.B. wenn globale Variablen für Zwischenwerte benutzt werden.

Der oft genannte Hinweis in der ISR nur ein Flag zu setzen, und dann die ganze Rechnung im Hauptprogramm zu machen hilft oft auch nicht weiter. Zum einen setzt die Hardware schon von sich aus meistens ein Flag in einem IO-Register, wenn ein Interrupt ausgelöst werden könnte. Nur um ein Flag zu setzen braucht man also den Interrupt meist gar nicht, ein Flag hat die Hardware schon gesetzt. Es geht dann also besser ganz ohne Interrupt. Wenn eine andere ISR zeitkritisch ist, kann man ggf. in der ISR Interrupts freigeben und so geschachtelte Interrupts erlauben. Der Code kann dann weiter in der logischen Reihenfolge bleiben und man spart sich die dauernde Abfrage des Flags im Hauptprogramm. Wenn der selbe Interrupt noch mal kommt, hat man mit dem Flag im Hauptprogramm auch ein Problem.

Aufgaben wie die Ausgabe mehrerer Bytes per UART oder an ein ähnliches langsames Gerät wie ein LCD löst man besser, indem man die Ausgabe puffert. Die eigentliche Ausgabe erledigt eine andere ISR, die dann jeweils 1 Byte ohne Wartezeiten ausgibt. Viele kurze Interrupts sind meist das kleinere Problem als eine langsame ISR. Die Koordination mit ggf. vorhanden Ausgaben des Hauptprogramms ist dabei noch eine andere Baustelle.

Siehe auch


LiFePO4 Speicher Test