Hallo, ich habe ein Verständnisproblem. Laut der Beschreibung in
http://www.mikrocontroller.net/articles/Interrupt. Interrupt soll beim
Atomarer Datenzugriff ausgeschaltet werden.Z.B.: Wenn 16-Bit Zahl
dekrementiert wird? Oder hier
" IN r16,port
ORI r16,0x03
OUT port,r16
Wenn nun zwischen IN und OUT ein Interrupt auftritt, der beispielsweise
Bit 7 verändert, dann geht mit dem OUT-Befehl diese Änderung verloren,
da der OUT-Befehl den alten Zustand vor dem Interrupt wiederherstellt. "
Gilt es auch für Assemblerprogrammierung oder nur für C? In Assembler
kann man bei wenn Interrupt auftitt, den SREG-Register in SRAM sichern.
Oder verstehe ich etwas falsch?
Alex schrieb:> Gilt es auch für Assemblerprogrammierung oder nur für C?
für beide
> In Assembler kann man bei wenn Interrupt auftitt, den SREG-Register in> SRAM sichern. Oder verstehe ich etwas falsch?
das macht C auch nicht anders.
Aber das Probelm liegt woanders:
IN r16,port
ISR
ORI r16,0x03
ISR
OUT port,r16
stellt dir mal vor in den Zeilen ISR tritt ein interupt ein und setzt
von dem Port ein bit. Dann wird diesen bit beim out nicht wieder
hergestellt.
Hi
> Gilt es auch für Assemblerprogrammierung oder nur für C?
Auch für Assembler.
In Assembler
kann man bei wenn Interrupt auftitt, den SREG-Register in SRAM sichern.
Oder verstehe ich etwas falsch?
Im RAM oder einem dafür reservierten Register.
Die fragen haben aber nichts miteinander zu tun.
MfG Spess
Welches Bit7? Das von r16 oder das vom Port?
Falls Port, musst du vor IN r16,port ein cli setzen.
Falls r16 musst du in der ISR mit push r16 sichern unt vor reti wieder
pop r16 zurückholen
Ein Beispiel: 16-Bit-Zähler verwendet und von 0x00FF auf 0x0100
hochzählt,dann tritt der Interrupt auf. Dieser Zähler wird nicht in der
Interrupt-Unterprogramm verwendet. Angenommen es wird nur in
Hauptprogramm angewendet. Nach ISR_Verlassen kommr es auch zum Fehler?
Oder es wird richtig übergehen?
Peter II schrieb:> Alex schrieb:> Aber das Probelm liegt woanders:>> IN r16,port> ISR> ORI r16,0x03> ISR> OUT port,r16>> stellt dir mal vor in den Zeilen ISR tritt ein interupt ein und setzt> von dem Port ein bit. Dann wird diesen bit beim out nicht wieder> hergestellt.
Sinniger wäre eventuell das hier:
1
sbi PORTx,0
2
sbi PORTx,1
Zwar werden dann die IO-Leitungen nicht exakt gleichzeitig auf High
gesetzt, aber es gibt keine Probleme mit fehlender Atomarität.
Alex schrieb:> Nach ISR_Verlassen kommr es auch zum Fehler?> Oder es wird richtig übergehen?
nein da gibt es keine Probleme. Nur wenn eine Resource gleichzeitg in
der ISR und dem Rest verwendet wird.
Alex schrieb:> Ein Beispiel: 16-Bit-Zähler verwendet und von 0x00FF auf 0x0100> hochzählt,dann tritt der Interrupt auf.
Wann? Nach dem Addieren oder dabei?
> Dieser Zähler wird nicht in der> Interrupt-Unterprogramm verwendet. Angenommen es wird nur in> Hauptprogramm angewendet.
Was es? Das Zähler?
> Nach ISR_Verlassen kommr es auch zum Fehler?
Das hängt von der ISR ab. Siehe unten.
> Oder es wird richtig übergehen?
An wen? Hier findet keine Übergabe statt. Versuche Dich mal klar
auszudrücken. Das ganze hat nichts mit dem Code in Deinem Eingansposting
zu tun.
Wenn Du mit Übertrag rechnest, und das musst Du bei einem 16 bit Zähler,
verlässt Du Dich auf das C-Bit in SREG.
Deswegen und weil auch andere Befehle (z.B. bedingte Sprünge) sich auf
den korrekten Wert der Bits in SREG verlassen müssen, muss eine ISR das
SREG-Register einlesen und zwischenspeichern, um es am Ende restaurieren
zu können.
1
Hochzaehlen:
2
subi r16,-1 ; Unteres Byte hochzählen, bei Überlauf C-Flag setzen.
3
; <=ISR-Aufruf
4
sbci r17,0 ; Evtl. Übertrag in C-Flag auf oberes Byte übernehmen.
Hi
Eigentlich gilt: alle in der ISR benutzeten Tegister müssen vorher auf
den Stack gelegt werden. Da ist zuerst das Statusregister "SREG". Das
wird höchstwahrscheinlich verändert, daher ist es wie bereits
geschrieben, auch zwischenzuspeichern. Werden nun noch andere im
Programm verwendete Register in der ISR benutzt, z. B. R16, R17 etc.
dann sind auch diese auf den Sack abzulegen und später in umgekehrter
Reihenfolge wieder herzustellen.
Push a
Push B
Push C
....
POP C
POP B
POP A
Dazu braucht es keine Abschaltung der Interrupts.
Lediglich beim Schreiben auf den EEProm ist soweit ich's in Erinnerung
habe, der Interrupt abzuschalten, weil das "Brennen" etwas länger dauert
und nicht unterbrochen werden darf.
Gruß oldmax
oldmax schrieb:> Eigentlich gilt: alle in der ISR benutzeten Tegister müssen vorher auf> den Stack gelegt werden.
Ja, C-Compiler machen das meisten so. Trotzdem kostet es viel
Rechenzeit, was grad bei einer Interrupt-Routine wehtun kann.
Wenn man schon in Assembler programmiert, kann man ohne Weiteres zwei
oder drei Register von den 32 vorhandenen auswählen und diese NUR in der
ISR benutzen.
Das SREG sollte man tunlichst sichern, das ist richtig, aber auch dieses
braucht man nicht auf den Stack zu legen, man sichert es einfach in ein
sonst nicht verwendetes Register.
Nicht selten werden ISR dadurch doppelt oder dreimal so schnell
durchlaufen, als wenn man alles auf den Stack sichern würde. Jedes PUSH
kostet 2 Zyklen, jedes POP ebenfalls.