mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik AVR: PORTB |= 0b00001111; atomar?


Autor: michael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Andreas Ferber (aferber)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas Ferber schrieb:
> michael schrieb:
>> Daher meine Fragen:
>> Sind Anweisungen wie PORTB |= 0b00001010; oder PORTB |= 1 << 3; atomar?
>
> Nein.

Naja, das zweite Beispiel schon.

Autor: michael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Andreas Ferber (aferber)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Drachenbändiger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da wird wohl "sbi PORTB, 3" draus, also atomar!

Autor: michael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja.

Autor: Andreas Ferber (aferber)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Andreas Schweigstill (Firma: Schweigstill IT) (schweigstill) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Walter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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);

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Abdul K. (ehydra) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Andreas Ferber (aferber)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Abdul K. (ehydra) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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!

Autor: Reinhard Kern (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Abdul K. (ehydra) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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!

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Siehe Interrupt, dort steht das ALLES schon seit Ewigkeiten drin. . 
.

Autor: Abdul K. (ehydra) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  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.

Autor: Abdul K. (ehydra) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.