PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Timer in CTC, Berechnung von OCR



CowZ
03.10.2007, 20:01
Hi,

ich verwende den Timer0 eines Mega32 im CTC-Modus. Ich habe einen 16MHz Quarz angeschlossen, Fuses sind gesetzt. Ich möchte Interrupt alle 2µs auslösen.

Welchen Wert muss ich nun einsetzen? Prescaler habe ich ausgeschaltet (Clocksource ist also der Systemtakt (16MHz)).

Meine Berechnung:
Ein Takt dauert 1 / 16MHz = 62.5ns
Ich muss also alle (2µs / 62.5ns = 32) Takte einen Interrupt auslösen.
Folglich stelle ich OCR auf 32.

Es ergibt sich aber (mit Oszi-Messung), dass der Zeitabstand zwischen den IRQs (gemessen wird PORTA:0) etwas größer ist als 2µs (genauer gesagt: er ist 2,3µs groß).

Woran liegt das?
Dachte, es liegt vllt daran, dass durch den IRQ-Aufruf Zeit verbraucht wird, aber das sollte sich ja ausgleichen.

Gruß, CowZ
PS: Hier der Code:

#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>

uint8_t sync;

int main(void)
{
DDRA = 0xFF;

// Timer initialisation
// CTC
TCCR0 |= (1<<WGM01);
TCCR0 &= ~(1<<WGM00);
// OC0 disabled
TCCR0 &= ~( (1<<COM01) | (1<<COM01) );
// Clock
TCCR0 |= (1<<CS00);
TCCR0 &= ~( (1<<CS02) | (1<<CS01) );
// OCR Settings
OCR0 = 32;
// IRQ-Settings
TIMSK |= (1<<OCIE0); // Compare Match IRQ

sync = 0;

sei();
while(1)
{};
}

ISR(TIMER0_COMP_vect)
{
if (sync)
{
PORTA = 1;
sync = 0;
}
else
{
PORTA = 0;
sync = 1;
}
}

izaseba
03.10.2007, 20:44
alle 32 Takte ein Interrupt ?
Nicht schlecht, soll der Controller sonst noch was machen ?
Poste mal bitte die *.lss Datei, damit man sehen kann, wie lange verweilt er in dem Interrupt.

Gruß Sebastian

CowZ
03.10.2007, 21:31
Hi,

du meinst du .lst Datei?

Kein Problem, ist im Anhang :)

Gruß, CowZ

izaseba
03.10.2007, 21:59
Ich meinte schon *lss, aber egal, die ist auch gut ;-)
Ich habe die ISR rauskopiert und die Takte eben gezählt(Hoffe, daß ich mich nicht grob verechnet habe)


ISR(TIMER0_COMP_vect)
{
ca: 1f 92 push r1 2
cc: 0f 92 push r0 4
ce: 0f b6 in r0, 0x3f 5
d0: 0f 92 push r0 7
d2: 11 24 eor r1, r1 8
d4: 2f 93 push r18 10
d6: 8f 93 push r24 12
if (sync)
d8: 80 91 60 00 lds r24, 0x0060 14
dc: 88 23 and r24, r24 15
de: 29 f0 breq .+10 16
{
PORTA = 1;
e0: 81 e0 ldi r24, 0x01 17
e2: 8b bb out 0x1b, r24 18
sync = 0;
e4: 10 92 60 00 sts 0x0060, r1 20
e8: 04 c0 rjmp .+8 22
}
else
{
PORTA = 0;
ea: 8b bb out 0x1b, r24 19
sync = 1;
ec: 21 e0 ldi r18, 0x01 20
ee: 20 93 60 00 sts 0x0060, r18 22
f2: 8f 91 pop r24 24/24
f4: 2f 91 pop r18 26/26
f6: 0f 90 pop r0 28/28
f8: 0f be out 0x3f, r0 29/29
fa: 0f 90 pop r0 31/31
fc: 1f 90 pop r1 33/33
fe: 18 95 reti 37/37

Bevor der µC in die ISR springt vergehen noch 3(?) Takte insgesammt dann 40(?), tja dumm gelaufen...

Kannst Du das nicht anders lösen ?
Den zugehörigen Pin in Hardware toogeln lassen ?

Gruß Sebastian

P.S. Doch verrechnet ](*,) Es war ein Takt zu viel....

Gock
04.10.2007, 13:16
So sieht's aus!
Aber hast Du schon die unterschiedlichen Optimierungen versucht? Ich würde mit der Optimierung s (Space) anfangen. Es besteht Optimierungspotential bei den verwendeten Registern. Eigentlich käme der Compiler nämlich auch mit weniger als 5 Registern aus. Dann würdest Du einige Pushs usw. sparen und kämst so vielleicht in die Region von 25-31 Takte. Wenn Du dann noch als erstes in der ISR den Timer ausschaltest, und den OCR1 Wert auf 32-(optimierte Taktzahl) einstellst), also irgendwas zwischen 1-10, dann könnte es gehen.
Ansnonsten sehe ich gerade nur die Möglichkeit, das Programm in Assembler zu schreiben. Dann kannst Du Dir die ganzen Pushs und Pops sparen. Das müsste gehen, wenngleich dann auch nicht mehr viel weiteres geht.
Möglicherweise kannst Du auch (zb mit Inline Assembler) in C die ISR umgehen, indem Du statt des Funktionsaufrufs den Sprung selbst nutzt. Keine Ahnung ob und wie sowas geht. Vielleicht weiß das wer anders...
Gruß

izaseba
04.10.2007, 15:59
Hallo,
als größte Optimierung würde ich die Globale Variable sync rausschmeissen und den Pin einfach nur in der ISR toogeln,


PORTA ^=(1<<PA1);


Das dürfte schon ein paar Takte einsparen :-k

Aber wie gesagt, am besten alles in Hardware machen,
non PWM ,den zugehörigen PIN bei Compare Match toogeln und OCR0 auf 16 stellen.

Nachteil, es ist nicht unbedingt PA1
Vorteil der Controller kriegt langeweile und kann in der Zeit was anderes machen ;-)

Gruß Sebastian

Gock
05.10.2007, 09:34
Ja stimmt, synch muss raus, aber
PORTA xor (1<<PA1) ?
warum nicht
PORTA = ~PORTA
Mit Optimierung meinte ich die Option im C-Compiler.
Ist ein µC keine Hardware??? ;-)
Gruß

izaseba
05.10.2007, 15:05
Hallo Gock,


Ja stimmt, synch muss raus, aber
PORTA xor (1<<PA1) ?
warum nicht
PORTA = ~PORTA
Ich weiß nicht, was CowZ vor hat :-k
Mit PORTA = ~PORTA;
wackelst Du an allen PortA Pins
mit
PORTA^=(1<<PA0); <- PA0 und nicht PA1 ](*,)
nur am PA0 was der Aufgabenstellung eher entspricht
Na egal, wir wissen ja nicht, was wirklich verlangt wird...



Mit Optimierung meinte ich die Option im C-Compiler.
Ich weiß, wie Du das meinst, die Variable rauszuschmeissen bringt aber das meiste

Ist ein µC keine Hardware???
:Haue klar, ich meine das Toggeln komplett in Hardware machen, ohne Interrupts!
Bei M32 wäre das der Pin PB3, der mit der ComparMatch Unit von Timer 0 zusammenhängt...

Gruß Sebastian

CowZ
05.10.2007, 15:07
Hi,

was ich schlussendlich vorhatte/vorhabe: einen BAS-Sync erzeugen. Mal schauen, vllt mach ich das auch mit nem CPLD, mal schauen.

Vielen Dank erstmal für eure Hilfe. Bin ab morgen eine Woche in Barcelona, danach mal gucken, wie ich das mache :)

Gruß, CowZ

Gock
06.10.2007, 11:04
@ izaseba
Ach die Hardware meinst Du... Sag das doch gleich! ;-)
Ja, auch ne gute Idee, aber wie Du schon sagtest, man weiß zu wenig, den optimalen Tip zu geben.
Die Schreibweise mit dem XOR kannte ich noch nicht.
Gruß