Forum: Mikrocontroller und Digitale Elektronik Zeitproblem beim AVR Interrupt


von Reinhard #. (gruebler)


Lesenswert?

Hallo zusammen
Ich betreibe hier einen ATtiny13A mit dem
RC-Oszillator bei 9,6MHz.
Eine ISR soll alle 20µs aufgerufen werden.
Dazu habe ich folgendes Programm geschrieben,
in dem zur Messung ein Ausgang bei jedem Aufruf
gekippt wird.
ERgebnis: Der Aufruf erfolgt alle 23µs.

So ungenau kann der RC_Osz. doch nicht sein.

Ich habe daher ein zweites Programm geschrieben,
bei dem ich die Delay-Funktion benutze. Hier
messe ich 20,08µs. Das finde ich akzeptabel.

Kann mir eine sagen, welcher Fehler in meiner
ersten Programmversion steckt? Ich will natürlich
die Interruprvariante nutzen.
1
//Version 1 mit Interrupt
2
#define F_CPU 9600000UL      //CPU-Takt 9,6MHz ohne Teiler durch 8
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
6
#define OUT  0 //Taktausgang
7
8
int main(void)
9
{
10
  DDRB =  (1<<OUT);                //Ausgang festmachen.
11
 
12
  //Zähler 0 mit Compare-Interrupt einrichten
13
  //Die ISR wird alle 20µs aufgerufen
14
  TCCR0B = (1<<CS00);    //ohne Vorteiler.
15
  OCR0A = 192;           //1/9,6MHz * 192 = 20µs
16
  TIMSK0 = (1<<OCIE0A);  //Interrupt bei erreichen von OCR0A
17
  sei();                 //generelle Interruptfreigabe
18
19
  while (1)
20
  {} //Hier ist noch nichts zu tun
21
}
22
23
ISR(TIM0_COMPA_vect)  //Aufruf alle 20µs
24
{
25
  TCNT0 = 0;  //Timer zurücksetzten
26
  PORTB ^= (1<<OUT);
27
}
28
29
//###################################
30
31
//Version 2 mit delay
32
#define F_CPU 9600000UL      //CPU-Takt 9,6MHz ohne Teiler durch 8
33
#include <avr/io.h>
34
#include <util/delay.h>
35
36
37
#define OUT  0 //Taktausgang
38
39
int main(void)
40
{
41
  DDRB =  (1<<OUT);   //Ausgang festmachen.
42
43
  while (1)
44
  {
45
    PORTB ^= (1<<OUT);
46
    _delay_us(19.2); //ergibt 20µs bei 9,6MHz
47
  } 
48
}

von Peter II (Gast)


Lesenswert?

1
 TCNT0 = 0;  //Timer zurücksetzten

das wird nicht funktionieren, denn der Aufruf erfolgt erst einige Takte 
später. Da verlierst du immer Zeit.

Schau dir den CTC Modus vom Timer an.

von m.n. (Gast)


Lesenswert?

Reinhard #. schrieb:
> TCNT0 = 0;  //Timer zurücksetzten

Das ist der Fehler. Das Rücksetzen erfolgt zu spät.
Abhilfe bringt eine andere Betriebsart des Timers oder - schlechte 
Lösung - ein TCNT0 = xx, wobei xx die µs für den Aufruf der ISR 
kompensiert.

von spess53 (Gast)


Lesenswert?

Hi

> OCR0A = 192;           //1/9,6MHz * 192 = 20µs

Ich komme auf 191 (allerdings nicht mit deiner Rechnung) Lies mal das 
Datenblatt.

MfG spess

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


Lesenswert?

CTC ist das einzig richtige hier. Nebenbei solltest du auch
1
  OCR0A = 192;           //1/9,6MHz * 192 = 20µs
auf 191 korrigieren, denn die Null zählt ja mit. Nebenbei bemerkt, du 
brauchst im CTC Mode gar keine ISR, wenns dir nur im Toggeln des Pins 
geht, das kann der kleine Kerl in Hardware an OC0A = PB0 mit dem COM0n 
Bits.

von m.n. (Gast)


Lesenswert?

Matthias S. schrieb:
> CTC ist das einzig richtige hier.

Nee, nee ;-)


#define NACHLADEWERT (F_CPU/50000)  // 50 kHz
ISR(TIM0_COMPA_vect)                // Aufruf alle 20µs
{
  OCR0A += NACHLADEWERT; // nächsten Zeitpunkt festlegen
  PORTB ^= (1<<OUT);
}

von Peter II (Gast)


Lesenswert?

m.n. schrieb:
> Nee, nee ;-)
>
> #define NACHLADEWERT (F_CPU/50000)  // 50 kHz
> ISR(TIM0_COMPA_vect)                // Aufruf alle 20µs
> {
>   OCR0A += NACHLADEWERT; // nächsten Zeitpunkt festlegen
>   PORTB ^= (1<<OUT);
> }

doch.
1
 OCR0A += NACHLADEWERT;
ist keine atomare Operation, damit geht auch immer mindestens 1 Takt 
verloren.

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


Lesenswert?

m.n. schrieb:
> OCR0A += NACHLADEWERT; // nächsten Zeitpunkt festlegen

Auch da ist der unbedeutende Rundungsfehler wieder drin, denn aus dem 
Nachladewert kommt 192 raus und nicht 191, was richtig wäre. Ausserdem 
verstehe ich nicht, warum man sich unbedingt Jittern einfangen will.
1
  //Zähler 0 mit CTC einrichten
2
  //Zero Effort Toggle PB0 mit 20µs
3
  TCCR0A = (1 << COM0A0) | (1 << WGM01);
4
  OCR0A = 191;           //1/9,6MHz * 192 = 20µs
5
  TCCR0B = (1<<CS00);    //ohne Vorteiler.
Das ganze läuft ohne ISR im Hintergrund. An- und Ausschalten kann man 
z.B. mit dem DDRB.

von m.n. (Gast)


Lesenswert?

Matthias S. schrieb:
> Ausserdem
> verstehe ich nicht, warum man sich unbedingt Jittern einfangen will.

Das war die Anforderung:
> Eine ISR soll alle 20µs aufgerufen werden.

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


Lesenswert?

m.n. schrieb:
> Das war die Anforderung:
>> Eine ISR soll alle 20µs aufgerufen werden.

Gut, in der vorhandenen ISR wird aber wieder nur PB0 getoggelt. Aber ist 
ja einfach. Fügt man eben noch
1
TIMSK0 = (1 << OCIE0A);
2
sei();
hinzu. Dann wird getoggelt und auch noch 'ne ISR aufgerufen. Nur das man 
in der ISR sich um keine Timerladerei kümmern muss und der Pin toggelt 
auch schon von alleine.

von m.n. (Gast)


Lesenswert?

Matthias S. schrieb:
> Gut, in der vorhandenen ISR wird aber wieder nur PB0 getoggelt.

Nochmal vollständig zitiert:
> Eine ISR soll alle 20µs aufgerufen werden.
> Dazu habe ich folgendes Programm geschrieben,
> in dem zur Messung ein Ausgang bei jedem Aufruf
> gekippt wird.

PB0 zu toggeln ist nur Mittel zum Zweck und wird vermutlich anschließend 
wieder gelöscht.
Mit dem CTC-Modus verbaut man sich die Möglichkeit, Timer0 für weiters 
Timing zu nutzen, sowohl mit OCR0B als auch direkt TCNT0 zu verwenden.

von Rene K. (xdraconix)


Lesenswert?

Reinhard #. schrieb:
> zur Messung ein Ausgang bei jedem Aufruf
> gekippt wird

Ein Pin zu toggeln ist doch garnicht Ziel des ganzen, er nutzt ihn nur 
zum Debuging. Ziel ist es die ISR alle 20us aufzurufen. WAS er dann 
später in der ISR machen will steht ja noch garnicht auf dem Blatt.

Edit: M.N. war schneller ?

von Peter D. (peda)


Lesenswert?

Peter II schrieb:
> OCR0A += NACHLADEWERT;
> ist keine atomare Operation, damit geht auch immer mindestens 1 Takt
> verloren.

Da geht nichts verloren und es muß 192 addiert werden. Das OCR0A 
Berechnen  muß nur vor dem nächten Match erfolgt sein.

von Peter II (Gast)


Lesenswert?

Peter D. schrieb:
> Da geht nichts verloren und es muß 192 addiert werden. Das OCR0A
> Berechnen  muß nur vor dem nächten Match erfolgt sein.

ja stimmt, ich dachte TCNT0 wird verwendet.

von Reinhard #. (gruebler)


Lesenswert?

Rene K. schrieb:
> Ein Pin zu toggeln ist doch gar nicht Ziel des ganzen, er nutzt ihn nur
> zum Debuging.
Danke Rene. K und M. N. ihr habt es verstanden.

Das war ein guter Gedanke:
1
#define NACHLADEWERT (F_CPU/50000)  // 50 kHz
2
ISR(TIM0_COMPA_vect)                // Aufruf alle 20µs
3
{
4
  OCR0A += NACHLADEWERT; // nächsten Zeitpunkt festlegen
5
  PORTB ^= (1<<OUT);
6
}

Ich bin jetzt im Bereich der RC-Osz.-Genauigkeit.
Man lernt immer noch dazu. Danke!

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Reinhard #. schrieb:
> Das war ein guter Gedanke:
> #define NACHLADEWERT (F_CPU/50000)  // 50 kHz
> ISR(TIM0_COMPA_vect)                // Aufruf alle 20µs
> {
>   OCR0A += NACHLADEWERT; // nächsten Zeitpunkt festlegen
>   PORTB ^= (1<<OUT);
> }
>
> Ich bin jetzt im Bereich der RC-Osz.-Genauigkeit.
> Man lernt immer noch dazu. Danke!

 Und genau dafür gibt es CTC-Mode bei AVRs - wozu die ganze
 Rechnerei und manuelles rücksetzen ?
1
  TCCR0A = (1<<WGM1);    //* CTC-MODE
2
  TCCR0B = (1<<CS00);    //ohne Vorteiler.
3
  OCR0A = 191;           //1/9,6MHz * 192 = 20µs
4
  TIMSK0 = (1<<OCIE0A);  //Interrupt bei erreichen von OCR0A

 Und in der ISR brauchst du dich weder um TCNT0 noch um OCR0A
 zu kümmern...

von Karl M. (Gast)


Lesenswert?

Guten Morgen miteinander,

wie allgemein bekannt aus dem Datenblatt des attiny13a:
*10.2.2 Toggling the Pin*
/Writing a logic one to PINxn toggles the value of PORTxn, independent 
on the value of DDRxn. Note that the SBI instruction can be used to 
toggle one single bit in a port./

Kann man hier noch ein wenig optimieren.
> ISR(TIM0_COMPA_vect)                // Aufruf alle 20µs
> {
>   OCR0A += NACHLADEWERT; // nächsten Zeitpunkt festlegen
>   PINB.0 = 1;
> }
Wenn man die passende Definition von PINB.0 im Code hat.

von m.n. (Gast)


Lesenswert?

Marc V. schrieb:
> Und genau dafür gibt es CTC-Mode bei AVRs - wozu die ganze
>  Rechnerei und manuelles rücksetzen ?

Schon wieder Einer ;-)

Im CTC-Modus wird der Timer sehr schlecht genutzt. Es entfällt die 
Möglichkeit, einen weiteren periodischen Interrupt über OCR0B 
einzustellen, den OVFL-Interrupt zu nutzen oder den Zählerstand selber 
für kurze Zeiten auszulesen und zu verwenden.
Mit Rechnerei hat das doch alles nichts zu tun.

Verwendet man z.B. für den Timer einen Vorteiler von 64, lassen sich mit 
einem Nachladewert von 3 ebenfalls 20 µs erzeugen. Benötigt man noch 
eine ISR im 1 ms Takt, so kann man das über OCR0B mit 150 als 
Nachladewert erreichen.

Karl M. schrieb:
> *10.2.2 Toggling the Pin*

Der Punkt war doch schon längst abgehakt.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

m.n. schrieb:
> Schon wieder Einer ;-)
>
> Im CTC-Modus wird der Timer sehr schlecht genutzt.
> Es entfällt die Möglichkeit, einen weiteren periodischen Interrupt
> über OCR0B einzustellen,

 Wo hat der TO das verlangt, bzw. überhaupt erwähnt ?


> den OVFL-Interrupt zu nutzen

 Diese Anforderung habe ich auch nicht gesehen...


> Zählerstand selber für kurze Zeiten auszulesen und zu verwenden.

 Das ist natürlich Blödsinn...

m.n. schrieb:
> Verwendet man z.B. für den Timer einen Vorteiler von 64, lassen sich mit
> einem Nachladewert von 3 ebenfalls 20 µs erzeugen. Benötigt man noch
> eine ISR im 1 ms Takt, so kann man das über OCR0B mit 150 als
> Nachladewert erreichen.

 Man kann sich noch viele (unnötige) Möglichkeiten ausdenken, aber ich
 schlage dir mal vor, den ersten Beitrag von TO zu lesen...

von m.n. (Gast)


Lesenswert?

Gut, Du kennst nur CTC, dann mache es so. Ich will Dich ja nicht 
überfordern.

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.