ATmega8 - der Aufruf der ISR daurt sehr lange

#3901911
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.
#3901935
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.
#3901968
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.
Angehängte Dateien:
Gast #3901975
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.
#3901977
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.
Gast #3901978
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.
#3901983
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?
Gast #3901987
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.
#3901995
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.
Gast #3901997
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
Gast #3902005
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.
#3902006
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.
Gast #3902012
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren