PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [ERLEDIGT] Timer2 init am Mega644 klappt einfach nicht



ad°FX
07.03.2013, 11:33
Hallo alle zusammen,

schön dass es dieses Forum gibt. Also schnell angemeldet und mal Hallo an alle gesagt. Ich bin ja neu hier und hoffe auf Euren großen Erfahrungsschatz. Ich selbst scheine an sowas wie Betriebsblindheit zu leiden :D
Folgendes ist mein Vorhaben:

Ich benötige für eine Fahrradlampen Schaltung ein PWM Signal um eine LED zu dimmen. Gleichzeitig möchte über den selben Timer den Kontrast für ein LCD einstellen können. Ist ja an und für sich kein Problem. Timer2 hat zwei Compare Register (OCR2A&B), die an OC2x ausgegeben werden können. Eigentlich bin ich auch recht fit im Umgang mit Timern. Timer0 und 1 laufen in demselben Programm ja einwandfrei. Allerdings nicht als PWM. Der eine liefert eine Zeitreferenz, der andere wertet Dynamo-Impulse aus. Schön über ISR's und läuft. Aber das führt vorerst zu weit. Beim initialisieren vom Timer2 komme ich allerdings ins Straucheln. Kann einer von Euch mal eben über den Code schauen und mir sagen wo sich der Fehlerteufel eingeschlichen hat?


TCCR2A |= (1<<COM2A0) | (1<<COM2A1); // Setze OC2A bei Compare, reset@bottom, inverted Mode
TCCR2A |= (1<<COM2B1); // Lösche OC2B bei Compare, set@bottom
TCCR2A |= (1<<WGM20) | (1<<WGM21); // WaveFormGenerator --> fast PWM Mode
OCR2A = 128;
DDRD |= (1<<PD6) | (1<<PD7); // PD6&7 als Ausgang um PWM-Signal sichtbar zu machen
TCCR2B |= (1<<CS22); // Prescaler auf 64 (PWM-Freq=1,125kHz) und start Counter2


OCR2B wird später gesetzt und ist bei Start=0. Am OCR2B soll also erstmal ein High-Signal anliegen, das ich mit nem Oszi mal eben darstellen wollte. Nix da. ich bekomme weder an OC2A noch an OC2B ein Signal. Kein High, kein PWM. An OC2A liegt evtl. sowas wie ein rauschen (+-0.2V) an??? Wenn ich OCR2A=128 setze sollte ich ja eher ein "50% Signal" meiner Grundfrequenz erhalten, also ca 562Hz, oder?
Hab ich das Datenblatt richtig verstanden, dass ein Update der OCR2x erst bei Bottom stattfindet? Ich kann demzufolge also in der Main die Compare-Register ändern und muss das nicht über ISR machen? Vielen Dank für Eure Hilfe und genießt die sich langsam zeigende Sonne!!!

Grüße
Eddy
Hab ich irgendwas vergessen beim init? Ich hofffe mein Problem ist klar geworden. Wenn nicht liefer ich natürlich (Code-)nachschub.

markusj
07.03.2013, 12:30
Hab ich das Datenblatt richtig verstanden, dass ein Update der OCR2x erst bei Bottom stattfindet? Ich kann demzufolge also in der Main die Compare-Register ändern und muss das nicht über ISR machen?

Richtig, die sind gepuffert.

Zu deinem Problem: Ich finde keinen Fehler im Code, im Simulator (AVR Simulator 2, der andere setzt beim Timer keine Pins) funktioniert er problemlos.
Ach ja, ein Systemtakt von 72kHz ist sehr wenig ...

Testcode:


#include <avr/io.h>

int main(void) {
TCCR2A |= (1<<COM2A0) | (1<<COM2A1); // Setze OC2A bei Compare, reset@bottom, inverted Mode
TCCR2A |= (1<<COM2B1); // Lösche OC2B bei Compare, set@bottom
TCCR2A |= (1<<WGM20) | (1<<WGM21); // WaveFormGenerator --> fast PWM Mode
OCR2A = 128;
DDRD |= (1<<PD6) | (1<<PD7); // PD6&7 als Ausgang um PWM-Signal sichtbar zu machen
TCCR2B |= (1<<CS22); // Prescaler auf 64 (PWM-Freq=1,125kHz) und start Counter2

char last = PIND;
for(;;) {
char in = PIND;

if (last != in) {
last = in;
GPIOR0 = last; // set breakpoint here
}
}
}


mfG
Markus

ad°FX
07.03.2013, 13:43
Vielen Dank für die schnelle Antwort. So was ähnliches hatte ich ja befürchtet. Bei den zwei Registern kann man ja auch eigentlich nicht viel falsch machen...

@Markus: wie kommst du auf 72kHz? Der Mega rennt mit 18,432Mhz und der PWM soll mit 1,125kHz laufen.

Also tiefer ins Detail: Am PortD wo die OC2A&B Pin's sitzen habe ich noch den INT0 beschaltet. Der zündet den INT0_vect:

ISR( INT0_vect ) // Int2 liest DynamoImpulse ein
{

if (ImpulsCheck == 0) // kein DynamoImpuls vorweg
{
TCCR1B |= (1<<CS12) | (1<<CS10); // Prescaler für Timer1 auf 1024 setzen,
// dadurch 'füllt' sich TCNT1 mit 18kHz bei 18,432Mhz Fcpu
ImpulsCheck=1;
}
else // DynamoImpuls vorher kam, also Timer auswerten für Frequenzmessung
{
Timer1Register = TCNT1; // Übergabe des Timer1 Registers an globale Var zur Verrechnung in main
TCNT1=1; // Register Nullen um Messung neu zu beginnen
}
Impulse++; // Impulse um eins erhöhen um DynamoImpulse zu zählen, daraus Strecke
}

Hier wird aber meiner Meinung nach nichts am PortD geändert was die beiden OC2A&B "verwirren" könnte.

An die Variable ImpulsCheck ist eine (andere) LED gekoppelt, die bei ImpulsCheck=1 an ist, sonst eben aus. Eine einfache visuelle Kontrolle für mich:

if (ImpulsCheck == 1)
{
PORTD= (1<<PD3);
}
else
{
PORTD &= ~(1<<PD3);
}

So das war's was ich an PortD veranstalte. Vllt ist hier ja was bei, was den Timer nicht starten lässt. Ich komme dem Problem einfach nicht auf die Schliche :(
Vielen Dank für Eure Hilfe

MfG
Eddy

oberallgeier
07.03.2013, 14:04
... Ich komme dem Problem einfach nicht auf die Schliche ...Muss für den Timerstart nicht irgendwann der Timerinterrupt enabled werden ( TIMSK2 |= (1<<OCIE2A) ...) ? Die dümmste Frage will ich ja eigentlich nicht stellen: sind Interrupts global erlaubt ( sei(); ). Nix für ungut.

markusj
07.03.2013, 14:12
@Markus: wie kommst du auf 72kHz? Der Mega rennt mit 18,432Mhz und der PWM soll mit 1,125kHz laufen.
Rechenfehler meinerseits. Ich hatte nur 1,125kHz * 64 gerechnet und den Faktor von 2^8 Bit vergessen.




if (ImpulsCheck == 1)
{
PORTD= (1<<PD3); // !!! Überschreibt PORTD komplett
}
else
{
PORTD &= ~(1<<PD3);
}

Ich glaube da haben wir den Schuldigen. Du bügelst einen eigenen Wert über das vom Timer erzeugte Signal. "|=" wäre wohl eher das Mittel der Wahl.
Edit: Der Zugriff auf PORTD kannn nicht schuld sein, der Timer hat Vorrang. Entweder du misst falsch oder der Fehler liegt an anderer Stelle.


Muss für den Timerstart nicht irgendwann der Timerinterrupt enabled werden
Nein, der Timer läuft auch ohne Interrupts. Die sind nur Bonusprogramm.

mfG
Markus

ad°FX
07.03.2013, 14:38
Jip und danke Markus, hab's noch nicht getestet, aber mit sowas hatte ich fast gerechnet. Ganz klarer Fall von ODER vergessen. Daher nämlich auch das Rauschen auf PD7. Ich teste das mal eben!!!

EDIT: Hast Recht. Das war's nicht.

Was meinst du mit falsch messen? Oszi? Ist auszuschließen. Ich kann mir die Pegel am TWI wunderbar anschauen.

- - - Aktualisiert - - -

Folgendes: ich habe die "Test" LED mal spaßenshalber angehen lassen wenn das OCR2x == 128 ist. funktioniert, d.h. das Compare-Register wird in seinem Zustand verändert. Dann dachte ich mir die Test LED als abfrage für TCNT2 zu benutzen a la:

if (TCNT2 == 128 )
{
PORTD |= (1<<PD3);
}
else
{
PORTD &= ~(1<<PD3);
}
Die LED sollt ja dann erwartungsgemäß gleichmäßig blinken. Tut sie aber nicht. Leider blinkt die LED auch ohne jegliches Muster das man irgendeiner funktion zu ordnen kann. Auf jedenfall ist der Fehler schonmal eingegrenzt. Aus irgendwelchen Gründen läuft der Timer bzw das Register TCNT2 nicht sauber hoch. Hat vllt einer von Euch eine Idee woran das liegen kann?

Vielen Dank für Eure Hilfe.
MfG
Eddy

Searcher
07.03.2013, 15:22
Ich kann auch keinen Fehler in der Timerkonfiguration feststellen.
Markus hat sein Testprogramm gepostet. Hast du genau das mal laufen lassen?
Gibt es eine äußere Beschaltung von PD6, PD7?

Gruß
Searcher

ad°FX
07.03.2013, 19:58
Guten Abend zusammen und vielen Dank für Eure schnellen Antworten und Lösungsvorschläge.

Ich habe den Code von Markus mal in ein neues Projekt kopiert und der läuft so geschrieben einwandfrei. Habe also auf dem Oszi genau den 50% Cycle auf OC2A und 0V auf OC2B. So soll es ja auch vorerst sein.
Um Searchers Frage vorweg zu beantworten PD6&7 sind im Moment nicht beschaltet. Findet alles auf nem Test-Board statt. Daran liegt es wohl leider auch nicht, da der Code in einem seperaten Programm ja läuft.
Das heißt für mich allerdings Sysiphos arbeit, da sich ganz offensichtlich irgendetwas mit dem schon bestehenden Programm beißt. Ich werde also mal alle PortD betreffenden Code Segmente prüfen (müssen) und halte Euch auf dem laufenden. Falls ich nichts finde muss ich noch mal auf Eure Hilfe zurückgreifen und evtl. das ganze Programm posten. Das wird dann wohl etwas umfangreicher. Aber ich habe ja noch ein paar Ansatzmöglichkeiten. Bis dahin wünsche ich Euch einen schönen Abend.

Gruß
Eddy

markusj
07.03.2013, 19:59
Die LED sollt ja dann erwartungsgemäß gleichmäßig blinken. Tut sie aber nicht. Leider blinkt die LED auch ohne jegliches Muster das man irgendeiner funktion zu ordnen kann. Auf jedenfall ist der Fehler schonmal eingegrenzt. Aus irgendwelchen Gründen läuft der Timer bzw das Register TCNT2 nicht sauber hoch. Hat vllt einer von Euch eine Idee woran das liegen kann?

Sollte sie nur genau dann, wenn die Aufruffrequenz des Codeschnipsels hoch genug ist. Ein Vergleich >= 128 wäre zuverlässiger.

Ggf. ist es langsam Mal an der Zeit, den ganzen Code zu zeigen.

mfG
Markus

ad°FX
07.03.2013, 20:14
Das mit der LED ist tatsächlich immernoch nicht so wie ich mir das dachte. Macht aber nix, WEIL: ich habe den Fehler gefunden. "Schuld" (bin natürlich ich) ist die Test-LED. Ich habe mal wieder ein ODER in der Zuweisung des PORTD vergessen, so dass als letzte Zuweisung


DDRD = 1<<PD3;


stand. Das hat natürlich zur Folge das PD6&7 nicht mehr als Ausgang definiert sind und somit das Signal am Ausgang nicht sichtbar ist. Es muss natürlich


DDRD |= 1<<PD3;


heißen und siehe da alles läuft einwandfrei. Man man man ist mir ja peinlich. Werde mir n großes Plakat an die Wand tackern und das mit "|" voll malen :D

Vielen Dank für Eure Hilfe. Ich glaube nicht dass ich von alleine so schnell zur Lösung gelangt wäre. Dieser Fred kann als gelöst angesehen werden.

Grüße aus Berlin
Eddy