Hallo, ich möchte die unteren 4bit von PORTB als Datenbits für ein lcd (hd44780 kompatibel) mit 4-bit Ansteuerung verwenden. Die oberen bit von PORTB sollen unabhängig davon als IO pins verwendet werden. Auf diese pins soll auch aus einer ISR zugegriffen werden. Daher meine Fragen: Sind Anweisungen wie PORTB |= 0b00001010; oder PORTB |= 1 << 3; atomar? Falls nicht: Können Probleme entstehen, wenn einer dieser Befehle durch eine ISR unterbrochen wird, in der ein Befehl wie PORTB |= 1 << 7; ausgeführt wird? Vielen Dank für alle Antworten Michael
michael schrieb: > Daher meine Fragen: > Sind Anweisungen wie PORTB |= 0b00001010; oder PORTB |= 1 << 3; atomar? Nein. > Falls nicht: > Können Probleme entstehen, wenn einer dieser Befehle durch eine ISR > unterbrochen wird, in der ein Befehl wie PORTB |= 1 << 7; ausgeführt > wird? Ja. Der Effekt der ISR auf Pin 7 geht dann je nach genauem Timing verloren. Andreas
Andreas Ferber schrieb: > michael schrieb: >> Daher meine Fragen: >> Sind Anweisungen wie PORTB |= 0b00001010; oder PORTB |= 1 << 3; atomar? > > Nein. Naja, das zweite Beispiel schon.
Hi, wäre die einfachste Lösung für das Problem dann, den Befehl PORTB |= 0b00001010; mit <util/atomic.h> atomar zu machen? Problematisch könnte hier sein, dass ich ähnliche Zugriffe auf PORTB oft brauche und zwischen den Befehlen häufig delays liegen, um das Timing des lcds einzuhalten. Gibt es noch eine einfachere Lösung? Vielen Dank, Michael
michael schrieb: > Problematisch könnte > hier sein, dass ich ähnliche Zugriffe auf PORTB oft brauche und zwischen > den Befehlen häufig delays liegen, um das Timing des lcds einzuhalten. Du solltest natürlich nur für einen einzelnen Zugriff die Interrupts ausschalten und nicht während des Delays. Schreib dir doch einfach eine kleine inline-Funktion, die du für den Zugriff auf den LCD-Teil des Ports aufrufst, und in der deaktivierst du die Interrupts.
Rolf Magnus schrieb: >>> Sind Anweisungen wie PORTB |= 0b00001010; oder PORTB |= 1 << 3; atomar? >> Nein. > Naja, das zweite Beispiel schon. Nein. Bloss weil eine andere Konstante verwendet wird macht das das "|=" nicht atomar, es bleibt ein read-modify-write. Andreas
Andreas Ferber schrieb: >>>> Sind Anweisungen wie PORTB |= 0b00001010; oder PORTB |= 1 << 3; atomar? >>> Nein. >> Naja, das zweite Beispiel schon. > > Nein. Bloss weil eine andere Konstante verwendet wird macht das das "|=" > nicht atomar, es bleibt ein read-modify-write. ... das der Prozessor mit einem einzelnen Assembler-Befehl, und damit atomar durchführen kann.
Hallo, werde ich das Problem auch los, indem ich die Zugriffe auf PORTB aus der ISR über ein interrupt-Flag in die Hauptschleife verschiebe? Vielen Dank, Michael
Rolf Magnus schrieb: >> Nein. Bloss weil eine andere Konstante verwendet wird macht das das "|=" >> nicht atomar, es bleibt ein read-modify-write. > ... das der Prozessor mit einem einzelnen Assembler-Befehl, und damit > atomar durchführen kann. In diesem speziellen Fall vielleicht, wenn die Optimierung beim Compiler richtig gesetzt ist. Und z.B. beim Zugriff auf PORTF beim ATmega128 fliegst du dann plötzlich auf die Schnauze, weil SBI damit nicht geht, dein Compiler dir das aber nicht sagt (warum auch, aus seiner Sicht ist nachwievor alles in bester Ordnung). Wenn man sowas verlässlich haben will, dann sollte man es als (Inline-)Assembler explizit hinschreiben. Sich darauf zu verlassen, dass der Compiler aus bestimmten Konstrukten bestimmten Maschinencode generiert, führt über kurz oder lang zu grauen Haaren. Andreas
Rolf Magnus schrieb: >> Nein. Bloss weil eine andere Konstante verwendet wird macht das das "|=" >> nicht atomar, es bleibt ein read-modify-write. > > ... das der Prozessor mit einem einzelnen Assembler-Befehl, und damit > atomar durchführen kann. Wie schon an anderer Stelle erwähnt, ist das eine viel zu gefährliche Annahme. Die Atomizität des Zugriffs folgt weder aus dem C-Sprachstandard noch aus der Leistungsbeschreibung des eingesetzten Compilers.
michael schrieb: > Hallo, > > werde ich das Problem auch los, indem ich die Zugriffe auf PORTB aus der > ISR über ein interrupt-Flag in die Hauptschleife verschiebe? verstehe ich jetzt nicht ganz, wenn du den Zugriff in der ISR machst ist es doch egal ob atomar oder nicht, da kann ja kein weiterer IRQ dazwischen kommen
Auf AVRs neuer als Mega8/Mega32 kann man die Toggle-Funktion von Schreibvorgängen nach PINx verwenden, um die unteren 4 Bits auf einen bestimmten Wert zu setzen, ohne dabei Änderungen an den oberen 4 Bits durch einen Interrupt-Handler in die Quere zu kommen: PINA = (PORTA & 0b00001111) ^ (data & 0b00001111);
PS: Diese Technik ist nur bezüglich der nicht betroffenen Bits atomar. Wenn die ISR auch die unteren Bits verändert, dann funktioniert dieses Verfahren nicht. Es ist also kein universeller atomarer Ersatz für SBI/CBI. Aber es ist unabhängig von der Adressierung des verwendeten Ports und faktisch unabhängig von Compiler und Optimierungsstufe.
Andreas Ferber schrieb: > Rolf Magnus schrieb: >>>> Sind Anweisungen wie PORTB |= 0b00001010; oder PORTB |= 1 << 3; atomar? >>> Nein. >> Naja, das zweite Beispiel schon. > > Nein. Bloss weil eine andere Konstante verwendet wird macht das das "|=" > nicht atomar, es bleibt ein read-modify-write. > Die Sache ist noch viel schwieriger, denn auch die externe Hardware kann während dem -modify-, also dann wenn die CPU die Maskierung in der ALU berechnet, AUCH den Zustand ändern. Schreibt die CPU dann das Ergebnis heraus, sind zwar die neuen Bits richtig, aber die alten werden auch geschrieben, obwohl neuere vorliegen! Es gibt wohl einige wenige Prozessoren, die Bit-Manipulation direkt unterstützen. Und hier sieht man, das C niemals für Hardware gedacht war. Der Keil-Compiler unterstützt übrigens native Bits auch in C. Eine seltene Ausnahme. Der 8051 kann da übrigens an den Ports auch zur Falle werden. Also unbedingt die Port-Kapitel im betreffenden Mikrocontroller-Manual durchackern und alles nietundnagelfest programmieren.
Abdul K. schrieb: > Die Sache ist noch viel schwieriger, denn auch die externe Hardware kann > während dem -modify-, also dann wenn die CPU die Maskierung in der ALU > berechnet, AUCH den Zustand ändern. Schreibt die CPU dann das Ergebnis > heraus, sind zwar die neuen Bits richtig, aber die alten werden auch > geschrieben, obwohl neuere vorliegen! Nein. Das PORTx-Register ändert nur durch die CPU seinen Inhalt. Die alternativen Portfunktionen werden zwischen PORTx und dem Pin "eingeschleift". Durch externe Ereignisse (und die genannten alternativen Portfunktionen) kann sich nur das PINx-Register ändern, dieses ist aber wiederum nicht durch die CPU schreibbar (die Toggle-Funktion bei neueren AVRs schreibt nicht wirklich in das PINx-Register). Erkennen kann man das alles in dem Schaltplan unter "Alternate Port Functions" im Datenblatt. > Es gibt wohl einige wenige Prozessoren, die Bit-Manipulation direkt > unterstützen. Und hier sieht man, das C niemals für Hardware gedacht > war. Wie sollte eine portable Programmiersprache auch auf Spezialitäten einer einzelnen Architektur eingehen? Es ist aber nicht verboten, C entsprechend zu erweitern (siehe z.B. die MMX-Intrinsics beim x86-GCC), nur hat für AVR das eben niemand konsequent getan, und deshalb muss man mit Unzulänglichkeiten wie der Nicht-Atomizität (bzw. der Nicht-Garantie der Atomizität) bei Bitoperationen auf PORTx leben. Programme, die solche Spracherweiterungen benutzen, sind dann natürlich nicht mehr portabel, aber das sind Mikrocontroller-Programme im allgemeinen sowieso nicht. > Also unbedingt die Port-Kapitel im betreffenden Mikrocontroller-Manual > durchackern und alles nietundnagelfest programmieren. Ack. Die relevanten Kapitel des Manuals sollte man sowieso immer zuerst lesen, egal was man macht. Andreas
OK, ich bezog mich nicht auf AVR. Es war sehr allgemein gedacht. Und ich habe nur Erfahrung mit anderen Prozessoren, vor allem 8051, PSoC. Und Sachen wie 8255, PCF8574 usw. gibts auch noch!
Abdul K. schrieb: > OK, ich bezog mich nicht auf AVR. Es war sehr allgemein gedacht. Und ich > habe nur Erfahrung mit anderen Prozessoren, vor allem 8051, PSoC. > > Und Sachen wie 8255, PCF8574 usw. gibts auch noch! Und bei denen steht in der Dokumentation auch ausdrücklich drin, dass ein Befehl Setbit irgendwas eben nicht ein einzelnes Bit setzt ohne Nebenwirkungen, sondern in Wirklichkeit ein Read-Modify-Write des ganzen Ports auslöst und daher z.B. die Möglichkeit besteht, einen 0-Eingang versehentlich "einzufrieren" (weil die 0 wieder zurückgeschrieben wird), je nachdem wie der Port im Detail aufgebaut ist. Atomare Operationen gibt es nur in Assembler bzw. Maschinencode. Selbst innerhalb des gleichen Prozessors kann das von Port zu Port verschieden sein. Schliesslich SOLL C-Code ja hardware-unabhängig sein. Dass eine ISR nicht durch eine weitere ISR unterbrochen werden kann, sollte man auch nicht so einfach annehmen. Eine ISR kann sich sogar selbst unterbrechen, aber dann ist in der Regel was falsch gelaufen. Gruss Reinhard
Ja ja ja Reinhard. Das sollte einfach nur explizit dargestellt werden. Ist nämlich ein fieser Fehler und damit schwer zu finden, wenn man das nicht in Erwägung zieht!
Falk Brunner schrieb: > Siehe Interrupt, dort steht das ALLES schon seit Ewigkeiten drin. . > . Ach Falk. ALLES das steht nur in der Bibel. Du hast mehr drauf.
@ Abdul K. (ehydra) Benutzerseite >Ach Falk. ALLES das steht nur in der Bibel. >Du hast mehr drauf. Als die Bibel . . .? Lass das mal nicht den großen Chef hören ;-) MfG Falk P S Ich habe, im Gegensatz zu vielen anderen Forumsteilnehmern, keine Lust, 1001 mal die gleiche Geschichte zu den gleichen Problemen zu erzählen. Deshalb schreibe ich Artikel im Wiki und verweise auf sie. Willst du jedes Mal die UART/LCD/FUSE/INTERRUPT/WHATEVER Probleme der Leute haarklein neu "lösen"? Ich nicht.
Falk, das stimmt. Es ist nur leider so, daß Menschen zuviel gute Organisation oft ablehnen. Hat auch seinen Grund. Das Schwein das nie einen Artikel verfaßte - Abdul
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.