Forum: Mikrocontroller und Digitale Elektronik ATmega8 - der Aufruf der ISR daurt sehr lange


von Thomas B. (dertom83)


Lesenswert?

Hallo zusammen,
mir kommt gerade bei der Programmierung eines ATmega8 etwas spanisch 
vor.
Eingestellt ist er auf 8MHz.
Das beduetet ja, dass ein Prozessortakt 125ns dauert.
Ich habe nun folgendes programmiert und mit nem Osca gemessen:
1
int main(void)
2
{
3
 while(1){
4
 PORTB ^=(1 << PB1);
5
 }
6
}

Das bit ist laut Messung je 615ns gesetzt und 615ns zurückgesetzt - 
alles ok.

Änder ich jetzt die Programmierung ab und lasse in einer ISR vom Timer0 
überlauf den Ausgang togglen, dauert das ganze 5µs
Ich finde das steht nicht im verhältnis. Warum dauert der ISR aufruf so 
lange?
1
int main(void)
2
{  
3
//TIMER0 initialisieren
4
 TCCR0= (0<<CS02)|0<<CS01|(1<<CS00);  // Start Timer 0 OHNE Prescaler              
5
 TCNT0  = 255;        // Vorladen
6
 TIMSK |= (1<<TOIE0);      // Interrupts aktivieren
7
 sei();          // Das I-bit im SREG Register setzen
8
  
9
//Endlosschleife
10
 while(1){
11
 }
12
}
13
14
ISR(TIMER0_OVF_vect)
15
{
16
 PORTB ^=(1 << PB1);
17
 TCNT0  = 255;
18
 }

Vor jahren habe ich mal mit nem PIC und Assamlber programmiert - nun ist 
es ein ATMEL mit c...
Ich könnte mir daher vorstellen, dass ich den Timer oder die ISR falsch 
aufgerufen habe - könnt ihr mir einen Tip geben?
Vielen Dank schonmal.

von Peter II (Gast)


Lesenswert?

Thomas Borsdorf schrieb:
> Warum dauert der ISR aufruf so
> lange?

schau dir den ASM code an! Da wird schon noch etwas mehr gemacht.

Dann wird nach jedem return aus einer ISR auch noch mindestens 1 asm 
Befehl ausgführt bevor es wider in eine ISR geht.

von Karl H. (kbuchegg)


Lesenswert?

Thomas Borsdorf schrieb:

> Änder ich jetzt die Programmierung ab und lasse in einer ISR vom
> Timer0 überlauf den Ausgang togglen, dauert das ganze 5µs

Wie vertrauenswürdig sind diese 5µs? Sind das 5.000µs?

5µs wären 40 Takzyklen. Ist in der Tat ein wenig viel.

Das LSS-File schon mal angesehen?

von Karl H. (kbuchegg)


Lesenswert?

Thomas Borsdorf schrieb:

> Eingestellt ist er auf 8MHz.

interner Takt?
Dann sind diese 8Mhz auch nicht besonders vertrauenswürdig.

> Das bit ist laut Messung je 615ns gesetzt und 615ns zurückgesetzt -
> alles ok.

Da 615 nicht durch 125 teilbar ist, ist das schon mal ein Hinweis, dass 
die 8Mhz wohl daneben sein werden. Du solltest mal von diesem Test das 
Assembler LSS File ansehen und dort die Takte zählen, die die Schleife 
wirklich braucht. Aus den gemessenen 615ns und der Anzahl der Takte 
kannst du dir dann die echte Taktzykluszeit ausrechnen.

von uwe (Gast)


Lesenswert?

Laut meiner berechnung sollte es sogar 31,875µs Dauern.

von Glania (Gast)


Lesenswert?

uwe schrieb:
> Laut meiner berechnung sollte es sogar 31,875µs Dauern.

Bitte orrechnen.

von Ralf G. (ralg)


Lesenswert?

Karl Heinz schrieb:
> 5µs wären 40 Takzyklen. Ist in der Tat ein wenig viel.

Die ISR ist genau 20 Instruktionen lang. Das ergibt hier 40 Taktzyklen.

uwe schrieb:
> Laut meiner berechnung sollte es sogar 31,875µs Dauern.
siehe:
Thomas Borsdorf schrieb:
> TCNT0  = 255;

von Thomas B. (dertom83)


Angehängte Dateien:

Lesenswert?

Erstmal vorweg: im Anfangsbeitrag sind es 625ns nicht 615ns - 
Tippfehler.

Ralf G. schrieb:
> Karl Heinz schrieb:
>> 5µs wären 40 Takzyklen. Ist in der Tat ein wenig viel.
>
> Die ISR ist genau 20 Instruktionen lang. Das ergibt hier 40 Taktzyklen.

Das klingt doch schonmal nach einer Erklärung.

Gibt es auch eine Lösung, oder sind alle ISR Aufrufe so "Langsam"
Würde es Sinn machen auf Assambler umzusteigen?
Im anhang die Screenshotas der Messung.

von uwe (Gast)


Lesenswert?

>TCNT0  = 255;
Ah hab das hier übersehen, jetzt verstehe ich was du erreichen willst, 
du willst einen Overflow sofort nach dem beedigen des Interupthandlers.
Aber der sichert jetzt erst mal das Statusregister zurück, und die 
Register vom Stack und dann springt er zurück in die main. Danach führt 
er einen weiteren Befehl aus von der main und springt wieder in den 
Handler sichert die Statusflags und packt Register auf den Stack. 
Wieviele Register packt er denn auf den Stack und holt sie auch wieder 
runter?
-also der sprung in den interupt sind  2 Takte.
-laden des statusflags in ein Register 1 Takt.
-speichern des registers auf dem Stack 2 Takte.
-speichern der restlichen Register n x 2 Takte.
-Portb1 invertieren                    1 Takt.
-counter auf 255 setzen                1 Takt.
-laden der gesichtern register     n x 2 Takte. (hier ist der Counter 
schon wieder übergelaufen)
-laden des registers mit den Flags     2 Takte.
-speichern der flags im Statusregister 1 Takt.
-Rücksprung zu main                    2 takte.
-hier wird mindestens 1 Befehl abgearbeitet 1 Takt (obwohl Overflow 
gesetzt)
-wieder nach oben
Macht wenn ich von zwei Registern ausgehe 21 Takte.
macht 2,625µs an und 2,625µs aus zusammen 5,25µs.

von Karl H. (kbuchegg)


Lesenswert?

Ralf G. schrieb:
> Karl Heinz schrieb:
>> 5µs wären 40 Takzyklen. Ist in der Tat ein wenig viel.
>
> Die ISR ist genau 20 Instruktionen lang. Das ergibt hier 40 Taktzyklen.

Tatsächlich.
1
  5e:  1f 92         push  r1
2
  60:  0f 92         push  r0
3
  62:  0f b6         in  r0, 0x3f  ; 63
4
  64:  0f 92         push  r0
5
  66:  11 24         eor  r1, r1
6
  68:  8f 93         push  r24
7
  6a:  9f 93         push  r25
8
9
  6c:  88 b3         in  r24, 0x18  ; 24
10
  6e:  92 e0         ldi  r25, 0x02  ; 2
11
  70:  89 27         eor  r24, r25
12
  72:  88 bb         out  0x18, r24  ; 24
13
  74:  8f ef         ldi  r24, 0xFF  ; 255
14
  76:  82 bf         out  0x32, r24  ; 50
15
16
  78:  9f 91         pop  r25
17
  7a:  8f 91         pop  r24
18
  7c:  0f 90         pop  r0
19
  7e:  0f be         out  0x3f, r0  ; 63
20
  80:  0f 90         pop  r0
21
  82:  1f 90         pop  r1
22
  84:  18 95         reti

war mir so noch gar nicht bewusst, dass für Präambel und Postambel schon 
14 Befehle draufgehen.

von Peter II (Gast)


Lesenswert?

Thomas Borsdorf schrieb:
> Gibt es auch eine Lösung, oder sind alle ISR Aufrufe so "Langsam"
man könnte die Funktion als naked deklarieren, dann geht es schneller. 
Das kann man aber nur machen, Arbeitsregister in der ISR ändert. In 
diesem Fall sollte es gehen, in der Praxis meist nicht.

> Würde es Sinn machen auf Assambler umzusteigen?
ja, aber spätestens wenn der code etwas mehr machen soll, wird es 
genauso langsam. Denn da musst du auch die Register sichern und 
widerherstellen.

von Karl H. (kbuchegg)


Lesenswert?

Thomas Borsdorf schrieb:

> Gibt es auch eine Lösung, oder sind alle ISR Aufrufe so "Langsam"

Mein Gedächtnis kramt da noch was raus, dass man ISR auch 'naked' machen 
kann. Habs aber noch nie wirklich gebraucht. Denn 5µs sind ja nicht 
wirklich langsam. Wann hat man schon mal den Fall, dass man Interrupts 
in derart kurzen Abständen braucht?

> Würde es Sinn machen auf Assambler umzusteigen?

Wenn du den Speed brauchst.
Brauchst du den wirklich?

von Peter II (Gast)


Lesenswert?

Karl Heinz schrieb:
> war mir so noch gar nicht bewusst, dass für Präambel und Postambel schon
> 14 Befehle draufgehen.

ein schönes Beispiel für Leute die immer behaupten, der Compiler macht 
es schon optimal.

Hier geht es sehr großzügig mit Registern um, ein Register hätte 
gereicht.

von ich (Gast)


Lesenswert?

Hi, ist denn die ISR schon fertig bevor der Timer überläuft? (Weil es 
müssen ja noch register zurück geschrieben werden?)
MfG
ich

von ich (Gast)


Lesenswert?

So, jetzt ziehe ich meine Frage zurück.
MfG
ich

von Karl H. (kbuchegg)


Lesenswert?

Peter II schrieb:
> Karl Heinz schrieb:
>> war mir so noch gar nicht bewusst, dass für Präambel und Postambel schon
>> 14 Befehle draufgehen.
>
> ein schönes Beispiel für Leute die immer behaupten, der Compiler macht
> es schon optimal.

:-)
Seitenhieb akzeptiert.

> Hier geht es sehr großzügig mit Registern um, ein Register hätte
> gereicht.

Jep. Ist halt die einfache allgemeine ISR Präambel. Wundert mich 
eigentlich, dass da einiges nicht wegoptimiert wird. Ich hatte das 
eigentlich anders in Erinnerung. Zumindest das r1 überhaupt nicht 
verändert wird (*), hätte er schon rausfinden können.

* gemeint ist: vom eigentlichen Nutzcode. Der fixe eor r1, r1 in der 
Präambel zählt nicht.

von uwe (Gast)


Lesenswert?

> Würde es Sinn machen auf Assambler umzusteigen?
Output compare Einheit verwenden, die macht das togglen ohne Interupt.
Ansonsten wenns nen anderer Pin als OC0 sein muß, dann Output Compare 
Interupt. Wenn du dann nichts im interupt machst brauchst du auch nicht 
Statusregister und andere auf den Stack legen.
-also der sprung in den interupt sind  2 Takte.
-Pin Togeln                            1 Takt
-Rücksprung zu main                    2 Takte.
-hier wird mindestens 1 Befehl abgearbeitet 1 Takt (obwohl Overflow
gesetzt)
-wieder nach oben
Sind dann 6 Takte

von c-hater (Gast)


Lesenswert?

uwe schrieb:

> -also der sprung in den interupt sind  2 Takte.
> -laden des statusflags in ein Register 1 Takt.
> -speichern des registers auf dem Stack 2 Takte.
> -speichern der restlichen Register n x 2 Takte.
> -Portb1 invertieren                    1 Takt.
> -counter auf 255 setzen                1 Takt.
> -laden der gesichtern register     n x 2 Takte. (hier ist der Counter
> schon wieder übergelaufen)
> -laden des registers mit den Flags     2 Takte.
> -speichern der flags im Statusregister 1 Takt.
> -Rücksprung zu main                    2 takte.
> -hier wird mindestens 1 Befehl abgearbeitet 1 Takt (obwohl Overflow
> gesetzt)

Da fehlt ganz zu Anfang noch was, nämlich die statische Interruptlatenz 
von 4 Takten. Die werden gebraucht, um die Rücksprungadresse auf den 
Stack zu legen.

von Thomas B. (dertom83)


Lesenswert?

Super, danke für die Erklärung, jetzt wird es mir auch klar.

Karl Heinz schrieb:
> Wenn du den Speed brauchst.
> Brauchst du den wirklich?

Gute Frage - ich lese ein Protokol aus und möchte keine Information 
verlieren.

Dachte mir ursprünglich, dass es einfacher den Timer einfach hoch zu 
stellen.
Jetzt werde ich wohl umdenken und mich mit int0/int1 bechäftigen - beim 
PIC war das immer so Aufwendig -.-
Mal schauen wie es mit nem Atmel läuft.

Danke nochmal für die Hilfe und Infos.

von Dr. Sommer (Gast)


Lesenswert?

Für zeitkritische Aufgaben gibt es daher Controller wie den Cortex-M3, 
der generell höhere Taktfrequenzen erreicht, und einen Interrupt in 12 
Takten aufruft (inklusive der Sicherung von 4 Registern + 
Status-Register), und bei aufeinanderfolgenden Interrupts das 
Wiederherstellen-Sichern wegfallen lässt.

von uwe (Gast)


Lesenswert?

Output compare Einheit verwenden, die macht das togglen ohne Interupt.

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.