Forum: Mikrocontroller und Digitale Elektronik Interrupt Latenzzeit eines 8-bit AVRs


von UweLoh (Gast)


Lesenswert?

Hallo zusammen,

bin gerade dabei die Interrupt Latenzzeit eines Standard 
Mikrocontrollers wie dem ATmega8 oder vergleichbarem zu berechnen.
Wo verstecken sich denn die Hinweise auf die Interrupt Latenzzeit in den 
Datenblättern ?
Scheine den richtigen Suchbegriff noch nicht gefunden zu haben.
Kann man davon ausgehen, dass im Vergleich zu einem internen Interrupt, 
bei einem extern ausgelösten lediglich die Takte für die 
Signalsynchronisierung dazu kommen (ca. 2-4 Takte im Normalfall) ?

Grüße Uwe

von Stefan S. (chiefeinherjar)


Lesenswert?

UweLoh schrieb:
> Wo verstecken sich denn die Hinweise auf die Interrupt Latenzzeit in den
> Datenblättern ?

Ich nehme mal an, du meinst mit "Latenzzeit" die Zeit, die zwischen dem 
Ereignis und der Ausführung der eigentlichen Interrupt-Routine vergeht.

Die Zeit ist nicht fest sondern von mehreren Faktoren - wie z.B. dem 
Code und dem Compiler abhängig. Vor dem Anspringen des Interrupts werden 
die notwendigen Register gesichtert. Die Befehle sind "push" (sichern) 
und "pop" (zurücklesen)

Wenn viele Register gesichtert werden müssen, dauert es natürlich 
länger.

von Georg G. (df2au)


Lesenswert?

UweLoh schrieb:
> den richtigen Suchbegriff

"atmega interrupt latency" bringt gut 30.000 Beiträge. Im Datenblatt 
unter "Interrupt Response Time" findet man auch Hinweise. Hier im Forum 
"Wie viele Taktzyklen benötigt ein Interruptaufruf beim AVR INT0 
(Assembler)".

von Rolf M. (rmagnus)


Lesenswert?

UweLoh schrieb:
> Scheine den richtigen Suchbegriff noch nicht gefunden zu haben.
> Kann man davon ausgehen, dass im Vergleich zu einem internen Interrupt,
> bei einem extern ausgelösten lediglich die Takte für die
> Signalsynchronisierung dazu kommen (ca. 2-4 Takte im Normalfall) ?

Was meinst du mit "internen Interrupt"?

von J. T. (chaoskind)


Lesenswert?

Rolf M. schrieb:
> Was meinst du mit "internen Interrupt"?

Vermutlich einen, der nicht extern ist? Sowas wie Zählerüberlauf oder 
oder odet

von Karl M. (Gast)


Lesenswert?

Rolf M. schrieb:
> Was meinst du mit "internen Interrupt"?

INT0, INT1, PCINT0, PCINT1 usw. sind externe Interrupt,
z.B. die TimerN mit ihren unterschiedlichen Interruptquellen wären dann 
interne Interrupt.

von Jim M. (turboj)


Lesenswert?

UweLoh schrieb:
> Interrupt Latenzzeit eines Standard
> Mikrocontrollers wie dem ATmega8

Sobald Du mehr als 1 Interrupt hast wird diese Berechnung eher 
akedemisch.

Denn die maximale Latenz verlängert sich um die Laufzeit der vorher 
(bzw. gleichzeitig) aufretretenen Interrupt Handler.

Daher lautet bei AVR die Device: Interrupts so schnell wie möglich 
abarbeiten.

von Daniel78 (Gast)


Lesenswert?

Wenn du die Abarbeitungszeit wissen willst schalt ne LED an und aus in 
den Routinen und Messe mit dem Oszi doch mal die Zeiten.....

von Rolf M. (rmagnus)


Lesenswert?

Karl M. schrieb:
> Rolf M. schrieb:
>> Was meinst du mit "internen Interrupt"?
>
> INT0, INT1, PCINT0, PCINT1 usw. sind externe Interrupt,
> z.B. die TimerN mit ihren unterschiedlichen Interruptquellen wären dann
> interne Interrupt.

Und warum sollte da ein Unterschied in der Interrupt-Latenz sein? Für 
mich sind beide aus Sicht des Interrupt-Handling das gleiche: Durch 
Peripherie-Einheiten ausgelöste Interrupts. Ob das jetzt ein Timer oder 
ein I/O-Port ist, spielt doch gar keine Rolle.

von Carl D. (jcw2)


Lesenswert?

Was mir immer hilft ist schlicht: messen.
In der ISR mit Pin wackeln. Externen Int über Pin auslösen, der von der 
Mainloop gewackelt wird. Und dann mit dem LogicAnalyser beobachten.
Kosten <10€ + 0€ für sigrok/pulseview. Wenn z.B. alle ISR's den selben 
Pin wackeln lassen, dann kann man mit dem "PWM-Decoder" die 
ISR-Auslastung in % einfach anzeigen lassen.

von Axel S. (a-za-z0-9)


Lesenswert?

Stefan S. schrieb:
> Vor dem Anspringen des Interrupts werden
> die notwendigen Register gesichtert.

Das ist gleich doppelt falsch. Denn natürlich wird nicht der Interrupt 
angesprungen, sondern die Interrupt Service-Routine (ISR). Und Register 
werden nicht vor dem Aufruf der ISR gesichert, sondern in der ISR. 
Das einzige was automatisch auf den Stack geht, ist der PC. So wie bei 
einem normalen Unterprogrammaufruf auch.

von Purzel H. (hacky)


Lesenswert?

Also. Ein AVR beendet die gradige Instruktion, welche 1 oder 2 takte 
dauern kann. Dann kommt push(PC) & call(ISR).
In der ISR macht man als Minimum noch ein push(Status) und wenn der 
Compiler nichts kann, wird noch ein push(alle Register) durchgefuehrt.

Ich glaub der AVR Siumlator kann auch Interrupts simulieren.

von Patrick J. (ho-bit-hun-ter)


Lesenswert?

Hi

Zwölf M. schrieb:
> In der ISR macht man als Minimum noch ein push(Status)

Im Normalfall ja, wenn keine Statusregister verändert werden, kann man 
Sich Das sparen.
Z.B. setze ich in der WatchDog-ISR nur ein Flag
1
sbr rFlag,(1<<fWatchDog)
2
reti
Wobei rFlag (Register mit dem Namen Flag) diverse Flags enthält.
Das fWatchDog (Flag mit dem Namen WatchDog) ist eine Bitposition 0...7 
und wird in der ISR nur gesetzt.
Im Hauptprogramm wird dann darauf reagiert und das Flag wieder entfernt 
(und der WatchDog-ISR erneut scharf geschaltet, sonst gibt's beim 
nächsten Wachhund-Biss einen Reset).

Aber Ja, Du hast Recht: Wenn man sich in der ISR ein Register des 
Hauptprogramm versaut, sind die Fehler vielfältig, bösartig unregelmäßig 
und kaum zu finden :)

AUf dem 80286 (unter DOS mit DEBUG) wurde großzügig gepushed und 
gepoped, auf dem ATtiny muß ich aber manch Mal auf die Laufzeit achten 
und nur sichern, was wirklich nötig ist.

MfG

von c-hater (Gast)


Lesenswert?

Jim M. schrieb:

> Sobald Du mehr als 1 Interrupt hast wird diese Berechnung eher
> akedemisch.

Nein. Man muss einfach nur wissen, wie man das richtig berechnet...

> Denn die maximale Latenz verlängert sich um die Laufzeit der vorher
> (bzw. gleichzeitig) aufretretenen Interrupt Handler.

Nein. Sie verlängert sich nur um jedes Teil, was EXKLUSIV läuft. Das 
ist nicht notwendigerweise die komplette ISR, sondern sind im Extremfall 
nur 5 Takte. Nämlich der allfällige ISR-Entry-Overhead (im günstigsten 
Fall halt 4 Takte) und die Zeit, für eine sei-Anweisung auf der Adresse 
des Interrupt-Vectors benötigt wird, also ein weiterer Takt.

Bei AVR8 mit sehr viel Flash (>128k) oder AVRs mit externem RAM können 
da noch weitere Takte hinzukommen, im worst case (22-Bit PC und Stack 
im externen RAM) sind das nochmal 5 Extra-Takte für den 
ISR-Entry-Overhead, also dann insgesamt 10 statt 5.

> Daher lautet bei AVR die Device: Interrupts so schnell wie möglich
> abarbeiten.

Unsinn, das scheint nur unwissenden C-lern so...

Tatsächlich ist es so: jegliche Instanz von exklusiv ausgeführtem Code 
sollte so kurz wie möglich sein. Exklusiv ausgeführter Code sind aber 
erstens nicht nur ISRs (sondern auch jeglicher mit cli/sei oder 
hochsprachentechnischen Verwandten geklammerter Kram) und zweitens nicht 
zwingend komplette ISRs, sondern nur der Teil dieser bis zum ersten 
sei...

Natürlich ist es selten sinnvoll, die ISR gleich mit einem sei zu 
beginnen, aber es ist sehr oft sinnvoll, kurz nach dem Beginn ein sei 
einzufügen. Nämlich genau dann, wenn alles erledigt ist, was man 
sinnvollerweise erledigen sollte, solange der eigene Code noch exklusiv 
läuft.

Und wenn man das immer so macht, ergeben sich komplette Anwendungen, die 
nur aus solcherart konstruierten ISRs bestehen. Kein dümmliches, sinnlos 
Rechenzeit und Energie verbrauchendes Polling in main() ist dann mehr 
nötig.
main() dient ausschließlich dazu, freie Rechenzeit "wahrzunehmen" und 
unmittelbar dazu zu nutzen, das System einzuschläfern. Wozu soll es auch 
laufen, wenn es keine Änderung des Status geben kann, da ja kein 
Ereignis eingetreten ist, was irgendwas am Status ändern könnte?

Du musst noch viel lernen...

von Rolf M. (rmagnus)


Lesenswert?

Zwölf M. schrieb:
> Also. Ein AVR beendet die gradige Instruktion, welche 1 oder 2 takte
> dauern kann.

Oder mehr. Die längste Instruktion ist je nach Größe des Flash 4 oder 5 
Taktzyklen lang. Beim Atmega8 sind es 4, z.B. bei RET.

> Dann kommt push(PC) & call(ISR).

Eher so:

push(PC)
CLI
call(Interrupt-Vektor)

und in dem Interrupt-Vektor-Eintrag steht dann in der Regel ein RJMP 
ISR.
Was noch gar nicht erwähnt wurde: Wenn der Prozessor gerade im 
Sleep-Modus ist und durch den Interrupt aufgeweckt wird, verlängert sich 
die Reaktionszeit.

> In der ISR macht man als Minimum noch ein push(Status)

Kann man nicht. Man kann nur die Register r1 bis r15 pushen. Also muss 
man erst eins davon sichern, dann das SREG da rein kopieren, dann das 
Register nochmal pushen. Später dann vor Verlassen der ISR das 
umgekehrte.

> und wenn der Compiler nichts kann, wird noch ein push(alle Register)
> durchgefuehrt.

Oder wenn man dem Compiler keine andere Wahl lässt, z.B. weil man in der 
ISR eine Funktion aufruft, deren Inhalt der Compiler an der Stelle nicht 
kennt. Dann ist er gezwungen, prophylaktisch alle Register zu sichern.

c-hater schrieb:
> Tatsächlich ist es so: jegliche Instanz von exklusiv ausgeführtem Code
> sollte so kurz wie möglich sein. Exklusiv ausgeführter Code sind aber
> erstens nicht nur ISRs (sondern auch jeglicher mit cli/sei oder
> hochsprachentechnischen Verwandten geklammerter Kram) und zweitens nicht
> zwingend komplette ISRs, sondern nur der Teil dieser bis zum ersten
> sei...

Auch nach dem SEI blockiert die ISR weiterhin das Hauptprogramm. Das 
erklärt dann auch, warum du unbedingt das komplette Programm in die ISRs 
stecken willst. Jeglichen anderen Weg hast du dir ja verbaut.

> Natürlich ist es selten sinnvoll, die ISR gleich mit einem sei zu
> beginnen, aber es ist sehr oft sinnvoll, kurz nach dem Beginn ein sei
> einzufügen. Nämlich genau dann, wenn alles erledigt ist, was man
> sinnvollerweise erledigen sollte, solange der eigene Code noch exklusiv
> läuft.

Das ist aber fast immer auch die Stelle, an der die ISR am besten 
komplett zu ende sein sollte. Somit erübrigt sich das SEI dann.

> Und wenn man das immer so macht, ergeben sich komplette Anwendungen, die
> nur aus solcherart konstruierten ISRs bestehen.

Unnötig komplex und schlecht wartbar. Schlecht überschaubare Stackgröße 
und im Extremfall (Interrupt wird schneller ausgelöst als ISR ausgeführt 
werden kann) Stack-Overflow. Mehrwert: Praktisch keiner.

> Kein dümmliches, sinnlos Rechenzeit und Energie verbrauchendes Polling in
> main() ist dann mehr nötig.

?

> main() dient ausschließlich dazu, freie Rechenzeit "wahrzunehmen" und
> unmittelbar dazu zu nutzen, das System einzuschläfern. Wozu soll es auch
> laufen, wenn es keine Änderung des Status geben kann, da ja kein
> Ereignis eingetreten ist, was irgendwas am Status ändern könnte?

Muss es nicht. Das hat aber nichts damit zu tun, ob man nun die ISRs 
kurz hält oder das ganze Programm da reinstopft.

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.