Forum: Compiler & IDEs ATMega CTC Modus, keine 1us?


von Stefan Jaensch (Gast)


Lesenswert?

Hallo,

ich versuche schon die ganze Zeit einen Timer0 Interrupt mittels CTC
Modus hinzubekommen, um einen Takt von 1us für mein Programm zu
erzeugen. Die Initialsisierung und der Interrupt funktioniert an sich
schon, jedoch ist der kleinste Wert, den ich erreiche 2us!

Bei einem Systemtakt von 16MHz (ohne Prescaler) muß das OCR0 Register
mit 16 vorgeladen werden. Der Timer0 zählt bis 16 (bei 16MHz = 1us) und
wird durch den CTC Modus wieder zurückgesetzt und gleichzeitig wird der
SIG_OUTPUT_COMPARE0 Interrupt ausgelöst. Zum Test Toggle ich im
Interrupt den PortC. Aber ich messe High bzw. Low Zeiten von genau
2us.
ABER:
Lade ich das OCR0 Register mit z.B. 64 vor, so messe ich High/Low
Zeiten von genau 4us! Dieser Wert ist richtig. Auch für 128 stimmt es.
Für 16 erhalte ich auch nur wieder 2us!



2. Versuch:
Im Normalmodus von Timer0 muß jedes mal wenn ein
SIG_OVERFLOW0-Interrupt ausgelöst wird das Register mit TCNT0=240
vorgeladen werden. Damit verbleiben 16 Takte (= 1us) bis zum nächsten
Interrupt. Aber nein, er wird nur aller 2us ausgelöst, auch mit
TCNT0=247.

Woran kann das liegen???


Folgende Situation:

CPU:  ATMEGA32-16PU mit 16MHz getaktet
Sprache: C (gcc)

Der Timer0 (im CTC Modus) wird wie folgt initialisiert:

OCR0 = 16;
TCCR0 |= (1<<WGM01); // CTC Mod,
TCCR0 |= (1<<CS00);  // CPU Takt = 16 MHz

Danke für eine schnelle Antwort.
Stefan

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


Lesenswert?

> ich versuche schon die ganze Zeit einen Timer0 Interrupt mittels CTC
> Modus hinzubekommen, um einen Takt von 1us für mein Programm zu
> erzeugen. Die Initialsisierung und der Interrupt funktioniert an
> sich schon, jedoch ist der kleinste Wert, den ich erreiche 2us!

Wenn ich deine CPU wäre, würde ich auch nicht mehr erreichen
wollen. ;-)

Hast du dir schon einmal überlegt, dass die komplette Interruptannahme
und -ausführung dann keine 16 Takte Zeit hat?  Davon gehen
wimre. bereits 4 Takte für die Annahme drauf, weitere Takte für das
Retten und Rückspeichern des aktuellen Prozessorstatus.  Nicht jeder
Befehl ist in einem Takt ausgeführt...

Was bitte willst du denn da noch Sinnvolles 1.) innerhalb der ISR und
zweitens in den wenigen verbleibenden CPU-Zyklen im Hauptprogramm
anstellen?

von Stefan Jaensch (Gast)


Lesenswert?

Hallo,

danke für die schnelle Antwort,

ich brauche die 1us Auflösung für die Ansteuerung eines Multiplexers,
mit dem ich mehrere Spannungen hin und her schalten kann, um eine Art
einfachen Pulsgenerator zu bauen.

Im Restprogramm oder in der ISR soll nur noch eine Variable gezählt
werden und bei bestimmten Werten den Multiplexer entsprechend schalten

Stefan

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


Lesenswert?

Ich denke fast, dass ein Controller für dich die falsche
Lösung ist und du eher nach einem FPGA oder sowas suchst...

Anyway, codier' die ISR zu Fuß in Assembler.  Reserviere für
alle Dinge, die du in der ISR retten musst, Registervariablen
im C-Code.  Dann hast du vielleicht gerade mal so eine Chance.
Du solltest es in jedem Falle mit der Hand durchrechnen.  Wenn
du pro Mikrosekunden noch einen Befehl frei hast für das main(),
sollte das ja fast genügen... ;-)

von Stefan Jaensch (Gast)


Lesenswert?

Hallo,

ja, ein FPGA wäre für diese Sache besser geeignet, aber der AVR
übernimmt noch andere Steueraufgaben, so daß ich auf ihn angewiesen
bin.

Ich werde erstmal meine Anforderungen herunterschrauben und mich mit
einer Zeitauflösung von 10us begnügen. Und wenn mein Kopf wieder etwas
freier ist an die 1us heranwagen.

Trotzdem Danke!

Stefan

von peter dannegger (Gast)


Lesenswert?

"Und wenn mein Kopf wieder etwas freier ist an die 1us heranwagen."


Besser als 5µs wirds aber kaum werden.

Selbst in Asembler kostet ein nackter Interrupt 10 Zyklen, also ohne
was zu tun oder zu sichern.


Ich hab mal nen Assemblerinterrupt alle 64 Zyklen gemacht, nie wieder
!

Sämtliche anderen Interrupts mußten auch in Assembler gemacht werden,
um eine 2. Prioritätsstufe zu simulieren.

Sowas ist echt haarig.

Wenn ich das nächste mal kurze Interrupts benötige, dann nehme ich
wieder den 8051, da habe ich 4 Prioritäten. Die sollen mal mit dem
AT89LP4051 endlich aus die Puschen kommen, der ist immer noch nur
Sample-Status.


Peter

von Micha (Gast)


Lesenswert?

Hatte ähnliche Probleme, hab einen Ausgang gesetzt und wollte ihn nach 
eine 1 µs reseten. Allerdings in Basic - hat aber mit den wait Befehl 
gejittert. Hab dann die µs mit nop erzwungen. Genau 14 nops plus set und 
reset ergaben am Ausgang 1µs! Microkontroller: Atmega32 mit 16 MHZ 
crystal!

von Dino S. (Gast)


Lesenswert?

Da staune ich, was in Basic alles möglich ist.
Ist bestimmt BASCOM :-)

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.