Forum: Mikrocontroller und Digitale Elektronik Asynchroner Datenaustausch in C


von Micha (Gast)


Lesenswert?

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

von C Programmierer (Gast)


Lesenswert?

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;

von Julian B. (julinho)


Lesenswert?

Meinst du nicht, dass das von der Anwendung abhängt, wie viele Daten du 
austauscht, ob alle Daten verarbeitet werden müssen, etc?

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

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.

von drama (Gast)


Lesenswert?

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.

von drama (Gast)


Lesenswert?

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?

von Noch einer (Gast)


Lesenswert?

Erfahrungsgemäß die beste Variante -- erst mal nachdenken, ob sich 
Semaphore und FIFO vermeiden lassen. Oder ob man da überhaupt eine ISR 
braucht.

von Falk B. (falk)


Lesenswert?

@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.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

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?

von Irgendwer (Gast)


Lesenswert?

C Programmierer schrieb:
> ISR:
>
> while(bReading); // wait while reading from main is finished

Klasse Beispiel für einen perfekten deadlock:-)

von OldMan (Gast)


Lesenswert?

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.

von OldMan (Gast)


Lesenswert?

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-

von Noch einer (Gast)


Lesenswert?

> 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.

von OldMan (Gast)


Lesenswert?

Noch einer schrieb:
> alten PIC
> Library.

Man beachte "alten"!

von Noch einer (Gast)


Lesenswert?

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.

von Micha (Gast)


Lesenswert?

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.

von Micha (Gast)


Lesenswert?

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.

von A. H. (ah8)


Lesenswert?

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
Noch kein Account? Hier anmelden.