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:
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
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.
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.
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
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
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?
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.
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
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.
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
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.
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.
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.
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 ;-)
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.
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
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?