Hallo Leute,
ich habe ein Kapazitätsmessgerät (mit AVR) gebaut und bin derzeit gerade
etwas unschlüssig. Es wird die Zeit von 0-Tau mit dem ICP gemessen.
Funktioniert auch alles super. Ich möchte alle Eventualitäten absichern.
Eine besondere Eventualität ist folgende:
Timer1 wird im CTC-Modus mit einem Zählumfang von 25000 betrieben.
Gleichzeitig werden auch die Overflows gezählt. Soweit alles gut.
Angenommen der Fall tritt auf, dass der Zähler Gerade übergelaufen ist
und es gibt den Capture. Derzeit sieht mein Code wie folgt aus:
Jetzt stellt sich mir die Frage, wenn der Capture bei einem Zählwert von
1 kommt, wird dann der Overflowinterrupt trotzdem vorher aufgerufen? Es
liegt ja nur ein einziger Takt dazwischen. Und die Latenzzeit beträgt
lt. DB 4 Takte. Leider gibt das DB keine weiteren Hinweise dazu.
Leider lässt sich dieser Zustand nicht durch Ausprobieren testen...
Hi
>Jetzt stellt sich mir die Frage, wenn der Capture bei einem Zählwert von>1 kommt, wird dann der Overflowinterrupt trotzdem vorher aufgerufen? Es>liegt ja nur ein einziger Takt dazwischen.
Bei CTC gibt es keinen Overflowinterrupt.
MfG spess
spess53 schrieb:> Bei CTC gibt es keinen Overflowinterrupt.
Ok, das ist dann der Compare-Match Interrupt. Haste Recht. Aber du als
Assembleraner kannst mir doch auch sicher weiterhelfen bei meiner
Ursprungsfrage oder?
Ingo L. schrieb:> Jetzt stellt sich mir die Frage, wenn der Capture bei einem Zählwert von> 1 kommt, wird dann der Overflowinterrupt trotzdem vorher aufgerufen?
Du hast es noch nicht erkannt: Aber dieser Fall ist irgendwie sogar noch
die kleinere Hälfte des Problems...
Ich würde dir empfehlen, die Sache erstmal ganz ohne Interrupts
durchzuspielen, einzig durch Polling der IRQ-Flags. Das ist sehr viel
einfacher als ein vollständig interruptgesteuertes Szenario (aber immer
noch hinreichend komplex, um Einsteiger heftig in's Schwitzen zu
bringen).
Wenn du DAS beherrschst, dann hast du das erst das nötige Rüstzeug, um
auch die vollständig interruptgetriebene Variante zuverlässig
hinzubekommen. Die ist nämlich richtig Tricky.
Und es hat kaum damit zu tun, dass die AVR8-Architektur keine echten
Interruptprioritäten kennt, sondern vor allem damit, dass die
Timer-Hardware nicht auf den MCU-Kern wartet. DAS vor allem macht die
Sache so kompliziert. Wenn du ein Gehirn im Kopp hast, wirst du das bei
der Umsetzung des Polling-Szenarios selber erkennen...
Das (fast) gleichzeitige auftreten vom "Überlauf" und ICP interrupt ist
tatsächlich etwas komplizierter. Ob man es über Interupts oder per
Polling macht, macht dabei keinen so großen Unterschied.
Das Abfragen des ICP Werte für mögliche Sonderfälle ist schon richtig
gedacht, man muss es aber noch mit einem ggf. noch wartenden Interrupt
kombinieren. Durch noch auszuführende Befehle kann der Sonderfall auch
bei mehr als nur dem Wert 0 auftreten. Wenn noch andere Interrupts aktiv
sind oder zum atomaren Auslesen Interrupts zeitweise gesperrt werden
kann das auch einige 10 Zyklen lang sein. Der Fall den man abfangen muss
ist, dass der ICP Wert klein ist, aber noch ein Interrupt für den
"Überlauf" aussteht.
c-hater schrieb:> Wenn du DAS beherrschst, dann hast du das erst das nötige Rüstzeug, um> auch die vollständig interruptgetriebene Variante zuverlässig> hinzubekommen. Die ist nämlich richtig Tricky.
Dann erklär doch mal deinen Trick.
c-hater schrieb:> Wenn du ein Gehirn im Kopp hast
"Eure Arroganz blendet euch Meister Joda..."
Danke Lurchi für deine Hinweise. Ich habe das Ganze mal durch den
Simulator geschoben. Für den Fall das Input Capture und Compare-Match
gleichzeitig kommen (TCNT1 = 0) wird der ICP-Interrupt zu erst
ausgeführt, es muss dann der Overflowzähler per Hand um 1 erhöht werden.
Ich werde es so lassen...
Hallo Peter,
den Beitrag habe ich bereits gelesen. Er hat aber wenig mit meiner
Problemstellung zu tun, denn in meiner Lösung wird alles über Interrupts
gelöst, ein atomarer Zugriff auf die Daten ist nicht nötig. Weiter ist
es eindeutig, welcher Interrupt zu erst ausgeführt wird. Nur in dem
Fall, wenn der neue Capture-Wert sehr klein ist, muss mit einem noch
nicht berücksichtigtem Overflow (oder Compare-Match) gerechnet werden.
Das kann man aber durch Prüfung des entsprechenden Flags abfangen.
1
/* Special Case => Overflow missed */
2
if(NewTicks<=10&&TIFR1&(1<<TOV1)){
3
Overflows++;
4
TIFR1|=(1<<TOV1);
5
}
Ich hoffe ich liege mit dieser These nicht falsch, ich lasse mich gerne
belehren.
Ingo L. schrieb:> Er hat aber wenig mit meiner> Problemstellung zu tun
Es ist egal, ob Du den Zeitstempel im Main oder einem anderen Interrupt
haben willst, Du hast in beiden Fällen keine Kontrolle, was zuerst
passiert und daher mußt Du es abtesten.
Im Interrupt fällt die Interruptsperre weg, das ist der einzige
Unterschied.
Ingo L. schrieb:> Timer1 wird im CTC-Modus mit einem Zählumfang von 25000 betrieben.
Das macht das ICP allerdings schwer, da Du damit unkontrollierte Sprünge
im Zählbereich hast.
Besser ist daher, den Timer linear durchlaufen zu lassen und den
Comparewert im Interrupthandler neu zu setzen:
Peter D. schrieb:> Du hast in beiden Fällen keine Kontrolle, was zuerst> passiert und daher mußt Du es abtesten.
Doch, die Interruptpriorität des Capture ist höher als die der
Compare-Match (für zeitgleiches Auftreten beider).
Peter D. schrieb:> Das macht das ICP allerdings schwer, da Du damit unkontrollierte Sprünge> im Zählbereich hast.
Kannst du mir das näher erklären? Ich verstehe das Problem leider nicht
was du beschreibst. So wird der Timer initialisiert:
Ingo L. schrieb:> Doch, die Interruptpriorität des Capture ist höher als die der> Compare-Match (für zeitgleiches Auftreten beider).
Und wenn das Compare nun einen Zyklus früher erfolgt?
Dann hängt die Aufrufreihenfolge davon ab, ob zufällig ein Befehl zuende
ist oder noch weitere Zyklen braucht.
Bei einem Zählbereich bis 24999 muß man Differenzen noch modulo 25000
korrigieren.
Ich zähle daher lieber binär, dann spart man sich die Division /25000.
Peter D. schrieb:> Und wenn das Compare nun einen Zyklus früher erfolgt?> Dann hängt die Aufrufreihenfolge davon ab, ob zufällig ein Befehl zuende> ist oder noch weitere Zyklen braucht.
Das sollte damit abgefangen werden, oder? Wird der Compare-Match zuerst
aufgerufen ist kein Eingreifen mehr erforderlich. Wird der Capture
zuerst aufgerufen muss nachgebessert werden.
1
/* Special Case => Overflow missed */
2
if(NewTicks<=10&&TIFR1&(1<<TOV1)){
3
Overflows++;
4
TIFR1|=(1<<TOV1);
5
}
Peter D. schrieb:> Bei einem Zählbereich bis 24999 muß man Differenzen noch modulo 25000> korrigieren.
Du meinst das hier ist falsch?
Ob man die Überläufe gleich in Schritten von 25000 hoch zählt, oder
später mit 25000 multipliziert, kommt auf das selbe heraus.
Beim Test auf einen kleinen ICP-wert sollte man etwas großzügiger sein.
Wenn kein anderer Interrrupt oder so dazwischen kommt sollte es mit 10
als Grenze ausreichen, aber man muss die Grenze nicht so knapp setzen.
Ein gesetztes Flag für den "Überlauf" kommt nur vor wenn die ICP werte
entweder klein ist (meist kleiner 10) oder sehr groß ( hier > 24000).
Man darf da also mit der Grenze großzügiger (z.B. 10000) sein und so
auch andere Interrupts oder Phasen mit gesperrtem Interrupt zulassen. Wo
man die Grenze genau hinlegt ist relativ egal, da ist ein großer Bereich
der nicht vorkommen sollte.
Beim Zurücksetzen des Interuptflags sollte man nur das eine zurücksetzen
und nicht gleich alle. Also eher
TIFR1 = (1<<TOV1);
statt
TIFR1 |= (1<<TOV1);
Man verliert so aber auch ein Durchgang für die Tastenentprellung. Da
wäre es ggf. günstiger das Flag nicht zu löschen und den extra Überlauf
nur temporär zu merken.
Danke Lurchi für deine Anmerkungen. Einen Durchgang zu verlieren macht
keinen Unterschied, die Entprellung dauert 1000ms (bewusst so lang), da
ist +2,5ms verschmerzbar.
Grade noch dank dir einen Fehler gefunden, es muss natürlich das
Compare-Match-Flag gelöscht werden:
Ingo L. schrieb:> /* Special Case => Overflow missed */> if ( NewTicks <= 10 && TIFR1 & (1<<OCF1A) ){> Overflows++;> TIFR1 |= (1<<OCF1A);> }
Das entspricht ja meiner Lösung, nur setze ich die Schwelle nicht bei 10
sondern auf den halben Zählbereich. Damit können noch anderen Interrupts
zuschlagen, die mehr als 10 Zyklen brauchen.
Und die Reihenfolge der beiden Tests ist bei mir vertauscht. Da das Flag
nur selten gesetzt sein wird, ergibt das weniger Zeitverbrauch.
Ich setze das Flag auch nicht zurück, so daß der Interrupt nicht
verloren geht. Man will ja nur das Ergebnis korrigieren.
Ob das mit den 25000 so hinhaut, habe ich nicht geprüft. Ich lasse die
CPU immer alles in ihrem Lieblingsformat (Binär) machen und rechne erst
für die Ausgabe für den Menschen um.
Der Befehl
TIFR1 |= (1<<OCF1A);
löscht alle Interrupt flags, nicht nur den einen. Das dort eingetragene
Flag hat nur einen minimalen Einfluss (falls genau zu der Zeit das Flag
gesetzt wird). Wegen der Speziellen Logic im TIFR1 Register ist der
passende Befehl
TIFR1 = (1<<OCF1A);
Ingo L. schrieb:> Dann erklär doch mal deinen Trick.
Kein besonderer persönlicher Trick. Einfach nur angewandtes Wissen. Ich
wollte dir nur aufzeigen, wie du am schmerzärmsten ebenfalls zu diesem
Wissen kommen kannst.
> c-hater schrieb:>> Wenn du ein Gehirn im Kopp hast> "Eure Arroganz blendet euch Meister Joda..."
Von ganz unten betrachtet sieht alles irgendwie nach Arroganz aus...
> Danke Lurchi für deine Hinweise. Ich habe das Ganze mal durch den> Simulator geschoben. Für den Fall das Input Capture und Compare-Match> gleichzeitig kommen (TCNT1 = 0) wird der ICP-Interrupt zu erst> ausgeführt
Wenn die Interruptauslösung wirklich gleichzeitig passiert, ist die
Reihenfolge der Interruptabarbeitung klar, dazu braucht man keinen
Simulator bemühen, sondern einfach nur das Datenblatt zu lesen. Wenn du
nichtmal das weißt...
Viel spannender sind aber die Fälle, wenn der niedriger priorisierte
Interrupt kurz vor dem höher priorisierten ausgelöst wird. Dann kann es
nämlich passieren, dass seine ISR zuerst ausgeführt wird. Es kann aber
genausogut das Gegenteil passieren. Du musst wirklich noch viel
lernen...
Und dazu kommt dann halt noch, dass die Interruptabarbeitung beider
ISRs im Prinzip beliebig lange hinter der Interruptauslösung
hinterherhinken kann. Da schlägt dann gnadenlos das Problem der nicht
wartenden Hardware zu, auf dass ich eingangs bereits hinwies...