Forum: Mikrocontroller und Digitale Elektronik INT0, nach wieviel takten startet die ISR?


von elmo (Gast)


Lesenswert?

Hallo,

leider kann ich grade nichts testen deswegen frage ich.. (sorry)

Ich möchte ein Tacho bauen, dass so funktioniert:
Ein 8bit-Timer läuft durch. Der Timer Overflow Interrupt erhöht einen 
Counter. Wenn an INT0 eine Flanke kommt, wird der counter wert und die 
Zahl der Timer-'Ticks' gesamplet.
Die zahl der Ticks ist dann Counter*256+Rest-Ticks
Wenn der Controller nun die INT0-ISR betritt - die ISR ist ja naked, 
oder?, wie viele Ticks sind da vergangen bis der Erste Befehl ausgeführt 
wurde?
1
ISR(...) {
2
    sample = TCNTx
3
    ...
4
}
also wieviele Takte vergehen bis die erste Zeile erreicht bzw. 
durchgelaufen ist? Der Befehl ld register, TCNTx  , zählt der takt noch 
zu TCNTx dazu oder wird TCNTx erst nachdem der Befehl ausgeführt wurde 
inkrementiert?

Oder anders: Wieviele Takte muss ich von TCNTx abziehen damit ich die 
Korrekte anzahl der Ticks zum Zeitpunkt des Auftretens der Flanke habe?

Und: Springt INT0 direkt im Takt der Flankenerkennung in die ISR oder 
einen Takt später?

Vielen Dank,
Elmo

von Peter (Gast)


Lesenswert?

elmo schrieb:
> leider kann ich grade nichts testen deswegen frage ich.. (sorry)

warum nicht, geht dein simulator nicht?

Egal ob es nun 4 oder 5 Takte sind, es ist zuminest nicht konstant. Es 
kommt darauf an welcher befehl gerade ausgeführt wird. Es kann sogar 
viel mehr sein wenn gerade eine andere ISR ausgeführt wird. Dann Spielt 
auch noch eine rolle viele Variable in der ISR sind, dann es müssen 
Register gesichert werden. Es wird also so nicht gehen.

von g457 (Gast)


Lesenswert?

> Oder anders: Wieviele Takte muss ich von TCNTx abziehen damit ich die
> Korrekte anzahl der Ticks zum Zeitpunkt des Auftretens der Flanke habe?

Wenn Du die mit ein paar simplen Klimmzügen als hinreichend konstant 
annimmst, dann kannst Du die getrost unterschlagen.

> Und: Springt INT0 direkt im Takt der Flankenerkennung in die ISR oder
> einen Takt später?

Weder noch. Die Details stehen im Datenblatt.

Einfacher wirds vermutlich wenn Du keinen externen Interrupt nimmst um 
die Zeitdifferen zu messen, sondern das Tachosignal an den Zähler hängst 
und den dann per Timer regelmäßig abfragst. Zumindest dann wenn Du keine 
aberwitzig kurzen Reaktionszeiten brauchst - so wie bei einem 'Tacho' 
eben, da langt es locker flockig die Ausgabe ein paar mal pro Sekunden 
zu aktualisieren.

HTH

von Chris (Gast)


Lesenswert?

Für so etwas bietet sich die Input Capture Unit des Timers an. Leider 
schreibst Du nicht um welchen Controller es geht.

von elmo (Gast)


Lesenswert?

Angenommen ich mache das mit Assembler nicht inline sondern seperat. 
Dann müsste ich keine Variablen pushen. Angenommen in der anderen ISR 
(in der, der Counter inkrementiert wird) lasse ich das interrupt-flag 
eingeschaltet... Dann wäre das einzigste taktverlängernde Moment doch 
wenn ein 2- oder 3-Takt Befehl läuft?

Angenommen es kann sofort gesprungen werden:

Dann habe ich die Flanke -> Detektor erkennt das im nächsten Takt -> jmp 
zur Interrupt address -> jmp von da in die ISR -> register samplen.

das wären 1+2+2+2 = 7 Takte?

von Peter (Gast)


Lesenswert?

elmo schrieb:
> lasse ich das interrupt-flag
> eingeschaltet... Dann wäre das einzigste taktverlängernde Moment doch
> wenn ein 2- oder 3-Takt Befehl läuft?

nein, es kann sein das eine andere ISR schon läuft

von Detlev T. (detlevt)


Lesenswert?

Hallo elmo,

es spricht viel dafür, dass du von Atmel Controllern sprichst. ;-)

Allerdings machst du keine weitere Angaben. "Größere" ATTinys (z.B. 
ATTiny24) und neuere ATMEGAs haben eine "Input Capture"-Funktion. Damit 
wird auf ein externes Signal hin der aktuelle Timer1-Wert gespeichert 
(16-Bit). Dann kannst du dir "Zeit lassen" mit dem Eintritt in die ISR 
ohne Genauigkeit zu verlieren.

von Chris (Gast)


Lesenswert?

elmo schrieb:
> Angenommen ich mache das mit Assembler nicht inline sondern seperat.
> Dann müsste ich keine Variablen pushen. Angenommen in der anderen ISR
> (in der, der Counter inkrementiert wird) lasse ich das interrupt-flag
> eingeschaltet... Dann wäre das einzigste taktverlängernde Moment doch
> wenn ein 2- oder 3-Takt Befehl läuft?

Nein, das I-Flag wir automatisch beim Sprung in einen Interrupt 
gelöscht. Du könntest es höchstens dort wieder manuell setzen. Ist aber 
nicht gerade zu empfehlen.

von elmo (Gast)


Lesenswert?

ICU geht leider nicht, weil ich mehr als ein Signal habe. Der Controller 
ist irgendeiner aus der 'älteren' ATmega-Reihe (8,16,32) - sorry, dass 
ich das vergessen habe.

>Wenn Du die mit ein paar simplen Klimmzügen als hinreichend konstant
>annimmst, dann kannst Du die getrost unterschlagen.

Würde ich das alles Relativ betrachten ja, aber ich möchte auf ca. 0,1Hz 
genau messen. Das Problem ist, dass der Messbereich mit 10-60Hz relativ 
niedrig liegt, daher die Flanken-Methode. Ansonsten würde ich es ja 
anders machen.

> Weder noch. Die Details stehen im Datenblatt.

schön und gut, aber ich dachte es geht schneller und einfacher, wenn ich 
hier frage, anstatt den Haupt-Takt durch diverse Ebenen zu verfolgen und 
zu raten, wann der Flankendetektor zum Interrupt springt.

von Alex (Gast)


Lesenswert?

Beispiel für einen DSP von TI. Bei der C2000 Serie stehen 9 Takte im 
Datenblatt, real sind es eher 13-15, da noch einiges gesichert wird.

von Peter (Gast)


Lesenswert?

ist es nicht viel einfacher einfach einen Timer laufen zu lassen. Jeder 
Flankenwechsel erhöht eine Variable. Nach einem festen Zeitintervall 
fragt der Timer die Variabelen ab und setzt sie auf 0 zurück. Wenn du es 
aller 1s machst hast du sogar gleich die Angaben in Hz.

von elmo (Gast)


Lesenswert?

> elmo schrieb:
> > lasse ich das interrupt-flag
> > eingeschaltet... Dann wäre das einzigste taktverlängernde Moment doch
>  wenn ein 2- oder 3-Takt Befehl läuft?

> nein, es kann sein das eine andere ISR schon läuft

ja und? wenn das globale Interrupt-flag gesetzt ist?

@Detlev, ja ich spreche von Atmel ATmega, nur dumm, dass ich den 
16bit-Timer für eine relativ schnelle PWM brauche und der OC0-Eingang 
vom 8bit Timer nicht ausreicht (ATmega8,32..)

>Nein, das I-Flag wir automatisch beim Sprung in einen Interrupt
>gelöscht. Du könntest es höchstens dort wieder manuell setzen. Ist aber
>nicht gerade zu empfehlen.

Warum nicht? Wenn ich meine Takte abgezählt habe und genau weiß, dass 
die ISR nicht unendlich tief schachteln? aber ok, das I-Flag setzen wäre 
dann 1-Takt mehr.

von elmo (Gast)


Lesenswert?

@Peter: nein das geht nicht, weil die zu messende Frequenz sehr niedrig 
ist. Mit dieser Methode bekomme ich hier keine gute Auflösung hin.

von Chris (Gast)


Lesenswert?

Datenblatt ATMega8 Seite 83: Input Capture Unit

von elmo (Gast)


Lesenswert?

@Chris: schade, dass der controller nur einen ICP hat, sonst wäre 
"the-way-to-go"

von Peter (Gast)


Lesenswert?

elmo schrieb:
>> nein, es kann sein das eine andere ISR schon läuft
> ja und? wenn das globale Interrupt-flag gesetzt ist?

wann willst du es denn setzen, du kannst es ja nur setzen nach dem du in 
der ISR bist, aber da sind ja schon wieder ein paar takte vergangen.


> @Peter: nein das geht nicht, weil die zu messende Frequenz sehr niedrig
> ist. Mit dieser Methode bekomme ich hier keine gute Auflösung hin.

du kannst du Timer ja auch 1 Stunde festlegen, dann wird es sehr genau. 
Du must schon mal schreiben wie oft die aktuelle werte brauchst.

von elmo (Gast)


Lesenswert?

> wann willst du es denn setzen, du kannst es ja nur setzen nach dem du in
> der ISR bist, aber da sind ja schon wieder ein paar takte vergangen.

Es dürften ja Takte vergehen, ich möchte nur wissen wieviele. 6? 7? 8? 
Damit ich die vom TCNTx abziehen kann.

> du kannst du Timer ja auch 1 Stunde festlegen, dann wird es sehr genau.
> Du must schon mal schreiben wie oft die aktuelle werte brauchst.

10Hz - 60Hz, 0.1Hz Auflösung mindestens. 16Mhz Quarz, 16bit-Timer ist 
vergeben und durch sehr kleinen TOP-Wert unbrauchbar.

von Peter (Gast)


Lesenswert?

elmo schrieb:
> 10Hz - 60Hz, 0.1Hz Auflösung mindestens. 16Mhz Quarz, 16bit-Timer ist
> vergeben und durch sehr kleinen TOP-Wert unbrauchbar.

Die Frage war wie Oft du neue Werte brauchst, nicht in welchen 
Frequenzbereich du messen willst.

von (prx) A. K. (prx)


Lesenswert?

elmo schrieb:

> Es dürften ja Takte vergehen, ich möchte nur wissen wieviele. 6? 7? 8?
> Damit ich die vom TCNTx abziehen kann.

Einen festen Wert gibt es nicht, da es von der Laufzeit des grad aktiven 
Befehls abhängt.

Ausserdem sollte dir das einigermassen egal sein, denn wenn du die Zeit 
zwischen zwei Interrupts misst, dann tritt diese Latenz beidesmal auf 
und subtrahiert sich automatisch raus. Nur die Variabilität dieser Zeit 
wird mit gemessen und die kannst du nicht vermeiden.

von elmo (Gast)


Lesenswert?

willst du mir jetzt 1024-bit integer aufdrücken um mit 16Mhz Quartz 
genau zu messen oder was?

ich will doch bloß wissen, wie viele Takte vergehen von der Flanke bis 
zur Dispatcher Table und, ob TCNTx vor oder nach dem Befehl, der in 
diesem Takt bzw. den nächsten 2 ausgeführt wird inkrementiert wird, 
verdammt.

von (prx) A. K. (prx)


Lesenswert?

Apropos Latenz: Eine laufende ISR blockiert den Interrupt, d.h. zu den 
erwähnten Takten und der unwägbarkeit der Latenz kommt noch die Laufzeit 
der Timer-ISR hinzu.

von elmo (Gast)


Lesenswert?

>Ausserdem sollte dir das einigermassen egal sein, denn wenn du die Zeit
>zwischen zwei Interrupts misst, dann tritt diese Latenz beidesmal auf
>und subtrahiert sich automatisch raus. Nur die Variabilität dieser Zeit
>wird mit gemessen und die kannst du nicht vermeiden.


ja, dass stimmt natürlich, danke für den Gedankenanstoß, 1 oder 2 Takte 
sind mir egal, das dürfte trotzdem passen.

von Peter (Gast)


Lesenswert?

elmo schrieb:
> ich will doch bloß wissen, wie viele Takte vergehen von der Flanke bis
> zur Dispatcher Table und, ob TCNTx vor oder nach dem Befehl, der in
> diesem Takt bzw. den nächsten 2 ausgeführt wird inkrementiert wird,
> verdammt.
das kann dir niemand sagen, weil es nicht konstant ist. Es ist auch mit 
AMS nicht Konstant, du kannst nichts tun damit es Konstant wird.

> willst du mir jetzt 1024-bit integer aufdrücken um mit 16Mhz Quartz
> genau zu messen oder was?

60Hzv eingangsfrequenz, abfrage aller 10min. Dafür reicht ein 16bit int. 
Und dann bist du genauer als 0.01Hz

von (prx) A. K. (prx)


Lesenswert?

PS: Dazu kommt noch die nicht uninteressante Aufgabe, bei annähernd 
gleichzeitigem TimerOverflow und ExtInt den halb in Hardware und halb in 
Software gegossenden Gesamtzähler wirklich korrekt auszulesen, ohne 
dabei ab und zu 256 zu viel oder zu wenig zu erhalten.

von elmo (Gast)


Lesenswert?

>Apropos Latenz: Eine laufende ISR blockiert den Interrupt, d.h. zu den
>erwähnten Takten und der unwägbarkeit der Latenz kommt noch die Laufzeit
>der Timer-ISR hinzu.


die Timer-ISR läuft schneller als 60Hz, von daher aktiviere ich in der 
Timer-ISR einfach das interrupt-flag, dann läuft der Flanken-interrupt 
meinetwegen, aber der ist nur so kurz, dass diese ISR und die Timer-ISR 
durchlaufen können, bis die Timer-ISR das nächste mal aufgerufen wird. 
also kein problem.

von (prx) A. K. (prx)


Lesenswert?

elmo schrieb:

> die Timer-ISR läuft schneller als 60Hz, von daher aktiviere ich in der
> Timer-ISR einfach das interrupt-flag, dann läuft der Flanken-interrupt

Klar, aber damit sind es nicht mehr ein paar Takte Variabilität des 
laufenden Befehls, sondern deutlich mehr. Die Laufzeit der Timer-ISR ab 
Reaktion des Prozessors bis einschliesslich des Befehls nach SEI geht 
voll in die Ungenauigkeit ein.

von elmo (Gast)


Lesenswert?

>60Hzv eingangsfrequenz, abfrage aller 10min. Dafür reicht ein 16bit int.
>Und dann bist du genauer als 0.01Hz

Stimmt du hast recht, sorry.

>PS: Dazu kommt noch die nicht uninteressante Aufgabe, bei annähernd
>gleichzeitigem TimerOverflow und ExtInt den halb in Hardware und halb in
>Software gegossenden Gesamtzähler wirklich korrekt auszulesen, ohne
>dabei ab und zu 256 zu viel oder zu wenig zu erhalten.

deshalb schalte ich das i-Flag auch erst wieder ein, wenn ich den 
overflow vermerkt habe ;)

vielleicht wäre es auch sinnvoll, die ganze dispatch table einfach mit 
den befehlen für den interrupt vollzuklatschen, dann spare ich einen jmp 
im timer overflow, aber da brauche ich genug platz, damit ich nicht mit 
anderen Interrupts die ich brauche kollidiere --- lol

von elmo (Gast)


Lesenswert?

>Klar, aber damit sind es nicht mehr ein paar Takte Variabilität des
>laufenden Befehls, sondern deutlich mehr. Die Laufzeit der Timer-ISR ab
>Reaktion des Prozessors bis einschliesslich des Befehls nach SEI geht
>voll in die Ungenauigkeit ein.

deswegen packe ich gleich an die stelle in der dispatch table ein ld 
gefolgt von sei, dann habe ich nur 3 takte, ab dem vierten kann wieder 
gesprungen werden.

dann kann ich ein paar vektoren später aus der dispatch table in die 
restliche ISR springen ;)

von (prx) A. K. (prx)


Lesenswert?

elmo schrieb:

> deshalb schalte ich das i-Flag auch erst wieder ein, wenn ich den
> overflow vermerkt habe ;)

Was die maximale Latenz weiter erhöht.

Aber ich fürchte es wird schon ein bischen komplizierter. Zwischen 
Auslösung des ExtInt und dem Auslesen des Timer-Registers vergehen 
einige Takte. Wenn dazwischen der Timer überläuft, dann wird die Sache 
interessant. Selbst SEI im ExtInt-Handler bringt dich nicht wirklich 
weiter. Da musst du schon ein bischen mehr Grips reinstecken.

von Peter (Gast)


Lesenswert?

elmo schrieb:
> deswegen packe ich gleich an die stelle in der dispatch table ein ld
> gefolgt von sei, dann habe ich nur 3 takte, ab dem vierten kann wieder
> gesprungen werden.

geht aber nur wenn du die nächsten 2 ISR nicht brauchst.

von elmo (Gast)


Lesenswert?

>Ich fürchte es wird schon ein bischen komplizierter. Zwischen Auslösung
>des ExtInt und dem Auslesen des Timer-Registers vergehen einige Takte.
>Wenn dazwischen der Timer überläuft, dann wird die Sache interessant.
>Selbst SEI im ExtInt-Handler bringt dich nicht wirklich weiter

hmm, naja, aber das wäre ja ein ausreißer, den man durch genügend 
trägheit ausgleicht oder? außerdem tritt der auch nur alle 256 / 3 
durchläufe auf? alternativ könnte man zusätzlich das Timer register 
auslesen in der ExtInt ISR dann feststellen, ob ein Überlauf währen der 
Laufzeit dieser ISR erfolgt und dementsprechen den Timer zurücksetzen 
und die übrigen Ticks manuell akkumulieren. oder?

von (prx) A. K. (prx)


Lesenswert?

elmo schrieb:

> alternativ könnte man zusätzlich das Timer register
> auslesen in der ExtInt ISR dann feststellen, ob ein Überlauf währen der
> Laufzeit dieser ISR erfolgt

Müsste so gehen: Im ExtInt-Handler Interrupts gesperrt lassen. Timer 
auslesen, danach TimerOvf-Intflag testen. Wenn gesetzt und ausgelesener 
Timer-Wert hinreichend klein, dann hat man ihn verpasst.

von Peter (Gast)


Lesenswert?

elmo schrieb:
> alternativ könnte man zusätzlich das Timer register
> auslesen in der ExtInt ISR dann feststellen, ob ein Überlauf währen der
> Laufzeit dieser ISR erfolgt und dementsprechen den Timer zurücksetzen
> und die übrigen Ticks manuell akkumulieren. oder?

je mehr code man schreib je ungenauer wird das timing. Teste es doch 
einfach mal im Simulator und geht jede Situation mal durch. Du wirst 
merken das du damit nicht zum ziel kommst.

von elmo (Gast)


Lesenswert?

Alter Schalter, was für ein S.. natürlich ist das unpraktikabel und 
dummer Scheiß den niemand debuggen möchte, auch ich nicht, aber sich 
mindestens(!) theorethisch mit solchen Basteleien auseinanderzusetzen, 
das ist doch spannend. Besser als die Interrupt-Tabelle mit einer ISR 
vollzuklatschen ist doch nur ein Programm, dass sich aus einer 
mathematischen Funktion erzeugt und per SPM erstmal den Controller neu 
flasht bevor es losgeht...

Ich entscheide mich dann wohl doch lieber für Peters methode oder etwas 
ähnlich 'simples'..

Danke für die Hilfe.

von (prx) A. K. (prx)


Lesenswert?

Peter schrieb:

> je mehr code man schreib je ungenauer wird das timing. Teste es doch
> einfach mal im Simulator und geht jede Situation mal durch. Du wirst
> merken das du damit nicht zum ziel kommst.

Code an dieser Stelle zählt nicht. Kritisch ist der Code im 
TimerOvf-Handler bis SEI+nächster und im ExtInt-Handler bis zum Auslesen 
vom Timer. Der Rest dahinter geht nicht mit ins Ergebnis ein.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.