AVR ATmega16+Timer

Georg Meister schrieb:
Allerdings kann ich mir das Nichtfunktionieren der bisher diskutierten
Vorschläge nur erklären wenn deine CAN-Interruptroutine tatsächlich viel
länger dauert als angegeben. Das ist wahrscheinlich auch der Grund warum
bei dir der Vorschlag von Thomas nicht funktioniert hat.
Das Nichtfunktionieren interressiert mich auch.
Um aehnliche Denk-, Konzept- oder Programmierfheler zu vermeiden.

Vielleicht ein Fehler in der Interrupt Sense Control des ext. Interrupt.

Bei "low level" es dann ein Interrupt nach dem anderen.

Wenn du ein SEI machst, werden sämtliche offenen Interrupts in der
Reihenfolge ihrer Priorität abgearbeitet bevor das Hauptprogramm auch
nur einen Befehl weiterläuft.
* When the AVR exits from an interrupt, it will always return to
* the main program and execute one more instruction before any
* pending interrupt is served.
(ATMega16 Manual, Seite 12)

* The instruction following SEI will be executed before any pending
* interrupts.
(AVR Instruction Set Manual)

Nach RETI und SEI wird ein Befehl ausgefuehrt.

Hab schon Code (zu Demozwecken) von ein Singlestep-ISR gesehn.
(level gesteuerter externer Interrupt mit serieller Ausgabe der Register)

Ich würde mir das Ganze noch etwas anschauen. Wenn meine Vermutung stimmt,
würde nämlich der Timerinterrupt ab und zu blockiert werden und dann hinkt
deine Systemzeit etwas hinterher.
Ich habe Interrupts gerne mit dem Oszi kontrolliert.
Am Beginn der ISR setze ich einen unbenutzen IO-Pin auf High und am
Ende wieder auf Low. So kann ich Haeufigkeit und Dauer kontrollieren.

servus thomas
Ť
--
Die 4. Österreichische Fan-Convention zum Thema Japanische Popkultur
** AniNite 2004 ** 20.-22.August 2004 ** http://www.aninite.at/ **
Anime & Manga * J-Pop Bar * Cosplay * Videogames * Go * DDR * AMV *
Manga Workshop * Quiz * Trading Cards * Vortraege * Origami * Kyudo *
 
Wenn du ein SEI machst, werden sämtliche offenen Interrupts in der
Reihenfolge ihrer Priorität abgearbeitet bevor das Hauptprogramm auch
nur einen Befehl weiterläuft.

* When the AVR exits from an interrupt, it will always return to
* the main program and execute one more instruction before any
* pending interrupt is served.
(ATMega16 Manual, Seite 12)
Aha. Habe ich nicht gewusst.

Bei Debuggen meiner C-Programme ist mit das bisher nicht aufgefallen. Da
springt das Programm nach dem return sofort in die nächste ISR wenn ein
Interrupt offen ist. Man sollte halt ab und zu auf Assemblercode umschalten.

Schöne Grüsse
Georg
 
Thomas Mozgan wrote:
Georg Meister schrieb:

Allerdings kann ich mir das Nichtfunktionieren der bisher diskutierten
Vorschläge nur erklären wenn deine CAN-Interruptroutine tatsächlich viel
länger dauert als angegeben. Das ist wahrscheinlich auch der Grund warum
bei dir der Vorschlag von Thomas nicht funktioniert hat.


Das Nichtfunktionieren interressiert mich auch.
Um aehnliche Denk-, Konzept- oder Programmierfheler zu vermeiden.
Dein Vorschlag funktioniert glaube ich nicht, weil bei dem NOP
möglicherweise höher priorisierte Interrupts ausgeführt werden, und
nicht der Timer-Int.
Was ich jedoch sagen kann ist: Bei allen Versuchen, die ich gemacht
habe, passiert es sehr selten das TCTR0 zwischen 0 und 9 liegt und
SystemTime noch nicht erhöht wurde. Es gibt nie größere Werte. Die
längste mögliche Verzögerung scheint also bei 36us zu liegen, was in
etwa der berechneten Dauer der Hardware ISR entspricht.
Das ist auch bei dem Vorschlag von Georg so, und hier ist mir noch nicht
klar warum das so ist.
Vielleicht ein Fehler in der Interrupt Sense Control des ext. Interrupt.

Bei "low level" es dann ein Interrupt nach dem anderen.
Das habe ich ausgeschlossen: Ich habe einen Zähler beim Eintritt in die
ISR erhöht, und auch die Zahl der fallenden Flanken am Int.Pin extern
mitgezählt. Die Zähler laufen synchron.
Ich habe Interrupts gerne mit dem Oszi kontrolliert.
Am Beginn der ISR setze ich einen unbenutzen IO-Pin auf High und am
Ende wieder auf Low. So kann ich Haeufigkeit und Dauer kontrollieren.
Aber man merkt nicht, ob die Routine sehr selten einmal länger dauert
als erwartet. Es wäre schon großes Glück das am Speicher-Oszi. einmal zu
treffen. Mein Problem trat etwa alle vier Minuten auf, wenn
ununterbrochen TCTR0 und Systemtime ausgelesen wurden.
servus thomas
Ť
mfg
Helmut
 
Helmut Neemann schrieb:
Thomas Mozgan wrote:

Das Nichtfunktionieren interressiert mich auch.
Um aehnliche Denk-, Konzept- oder Programmierfheler zu vermeiden.

Dein Vorschlag funktioniert glaube ich nicht, weil bei dem NOP
möglicherweise höher priorisierte Interrupts ausgeführt werden, und
nicht der Timer-Int.
Ja, stimmt. Dadurch ist mein Vorschlag unbrauchbar.

Was ich jedoch sagen kann ist: Bei allen Versuchen, die ich gemacht
habe, passiert es sehr selten das TCTR0 zwischen 0 und 9 liegt und
SystemTime noch nicht erhöht wurde. Es gibt nie größere Werte. Die
längste mögliche Verzögerung scheint also bei 36us zu liegen, was in
etwa der berechneten Dauer der Hardware ISR entspricht.
Die 36us sind deine gezaehlten 533 Zyklen.

Du verwendest doch einen Prescaler von 64(?). Waehrend des Interrupts
sollte sich TCNT0 um 8 (533/64) erhoehen. Daher sollten keine Werte
zwischen 0-8 fuer TCNT0 im Hauptprogramm vorkommen.

Oder hab ich jetzt einen Logikfehler.

Das ist auch bei dem Vorschlag von Georg so, und hier ist mir noch
nicht klar warum das so ist.
Aber die von Georg vorgeschlagene Idee muss funktionieren.

* hs1:
* IN R3,TCNT0
* LDS R17,SYSTEMTIME
* LDS R18,SYSTEMTIME+1
* LDS R19,SYSTEMTIME+2
* LDS R20,SYSTEMTIME+3
* IN R4,TCNT0
* CP R4,R3
* BRLO hs1

Diese Code funktioniert nicht bei,

*) Interrupt zwischen CP/BRLO, keine Rekonstruktion der
SREG-Flags am Ende der ISR
*) Interrupt zwischen IN R3../CP welcher den Wert von R3 aendert

oder ein aehnlicher Fehler in deiner Test-/Vergleichsroutine

servus thomas
Ť
--
Die 4. Österreichische Fan-Convention zum Thema Japanische Popkultur
** AniNite 2004 ** 20.-22.August 2004 ** http://www.aninite.at/ **
Anime & Manga * J-Pop Bar * Cosplay * Videogames * Go * DDR * AMV *
Manga Workshop * Quiz * Trading Cards * Vortraege * Origami * Kyudo *
 
Thomas Mozgan wrote:
Helmut Neemann schrieb:

Dein Vorschlag funktioniert glaube ich nicht, weil bei dem NOP
möglicherweise höher priorisierte Interrupts ausgeführt werden, und
nicht der Timer-Int.


Ja, stimmt. Dadurch ist mein Vorschlag unbrauchbar.


Was ich jedoch sagen kann ist: Bei allen Versuchen, die ich gemacht
habe, passiert es sehr selten das TCTR0 zwischen 0 und 9 liegt und
SystemTime noch nicht erhöht wurde. Es gibt nie größere Werte. Die
längste mögliche Verzögerung scheint also bei 36us zu liegen, was in
etwa der berechneten Dauer der Hardware ISR entspricht.


Die 36us sind deine gezaehlten 533 Zyklen.

Du verwendest doch einen Prescaler von 64(?). Waehrend des Interrupts
sollte sich TCNT0 um 8 (533/64) erhoehen. Daher sollten keine Werte
zwischen 0-8 fuer TCNT0 im Hauptprogramm vorkommen.

Oder hab ich jetzt einen Logikfehler.
Die Hardware ISR für den CAN-Bus ist 533 Zyklen lang. Die Timer ISR
dauert maximal 76 Zyklen, und in den allermeisten Fällen sogar nur 40.
Das ist auch bei dem Vorschlag von Georg so, und hier ist mir noch
nicht klar warum das so ist.


Aber die von Georg vorgeschlagene Idee muss funktionieren.

* hs1:
* IN R3,TCNT0
* LDS R17,SYSTEMTIME
* LDS R18,SYSTEMTIME+1
* LDS R19,SYSTEMTIME+2
* LDS R20,SYSTEMTIME+3
* IN R4,TCNT0
* CP R4,R3
* BRLO hs1

Ich glaube ich habe einen Denkfehler gemacht, und die Prioritäten der
ISR nicht richtig im Kopf gehabt. Ich habe noch eine ADC ISR die mit
knapp 10kHz läuft und etwa 3.5% Rechenleistung verbraucht. Bisher dachte
ich sie hat die niedrigste Prio und muss nicht berücksichtigt werden.
Eben sehe ich aber, dass der Timer0 Compare Handler die niedrigste Prio
hat. Damit gibt es zwei Interrupts mit höhererer Priorität als der Timer.
Wenn nun das folgende Szenario eintritt: Unmittelbar vor dem ersten IN
wird die CAN-ISR gestartet. Während der CAN-ISR kommen ADC-Int und
Timer-Int. Nach der Hardware-ISR wird der IN Befehl ausgeführt und, da
der Timer schon überglaufen ist, ließt er eine Zahl zwischen 0 und 9.
Danach kommt die ADC-ISR an die Reihe und dann kommt das erste LDS. Erst
danach die wird die Timer-ISR ausgeführt. Wenn dann nach den restlichen
LDS-Befehlen der zweite IN Befehl kommt, wird eine Zahl größer 9 gelesen
und der Vergleich ist ok. Ich habe aber ein falsches Byte SystemTime
geladen und es ergibt sich genau das beobachtete Phänomen.

Jetzt muß man sich nur noch überlegen wie wahrscheinlich das ist, oder
den folgenden Code ausprobieren:

* hs1:
* IN R3,TCNT0
NOP
* LDS R17,SYSTEMTIME
* LDS R18,SYSTEMTIME+1
* LDS R19,SYSTEMTIME+2
* LDS R20,SYSTEMTIME+3
* IN R4,TCNT0
* CP R4,R3
* BRLO hs1

mfg
Helmut (für den die Welt wieder in Ordnung ist ;-)
 
Ich glaube ich habe einen Denkfehler gemacht, und die Prioritäten der ISR
nicht richtig im Kopf gehabt. Ich habe noch eine ADC ISR die mit knapp
10kHz läuft und etwa 3.5% Rechenleistung verbraucht. Bisher dachte ich sie
hat die niedrigste Prio und muss nicht berücksichtigt werden. Eben sehe
ich aber, dass der Timer0 Compare Handler die niedrigste Prio hat. Damit
gibt es zwei Interrupts mit höhererer Priorität als der Timer.
Wenn nun das folgende Szenario eintritt: Unmittelbar vor dem ersten IN
wird die CAN-ISR gestartet. Während der CAN-ISR kommen ADC-Int und
Timer-Int. Nach der Hardware-ISR wird der IN Befehl ausgeführt und, da der
Timer schon überglaufen ist, ließt er eine Zahl zwischen 0 und 9.
Danach kommt die ADC-ISR an die Reihe und dann kommt das erste LDS. Erst
danach die wird die Timer-ISR ausgeführt. Wenn dann nach den restlichen
LDS-Befehlen der zweite IN Befehl kommt, wird eine Zahl größer 9 gelesen
und der Vergleich ist ok. Ich habe aber ein falsches Byte SystemTime
geladen und es ergibt sich genau das beobachtete Phänomen.

Jetzt muß man sich nur noch überlegen wie wahrscheinlich das ist, oder den
folgenden Code ausprobieren:

* hs1:
* IN R3,TCNT0
NOP
* LDS R17,SYSTEMTIME
* LDS R18,SYSTEMTIME+1
* LDS R19,SYSTEMTIME+2
* LDS R20,SYSTEMTIME+3
* IN R4,TCNT0
* CP R4,R3
* BRLO hs1

Nicht schlecht.

Ich hatte gerade ein Szenario konstruiert, wo die Routine danebengeht, hab
aber inzwischen MONK im Fernsehen geguckt und nun komm ich zurück und schon
liegt die fertige Lösung da :)

Also ich erzähl trotzdem noch kurz was ich mir ausgedacht habe:

Wenn einen Befehl VOR dem IN R3 der externe Interrupt und der Timeroverflow
zugleich kommen, wird nach dem IN die ISR des ext. INT ausgeführt, und nach
dem LDS R17 der Timerinterrupt. Das Register R17 ist dann falsch.

Mein Problem war allerdings nicht nur, dass das extrem unwahrscheinlich ist
und nicht mit den 4 Minuten zusammenpasst, sondern auch, dass R3 dann auf
jeden Fall 0 ist und nicht 9 sein kann.

Helmuts Lösung erklärt das tatsächlich Beobachtete.
Assembler kann echt spannend sein.

Georg
 
Helmut Neemann schrieb:
Thomas Mozgan wrote:

Die 36us sind deine gezaehlten 533 Zyklen.

Du verwendest doch einen Prescaler von 64(?). Waehrend des Interrupts
sollte sich TCNT0 um 8 (533/64) erhoehen. Daher sollten keine Werte
zwischen 0-8 fuer TCNT0 im Hauptprogramm vorkommen.

Oder hab ich jetzt einen Logikfehler.

Die Hardware ISR für den CAN-Bus ist 533 Zyklen lang. Die Timer ISR
dauert maximal 76 Zyklen, und in den allermeisten Fällen sogar nur 40.
Gut. Dann ist meine Ueberlegung hinfaellig.
Da die Timer-ISR meist kuerzer als der Prescaler (64) ist.

Aber die von Georg vorgeschlagene Idee muss funktionieren.

* hs1:
* IN R3,TCNT0
* LDS R17,SYSTEMTIME
* LDS R18,SYSTEMTIME+1
* LDS R19,SYSTEMTIME+2
* LDS R20,SYSTEMTIME+3
* IN R4,TCNT0
* CP R4,R3
* BRLO hs1

Ich glaube ich habe einen Denkfehler gemacht, und die Prioritäten der
ISR nicht richtig im Kopf gehabt. Ich habe noch eine ADC ISR die mit
knapp 10kHz läuft und etwa 3.5% Rechenleistung verbraucht.
Ca 60 Taktzyklen?
Wenn die ADC-ISR mit rund 10kHz und die Timer0-ISR mit genau 1kHz
auftreten, gibt es ein langes Zeitfenster mit aufeinander folgenden
Kollisionen (d.h. die Timer0-ISR wird verzoegert).
Deckt sich die Fehler-Haeufigkeit mit meiner Ueberlegung?

Bisher dachte
ich sie hat die niedrigste Prio und muss nicht berücksichtigt werden.
Eben sehe ich aber, dass der Timer0 Compare Handler die niedrigste Prio
hat. Damit gibt es zwei Interrupts mit höhererer Priorität als der Timer.
Wenn nun das folgende Szenario eintritt: Unmittelbar vor dem ersten IN
wird die CAN-ISR gestartet. Während der CAN-ISR kommen ADC-Int und
Timer-Int. Nach der Hardware-ISR wird der IN Befehl ausgeführt und, da
der Timer schon überglaufen ist, ließt er eine Zahl zwischen 0 und 9.
Danach kommt die ADC-ISR an die Reihe und dann kommt das erste LDS. Erst
danach die wird die Timer-ISR ausgeführt. Wenn dann nach den restlichen
LDS-Befehlen der zweite IN Befehl kommt, wird eine Zahl größer 9 gelesen
und der Vergleich ist ok. Ich habe aber ein falsches Byte SystemTime
geladen und es ergibt sich genau das beobachtete Phänomen.
Aha, wirkt sehr konstruiert.

Wenn man jedoch verinnerlicht, dass die Timer-ISR zeitversetzt behandelt
wird (verzoegert durch Abarbeitung der anderen ISR) und zwischen
den einzelnen ISR je ein Befehl des Hauptprogrammes ausgefuehrt wird,
ist es nachvollziehbar.
Der Grundfehler liegt bisher in der Annahme, dass mit TCNT0=0..8
auf ein ausgefuehrten Timer0-Interrupt geschlossen wurde (LDS
jedoch einen alten Wert las).

Jetzt muß man sich nur noch überlegen wie wahrscheinlich das ist, oder
den folgenden Code ausprobieren:

* hs1:
* IN R3,TCNT0
NOP
* LDS R17,SYSTEMTIME
* LDS R18,SYSTEMTIME+1
* LDS R19,SYSTEMTIME+2
* LDS R20,SYSTEMTIME+3
* IN R4,TCNT0
* CP R4,R3
* BRLO hs1
Zwischen IN R3 und dem LDS muss der Timer-ISR nun garantiert kommen.
Also sollte der jetztige Code funktionieren (wenn weitere hoeherpriore
ISR existieren, noch weitere NOPs/Befehle).
Alternativ kannst du die ADC/CAN Interrupts unterbrechbar programmieren.

Wenn die Timer-ISR laenger als eine Aenderung von TCNT0 dauert (Prescaler)
kannst du BRLO durch BRNE ersetzen (und NOP streichen). Dadurch stellst
du sicher, dass zwischen den beiden IN keine Unterbrechung/Interrupt
laenger als Prescaler auftratt.

servus thomas
Ť
--
Die 4. Österreichische Fan-Convention zum Thema Japanische Popkultur
** AniNite 2004 ** 20.-22.August 2004 ** http://www.aninite.at/ **
Anime & Manga * J-Pop Bar * Cosplay * Videogames * Go * DDR * AMV *
Manga Workshop * Quiz * Trading Cards * Vortraege * Origami * Kyudo *
 

Welcome to EDABoard.com

Sponsor

Back
Top