Forum: Compiler & IDEs Input Capture Interrupt so langsam?


von Witali G. (witali)


Lesenswert?

Hallo zusammen!!

Ich wundere mich wie langsam der Aufruf vom Input Capture Interrupt im 
Simulator (AVR-Studio) ist. In möchte die Periode eines Rechtecksignals 
messen und rechne damit, dass die Interrupt-Routine einige Takte nach 
Auftreten des Capture-Ereignisses ausgeführt wird. In meinem Code unten 
will ich von dem aktuellen Zählerstand (Timer1) den Zählerstand zum 
Moment des Capture-Ereignisses abziehen um dann den InputCapture-Wert 
auszuwerten. Bei der Simulation stelle ich fest, dass nach der 
Substraktion der Zählerdatenregister auf 52 hexadezimal ist. Das heißt 
doch, dass bis die ISR-Routine (speziell diese Substraktion) ausgeführt 
wird ca. 80 Takte vergehen, oder? Ist es normal oder doch etwas zu viel? 
Oder habe ich hier irgend einen dummen Fehler gemacht?

Wäre für jeden Tipp sehr dankbar. Bin nur Anfänger.


[c]#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/io.h>

union{
    struct{
        char    b00:1;      //Bits 0-15
        char    b01:1;
        char    b02:1;
        char    b03:1;
        char    b04:1;
        char    b05:1;
        char    b06:1;
        char    b07:1;
        char    b08:1;
        char    b09:1;
        char    b10:1;
        char    b11:1;
        char    b12:1;
        char    b13:1;
        char    b14:1;
        char    b15:1;
    }b;
    struct{
        char    low;                // LowByte
        char    high;               // HighByte
    }byte;
    unsigned short  l;        //LowWord
    unsigned short  h;        //HighWord
  unsigned long  VDDig;      //LongWord
}VD;

unsigned long Var = 15441085;
unsigned long temp = 31456;

int main(void)
{
  DDRD = 0xff;      //Port D: alle Pins als Ausgang
  DDRB = 0xfe;      //Port B: Pin 0 als Eingang, Pins 1-7 als Ausgang
  PORTB |= 0x01;    //PullUp-Widerstand von PB0/ICP1 aktivieren
  TIMSK1 = 1 << ICIE1;
  TCCR1B = ((1 << ICNC1) | (1 << CS10));
  sei();
  while (1)  { }

  return 0;
}



ISR(TIMER1_CAPT_vect)
{
  TCNT1 = TCNT1 - ICR1;
}[c]

von Johannes M. (johnny-m)


Lesenswert?

Na, 80 Takte ist wirklich zu viel. Aber warum gehst Du nicht im 
Simulator schrittweise durch. Dann siehst Du am Zähler, wie viele Takte 
zwischen Capture-Ereignis und Eintritt in die ISR vergehen. Wesentlich 
mehr als 20 Takte sollten es selbst mit viel Register-Sichern nicht 
sein.

Aber Du solltest zum Probieren vielleich mal alles an überflüssigem 
Ballast aus dem Programm rauswerfen. Die ganzen Variablen, die Du da 
deklarierst, werden eh nirgends benutzt.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Johannes M. wrote:

> Wesentlich
> mehr als 20 Takte sollten es selbst mit viel Register-Sichern nicht
> sein.

8 Takte benötigt allein die Interruptannahme mit dem anschließenden
Sprung aus der Vektortabelle.  Weitere 8 Takte braucht der minimale
Prolog einer ISR.  Damit sind bereits 16 Takte erreicht, wenn die ISR
selbst keine weiteren Register sichern muss.

Wenn die ISR aber einen 16-bit-Wert lesen soll, muss sie wenigstens
noch 2 Register sichern, macht 4 weitere Takte dafür.  Erst dann kann
sie überhaupt irgendwas auf den IO-Ports machen.

> Aber Du solltest zum Probieren vielleich mal alles an überflüssigem
> Ballast aus dem Programm rauswerfen. Die ganzen Variablen, die Du da
> deklarierst, werden eh nirgends benutzt.

Dann generieren sie aber auch keinen Code, wenn man die Optimierung
einschaltet.  Aber genau da vermute ich, dass der Hase im Pfeffer
liegt...

von Johannes M. (johnny-m)


Lesenswert?

Jörg Wunsch wrote:
> 8 Takte benötigt allein die Interruptannahme mit dem anschließenden
> Sprung aus der Vektortabelle.  Weitere 8 Takte braucht der minimale
> Prolog einer ISR.  Damit sind bereits 16 Takte erreicht, wenn die ISR
> selbst keine weiteren Register sichern muss.
Klar, hatte grad nur kurz im Kopf überschlagen...

> Wenn die ISR aber einen 16-bit-Wert lesen soll, muss sie wenigstens
> noch 2 Register sichern, macht 4 weitere Takte dafür.  Erst dann kann
> sie überhaupt irgendwas auf den IO-Ports machen.
Auch das ist natürlich nicht von der Hand zu weisen.

Trotzdem halte ich 80 Takte in einem Programm solchen Umfangs für zu 
viel.

>> Aber Du solltest zum Probieren vielleich mal alles an überflüssigem
>> Ballast aus dem Programm rauswerfen. Die ganzen Variablen, die Du da
>> deklarierst, werden eh nirgends benutzt.
>
> Dann generieren sie aber auch keinen Code, wenn man die Optimierung
> einschaltet.  Aber genau da vermute ich, dass der Hase im Pfeffer
> liegt...
Das mit dem Wegschmeißen des unnötigen Ballasts war auch eher so 
gedacht, dass der OP erst mal ein übersichtliches Programm erstellen 
soll, das kein überflüssiges Zeug enthält, das vom Kern der Sache 
ablenkt.

Gruß

johnny

von Witali G. (witali)


Lesenswert?

Erstmals vielen Dank für eure Antworten!

Johannes M. wrote:
> Na, 80 Takte ist wirklich zu viel. Aber warum gehst Du nicht im
> Simulator schrittweise durch. Dann siehst Du am Zähler, wie viele Takte
> zwischen Capture-Ereignis und Eintritt in die ISR vergehen.

Genau das habe ich getan. Ich habe nur das Endergebnis mitgeteilt. 
Zwischen Capture-Ereignis und Eintritt in die ISR vergehen 12 Takte, nur 
bis zu dem Punkt, wo der Pfeil am Anfang der Interrupt-Routine steht. 
Bei dem Sprung zu dem einzigen Statement in der Routine werden dann 
gleich 34 Takte verbraucht. Ich habe aber keine Ahnung woran das liegt.

> Aber Du solltest zum Probieren vielleich mal alles an überflüssigem
> Ballast aus dem Programm rauswerfen. Die ganzen Variablen, die Du da
> deklarierst, werden eh nirgends benutzt.

Ich werde die Variablen dann zur Umrechnung und zur Ausgabe brauchen. 
Aber ich versuche mal die zunächst mal auszulassen.

von Jojo S. (Gast)


Lesenswert?

Die 34 Takte sind exakt das Sichern der Register. Beim Debuggen und 
durch den C-Code steppen siehst du das nicht, schalte die 
View/Disassembler Ansicht ein. Auch wenn es erstmal unübersichtlicher 
aussieht: zu jeder C-Code Zeile wird der Maschinencode angezeigt und man 
sieht das am Anfang der ISR jede Menge Register umkopiert werden.

von Witali G. (witali)


Lesenswert?

Ich habe auch versucht, die ganzen Variablendeklarationen 
auszukommentieren und neuzukompilieren, doch es ändern die Sache nicht. 
Das ist wohl normal, dass so viel Takte zum Aufruf notwendig sind. Na 
ja, bei 20MHz dauert es nicht so lang.

Ich danke euch allen für die Antworten!!!

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Hast du denn die Optimierung des Compilers eingeschaltet?

von Witali G. (witali)


Lesenswert?

Ich kenne diese Details gar nicht.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Witali Gustschin wrote:

> Ich kenne diese Details gar nicht.

Dann solltest du sie wohl kennen lernen. ;-)  Den Compiler ohne
Optimierung zu benutzen ist sowas, wie einen Ferrari mit angezogener
Handbremse zu fahren.

Da du von AVR Studio geschrieben hast, vermute ich stark, dass die
Optimierung noch ausgeschaltet ist, da das die Voreinstellung von
AVR Studio ist (leider).

von Witali G. (witali)


Lesenswert?

Ich habe jetzt im Tutorial und in avr-libc manual die Sachen über 
Optimierung gelesen aber irgend wie nicht schlau daraus geworden, wie 
man die Optrimierung einschaltet.

Kann man das im AVR-Studion durch setzten eines Häckchens in irgendeinem 
Dialogfenster oder auf so eine ähnliche Art machen? Oder passiert das 
nur über die Änderung von Makefile? Muss ich im Makefile irgendwo so 
etwas wie

OPT = 'Optimierungsgrad' z.B. s,
oder -Os

einfügen?

von Falk B. (falk)


Lesenswert?

@  Witali Gustschin (witali)

>Kann man das im AVR-Studion durch setzten eines Häckchens in irgendeinem
>Dialogfenster oder auf so eine ähnliche Art machen? Oder passiert das

Ja.

Menu Project -> Configuration Options -> Optimization

MfG
Falk

von Witali G. (witali)


Lesenswert?

Besten Dank!!!

von Witali G. (witali)


Lesenswert?

Jetzt habe ich die Optimierung eingeschaltet und stelle fest, dass mir 
anscheinend die Endlosschleife wegoptimiert wurde. Bei der Simulation 
springt der Simulator nicht in die Schleife. Die braucht man aber doch, 
wenn man nur bei Interrupts was tun möchte und sonst nur wartet.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Die wird nicht wegoptimiert, aber das AVR Studio kann offenbar
nicht damit umgehen, eine leere Schleife allein zu haben (das
ist ja dann nur ein RJMP auf sich selbst).

Abhilfe: schreib was rein:
1
   for (;;)
2
      asm volatile("nop");

von Witali G. (witali)


Lesenswert?

Wenn ich aber die Optimierung ausschalte, wird auch die Schleife bei der 
Simulation ausgeführt, solange bis ein Interrupt kommt.

von Witali G. (witali)


Lesenswert?

Vielen Dank für den Hinweis! Jetzt vergehen nur 37 (hex) Takte bis die 
ISR ausgeführt wird, deutlich schneller als mit 52 (hex) Takten. Eine 
Frage, die mir jetzt aufkommt, ist: Leidet das Programm selber nicht 
unter dieser Optimierung? Wenn früher mehr Takte bis zum Aufruf von ISR 
vergingen für wichtige Aktionen wie Zwischenspeicherung von wichtigen 
Registern und sonstiges, so werden diese Aktionen auf einmal unnö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.