Forum: Mikrocontroller und Digitale Elektronik atmega32 zu langsam?


von Michi (Gast)


Lesenswert?

Hallo zusammen,

gerade versuche ich mich an Timern und Interrupts und bin dabei auf ein 
Problem gestoßen, dass ich mir momentan nicht erklären kann.

Mein atmega32 läuft mit dem internen 1MHz Taktgeber.

Den Timer0 habe ich folgendermaßen konfiguriert:


1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
void enable_timer() {
5
  
6
  // Timer im CTC Modus mit Prescaler off konfigurieren:
7
    TCCR0 = (1<<WGM01) | (1<<CS00); // CTC Modus, Prescaler 1/1
8
  
9
  // Compare Register auf 0
10
  OCR0 = 127;
11
  
12
  // Timer-Interrupt aktivieren
13
  TIMSK |= (1<<OCIE0);
14
}
15
16
17
ISR (TIMER0_COMP_vect) {
18
  
19
  // IO D.7 invertieren
20
  PORTD ^= 0b10000000;
21
22
}
23
24
25
26
int main(void)
27
{
28
29
  enable_timer();
30
  sei();
31
    
32
  while(1) {
33
  }
34
35
}

Nach meinem Verständnis müsste ich doch nun an Pin D7 eine Frequenz von 
500 kHz messen können. Tatsächlich messe ich mit dem Oszi aber nur 14.7 
kHz.

Kann mir jemand erklären, was ich falsch gemacht habe?

Vielen Dank für eure Hilfe,

Michi

von Cyblord -. (cyblord)


Lesenswert?

Michi schrieb:

> Nach meinem Verständnis müsste ich doch nun an Pin D7 eine Frequenz von
> 500 kHz messen können. Tatsächlich messe ich mit dem Oszi aber nur 14.7
> kHz.
>

Nach deinem Verständnis benötigen also ISR Einsprung, Sichern aller 
Register, Register Wiederherstellung und Rücksprung aus der ISR 
keinerlei Zeit? Interessant. Erzähle mehr von dir.

von Peter D. (peda)


Lesenswert?

Michi schrieb:
> Nach meinem Verständnis müsste ich doch nun an Pin D7 eine Frequenz von
> 500 kHz messen können. Tatsächlich messe ich mit dem Oszi aber nur 14.7
> kHz.

Also bei mir ergibt
1MHz / 128 / 2 = 3,9kHz.

Interessant ist auch, daß an nem Eingang überhaupt was rauskommt.

: Bearbeitet durch User
von Michi (Gast)


Lesenswert?

Hallo,

vielen Dank für die Antworten.

@Peter: Sorry - kleiner Fehler im Code oben.
Den Wert für OCR0 hatte ich auf 1 gesetzt... 127 hatte ich nur zum 
Testen eingetragen, um das Meßergebnis irgendwie nachvollziehen zu 
können.

Daher müsste es eigentlich:
1
1MHz / 2 / 2 (<- den hab ich verstanden) heißen.
Wären dann doch immerhin noch 250 kHz.

@Cyblord: OK verstehe - beim 8051 ist es ja z.B. so, dass ein Zyklus 8 
Takte benötigt. Das kann man dann ja auch in den Timer einrechnen.

Wieviele Takte braucht denn der atmega? Im Datenblatt finde ich dazu 
nichts.

LG, michi

von wendelsberg (Gast)


Lesenswert?

Michi schrieb:
> Wieviele Takte braucht denn der atmega? Im Datenblatt finde ich dazu
> nichts.

Ich gebe zu, das kann man leicht ueberlesen. Hier die ersten vier Zeilen 
des DB vom Atmega64:

Features
• High-performance, Low-power Atmel AVR® 8-bit Microcontroller
• Advanced RISC Architecture
– 130 Powerful Instructions – Most Single Clock Cycle Execution

wendelsberg

von Michi (Gast)


Lesenswert?

Hallo wendelsberg,

ja - eben. Und in der while() Schleife wird ja netto mal garnichts 
gemacht.

Und der Overhead soll dafür sorgen, dass von 250khZ nur noch 14 khZ 
übrigbleiben, so wie Cyblord sagt?

Das fällt mir schwer zu glauben...

Wie berechnet man denn dann beim AVR die Timer, wenn ich bspw. eine 2khz 
Frequenz erzeugen will?

von (prx) A. K. (prx)


Lesenswert?

Michi schrieb:
> Und der Overhead soll dafür sorgen, dass von 250khZ nur noch 14 khZ
> übrigbleiben, so wie Cyblord sagt?

Bei 1MHz Takt und 14,7KHz Output ergeben sich ~34 Takte pro Aufruf des 
Interrupt-Handlers. Wär schon möglich.

Wenn diese Rechnung passt (hab grad keinen Compiler zu Hand), dann musst 
du entweder den Takt des Controller hochschrauben oder Moby den Gefallen 
tun und in Assembler programmieren. Denn dann bist du am Limit dessen, 
was ein AVR mit 1MHz Takt in als Interrupt-Frequenz C schafft. Am Timer 
zu drehen bringt dann nichts, das ist die falsche Stelle.

: Bearbeitet durch User
von Justus S. (jussa)


Lesenswert?

Michi schrieb:
> Das fällt mir schwer zu glauben...

da könnte ein Blick ins Assembler-Listing helfen...

von (prx) A. K. (prx)


Lesenswert?

Wobei sich Timer freilich auch so nutzen lassen, dass sie direkt einen 
Output steuern (=> PWM). Dann geht das ohne Interrupts ab.

von Hans (Gast)


Lesenswert?

Also ich würde so wie du das beschreibst im idealfall 58.8kHz 
erwarten...

Deine ISR müsste 5xpush, Read-Modify-Write, 5xpop enthalten.
Bis die nächste ISR kommt sinds dann 4us macht 17us => 58.8kHz

Was hast du "-Os" eingeschalten?

Dein Problem ist, dass deine ISR länger braucht wie die Zykluszeit des 
Timers...

Wenn die ISR als naked-function deklariert ist und du mit 8Mhz taktest 
sollten sich das dann ausgehen... aber 500kHz rechtecke würde ich mir 
trotzdem per PWM/Capture-Compare-Unit (also vom timer selbst) erzeugen 
lassen...

73

von Rolf M. (rmagnus)


Lesenswert?

Michi schrieb:
> Hallo wendelsberg,
>
> ja - eben. Und in der while() Schleife wird ja netto mal garnichts
> gemacht.
>
> Und der Overhead soll dafür sorgen, dass von 250khZ nur noch 14 khZ
> übrigbleiben, so wie Cyblord sagt?

In deinem Ursprungsposting war noch die Rede davon, daß du einen µC mit 
1 Mhz Takt hast und mit einer ISR an einem Pin so schnell wackeln 
willst, daß 500 Khz rauskommen. Dazu müßte die ISR einmal pro Taktzyklus 
durchlaufen werden. Der Taktzyklus reicht aber nicht mal zum Einsprung 
in die ISR aus.
Genau darauf hat Cyblord geantwortet.

Michi schrieb:
> Daher müsste es eigentlich:
> 1MHz  2  2 (<- den hab ich verstanden) heißen.
> Wären dann doch immerhin noch 250 kHz.

Also ein Aufruf der ISR alle 4 Taktzyklen... die sind schon verbraucht, 
bevor die ISR überhaupt los läuft.

von (prx) A. K. (prx)


Lesenswert?

Hans schrieb:
> Also ich würde so wie du das beschreibst im idealfall 58.8kHz
> Bis die nächste ISR kommt sinds dann 4us macht 17us => 58.8kHz

58kHz ISR-Frequenz ergibt 29KHz Pinfrequenz

von Rolf M. (rmagnus)


Lesenswert?

A. K. schrieb:
> Wenn diese Rechnung passt (hab grad keinen Compiler zu Hand), dann musst
> du entweder den Takt des Controller hochschrauben oder Moby den Gefallen
> tun und in Assembler programmieren. Denn dann bist du am Limit dessen,
> was ein AVR mit 1MHz Takt in als Interrupt-Frequenz C schafft.

Nicht am Limit, sondern weit darüber, auch mit Assembler.

Folgendes passiert bei einem Interrupt:

- Die aktuelle Instruktion wird fertig ausgeführt (Dauer je nach 
Instruktion und Zeitpunkt des Auftretens)
- Interrupts werden ausgeschaltet, die Rücksprungadresse wird gesichert 
und es wird in die Interrupt-Tabelle gesprungen (4 Takte)
- In der Tabelle steht ein JMP zur eigentlichen ISR (3 Takte)

* Dann wir der Code der ISR ausgefürt

- Am Ende steht ein RETI (4 Takzyklen)

Wenn die ISR auch was tun soll, müssen erstmal das SREG und alle 
verwendeten ALU-Register gesichert werden. Um das SREG zu sichern und am 
Ende wiederherzustellen, vergehen 6 Taktzyklen, für jedes ALU-Register 
kommen 4 Taktzyklen dazu.
Und dann braucht die eigentliche Aktion natürlich auch noch Zeit.

von (prx) A. K. (prx)


Lesenswert?

Rolf M. schrieb:
> Nicht am Limit, sondern weit darüber, auch mit Assembler.

Mein Aussage bezog sich auf die beobachtete ISR-Frequenz, nicht auf 
seine geforderte Frequenz. Er misst also das Limit der ISR-Frequenz bei 
1MHz Controllertakt in C.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Michi schrieb:
> @Cyblord: OK verstehe - beim 8051 ist es ja z.B. so, dass ein Zyklus 8
> Takte benötigt. Das kann man dann ja auch in den Timer einrechnen.

Beim 8051 gibt es Derivate mit 1, 2, 4, 6 und 12 Takten je CPU-Zyklus.
Welcher soll denn der mit 8 sein?

Der 8051 kann aber ein IO-Bit direkt drehen, ohne was zu sichern.
Beim AT89LP6440 wären das:
LCALL ISR + CPL Bit + RETI = 4 + 2 + 4 = 10 Takte.

Die 34 Takte beim AVR sind ziemlich das Optimum, kleiner kriegt man die 
ISR kaum.

von J. T. (chaoskind)


Lesenswert?

Peter D. schrieb:
> Die 34 Takte beim AVR sind ziemlich das Optimum, kleiner kriegt man die
> ISR kaum.

In Asm würds schneller gehen, wenn man aufs Registersichern verzichtet, 
was man hier tun kann. Also das Registersichern auslassen. Asm kann man 
natürlich immer benutzen, wenn man das mag, aber auch hier muss man 
manchmal Register sichern ;-)

von Karl H. (kbuchegg)


Lesenswert?

J. T. schrieb:
> Peter D. schrieb:
>> Die 34 Takte beim AVR sind ziemlich das Optimum, kleiner kriegt man die
>> ISR kaum.
>
> In Asm würds schneller gehen, wenn man aufs Registersichern verzichtet,
> was man hier tun kann.

Kann man beim gcc auch abschalten.

Ich würds aber trotzdem nur im absoluten Notfall abschalten. Denn wie 
immer gilt: wenn man nicht 100% weiss was man da tut, dann schiesst man 
sich sehr schnell ins Knie. Zumindest muss dann ein dicker, fetter 
Kommentar hin, der darauf hinweist, dass man in dieser ISR als 
Programmierer selbst dafür verantwortlich ist, kein Registerchaos zu 
veranstalten.

von Hans (Gast)


Lesenswert?

Mist, sorry war falsch.... Toggeln und RETI vergessen...

also nochmal abschätzen:

10 Takte push, 3 Takte read-modify-write, 10 Takte pop, 4 Takte RETI
Macht 27us +4us bis zur nächsten ISR= 31 * 2 = 62us oder 16,12kHz

Das laden von deiner Bitmakte dauert dann auch noch min. 1nen takt...

Passt also ganz gut... wie gesagt, ISR als naked deklarieren, dem gcc 
ein "-Os" mitgeben und schon solls schneller werden... aber kleinesfalls 
die 500kHz

73

von Carl D. (jcw2)


Lesenswert?

Naked macht aber kein RETI, das muß man selber machen ( und darf es 
nicht vergessen!

von c-hater (Gast)


Lesenswert?

Hans schrieb:

> aber kleinesfalls
> die 500kHz

Natürlich nicht.

Da beim Mega32 das (in pure Asm ohne Rücksicht auf irgendwelches 
C-Gebabbel tatsächlich erreichbare) theoretische Minimum für einen 
Interruptframe mit der gewünschten Funktionalität genau 11 Takte 
beträgt, ist natürlich nicht zu erwarten, daß es in C irgenwie möglich 
sein sollte, auf irgendeine Art über die solcherart maximal erreichbare 
ISR-Rate von rund 91kHz hinauszukommen.

Da das aber natürlich nur Togglefrequenz ist, ist die letztlich am Pin 
erzeugte Frequenz sogar nur halb so groß, also rund 45,5 kHz. Also eine 
ganze Größenordnung von dem weg, was der völlig unwissende TO erreichen 
wollte...

Da kann kein Optimierungstrick helfen. Weder in C noch in Asm. Nur 
intelligenter Einsatz vorhandener Peripherie-Hardware.

Thread beendet?

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.