Hi Leute, spricht etwas dagegen, in einer ISR eine weitere Unterfunktion aufzurufen? Wirkt sich das Register Pushen auf die Performance aus? Ich benutze einen STM32 @ 56Mhz. Sinn der Übung ist, meine ISR Handler in einer file zu haben, damit ich eine Übersicht habe. In den anderen c Dateien, die natürlich thematisch getrennt sind befindet sich die eigentliche Funktion zur Abarbeitung der ISR. Das hätte auch den Vorteil, dass ich alle (DMA) Puffer, Flags, Semaphoren etc, die ich sonst global machen müsste im lokalen Scope halten könnte, was ebenfalls der Übersicht dienlich ist. Danke und schöne Grüße, Jan
Moin Jan, ja es spricht was dagegen. Es bleibt normal nicht bei den Pushen der paar Register, sondern die CPU braucht auch ein paar Takte um den Sprung auszufuehren (ueber 10 wenn ich mich nicht irre). Auch steht die Aussage im Raum, dass man eine ISR ja so kurz wie nur moeglich halten sollte. Am Ende musst du aber wissen, wie kritisch deine ISR ist. Ich zweifle auch daran, dass du wirklich einen Schaden dadurch erleidest, wenn du es machst und es gibt auch genug Programme, bei denen unzaehlige Funktionsaufrufe in den ISRs sind.
Sagen wir mal so: Der kluge Mensch vermeidet das, wie der Teufel das Weihwasser. Die übliche Technik ist, in der ISR ein Flag zu setzen und auf dieses Flag in einer Schleife in main-Funktion zu reagieren. So erhälst Du auch die von Dir gewünschte organisatorische Aufteilung. Das hat eine Reihe von Gründen, die zu erläutern hier zu umfangreich würde. Dennoch findest Du hier bestimmt eine Menge Threads dazu.
Umsonst schrieb: > Sagen wir mal so: Der kluge Mensch vermeidet das, wie der Teufel das > Weihwasser. > > Die übliche Technik ist, in der ISR ein Flag zu setzen und auf dieses > Flag in einer Schleife in main-Funktion zu reagieren. So erhälst Du auch > die von Dir gewünschte organisatorische Aufteilung. > > Das hat eine Reihe von Gründen, die zu erläutern hier zu umfangreich > würde. Dennoch findest Du hier bestimmt eine Menge Threads dazu. Also mal davon abgesehen, dass es unmengen an Gruenden dafuer gibt es nicht zu machen (ich gebe dir Recht, damit kann man Threads fluten), ist es nicht unbedingt die "uebliche Technik". Gaengige Betriebssysteme fuer MCUs bieten sogar fuer die Queue Funktionen spezielle Funktionsaufrufe fuer ISRs an, die einen Aufruf ausloesen. Teilweise moechte man auch das ISR verhalten haben und lagert den Code daher nicht in die Main aus. Es haengt also stark davon ab, welche Art der parallelen Programmierung man gewaehlt hat und wie gut man damit umgehen kann. Btw.: Es gibt auch genuegend Software, die sogar im medizinischen Bereich eingesetzt wird, bei der die ISR erst eine Funktion aufruft, die dann die naechste Funktion aufruft und erst dann wird das Problem geloest. Wenn man das jedoch macht sollte man sich mit dem Timing sicher sein.
Umsonst schrieb: > Sagen wir mal so: Der kluge Mensch vermeidet das, wie der Teufel das > Weihwasser. > > Die übliche Technik ist, in der ISR ein Flag zu setzen und auf dieses > Flag in einer Schleife in main-Funktion zu reagieren. So erhälst Du auch > die von Dir gewünschte organisatorische Aufteilung. > > Das hat eine Reihe von Gründen, die zu erläutern hier zu umfangreich > würde. Dennoch findest Du hier bestimmt eine Menge Threads dazu. Naja, die übliche Technik ist, das in der ISR zu bearbeiten/zu triggern, was eben dann bearbeitet werden muss. Ich setze ja auch flags bzw inkrementiere meine Semaphore, aber ich muss immerhin den DMA Puffer resetten, den Counter neu setzen usw. Und mMn spricht auch nix dagegen, Kleinigkeiten in der ISR zu berechnen (z.B. ein Werte des Puffers addieren und in einen "echten" fifo schreiben), so spart man nämlich letztendlich Zeit, weil statt z.B. 10 Werten nur einer in den FIFO geschrieben werden muss. Und ja es gibt ein Haufen Threads hier, aus denen man sich so ziemlich jede Meinung zusammenreimen kann. Konkret meine Frage habe ich aber nicht gefunden. Es ist ein komplexes Programm, mit ein paar Flags ist es nicht getan, die leicht schlechtere Performance nehme ich für eine bessere Übersicht gerne in kauf. Mich würde nur interessieren, ob irgendwas auftreten kann, an das ich nicht gedacht habe.
Jan K. schrieb: > Mich würde nur interessieren, ob irgendwas auftreten kann, an das ich > nicht gedacht habe. Durch die Zeit, die du mehr in der ISR verbringst kann deine ISR durch eine mit hoeherer Prioritaet unterbrochen werden und wenn eine ISR mit niedriegerer Prioritaet zweimal ausgeloest werden wuerde wirst du nurnoch einmal davon sehen. Das sind so die Kernpunkte. Ansonsten werden die ISRs aber auch gerne fuer eine Funktion als Betriebssystem verwendet und dann wird richtig viel Code in die ISR gepackt. Ich komme jetzt leider nicht auf dem Namen. Jedoch gibt es Strategien, wie du bei zeitlich diskreten Systemen fast den kompletten Code in die ISRs deiner Timer legst und die Main sich nur am Hintern kratzt. Von daher wuerde es mich wundern, wenn du dir damit einen Schaden einfaengst (solange du die ersten Punkte im Hinterkopf hast).
Hm. Naja. Was ist dann "üblich"? Ich habe z.B. kein Betriebssystem vorausgesetzt. So gesehen, ist bei Hinzuziehung oder Absehen von beliebigen Aspekten, jede Aussage relativierbar, falsifizierbar oder eben auch zu bestätigen. Wenn der TO soetwas nicht festlegt und eine Rundumfrage abschiesst: >Mich würde nur interessieren, ob irgendwas auftreten kann, an das ich >nicht gedacht habe. , dann muss er eben damit leben, das er nur eine relative Antwort erhält (und der Antworter, dass er widerlegt wird). Jan K. schrieb: >Ich setze ja auch flags bzw inkrementiere meine Semaphore, aber ich muss >immerhin den DMA Puffer resetten, den Counter neu setzen usw. Gut dann mach das so. Es gibt vermutlich auch Fälle wo es nicht anders geht. Aber eben auch mindestens soviele in denen es auch nur mit einem Flag geht, auf das woanders reagiert wird. >Mich würde nur interessieren, ob irgendwas auftreten kann, an das ich >nicht gedacht habe. Sicher. Da kann "irgendwas" auftreten, an das Du nicht gedacht hast.
Arne Maximilian R. schrieb: > ja es spricht was dagegen. Es bleibt normal nicht bei den Pushen der > paar Register, sondern die CPU braucht auch ein paar Takte um den Sprung > auszufuehren (ueber 10 wenn ich mich nicht irre). Quatsch, beim Cortex-M4 (STM32F4) sind es 1-4 Takte je nach Momentanzustand der Pipeline. Dank Link-Register sind Funktionsaufrufe da sehr effizient. Wenn in der aufrufenden Funktion ( = die ISR) keine Register gesichert werden müssen (z.B. weil sie nur den Aufruf enthält) erfolgen auch keine PUSH'es. Wenn man Optimierungen (insb. LTO) einschaltet und die ISR nur einen Funktionsauruf enthält, wird die aufgerufene Funktion vom Linker in die ISR kopiert und der "Aufwand" entfällt komplett. Da der Cortex außerdem Interrupt-Prioritäten hat kann man wichtigeren Interrupts höhere Prioritäten geben und somit das "Blockieren" des Cores durch langwierige ISR's vermeiden. Somit ist es eigentlich ziemlich unnötig, die Verarbeitung in die main() umzulagern oder gar auf Funktionsaufrufe zu verzichten. Operationen wie in FIFO's schreiben/lesen, Pins togglen etc müssen ja wohl so oder so ausgeführt werden, und ob das jetzt in der ISR oder in der main() passiert ist doch wurst, da kann man es auch in der ISR machen wenn man sich dadurch die Fummelei mit dem Flag oder gar einer Event Queue spart. Was man nur vermeiden sollte ist in der ISR auf externe Ereignisse zu warten (= den Core lahmzulegen) wie abgeschlossene serielle Transfers z.B. über UART.
Dr. Sommer schrieb: > Quatsch, beim Cortex-M4 (STM32F4) sind es 1-4 Takte je nach > Momentanzustand der Pipeline. Dank Link-Register sind Funktionsaufrufe > da sehr effizient. Ok, da habe ich irgendwas verdreht. Danke noch einmal fuer die Aufklaerung. Dr. Sommer schrieb: > Da der Cortex außerdem Interrupt-Prioritäten hat kann man wichtigeren > Interrupts höhere Prioritäten geben und somit das "Blockieren" des Cores > durch langwierige ISR's vermeiden. Das wurde hingegen schon beschrieben. ;) War da nicht der generelle Tenor: Kurze und haeufige ISRs hohe Prioritaeten und je laenger die ISRs werden niedrigere Prioritaeten.
Eine Funktionsaufruf erzeugt ggf. etwas Overhead, insbesondere werden oft mehr Register benötigt. Ein wirkliches Ausschlusskriterium ist das aber nicht. Je nach Konstellation kann der Compiler viel wegoptimieren, insbesondere wenn die Funktion nur das eine mal in der SIR benutzt wird - allerdings geht das gerade dann schlecht, wenn die Funktion in einem anderen File (.c) steht. Ob man eine oder mehrere Funktionen aufruft macht dann keinen großen Unterschied mehr. Der größte Punkt ist das man einmal die zusätzlichen Register braucht. Je nach µC braucht das relativ viel Zeit die zu Retten - Beim ARM sollte das aber nicht so schlimm sein wie etwa beim AVR (relativ viele kleine Register). Bei Funktionsaufrufen muss man ggf. noch aufpassen ob die Funktionen reentrant sind, also mehrmals gleichzeitig laufen dürfen. Was gemacht werden muss, kann man auch in der ISR erledigen. Die Verlagerung ins Hauptprogramm verursacht nur zusätzlichen Overhead. Nur warten sollte man in der ISR eher nicht.
Die Forderung, sämtliche Interrupts kurz zu halten, ist nur bei MCs ohne Prioritäten akut, z.B. AVR. Schon der 8051 hatte 2 oder 4 Prioritäten, da ist das dann deutlich entspannter. Wichtig ist aber, daß die aufgerufenen Funktionen reentrant sein müssen.
Peter Dannegger schrieb: > Die Forderung, sämtliche Interrupts kurz zu halten, ist nur bei MCs ohne > Prioritäten akut, z.B. AVR. Natürlich hat auch der AVR Interruptprioritäten. Aber die haben rein gar nichts damit zu tun, ob ein Interrupthandler kurz oder lang sein soll. Auf keiner CPU.
prio schrieb: > Natürlich hat auch der AVR Interruptprioritäten. Hallo! Peter meinte: sich gegenseitig unterbrechbare Interrupts.
Aka verschachtelte Interrupts, neudeutsch nested interrupts. http://www.mikrocontroller.net/articles/Interrupt#Verschachtelte_Interrupts
prio schrieb: > Natürlich hat auch der AVR Interruptprioritäten. > Aber die haben rein gar nichts damit zu tun, ob ein Interrupthandler > kurz oder lang sein soll. Auf keiner CPU. Beim AVR nicht, aber beim 8051 schon. Z.B. der AT89C51CC03 hat 4 Interrupt Priority Register, damit kann man jeder Interruptquelle eine von 4 Prioritäten zuweisen: "Each interrupt source can also be individually programmed to one of four priority levels by setting or clearing a bit in the Interrupt Priority registers. A low-priority interrupt can be interrupted by a high priority interrupt but not by another low-priority interrupt. A high-priority interrupt cannot be interrupted by any other interrupt source. If two interrupt requests of different priority levels are received simultaneously, the request of the higher priority level is serviced. If interrupt requests of the same priority level are received simultaneously, an internal polling sequence determines which request is serviced. Thus within each priority level there is a second priority structure determined by the polling sequence, see Table 109." Und dann kann man auch lange Interrupts haben, weil die von denen mit höherer Priorität unterbrochen werden können. Man muß also nicht sämtliche Interrupts kurz halten.
1 | // Initialisierungen |
2 | |
3 | while (1) |
4 | { |
5 | __WFI(); |
6 | }; |
Auszug aus einer main() eines STM32F103C8. Alle anderen Routinen (USB, LCD, SD-Card, etc.) sind ISRs oder werden von diesen aufgerufen.
Davis schrieb: > Alle anderen Routinen (USB, > LCD, SD-Card, etc.) sind ISRs oder werden von diesen aufgerufen. Ja, sowas sieht man von Anfängern häufig. Es gibt aber keinen Grund, auf den klaren und eindeutigen Ablauf einer Mainloop zu verzichten. Das Problem bei Interrupts ist die völlig zufällige Abfolge. Z.B. Du willst einer Temperatur einer Meßstelle auf dem LCD ausgeben. Du gibts also die Nummer der Meßstelle aus. Nun willst Du den Wert ausgeben, aber genau dazwischen haut Dir die ADC-Routine und gibt schon den nächsten Wert aus. Und schon hast Du eine falsche Anzeige auf dem LCD.
Ulrich schrieb: > Eine Funktionsaufruf erzeugt ggf. etwas Overhead, insbesondere werden > oft mehr Register benötigt. Ein wirkliches Ausschlusskriterium ist das > aber nicht. Aber nur wenn sie auch tatsächlich benötigt werden, wenn da nur ein Funktionsaufruf steht passiert da gar nix mit Registern. Ulrich schrieb: > - allerdings geht das gerade dann schlecht, wenn die Funktion in einem > anderen File (.c) steht. Das geht ganz wunderbar, wenn man einen neuen GCC nimmt (>= 4.7.3) und mit -flto kompiliert & linkt. Ulrich schrieb: > Der größte Punkt ist das man einmal die zusätzlichen > Register braucht. Was für Register braucht man für einen Funktionsaufruf??? Peter Dannegger schrieb: > Es gibt aber keinen Grund, auf den klaren und eindeutigen Ablauf einer > Mainloop zu verzichten. Doch, die Fummelei Flags zu setzen und darauf zu warten. Und natürlich wenn man mehrere gleichzeitige Abläufe hat, und nicht nur ADC->LCD; dann bräuchte man schon "richtiges" Multithreading...
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.