Die AVR-SEI-Anweisung ( http://www.atmel.com/webdoc/avrassembler/avrassembler.wb_SEI.html ) wartet auf die Beendigung der nächsten Anweisung, bevor Interrupts aktiviert werden.
Wenn ich eine andere Anweisung verwende, um das I-Flag in SREG zu setzen, wird diese auch 1 Anweisung warten?
Mit anderen Worten: Ist das Warten ein Merkmal des SEI-Befehls oder des Statusregisters?
Wenn es sich um eine Funktion des SEI-Befehls handelt, an welchem Punkt wird das Flag dann tatsächlich gesetzt, in dem Zyklus, der SEI ausführt, oder mit dem nächsten Befehl?
Während die anderen Antworten nachdenklich und gut begründet sind, sind sie alle unvollständig oder nur Vermutungen. Wo die Dokumentation mehrdeutig ist, müssen wir experimentieren und jeden Fall testen.
Diese Frage verdient eine abschließende Antwort, also ziehen wir einen AVR heraus und fangen an, ein paar Bits einzustellen!
Zum Testen habe ich ein kleines Arduino-Programm (ATMEGA328P) erstellt, das ...
while (1)
)INT0
niedrig)Ich habe ein Prüfbett verwendet, das eine LED in der einzelnen Anweisung einschaltet, nachdem Interrupts aktiviert wurden. Indem ich verschiedene Möglichkeiten ausprobierte, Interrupts im Testbett zu aktivieren und die LED zu überprüfen, konnte ich feststellen, ob die Anweisung nach der Aktivierungsanweisung ausgeführt wurde oder nicht.
Wenn die LED nicht aufleuchtete, dann weiß ich, dass die ISR sofort ausgeführt (und gesperrt) wurde, nachdem Interrupts aktiviert wurden.
Wenn die LED aufleuchtete, dann weiß ich, dass die nächste Anweisung ausgeführt werden durfte, bevor die ISR aufgerufen wurde.
SEI
Anleitung (Basisfall)Code:
sei
Ergebnis: LED an. Folgende Anweisung ausgeführt.
OUT
AnweisungCode:
in r16,0x3f // Get SREG
ori r16,128 // Set I bit
out 0x3f,r16 // Save back to SREG
Ergebnis:
LED an. Folgende Anweisung ausgeführt.
ST
AnweisungCode:
clr r29 // Clear Y high byte
ldi r28,0x5f // Set Y low byte to point to SREG
ld r16, Y // Get SREG
ori r16,128 // Set I bit
st Y,r16 // Put SREG
Ergebnis:
LED an. Folgende Anweisung ausgeführt.
F: Ist das Warten eine Funktion des SEI-Befehls oder des Statusregisters?
A: Es scheint, dass das Ändern des I
Bits in SREG
is von a 0
zu a 1
die folgende Anweisung als nächstes ausführen lässt, selbst wenn ein anstehender Interrupt vorliegt, unabhängig davon, welche Anweisung zum Setzen des Bits verwendet wird.
Dies wurde tatsächlich zu einer sehr interessanten Frage mit vielen Komplikationen. Wenn Sie an den Details interessiert sind, schauen Sie sich...
http://wp.josh.com/2016/01/05/different-ways-to-set-i-bit-in-avr-sreg-besides-sei/
Aus der Dokumentation geht hervor, dass sich das Ausführen der sei
Anweisung nicht vom direkten Schreiben einer 1 in das I-Bit des SREG unterscheidet. Der Vorteil der Anweisung besteht darin, dass Sie nicht zuerst einen Wert 1<<I
in ein Arbeitsregister laden müssen, um das SREG zu ändern, wodurch Zeit gespart wird.
Um dies zu erläutern, verwenden Sie sei
:
sei ; One cycle
Das Setzen des Bits mit sbi
(würde nur funktionieren, wenn sich SREG in den unteren 32 Bytes der Registerzuordnung befände, aber es scheint, dass dies bei den meisten, wenn nicht allen, nicht der Fall ist.)
sbi SREG,7 ; Two cycles
Schreiben an I bit direkt in SREG:
in r24,SREG ;
ori r24,0x80 ;
out SREG,r24 ; Three cycles
Das I
Bit sollte in SREG gesetzt werden, sobald die sei
Anweisung (oder sbi
oder out
) abgeschlossen ist. Alle anstehenden Interrupts werden jedoch nicht behandelt, bis der nächste Befehl abgeschlossen ist – das Bit wird gesetzt, aber es dauert einen zusätzlichen Zyklus, bis die Interrupts aktiviert werden. Da ein Interrupt nicht mitten im Befehl behandelt werden kann und einige Befehle mehr als einen Zyklus zur Ausführung benötigen, geben sie die Zeit an, die benötigt wird, um als ein Befehl aktiviert zu werden. Dies sollte für alle Versionen des Codes der Fall sein – dh jede der obigen wird die Verzögerung einer Anweisung verursachen.
Nach einigem Suchen fand ich diesen Thread im Arduino-Forum, in dem verschiedene Tests durchgeführt wurden, um das Verhalten zu überprüfen. Es scheint mit dem übereinzustimmen, was ich oben gesagt habe.
Darüber hinaus gibt es laut diesem Thread, wenn das I
Flag bereits gesetzt ist, keine verzögerte Antwort eines Interrupts, der durch verursacht wird, sei
was impliziert, dass die verzögerte Antwort nicht durch die Anweisung selbst verursacht wird, sondern in der internen Hardware, die durch das I
Flag gesteuert wird - also jede Operation, die das Flag in SREG ändert, sei es oder sei
, wird genau das gleiche Verhalten haben.out
sts
SBI
nicht gesetzt werden kann, sodass Code, der dies tut, wahrscheinlich nicht wirklich im wirklichen Leben getestet wurde, da er nicht einmal assembliert wird. kann nur mit den unteren 32 Registern arbeiten und SREG befindet sich auf Steckplatz 63.
I
SREG
SBI
out
war das, das ich ursprünglich verwendet habe. Ich dachte, ich würde auf einen AVR stoßen (möglicherweise ein ATTiny), der das SREG in den unteren 32 Registern hat, aber ich bilde es mir vielleicht ein.IMHO verzögert das Schreiben in SREG immer noch 1 Anweisung, die wie folgt getestet werden kann (Pseudocode):
ISR() { PORTA = 0; while(1); }
main()
{
cli();
DDRA = 0xff;
configure_isr_for_level_interrupt_that_will_trigger_immediately();
SREG = 0xff;
cli();
PORTA = 0xff;
while(1);
}
Leider fehlt mir die Zeit dafür :(
Das ist nicht, was es sagt. Die Dokumentationen sagen
Die auf SEI folgende Anweisung wird vor irgendwelchen anhängigen Interrupts ausgeführt.
nicht, dass es auf die nächste Anweisung wartet. Ich lese dies, da das Flag sofort gesetzt wird, aber obwohl es aktiviert ist, werden keine Interrupts behandelt, bis die nächste Anweisung ausgeführt wurde.
Vorac
jayjay
gbulmer