IO Ports steuern und IRQ = Problem?

OP #1000660
Tach,

bin vor kurzem von der reinen Assembler-Programmierung (ATMEL) auf C 
umgestiegen. C-Kenntnisse sind zwar etwas eingerostet, aber vorhanden.

Bei der Umsetzung einiger Assembler Projekte in C bin ich auf folgendes 
Problem gestossen:

Um z.B. am PortA (ist auf Output geschaltet) am Pin 4 ein High-Signal 
auszugeben, benutzt man in Assembler die Anweisung:
1
sbi PORTA,4
in C mangels sbi die  Anweisung:
1
PORTA |= ~(1 << 4);

Im Prinzip wird nun in beiden Fällen das IO-Bit 4 im PORTA gesetzt.

Schaue ich mir den ASM-Code an, der vom Compiler erzeugt wird:
1
in  r24, 0x1b  
2
ori  r24, 0xFB  
3
out  0x1b, r24
Sieht auch OK aus. Doch was passiert im folgenden Fall:
Es existiert eine IRQ-Routine, welche im PortA die Bits 2 und 5 bedient.
Die Bits sind LOW.
Mal angenommen, der IRQ tritt auf, während der ASM-Code abgearbeitet 
wird, z.B. während das Portregister (in r24,01xb) eigelesen wird. Das 
würde dann folgendes bedeuten.

1.Die in Anweisung wird abgearbeitet, der Zustand des PORTA befindet 
sich nun im r24 (0b00000000)

2.Der IRQ wird ausgelöst, im IRQ werden die Bits 2&5 im PORTA gesetzt 
(0b00100100)

3. Nach Ende des IRQs gehts im Programm weiter mit "ori", aber in diesem 
Augenblick sind die Inhalte von r24 'veraltet', da der Inhalt von r24 
den Zustand des PORTA vor dem IRQ reflektiert.

4.Das Bitmuster 0b00010000 wird in den PORTA geschrieben, welches die 
Änderungen, welche durch den IRQ verursacht wurden, nicht 
berücksichtigt.

Das bedeutet für mich eigentlich, dass die Anweisung
1
PORTA |= ~(1 << 4);
 keine geeignete Anweisung darstellt, um irgendwelche Bit-orientierte 
Register im ATMEL anzusprechen.

sbi als C-Anweisung wird ja lt. DOKU nicht mehr unterstützt.

Gibt es eine Möglichkeit, dies Sinnvoll in "C" zu erledigen, ohne auf 
INLINE ASM zurückzugreifen?

Jürgen
OP
Danke! Trifft mein Problem zu 100%, nur das dauernde Ab/Anschalten des 
Globalen IRQ-Flag ist für mich nicht unbedingt die optimale Lösung, nur 
um ein IO-Bit zu ändern.

Werde wohl in diesem Fall nicht um ein selbst gestricktes sbi, welches 
wirklich nur ein einzelnes Bit bearbeitet (mit einer 
ASM-Anweisung)herumkommen.

Jürgen

Falk Brunner wrote:
> Siehe atomare Operationen im Artikel Interrupt
Jürgen W. wrote:
> Die Optimierung -0s ist eingeschaltet, Ergebnis bleibt gleich.

Richtig, weil diese Codezeile
1
PORTA |= ~(1 << 4);
gar nicht in ein sbi übersetzt werden kann. Dort wird nämlich nicht 1 
Bit gesetzt, sondern 7 Bits.

1
PORTA |= (1 << 4);
Das ist das Äquivalent zu deiner ASM-Zeile.
OP
Stefan Ernst wrote:
> Jürgen W. wrote:
>> Die Optimierung -0s ist eingeschaltet, Ergebnis bleibt gleich.
>
> Richtig, weil diese Codezeile
>
1
PORTA |= ~(1 << 4);
> gar nicht in ein sbi übersetzt werden kann. Dort wird nämlich nicht 1
> Bit gesetzt, sondern 7 Bits.
>
>
>
1
PORTA |= (1 << 4);
> Das ist das Äquivalent zu deiner ASM-Zeile.

Autsch! Stimmt! Vielen Dank! Kleiner aber feiner Unterschied!

Jürgen

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 18 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.