Hallo zusammen, ich wollte mal fragen was erfahrungsgemäß die beste Variante ist in C "asynchron" Daten auszutauschen, bspw. zwischen einer ISR und main? In der ISR die Daten in eine Art Schattenregister schreiben und dieses einmal pro Endlosschleifendurchlauf auslesen oder gleich per FIFO? Oder lieber ständig die Interrupts ein-/ausschalten? Gibt es noch weitere Methoden? Hängt es von der Richtung ab (main -> ISR bzw. ISR -> main) was die beste Lösung ist? Grüße, Micha
Nehmen wir an, du willst ein Array aus einer ISR an die main übergeben, dann könntest du zwei globale Bits erstellen: bReading, bWriting. ISR: while(bReading); // wait while reading from main is finished bWriting = 1; copyFromISR(); bWriting = 0; main: while(bWriting); // wait while writing from ISR is finished bReading = 1; copyToMain(); bReading = 0;
Meinst du nicht, dass das von der Anwendung abhängt, wie viele Daten du austauscht, ob alle Daten verarbeitet werden müssen, etc?
Da gibts kein allgemein gültiges Rezept. Ein UART Interrupt z.B. kann ein empfangenes Datum speichern und evtl. noch ein Flag setzen oder einen Pointer behandeln. Eine ISR, die mechanisch ausgelöst wird und was tun soll (ich emuliere hier z.B. gerade ein Cassettendeck) setzt nur ein Flag und der (langsame) Rest wird von einer Unterroutine von main() gemacht, da läuft parallel nämlich noch Digital Audio, das auf keinen Fall unterbrochen werden darf. Generell sollten ISR schnell fertig werden und vorhersehbares Zeitverhalten haben. Däumchen drehen kann man in main() immer noch.
Die Methode mit Schattenregister (also faktisch double buffering) ist gängig. Man kann das auch recht einfach zu einem Ringpuffer mit FIFO-Semantik aufbohren. Das habe ich so schon häufiger genutzt. Interrupts ausschalten würde ich nur im Notfall machen. Manche CPUs haben Instruktionen für atomare komplexe Operationen, die sind ggf. nützlich als Alternative dazu.
C Programmierer schrieb: > Nehmen wir an, du willst ein Array aus einer ISR an die main übergeben, > dann könntest du zwei globale Bits erstellen: bReading, bWriting. Und dann hast du einen Spinlock im IRQ. Halte ich tendenziell für gefährlich! Dann doch lieber Interrupts einfach deaktivieren, oder?
Erfahrungsgemäß die beste Variante -- erst mal nachdenken, ob sich Semaphore und FIFO vermeiden lassen. Oder ob man da überhaupt eine ISR braucht.
@Micha (Gast) >ich wollte mal fragen was erfahrungsgemäß die beste Variante ist in C >"asynchron" Daten auszutauschen, bspw. zwischen einer ISR und main? Siehe Interrupt. >In der ISR die Daten in eine Art Schattenregister schreiben und dieses >einmal pro Endlosschleifendurchlauf auslesen oder gleich per FIFO? Kommt auf die Anwendung an. >Oder >lieber ständig die Interrupts ein-/ausschalten? Warum sollte man das tun? Bestenfalls für atomare Zugriffe.
C Programmierer schrieb: > ISR: > > while(bReading); // wait while reading from main is finished und wer soll bReading freigeben, während du in der ISR deine Kreise ziehst?
C Programmierer schrieb: > ISR: > > while(bReading); // wait while reading from main is finished Klasse Beispiel für einen perfekten deadlock:-)
C Programmierer schrieb: > // wait while reading from main is finished Irgendwelche Waits in der main zu haben ist nicht gut. Warum soll ich auf einen Subtask warten, wenn ich was besseres zu tun habe. Wenn in der main nix zu tun ist, dann legt man sich schlafen oder übergibt an den Idle-Task. Beim AVR meistens sleep. UART-I/O kann man immer asynchron machen und die main via signale über den aktuellen Zustand informieren. Ich mache das schon immer so, dass ich einen Sende- und einen Empfangsringpuffer für den UART habe. Die ganze UART-Abwicklung macht die zugehörige ISR. Jeweils eine für TX, RX und evt. UART_ERROR_HANDLING. Viele habe damit ein Problem, weil sie sich nicht "virtuelle, asynchrone" Abläufe vorstellen können. Als Anregung kann ich nur jedem empfehlen sich mal mit einem "echten" RTOS zu beschäftigen und die darin verankerte "Quasiparallelität" anzueignen.
Noch einer schrieb: > Oder ob man da überhaupt eine ISR > braucht. Was ein Quark! Tja, wenn man von Interrupts keine Ahnung hat, dann kommen solche Empfehlungen heraus. -Gähn-
> Was ein Quark! Recht nettes Beispiel ist das SD-Card Zeug aus der das alten PIC Library. main() ruft regelmässig AsyncWriteTasks() auf. Das schaut nach, ob die SPI Hardware inzwischen das Interrupt-Flag gesetzt hat. ISR wird nicht aktiviert.
Ja, Saubande! Bei der Portierung auf die neuen XC Compiler haben diese Knaller die Hälfte weggelassen. Benutzt nur Hardware, für die es ein gcc gibt.
Falk Brunner schrieb: > Siehe Interrupt. Darin sehe ich am ehesten den Abschnitt "UART mit Interrupts" als relevant an und das Beispiel dort empfinde ich als relativ speziell. Speziell deswegen, weil vorausgesetzt wird, dass man sein Protokoll selbst definieren kann (\0 am Ende). Wenn dies aber nicht der Fall ist...? Der Mechanismus an sich ist aber natürlich anpass- und übertragbar.
Micha schrieb: > Speziell deswegen, weil vorausgesetzt wird, dass man sein Protokoll > selbst definieren kann (\0 am Ende). Natürlich funktioniert das auch nicht wenn \0 ein gültiges Datum ist.
Hallo Micha, mir scheint, Du fragst eher nach dem richtigen Locking als nach Datenaustausch. Da gilt, wie schon geschrieben: Für jeden Zweck das richtige Messer. Viel interessantes dazu findest Du in der Literatur zum Linux Kernel, zum Beispiel hier http://lwn.net/Kernel/LDD3/ oder hier http://tldp.org/LDP/tlk/tlk.html. Gruß, ah8
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.