AVR ATmega16+Timer

H

Helmut Neemann

Guest
Hallo,

ich habe das folgende Problem, und es will mir einfach keine Lösung
einfallen:

Ich habe den Timer0 so programmiert, dass er alle 1ms einen Interrupt
auslößt. In der Interrupt-Routine erhöhe ich einen 32-Bit-Zähler um eins
und erzeuge mir so eine Systemzeit. Funktioniert auch prima.

Dann und wann brauche ich aber eine genauere Zeitangabe. Da habe ich mir
gedacht ich kombiniere den 32-Bit-Zähler mit dem TCNT0-Register. Dieses
Register läuft bei mir immer bis 250 (Inhalt von OCR0), dann wird es auf
Null zurückgesetzt und ein Interrupt wird erzeugt.

Wie muß man das Auslesen des TCNT0-Registers und des 32-Bit-Zählers
programmieren, so das man eine korrekte Zeit erhält?

Die Kombination

IN R16,TCNT0
CLI
LDS R17,SYSTEMTIME ; uR17:R18:R19:R20="SystemTime"
LDS R18,SYSTEMTIME+1
LDS R19,SYSTEMTIME+2
LDS R20,SYSTEMTIME+3
SEI

funktioniert am besten. Wie zu erwarten kommt es aber manchmal zu
Problemen. Ich denke diese entstehen, wenn zwischen dem IN und dem CLI
der Zähler auf Null springt und ein Interrupt erzeugt wird. Vertauscht
man die Befehle jedoch gibt es viel häufiger Probleme. Das überrascht
auch nicht, denn der Zähler läuft ja um, egal ob Interrupts erzeugt
werden oder nicht.

Hat schon einmal jemand ein ähnliches Problem gehabt und eine Lösung
ersonnen?

mfg
Helmut
 
Helmut Neemann schrieb:

[Timer0, alle 1ms einen Interrupt, 32-Bit-Zähler, OCR0=250]

Output Compare Interrupt mit Prescaler=64 bei 16Mhz?

Wie muß man das Auslesen des TCNT0-Registers und des 32-Bit-Zählers
programmieren, so das man eine korrekte Zeit erhält?

Die Kombination

IN R16,TCNT0
CLI
LDS R17,SYSTEMTIME ; uR17:R18:R19:R20="SystemTime"
LDS R18,SYSTEMTIME+1
LDS R19,SYSTEMTIME+2
LDS R20,SYSTEMTIME+3
SEI

funktioniert am besten. Wie zu erwarten kommt es aber manchmal zu
Problemen. Ich denke diese entstehen, wenn zwischen dem IN und dem CLI
der Zähler auf Null springt und ein Interrupt erzeugt wird.
Dieser Fehler kann doch nicht so oft vorkommen?
Alle (250*Timer0_Prescale) Zyklen ist so eine kritische Situation.
Diese muss auch noch mit der Abfrage kollidieren.

Mein Vorschlag:

CLI
IN R16, TCNT0
IN temp, TIFR
ANDI temp, 2 ;(1<<OCF0)=2, test for flag
BREQ 1f ;skip next instruction if flag set
SEI
NOP
IN R16, TCNT0 ; "hmm, sollte eigentlich immer 0 sein"
CLI
1:
LDS R17,SYSTEMTIME ; uR17:R18:R19:R20="SystemTime"
LDS R18,SYSTEMTIME+1
LDS R19,SYSTEMTIME+2
LDS R20,SYSTEMTIME+3
SEI

Wenn du einfach nach dem Sichern des TCNT0, das zum Output Compare
Interrupt gehoerige Flag abfragst, kannst du den Reset des TCNT0
abfangen.

Ist OCF0 gesetzt, verwirfst du den gelesenen TCNT0 und laesst
den Output Compare Interrupt ausfuehren und SYSTEMTIME updaten.
Danach muss der TCNT0 und die SYSTEMTIME (fuer 1ms) atomic sein.

Was mit mehreren Interruptsflag mit verschiedenen Prioritaeten
nach dem SEI geschieht, weiss ich momentan nicht. Das NOP ist
notwendig da ein Befehl nach dem SEI auf jeden Fall ausgefuehrt wird.

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 *
 
Hallo

Du vergleichst am Ende nochmal TCNT0 mit R16. Wenn TCNT0 kleiner ist, weisst
du, dass inzwischen ein Overflow stattgefunden hat und du springst einfach
zurück und lädst alles nochmal. CLI und SEI können ganz entfallen.

Georg




"Helmut Neemann" <hneemann@despammed.com> schrieb im Newsbeitrag
news:2klvanF3vfofU1@uni-berlin.de...
Hallo,

ich habe das folgende Problem, und es will mir einfach keine Lösung
einfallen:

Ich habe den Timer0 so programmiert, dass er alle 1ms einen Interrupt
auslößt. In der Interrupt-Routine erhöhe ich einen 32-Bit-Zähler um eins
und erzeuge mir so eine Systemzeit. Funktioniert auch prima.

Dann und wann brauche ich aber eine genauere Zeitangabe. Da habe ich mir
gedacht ich kombiniere den 32-Bit-Zähler mit dem TCNT0-Register. Dieses
Register läuft bei mir immer bis 250 (Inhalt von OCR0), dann wird es auf
Null zurückgesetzt und ein Interrupt wird erzeugt.

Wie muß man das Auslesen des TCNT0-Registers und des 32-Bit-Zählers
programmieren, so das man eine korrekte Zeit erhält?

Die Kombination

IN R16,TCNT0
CLI LDS R17,SYSTEMTIME ; uR17:R18:R19:R20="SystemTime"
LDS R18,SYSTEMTIME+1
LDS R19,SYSTEMTIME+2
LDS R20,SYSTEMTIME+3
SEI

funktioniert am besten. Wie zu erwarten kommt es aber manchmal zu
Problemen. Ich denke diese entstehen, wenn zwischen dem IN und dem CLI der
Zähler auf Null springt und ein Interrupt erzeugt wird. Vertauscht man die
Befehle jedoch gibt es viel häufiger Probleme. Das überrascht auch nicht,
denn der Zähler läuft ja um, egal ob Interrupts erzeugt werden oder nicht.

Hat schon einmal jemand ein ähnliches Problem gehabt und eine Lösung
ersonnen?

mfg
Helmut
 
CLI
IN R16, TCNT0
IN temp, TIFR
ANDI temp, 2 ;(1<<OCF0)=2, test for flag
BREQ 1f ;skip next instruction if flag set
SEI
NOP
IN R16, TCNT0 ; "hmm, sollte eigentlich immer 0 sein"
CLI
1:
LDS R17,SYSTEMTIME ; uR17:R18:R19:R20="SystemTime"
LDS R18,SYSTEMTIME+1
LDS R19,SYSTEMTIME+2
LDS R20,SYSTEMTIME+3
SEI

Ich denke der Vorschlag hat das gleiche Problem. Der Overflow kann immer
noch nach dem Lesen von TIFR erfolgen und wird dann nicht bemerkt.

Georg
 
Georg Meister schrieb:

CLI
IN R16, TCNT0
IN temp, TIFR
ANDI temp, 2 ;(1<<OCF0)=2, test for flag
BREQ 1f ;skip next instruction if flag set
SEI
NOP
IN R16, TCNT0 ; "hmm, sollte eigentlich immer 0 sein"
CLI
1:
LDS R17,SYSTEMTIME ; uR17:R18:R19:R20="SystemTime"
LDS R18,SYSTEMTIME+1
LDS R19,SYSTEMTIME+2
LDS R20,SYSTEMTIME+3
SEI

Ich denke der Vorschlag hat das gleiche Problem. Der Overflow kann immer
noch nach dem Lesen von TIFR erfolgen und wird dann nicht bemerkt.
Das hat jedoch wenig Effekt auf die Gueltigkeit von TCNT0 und SYSTEMTIME.
SYSTEMTIME wird nicht zwischenzeitlich upgedated (Interrupt gesperrt) und
gilt fuer den gelesenen TCNT0.

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 *
 
Georg Meister schrieb:
Du vergleichst am Ende nochmal TCNT0 mit R16. Wenn TCNT0 kleiner
ist, weisst du, dass inzwischen ein Overflow stattgefunden hat und
du springst einfach zurück und lädst alles nochmal.
CLI und SEI können ganz entfallen.
Stimmt. Ist die eleganteste Loesung.

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 *
 
CLI
IN R16, TCNT0
IN temp, TIFR
ANDI temp, 2 ;(1<<OCF0)=2, test for flag
BREQ 1f ;skip next instruction if flag set
SEI
NOP
IN R16, TCNT0 ; "hmm, sollte eigentlich immer 0 sein"
CLI
1:
LDS R17,SYSTEMTIME ; uR17:R18:R19:R20="SystemTime"
LDS R18,SYSTEMTIME+1
LDS R19,SYSTEMTIME+2
LDS R20,SYSTEMTIME+3
SEI

Ich denke der Vorschlag hat das gleiche Problem. Der Overflow kann immer
noch nach dem Lesen von TIFR erfolgen und wird dann nicht bemerkt.

Das hat jedoch wenig Effekt auf die Gueltigkeit von TCNT0 und SYSTEMTIME.
SYSTEMTIME wird nicht zwischenzeitlich upgedated (Interrupt gesperrt) und
gilt fuer den gelesenen TCNT0.

Ja richtig. Hatte ich nicht gesehen.

Georg
 
Hallo,

das hört sich richtig gut an, liefert aber das gleiche Ergebnis wie die
Simpelimplementierung aus meinem ersten Posting.

Ich habe folgenden Code getestet:

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

Bei einem Versuch ist in R3=9 zu finden und SYSTEMTIME wurde noch nicht
erhöht. Aufgefallen ist mir jedoch, dass das Problem nur auftritt, wenn
externe Interrupts, die ja eine höhere Priorität haben als der Timer,
ausgelößt werden. Die Interrupts kommen aber nur mit 100Hz, können also
nicht den Timer-Int auf Dauer lahmlegen.

Gruss vom ratlosen
Helmut

Georg Meister wrote:
Hallo

Du vergleichst am Ende nochmal TCNT0 mit R16. Wenn TCNT0 kleiner ist, weisst
du, dass inzwischen ein Overflow stattgefunden hat und du springst einfach
zurück und lädst alles nochmal. CLI und SEI können ganz entfallen.

Georg




"Helmut Neemann" <hneemann@despammed.com> schrieb im Newsbeitrag
news:2klvanF3vfofU1@uni-berlin.de...


IN R16,TCNT0
CLI LDS R17,SYSTEMTIME ; uR17:R18:R19:R20="SystemTime"
LDS R18,SYSTEMTIME+1
LDS R19,SYSTEMTIME+2
LDS R20,SYSTEMTIME+3
SEI
 
das hört sich richtig gut an, liefert aber das gleiche Ergebnis wie die
Simpelimplementierung aus meinem ersten Posting.

Ich habe folgenden Code getestet:

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

Bei einem Versuch ist in R3=9 zu finden und SYSTEMTIME wurde noch nicht
erhöht. Aufgefallen ist mir jedoch, dass das Problem nur auftritt, wenn
externe Interrupts, die ja eine höhere Priorität haben als der Timer,
ausgelößt werden. Die Interrupts kommen aber nur mit 100Hz, können also
nicht den Timer-Int auf Dauer lahmlegen.

Ich hab den Verdacht, dass deine externen Interruptroutinen einfach zu lange
dauern.

Das Programm funktioniert natürlich nicht, wenn irgendeine Interruptroutine
den obigen Code für länger als 1/2 ms blockiert. Ausserdem muss auch der
Timerint alle 1 ms seine Chance bekommen, damit die Systemzeit überhaupt
Sinn macht.

Georg
 
Hallo,

gerade habe ich einmal die Zyklen gezählt: 533 Zyklen braucht meine
externe Interrupt-Routine maximal. Bei 16MHz Systemtakt sind das etwa
33us. Bei 100Hz ergeben sich 53300 Zyklen/s was nur 3 Promille
Auslastung ergibt.
Die Interrupt-Routine für den Timer braucht nur maximal 76 Zyklen. Bei
einem 1kHz sind das 76000 Zyklen/s, ist also nicht wesentlich mehr.
Daran kann es eigentlich nicht liegen.

mfg
Helmut

Georg Meister wrote:
Ich hab den Verdacht, dass deine externen Interruptroutinen einfach zu lange
dauern.

Das Programm funktioniert natürlich nicht, wenn irgendeine Interruptroutine
den obigen Code für länger als 1/2 ms blockiert. Ausserdem muss auch der
Timerint alle 1 ms seine Chance bekommen, damit die Systemzeit überhaupt
Sinn macht.

Georg
 
gerade habe ich einmal die Zyklen gezählt: 533 Zyklen braucht meine
externe Interrupt-Routine maximal. Bei 16MHz Systemtakt sind das etwa
33us. Bei 100Hz ergeben sich 53300 Zyklen/s was nur 3 Promille Auslastung
ergibt.
Die Interrupt-Routine für den Timer braucht nur maximal 76 Zyklen. Bei
einem 1kHz sind das 76000 Zyklen/s, ist also nicht wesentlich mehr.
Daran kann es eigentlich nicht liegen.
Ist das simuliert oder hast den ATmega16 am JTAG-Debugger hängen?

Was du noch machen kannst:

Lass mal den 16-Bit Timer mit dem gleichen Takt wie den Timer 0 laufen und
merk dir die TCNT1L/H Werte vor und nach den kritischen Routinen (H/L in der
richtigen Reihenfolge auslesen!). Sozusagen als Stoppuhr.

Noch was:
Wie stellst du das Problem eigentlich genau fest? Und die Häufigkeit?

Georg
 
In article <2ko3qiF4gkutU1@uni-berlin.de>,
Helmut Neemann <hneemann@despammed.com> writes:
Hallo,

gerade habe ich einmal die Zyklen gezählt: 533 Zyklen braucht meine
externe Interrupt-Routine maximal. Bei 16MHz Systemtakt sind das etwa
33us. Bei 100Hz ergeben sich 53300 Zyklen/s was nur 3 Promille
Auslastung ergibt.
Hast du geprüft daß sie 533 Zyklen immer nur einmal duechlaufen?

--
MFG Gernot
 
Georg Meister wrote:
gerade habe ich einmal die Zyklen gezählt: 533 Zyklen braucht meine
externe Interrupt-Routine maximal. Bei 16MHz Systemtakt sind das etwa
33us. Bei 100Hz ergeben sich 53300 Zyklen/s was nur 3 Promille Auslastung
ergibt.
Die Interrupt-Routine für den Timer braucht nur maximal 76 Zyklen. Bei
einem 1kHz sind das 76000 Zyklen/s, ist also nicht wesentlich mehr.
Daran kann es eigentlich nicht liegen.


Ist das simuliert oder hast den ATmega16 am JTAG-Debugger hängen?

Was du noch machen kannst:

Lass mal den 16-Bit Timer mit dem gleichen Takt wie den Timer 0 laufen und
merk dir die TCNT1L/H Werte vor und nach den kritischen Routinen (H/L in der
richtigen Reihenfolge auslesen!). Sozusagen als Stoppuhr.

Noch was:
Wie stellst du das Problem eigentlich genau fest? Und die Häufigkeit?

Georg
Die Zyklen habe ich einfach abgezählt: Alle Zyklenzahlen der
Assemblerbefehle addiert. ;-)
Und die Diagnose des Problems ist einfach: Ich berechne pausenloss
SYSTEMTIME*250+TCNT0 und erhöhe einen Zähler, wenn eine Berechnung ein
kleineres Ergebnis liefert wie die letzte Berechnung. Diesen Zähler
schaue ich mir dann an.

Der externe Interrupt wird von einem CAN-Controller SJA1000 ausgelöst,
der einen Interrupt erzeugt, wenn er eine CAN-Botschaft empfangen hat.
Meine Interrupt-Routine ließt dann die Botschaft aus dem Controller aus
und schreibt sie in einen Buffer. Das Hauptprogramm beantwortet die
Botschaft dann. Der AVR hat einen Teil des CCP-Protokolls implementiert,
welches mir erlaubt beliebige RAM-Zellen per CAN auszulesen. Mit
entsprechenden CAN-Diagnoseprogrammen kann man dann sehr komfortabel
Analysen durchführen. Das geht natürlich längst nicht so Taktgenau wie
mit einem JTAG-Interface, aber meistens reicht es.

mfg
Helmut
 
Gernot Fink wrote:

In article <2ko3qiF4gkutU1@uni-berlin.de>,
Helmut Neemann <hneemann@despammed.com> writes:

Hallo,

gerade habe ich einmal die Zyklen gezählt: 533 Zyklen braucht meine
externe Interrupt-Routine maximal. Bei 16MHz Systemtakt sind das etwa
33us. Bei 100Hz ergeben sich 53300 Zyklen/s was nur 3 Promille
Auslastung ergibt.


Hast du geprüft daß sie 533 Zyklen immer nur einmal duechlaufen?

Habe ich gerade getestet: Die Interrupt-Routine wird genau so oft
Ausgeführt wie erwartet.

mfg
Helmut
 
Die Zyklen habe ich einfach abgezählt: Alle Zyklenzahlen der
Assemblerbefehle addiert. ;-)
Und die Diagnose des Problems ist einfach: Ich berechne pausenloss
SYSTEMTIME*250+TCNT0 und erhöhe einen Zähler, wenn eine Berechnung ein
kleineres Ergebnis liefert wie die letzte Berechnung. Diesen Zähler schaue
ich mir dann an.
Ich denke ich weiss was dein Problem ist.

OCR0 ist falsch sollte 249 sein.
TCNT0 läuft von 0 bis OCR0 nicht OCR0 - 1.

Der externe Interrupt wird von einem CAN-Controller SJA1000 ausgelöst, der
einen Interrupt erzeugt, wenn er eine CAN-Botschaft empfangen hat. Meine
Interrupt-Routine ließt dann die Botschaft aus dem Controller aus und
schreibt sie in einen Buffer. Das Hauptprogramm beantwortet die Botschaft
dann. Der AVR hat einen Teil des CCP-Protokolls implementiert, welches mir
erlaubt beliebige RAM-Zellen per CAN auszulesen. Mit entsprechenden
CAN-Diagnoseprogrammen kann man dann sehr komfortabel Analysen
durchführen. Das geht natürlich längst nicht so Taktgenau wie mit einem
JTAG-Interface, aber meistens reicht es.
Als Ferndiagnose im laufenden Betrieb sicher praktisch. Zur
Firmwareentwicklung aber unbrauchbar.

Mit einem JTAG-ICE setzt du ein paar Breaks (Timer wird dabei gestoppt),
schaust dir die Register an und weisst sofort woran es liegt. Besorg dir
doch so ein Ding (Nachbauten ab EUR 40), alles andere ist nur mühselige
Raterei.

Schöne Grüsse
Georg
 
Georg Meister wrote:
Ich denke ich weiss was dein Problem ist.

OCR0 ist falsch sollte 249 sein.
TCNT0 läuft von 0 bis OCR0 nicht OCR0 - 1.

Leider habe ich daran gedacht: OCR0 ist 249. ;-)

Als Ferndiagnose im laufenden Betrieb sicher praktisch. Zur
Firmwareentwicklung aber unbrauchbar.

Dieses Interface ist eigentlich auch nicht für die Firmware-Entwicklung
gedacht gewesen, sondern für die Diagnose der Applikation die unter der
Firmware ausgeführt wird. Es ist im Moment aber das beste was ich habe.

Mit einem JTAG-ICE setzt du ein paar Breaks (Timer wird dabei gestoppt),
schaust dir die Register an und weisst sofort woran es liegt. Besorg dir
doch so ein Ding (Nachbauten ab EUR 40), alles andere ist nur mühselige
Raterei.

Darüber habe ich auch schon einmal nachgedacht. Nur leider habe ich in
diesem Projekt die Pins für das JTAG-Interface schon belegt.
Wie sieht es denn mit Debugger-Software aus? Ich habe keine Erfahrung
mit JTAG. Beinhaltet das AVRStudio einen brauchbaren JTAG-Debugger, oder
ist weitere Software notwendig?

mfg
Helmut
 
Vielleicht so:

NochEinmal:
IN R16,TCNT0

LDS R17,SYSTEMTIME ; uR17:R18:R19:R20="SystemTime"
LDS R18,SYSTEMTIME+1
LDS R19,SYSTEMTIME+2
LDS R20,SYSTEMTIME+3

LDS R?,SYSTEMTIME
cp R?,R17
brne NochEinmal

Gruß Klaus Beier
 
Ich denke ich weiss was dein Problem ist.

OCR0 ist falsch sollte 249 sein.
TCNT0 läuft von 0 bis OCR0 nicht OCR0 - 1.

Leider habe ich daran gedacht: OCR0 ist 249. ;-)
Schade. Du hattest im OP geschrieben, TCNT0 läuft bis 250 (Wert von OCR0).

Kann es nicht vielleicht doch sein, dass deine CAN-Interruptroutine zu lange
dauert? Könnte ja ein Fehler drinnen sein und eine Schleife wird zu oft
ausgeführt. Deswegen mein Vorschlag mit der Timer 1 als Stoppuhr. Oder der
nächste CAN-Interrupt kommt schon, während die Routine noch läuft.

Mit einem JTAG-ICE setzt du ein paar Breaks (Timer wird dabei gestoppt),
schaust dir die Register an und weisst sofort woran es liegt. Besorg dir
doch so ein Ding (Nachbauten ab EUR 40), alles andere ist nur mühselige
Raterei.

Darüber habe ich auch schon einmal nachgedacht. Nur leider habe ich in
diesem Projekt die Pins für das JTAG-Interface schon belegt.
Das ist tatsächlich oft ein Nachteil, dass man dafür 4 Pins opfern muss.
Aber Atmel will ja die neuen ATmegas mit DebugWire ausrüsten, dann läuft das
über den Reset-Pin.

Wie sieht es denn mit Debugger-Software aus? Ich habe keine Erfahrung mit
JTAG. Beinhaltet das AVRStudio einen brauchbaren JTAG-Debugger, oder ist
weitere Software notwendig?
Nein geht alles mit AVR Studio.

Georg
 
Hallo,

ich glaube ich habe die Lösung gefunden. Der Vorschlag von Thomas Mozgan
funktioniert nicht, da ich, wenn ich dem Timer-Int nur einmal die Chance
gebe durchzulaufen, er nicht zum Zuge kommt, wenn ein Hardware-Int mit
höherer Priorität stattdessen ausgeführt wird.

Diese leicht abgewandelte Routine wartet, bis tatsächlich der Timer-Int
ausgeführt wurde:

p_hs1: CLI
LDS R17,SYSTEMTIME ; uR17:R18:R19:R20="SystemTime"
LDS R18,SYSTEMTIME+1
LDS R19,SYSTEMTIME+2
LDS R20,SYSTEMTIME+3
IN R16,TCNT0
IN R21,TIFR
SEI
ANDI R21,1<<OCF0 ;1 = Int pending
BRNE p_hs1

Eigentlich total naheliegend, man muss halt nur drauf kommen! ;-))

Vielen Dank an alle Ratgeber!

mfg
Helmut
 
ich glaube ich habe die Lösung gefunden. Der Vorschlag von Thomas Mozgan
funktioniert nicht, da ich, wenn ich dem Timer-Int nur einmal die Chance
gebe durchzulaufen, er nicht zum Zuge kommt, wenn ein Hardware-Int mit
höherer Priorität stattdessen ausgeführt wird.

Diese leicht abgewandelte Routine wartet, bis tatsächlich der Timer-Int
ausgeführt wurde:

p_hs1: CLI
LDS R17,SYSTEMTIME ; uR17:R18:R19:R20="SystemTime"
LDS R18,SYSTEMTIME+1
LDS R19,SYSTEMTIME+2
LDS R20,SYSTEMTIME+3
IN R16,TCNT0
IN R21,TIFR
SEI
ANDI R21,1<<OCF0 ;1 = Int pending
BRNE p_hs1

Eigentlich total naheliegend, man muss halt nur drauf kommen! ;-))

Ja das glaube ich auch dass das auf jeden Fall funktioniert.

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. 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.

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.

Georg
 

Welcome to EDABoard.com

Sponsor

Back
Top