Forum: Mikrocontroller und Digitale Elektronik Wie viele Takte braucht diese ISR ca?


von Andre (Gast)


Lesenswert?

Hallo,
kann mir jemand sagen, wieviele Takte die ISR ca braucht?
1
ISR(TIMER1_COMPA_vect)
2
{
3
  cli();
4
  Schrittzaehler++;
5
  PORTC &= ~(1<<PC1);                      // PWM-Ausgang
6
  
7
  if(sflags & (1<<rampe_aktiv))                // Solange eine Rampe gefahren wird
8
  {
9
    if(sflags & (1<<beschleunigungsrampe))          // Abfrage ob Hochlauframpe
10
    {
11
      Rampenschritt++;
12
      OCR1A = hochlauframpe[Rampenschritt];        // nächste Schrittfrequenz ins OCRA laden
13
      
14
      if(Rampenschritt == (Rampenlaenge))          // Wenn das Rampenende erreicht ist
15
      {
16
        OCR1A = Sollfrequenz;              // Nach der Rampe den Sollwert ins OCR1A laden
17
        sflags &= ~(1<<rampe_aktiv);          // Rampenflag löschen
18
        Rampenschritt = (Rampenlaenge);          // Indexwert für die Stop-Rampe vorladen
19
        sflags &= ~(1<<beschleunigungsrampe);      // Flag für die Hochlauframpe löschen
20
      }
21
      
22
    }
23
    // Stoprampe abfahren
24
    else
25
    {
26
      if(Rampenschritt == 0)                // Wenn  die Stoprampe abgarbeitet ist, alles ausschalten
27
      {
28
        jflags |= (1<<pwm_stoppen);
29
      }
30
      Rampenschritt--;
31
      OCR1A = hochlauframpe[Rampenschritt];        // nächste Schrittfrequenz ins OCR0A vorladen
32
    }
33
  } 
34
  // Abfrage, ob die gefordeterte Verfahrlänge erreicht ist oder ob der Referenzschalter angefahren wurde
35
  if((Schrittzaehler == ((Schrittanzahl - Rampenlaenge)) && !(kontinuierlich_drehen))  || (tflags & (1<<referenz_erreicht)))
36
  {
37
    sflags |= (1<<rampe_aktiv);
38
    OCR1A = hochlauframpe[Rampenschritt];
39
  }
40
  sei();
41
}

Wenn ich das richtig im Kopf hab, sind If Abfragen relativ 
takt-intensiv, oder?
Und falls jemand eine Quelle kennt wo man die Takte verschiedener 
Befehle nachlesen kann, immer her damit.
MfG Andre

von tja (Gast)


Lesenswert?

schau dir die *.lss Datei an. Da siehst du zu deiner ISR jeden einzelnen 
Assembler-Befehl. Mit dem Datenblatt (da gibts irgendwo eine Liste mit 
allen Assemblerbefehle und die benötigten Takte zum ausführen) kannst du 
dann die Takte zusammenzählen.

von Martin (Gast)


Lesenswert?

Die Takte kann mit dem Debugger des AVR-Studios schnell bestimmen.

> Wenn ich das richtig im Kopf hab, sind If Abfragen relativ
> takt-intensiv, oder?

Deine erste wohl nicht. Für die letzte würde ich meine Hand nicht ins 
Feuer legen.

Es ist für eine Programm (fast) immer besser, wenn die IRQ-Routine das 
Ereignis z. B. in einer Variablen ablegt und im Hauptprogramm alles 
weitere bearbeitet wird.

von Peter D. (peda)


Lesenswert?

Bei long long wird es wohl länger dauern.
Es gehört sich bei Codeschnipselchen, wenigstens den Typ aller Variablen 
zu deklarieren.

von Stefan F. (Gast)


Lesenswert?

cli() und sei() haben innerhalb von ISR nicht zu suchen. Damit bewirkst 
du ganz sicher nicht das, was du wolltest, sondern eher einen Stack 
Überlauf.

Schreibe Konstanten in Großbuchstanben, damit man sie als solche 
Erkennt. Bei den Schiebe-Operationen spielt es eine sehr große Rolle, ob 
die Zahl rechts von "<<" konstant ist, oder variabel.

von Wolfgang (Gast)


Lesenswert?

Andre schrieb:
> kann mir jemand sagen, wieviele Takte die ISR ca braucht?

Der Simulator zu deinem Controller

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


Lesenswert?

Martin schrieb:
>
> Es ist für eine Programm (fast) immer besser, wenn die IRQ-Routine das
> Ereignis z. B. in einer Variablen ablegt und im Hauptprogramm alles
> weitere bearbeitet wird.

So allgemein ist das Quatsch. Es kommt auch darauf an, wie oft die ISR 
aufgerufen wird (werden kann). Der TE fragt schon richtig. Wenn man 
sicherstellen kann, daß die ISR auch im worst case weniger Zeit 
braucht, als minimal zwischen zwei Triggerungen des Interrupts liegt, 
ist man auf der sicheren Seite.

von Andre (Gast)


Lesenswert?

Danke für die Antworten

Schrittzaehler ist eine uint16_t Variable, alles andere sind uint8_t.

Den Hinweis mit den den Großbuchstaben für Konstanten merke ich mir, in 
dem Fall sind in der Tat alles Konstanten im Zusammenhang mit 
Schiebeoperatoren.

Ich werde mir das im Simulator anschauen, mal schauen ob ich es finde.

von Ida O. (keil-er)


Lesenswert?

Andre schrieb:
> Ich werde mir das im Simulator anschauen, mal schauen ob ich es finde.

Poste doch mal bitte den Abschnitt aus dem LSS file.

Dann kann einer von uns die Takte dazuschreiben und du siehst, die 
andere Möglichkeit.

von Sebastian W. (wangnick)


Lesenswert?

Andre schrieb:
> Und falls jemand eine Quelle kennt wo man die Takte verschiedener
> Befehle nachlesen kann, immer her damit.

Im Datenblatt gibt es ein Kapitel "Instruction set Summary". Details in 
https://ww1.microchip.com/downloads/en/DeviceDoc/AVR-InstructionSet-Manual-DS40002198.pdf.

LG, Sebastian

von Norbert (Gast)


Lesenswert?

Zu Beginn der ISR einen Pin auf High, zum Schluss wieder auf Low.
Oszilloskop dran, auf'n Bildschirm schauen, fertig!

von Hugo H. (hugo_hu)


Lesenswert?

Norbert schrieb:
> Zu Beginn der ISR einen Pin auf High, zum Schluss wieder auf Low.
> Oszilloskop dran, auf'n Bildschirm schauen, fertig

Ja, das bringt es - bei enthaltenen IF-Abfragen.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Stefan ⛄ F. schrieb:
> cli() und sei() haben innerhalb von ISR nicht zu suchen. Damit bewirkst
> du ganz sicher nicht das, was du wolltest, sondern eher einen Stack
> Überlauf.

Einen Stacküberlauf gibt es nicht, aber es ist doppelt gemoppelt, weil 
das globale IRQ Flag sowieso beim ISR Eintritt gelöscht und am Ende 
wieder gesetzt wird.
Möchte man die ISR wirklich durch eine weitere unterbrechen, hat es 
Sinn, am Anfang ein sei() zu schreiben oder (besser) die ISR als NOBLOCK 
zu deklarieren.

: Bearbeitet durch User
von Sebastian (Gast)


Lesenswert?

Matthias S. schrieb:
> Einen Stacküberlauf gibt es nicht

Na ja, wenn die Interrupt-Bedingung längere Zeit besteht dann sorgt RETI 
dafür dass der nächste IRQ-Aufruf erst nach dem Rücksetzen des Stacks 
passiert und nicht davor zwischen SEI und RETI mit entsprechendem 
Wachstum des Stack ...

LG, Sebastian

von MaWin (Gast)


Lesenswert?

Andre schrieb:
> Wenn ich das richtig im Kopf hab, sind If Abfragen relativ
> takt-intensiv, oder?
> Und falls jemand eine Quelle kennt wo man die Takte verschiedener
> Befehle nachlesen kann, immer her damit

Grob gesagt: 10 Takte pro Zeile mit 1 Befehl.

Ja, deine Interruptroutine ist lang und zeitaufwändig.

Genauer: Assemblerausgabe angucken und Takte danebenschreiben, stehen ja 
im Assemblermanual des AVR.

Ich glaubt Atmel Studio zeigt die sogar im Listing an (eventuell nur 
beim Debuggen...)

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Sebastian schrieb:
> Na ja, wenn die Interrupt-Bedingung längere Zeit besteht dann sorgt RETI
> dafür dass der nächste IRQ-Aufruf erst nach dem Rücksetzen des Stacks
> passiert und nicht davor zwischen SEI und RETI mit entsprechendem
> Wachstum des Stack ...

Um es nochmal zu sagen. Das cli() am Anfang einer ISR und das sei() am 
Ende macht der AVR von alleine in Hardware. Das hat nichts mit dem Stack 
zu tun und ist bei TE einfach nur doppelt gemoppelt und unnötig.

von Johannes S. (Gast)


Lesenswert?

Norbert schrieb:
> Zu Beginn der ISR einen Pin auf High, zum Schluss wieder auf Low.
> Oszilloskop dran, auf'n Bildschirm schauen, fertig!

besser noch mit einem USB Logic Analyzer aufzeichnen und ansehen. Eine 
komplette Fahrt mit Beschleunigungs- und Bremsrampe kann man komplett in 
hoher Auflösung speichern. LA Software wie von Saleae kann mit wenigen 
Klicks die Min/Max/Mittelwerte der Pulslängen anzeigen.

von Charly B. (charly)


Lesenswert?

Norbert schrieb:
> Zu Beginn der ISR einen Pin auf High, zum Schluss wieder auf Low.
> Oszilloskop dran, auf'n Bildschirm schauen, fertig!

falls kein oszilloguck vorhanden, einen  timer auf 0 und nach isr
auslesen & ausgeben, event. prescaler anpassen

VlG
charly

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Andre schrieb:
> if(sflags & (1<<beschleunigungsrampe))

Wenn der shift zur Laufzeit berechnet wird, ist die Zeile teuer, und 
davon gibts ja ein paar mehr. Wenn das zur Compilezeit berechnete Masken 
sind, dann ist das ok.
Der Rest ist auch nicht wirklich kritisch. Die ISR wird ja nicht im 
MHz-Takt laufen müssen, und für einige KHz reicht es allemal, wenn der 
Prozessor nicht gerade mit einem Uhrenquarz getaktet wird.

Wie schon gesagt wurde, zählt dir der Atmel/Microchip-Simulator im 
Studio die Takte.

Oliver

von Wolfgang (Gast)


Lesenswert?

Hugo H. schrieb:
> Ja, das bringt es - bei enthaltenen IF-Abfragen.

Genau, den kann man sich auch gleich die statistische Verteilung der 
ISR-Laufzeiten angucken.

von Rolf M. (rmagnus)


Lesenswert?

Axel S. schrieb:
> Martin schrieb:
>>
>> Es ist für eine Programm (fast) immer besser, wenn die IRQ-Routine das
>> Ereignis z. B. in einer Variablen ablegt und im Hauptprogramm alles
>> weitere bearbeitet wird.
>
> So allgemein ist das Quatsch. Es kommt auch darauf an, wie oft die ISR
> aufgerufen wird (werden kann). Der TE fragt schon richtig. Wenn man
> sicherstellen kann, daß die ISR auch im worst case weniger Zeit
> braucht, als minimal zwischen zwei Triggerungen des Interrupts liegt,
> ist man auf der sicheren Seite.

Auch das ist so pauschal Unsinn.

Matthias S. schrieb:
> Sebastian schrieb:
>> Na ja, wenn die Interrupt-Bedingung längere Zeit besteht dann sorgt RETI
>> dafür dass der nächste IRQ-Aufruf erst nach dem Rücksetzen des Stacks
>> passiert und nicht davor zwischen SEI und RETI mit entsprechendem
>> Wachstum des Stack ...
>
> Um es nochmal zu sagen. Das cli() am Anfang einer ISR und das sei() am
> Ende macht der AVR von alleine in Hardware. Das hat nichts mit dem Stack
> zu tun und ist bei TE einfach nur doppelt gemoppelt und unnötig.

Das cli() und sei() des TE hat aber mit dem Stack zu tun. Das ist nicht 
nur unnötig, sondern potenziell schädlich. Denn damit wird sei() 
ausgeführt, bevor alle in der ISR auf dem Stack gesicherten Register 
wieder zurückgeschrieben werden. Wenn die Interrupt-Bedingung in dem 
Moment wieder anliegt, wird dann gleich wieder in die ISR gesprungen, 
ohne dass vorher die Register zurückgeschrieben werden. Damit erhöht 
sich die Stacknutzung. Deshalb macht man niemals ein sei() in einer ISR, 
es sei denn, man hat einen ganz konkreten Grund, weshalb man das 
unbedingt braucht. Und selbst dann überlegt man dreimal, ob man es auch 
wirklich braucht.

: Bearbeitet durch User
von Norbert (Gast)


Lesenswert?

Hugo H. schrieb:
> Norbert schrieb:
>> Zu Beginn der ISR einen Pin auf High, zum Schluss wieder auf Low.
>> Oszilloskop dran, auf'n Bildschirm schauen, fertig
>
> Ja, das bringt es - bei enthaltenen IF-Abfragen.

Vielleicht probierst du es erst mal bevor du mit dem Meckern anfängst.
Dann wirst du nämlich feststellen, das es mehrere unterschiedlich stark 
ausgeprägte (je nach Häufigkeit) abfallende Flanken gibt. Daran kannst 
du sogar die einzelnen Wege erkennen welche in der ISR eingeschlagen 
werden.

von Der Da (Gast)


Lesenswert?

Norbert schrieb:
> Zu Beginn der ISR einen Pin auf High, zum Schluss wieder auf Low.
> Oszilloskop dran, auf'n Bildschirm schauen, fertig!

Jein. Dann Fehlen aber noch die PUSH/POP Befehle, welche vor bzw. nach 
der "ersten und letzten C-code" Zeile ausgeführt werden. Aber es stimmt 
schon, man bekommt ein vernünftiges Gefühl, wie lange der ISR dauert.

Trotzdem schließe ich mich an: der Ersteller der Anfrage sollte sich die 
Tipps und Tricks zum effizienten Programmieren von ISR´s mal zur Gemüte 
führen. Ohne den vollständigen Code zu kennen, scheint es aber trotzdem 
so, daß hier "noch was zum Optimieren" ist.

Auf dem Ersten Blick scheint es auch so, daß alle Variablen global (und 
dann hoffentlich auch volatile deklariert) sind. Ist das wirklich nötig? 
Könnte man vielleicht die eine oder andere Variable fest an ein 
Prozessor-Register binden?

Gruß

Robert

von Hugo H. (hugo_hu)


Lesenswert?

Norbert schrieb:
> Zu Beginn der ISR einen Pin auf High, zum Schluss wieder auf Low.
> Oszilloskop dran, auf'n Bildschirm schauen, fertig!

Norbert schrieb:
> Vielleicht probierst du es erst mal bevor du mit dem Meckern anfängst.
> Dann wirst du nämlich feststellen, das es mehrere unterschiedlich stark
> ausgeprägte (je nach Häufigkeit) abfallende Flanken gibt. Daran kannst
> du sogar die einzelnen Wege erkennen welche in der ISR eingeschlagen
> werden.

Nach Deinem Vorschlag gibt genau eine abfallende Flanke zum Ende jeder 
ISR. Anhand der Ausführungszeit der ISR kann man - wenn man denn 
ungefähr weiß, welcher Weg welche Zeiten verbrät - schließen, welche 
Zweige durchlaufen wurden. Das beinhaltet, dass man wissen sollte 
(zumindest grob) wie viele Takte jeder Zweig benötigt. -> LSS lesen und 
Takte zählen oder mehr Pins wackeln lassen.

von Justin S. (Gast)


Lesenswert?

Andre schrieb:
> Schrittzaehler ist eine uint16_t Variable, alles andere sind uint8_t.

DAS ist eine ganz entscheidende Information, da 16-Bit-Variablen auf 
einem ATMEGA328 grob doppelt so lang brauchen wie 8-Bit-Variablen und 
32-Bit wiederum doppelt so lange. Dagegen sind die ca. 2-10T für eine 
if-Abfrage Peanuts.

Es fehlt aber noch die Angabe des Microprozessors.

Trotzdem kann man schon jetzt sagen, dass die ISR in jedem ihrer Zweige 
vergleichsweise schnell beendet wird, auf einem ATMEGA328 sicher unter 
10µs (woher ich das weiss? Weil ich das schon bei vielen ISRs 
ausgerechnet habe und hier auch, wenn auch nur grob überschlagsmäßig).

Was ist denn Dein kritischer Wert?


MaWin schrieb:
> Ja, deine Interruptroutine ist lang und zeitaufwändig.

Das ist alles relativ und lässt sich so nicht sagen. Z.B. auf dem 
ATMEGA328 kann man kaum eine sinnvolle ISR machen, die weniger als 2-3µs 
braucht. So gesehen sind weniger 10µs nicht viel.

Und es wurde schon oft gesagt, cli/sei weg. Sind zwar nur zwei gesparte 
Takte, aber eben völlig überflüssig.

von Hugo H. (hugo_hu)


Lesenswert?

Wenn man sich eine ISR anschaut sollte man auch - falls man die 
Verwaltung nicht selbst macht (Stichwort ISR_NAKED) - Prolog und Epilog 
beachten.

von Der Da (Gast)


Lesenswert?

Justin S. schrieb:
> Trotzdem kann man schon jetzt sagen, dass die ISR in jedem ihrer Zweige
> vergleichsweise schnell beendet wird, auf einem ATMEGA328 sicher unter
> 10µs (woher ich das weiss? Weil ich das schon bei vielen ISRs
> ausgerechnet habe und hier auch, wenn auch nur grob überschlagsmäßig).

Aha. Und was sagt Deine Glaskugel zum Prozessortakt?

von Norbert (Gast)


Lesenswert?

Hugo H. schrieb:
> Nach Deinem Vorschlag gibt genau eine abfallende Flanke zum Ende jeder
> ISR. Anhand der Ausführungszeit der ISR kann man - wenn man denn
> ungefähr weiß, welcher Weg welche Zeiten verbrät - schließen, welche
> Zweige durchlaufen wurden. Das beinhaltet, dass man wissen sollte
> (zumindest grob) wie viele Takte jeder Zweig benötigt. -> LSS lesen und
> Takte zählen oder mehr Pins wackeln lassen.

Also mein Oszilloskop leuchtet nach. Da sehe ich eine helle positive 
Flanke (immer an der gleichen Stelle, da hier getriggert wird) und 
mehrere negative Flanken an verschiedenen Stellen. Die relative 
Häufigkeit des Vorkommens wird durch die unterschiedliche Helligkeit 
angezeigt.
Wenn ich dann noch weiß wie der Prozessor-Takt bzw. die Periodendauer 
ist, kann ich ablesen und mittels der Grundrechenarten die Taktzyklen 
bestimmen.
Beileibe kein Hexenwerk, insbesondere da der TO explizit nach einem ›ca‹ 
Wert gefragt hatte.

von Terence S. (takeshi)


Lesenswert?

Lass einen Timer laufen, schreibe dir am Anfang den Counter in eine 
Variable und am Ende den Counter in eine andere Variable. Am besten 
zählt der Counter bis zum Maximum und die Variablen haben die gleiche 
Größe, womit du auch Fälle abfängst, in denen der Zähler innerhalb der 
ISR über Null geht. Wenn die ISR durch einen Timer getriggert wird, 
verwendest du aber am besten direkt diesen Timer.
Irgendwo in der Main bildest du die Diffeenz und speicherst diese wieder 
in einer Variable. Die guckst du dir dann über die 
Debugging-Möglichkeiten der IDE an. Damit hast du zumindest die Zeit 
innerhalb der ISR. Willst du es genau für die ganze ISR wissen, gibt es 
in der Richtung auch Möglichkeiten, aber ich vermute so reicht das 
schon.
Wichtig: Du darfst dir nicht die Differenz in der IDE bilden lassen, das 
ist fehlerbehaftet, da die Werte beider Variablen selten 
zusammengehören.

Andre schrieb:
> Wenn ich das richtig im Kopf hab, sind If Abfragen relativ
> takt-intensiv, oder?

Ich habe letztens die Anzahl der Takte für eine einfache if-Abfrage 
gestet und kam auf 6 Takte. Im Argument stand nur eine einzelne 
Variable. Logische Verknüpfungen benötigen natürlich weitere Takte.
Also:
1
if(variable)
2
{
3
  // mein Code
4
}
Es handelte sich dabei um einen Mikrocontroller von Texas Instruments, 
ein F2838x. Wie übertragbar das auf andere ist, weiß ich nicht.

von EAF (Gast)


Lesenswert?

Terence S. schrieb:
> und kam auf 6 Takte. Im Argument stand nur eine einzelne
> Variable.

Aus dem Speicher in die Register holen, irgendwie einen Vergleich auf 
"not Null" machen und ein bedingter Sprung.
6 Takte sind da schon gut.
Ohne es geprüft zu haben: Ein AVR schaffts auch nicht schneller.

von Peter D. (peda)


Lesenswert?

Ein AT89LP4052 schafft ein "DJNZ Adresse" in 4 Zyklen (= 200ns @20MHz).
Will man nur auf 0 testen ohne Decrement, muß noch ein "INC Adresse" 
davor, dann sind 6 Zyklen.
Vorteilhaft für Interrupts ist dabei, daß kein Register benötigt wird 
und das Statuswort nicht beeinflußt wird, d.h. kein PUSH/POP nötig.

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.