Nabend !
Da die Benutzung von Interrupts beim programmieren vom avr in assembler
(von c mal abgesehen, darin programmier ich nicht) einige Fallstricke
bereit hält hab ich mal das Internet durchforstet um sicherzugehen das
bei meinem programm auch alles klappt ! Und nicht solche blöden Fehler
wie "tritt hin und wieder auf" vorkommenen.
Also meine Frage:
zu beginn der ISR schiebe ich die in der ISR benutzten register auf den
stack !
das sind bei mir z.B. r16,r17 das statusregister und das Doppelregister
zl und zh.
am ende der ISR hole ich sie wieder vom stapel.
ich dachte damit wäre alles safe !
doch dann hab ich das gefunden:
---Quote anfang
http://www.avr-asm-tutorial.net/avr_de/interrupts/int_ressourcen.html
Die oben beschriebene Zugriffssteuerung über eine Interrupt-Blockage
mit CLI/SEI ist auf jeden Fall dann zwingend, wenn ein Doppelregister
außerhalb von Interrupt-Service-Routinen auf einen neuen Wert gesetzt
werden muss und innerhalb von Service-Routinen verwendet wird. Zwischen
dem Setzen des einen Bytes des Doppelregisters und des zweiten könnte
ein Interrupt zuschlagen und einen völlig verqueren Wert vorfinden.
Solche Fehler sind teuflisch, weil es in der Regel korrekt funktioniert
und nur alle paar Stunden ein Mal dieser Fall eintritt. So einen
eingebauten Bug findet man garantiert nicht, weil er sich so selten in
freier Wildbahn in der Schaltung zeigt.
Daher sollten folgende Regeln gelten:
* Register möglichst klar der alleinigen Verwendung innerhalb und
außerhalb von Interrupt-Service-Routinen zuordnen.
* Jede gemeinsame Nutzung von Registern intensiv auf mögliche
Konflikte hin durchdenken. Vorher denken vermeidet die Fehlersuche
hinterher.
* Vorsicht bei der gemeinsamen Nutzung von Doppelregistern.
Interrupts blockieren! Und hinterher nicht vergessen, sie wieder
zuzulassen.
---Quote ende
Heißt das ich muß die Interrupts beim Benutzen von Doppelregistern
trotzdem deaktivieren ? obwohl ich sie am anfang der ISR auf den stack
packe?
Hauptprogramm:
ldi zl,LOW(UART_RX_STRING)
ldi zh,HIGH(UART_RX_STRING)
wo ist das problem wenn nach dem laden von zl der Interrupt ausgelöst
wird, Z sichert, dann verändert, wiederherstellt und dann im
hauptprogramm zh geladen wird ?
> wo ist das problem wenn nach dem laden von zl der Interrupt ausgelöst> wird, Z sichert, dann verändert, wiederherstellt und dann im> hauptprogramm zh geladen wird ?
Streiche 'wiederherstellt', dann erkennst Du das mögliche Problem.
Alternativ streiche 'sichert, dann verändert, wiederherstellt' und
setzte stattdessen 'verwendet', dann tritt das selbe Problem (in die
andere Richtung) auf.
HTH
ist mir nicht klar sorry :-(
ich meine ich hab auch kein problem damit die interrupts einfach zu
sperren !
ich wills doch einfach nur verstehen ! :-))
bei manchen 16bit registern versteh ichs ja weil sich der 16bit inhalt
verändern kann und dann low und high byte nicht mehr zusammenpassen.
Aber in meinem beispiel verändert sich doch die adresse im sram von
(UART_RX_STRING) durch den interrupt nicht.
zl wurde vor dem IRQ erfolgreich geladen, über die ISR hinweg gesichert
per stack. und zh wird nach dem irq geladen. das sollte doch gehen.
wie gesagt ich verstehs halt net.
ich kanns auch einfach als Tatsache hinnehmen, ich meine im datenblatt
steht ja auch nur:
It is important to notice that accessing 16-bit registers are atomic
operations. If an interrupt
occurs between the two instructions accessing the 16-bit register, and
the interrupt code
updates the temporary register by accessing the same or any other of the
16-bit Timer Registers,
then the result of the access outside the interrupt will be corrupted.
Therefore, when both
the main code and the interrupt code update the temporary register, the
main code must disable
the interrupts during the 16-bit access.
vielleicht findet sich ja ein geduldiger Mensch der mich aufklärt ^^
gruß marco
Marco Oklitz schrieb:> wo ist das problem wenn nach dem laden von zl der Interrupt ausgelöst> wird, Z sichert, dann verändert, wiederherstellt und dann im> hauptprogramm zh geladen wird ?
Da gibts keine Probleme.
Diese Probleme mit 16bit-Zugriffe entstehen, wenn du auf ein nicht
sicherbares "Ding" zugreifst, also z.B. eine Speicheradresse oder ein
I/O-Register.
So als Fallbeispiel:
Du hast eine 16 bit Variable im SRAM, die die Overflows eines Timers
mitzählt (meinetwegen für ne Uhrzeit).
Dann läuft das ganze im Worst case so ab:
Im Low Byte steht 0xFF im High Byte 0x04
ld r2, lowbyte
;<- hier kommt der interrupt
ld r3, highbyte
im Interrupt nach dem Sichern
ld r16, lowbyte
ld r17, highbyte
inc r16
brne kein_high_inc
inc r17
kein_high_inc:
st lowbyte, r16
st highbyte, r17
Interrupt ende, die REgister werden wieder hergestellt, nicht aber die
SRAM-Variablen.
Im Hauptprogramm steht dann wegen des Interrupts in
r2 = 0xFF und r3 = 0x05
obwohl es eigentlich 0x00 und 0x05 sein sollten.
Problematik klar?
:-)
dein beispiel ist vollkommen einleuchtend
also besteht das problem doch nur dann, wenn ich das was ich ich ein
register im hauptprogramm laden will sich während des interrupts ändern
könnte oder ändern kann.und nicht durch den stack gesafet werden kann.
damit kann ich umgehen, das ist einleuchtend.
ich dachte das wäre sowas wie ein grundlegendes problem das das high und
low byte immer direkt hintereinander geladen werden muß, weil es sonst
zu prozessorinternen problemen führt. das es probleme gibt wenn ich die
werte ändere ist klar.
danke dir