Forum: Compiler & IDEs IO Ports steuern und IRQ = Problem?


von Jürgen W. (coffeejunk)


Lesenswert?

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

von Stefan E. (sternst)


Lesenswert?

Aktiviere beim Compiler die Optimierungen (z.B. -Os), dann macht er aus 
der Codezeile oben auch einen einzigen sbi-Befehl.

von Falk B. (falk)


Lesenswert?

Siehe atomare Operationen im Artikel Interrupt

MfG
Falk

von Jürgen W. (coffeejunk)


Lesenswert?

Die Optimierung -0s ist eingeschaltet, Ergebnis bleibt gleich.

von Jürgen W. (coffeejunk)


Lesenswert?

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

von Stefan E. (sternst)


Lesenswert?

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.

von Jürgen W. (coffeejunk)


Lesenswert?

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

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.