Problem: Arduino Micro PWM auf Pin D5 mit Timer 4

Hallo zusammen,

nach nun zwei langen und erfolglosen Versuche ein PWM Signal auf dem Pin D5 zu erzeugen, wende ich mich an euch.

Kurze Beschreibung:

Ich möchte eine H-Brücke mit dem Arduino Micro ansteuern, hierfür stehen folgende Pins zur Verfügung: D5, D13, D9, D10.

Zum Problem:

Pin D5 (PC6) kann laut Beschreibung mit Timer 4 (!OC4A) angesteuert werden. Leider bekomme ich kein Signal aus dem Controller auf den Pin, wenn ich es über den Timer 4 versuche. Die Verwendung von Timer 3 ist leider aufgrund der Synchronisierung zu D13 nicht möglich.

Anbei der Code für den Timer 4:

DDRC |= 0b11000000;

PORTC |= 0b11000000; // Hier bin ich mir nicht sicher ob 0b00000000 richtig wäre, geht jedoch beides nicht

TCCR4A = 0b01100010;
TCCR4B = TCCR4B | 0b00000000; // Invert D13 with 0b10000000
TCCR4C = TCCR4C | 0b10101000;
TCCR4C |= (1<<COM4D0)|(1<<PWM4D);
TCCR4D = 0b00000000;
TCCR4E = TCCR4E | 0b00000001;

Der Pin D13 funktioniert ohne Probleme mit dem gewünschten Signal, leider macht der Pin D5 garnichts.
ich hoffe Ihr könnt mir dabei helfen, an dem Pin ein PWM Signal mit Timer 4 zu erzeugen.

Vielen Dank und viele Grüße

Hallo,

was machst du mit Timer 3 im Zusammenhang mit einer Syncronisierung?

Zum Timer 4 und dem Code.

Ganz wichtig. Gewöhne dir die Bit Schreibweise ab. Kann kein Schwein lesen :wink: und es ist fehlerträchtig ohne Ende.

Mit dieser Schreibweise kann jeder sofort sehen welches Bit gesetzt wird und es ist Manual kompatibel.

TIMSK1 = (1 << OCIE1B); // enable Compare Match B ISR
TCCR1B |= (1 << CS11);  // Prescaler 8

Die Pin Konfig kannste mit pinMode machen. Wenn du ein Bit im DDRx setzt dann ist dieser Pin ein Ausgang. Wenn du dann noch ein Bit im PORTx Register setzt, dann schaltest du den Pin, also den Ausgang, auf High. Für verodern mit Null kannste gleich = 0 schreiben.

Dein Code sagt mir, dass dein Timer nicht gestartet wird. Es sind keine Prescaler Select Bits (CS) gesetzt. Null = Stopp. Register TCCR4B.
Der Timer Mode ist der Normalmode. TCCR4D ist auf 0. Ich weiß nicht ob das so gewollt ist. Um damit PWM zu erzeugen muss man im Interrupt den Compare-Wert nachziehen/aufaddieren oder den Timerzähler nullen. Sehe ich hier nicht. Das einfachste wäre erstmal den Fast-PWM Mode zu nutzen. Mittels Prescaler und OCR4C legst du die Frequenz fest. Dann schaltest du “clear on compare Match” ein für den OC4A Pin. TCCR4C brauchste laut meiner Meinung nicht. Das ist etwas Spezielles. Was aber wichtig ist, vorher alle Timer 4 Register nullen. Egal ob du die dann konfigurierst oder nicht.

Für den Timer 1 hatte ich das mal ausführlicher hier erklärt. Sollte analog zum Timer 4 sein. Auch wenn der beim 32U4 noch viel mehr kann. http://forum.arduino.cc/index.php?topic=519208.0 Vielleicht kannste das für Timer 4 und den Pin schon adaptieren. Das Prinzip ist immer ähnlich. Ansonsten nochmal Bescheid geben.

Edit:
mir fiel nochwas ein, die Timer erzeugen im Fast-PWM Mode unter bestimmten Umständen ungewollt ganz kurze Nadelimpulse. Eigentlich nur wenn das OCRnA (Compare Register) = 0 ist. Im Manual beim Timer 4 ist vom OCR4C Register die Rede. Allerdings ist das in allen Waveform Modi immer für den TOP Wert zuständig. Das irritiert mich ein wenig. Würde aktuell für mich bedeuten man muss Frequenzeinstellungen mit OCR4C = 0 vermeiden. Testen kann ich das leider nicht, mein einziger Micro ist verbaut. Die Problematik generell vermeiden kann man mit Verwendung eines anderen Waveform Modi. Zum Bsp. Phase & Frequency correct. Nicht das deine H-Brücke verwundert Unsinn macht.

Die Arduino IDE behilft sich zur Vermeidung der Nadelimpulse mit knallharten digitalen überschreiben der Pin Funktion. Wenn Duty Cycle wieder erwünscht ist, wird erneut die Pin Funktion überschrieben. Kann man machen - muss man aber nicht. :wink:

Hi,

vielen Dank für deine schnelle Antwort, ich denke ich habe ein Problem gefunden.
Wenn ich die Register beschreibe, dann steht anschließend nicht der richtige Wert darin.

Hier beschreibe ich die Register (nur TCCR4A):

delay(1000);
//TCCR4E = 0b00000011;
//TCCR4D = 0b00000000;
//TCCR4C = 0b00001001;
//TCCR4B = 0b01000001;
TCCR4A = 0b10000010; // = 130

Das sind die Werte der Register vor dem Beschreiben:

TCCR4A: 2
TCCR4B: 2
TCCR4C: 9
TCCR4D: 0
TCCR4E: 3

Das sind die Werte nach dem Beschreiben von TCCR4A mit den Werten von oben.

After change TCCR4A:
TCCR4A: 130
TCCR4B: 2
TCCR4C: 137
TCCR4D: 0
TCCR4E: 3

Normal sollte sich nur das Register TCCR4A ändern, aber leider ändert sich auch das Register TCCR4C.
Hat hierzu jemand eine Idee, an was das liegen könnte?

Vielen Dank und Grüße

Hallo,

um zu wissen was dein Code im Gesamten wirklich macht solltest du den gesamten Testcode zeigen. Auf einen Umstand hatte ich schon hingewiesen. Alle Timerregister müssen vorher resetet (genullt) werden vor der eigenen Konfiguration. Vermutlich veroderst du alle Register Zuweisungen. Die IDE belegt diese für verschiedenen Funktionen im Hintergrund vor. Deswegen vielleicht deine Ausleseunterschiede. Eine Bitte. Den Sketch ohne Bitschreibweise, einfach mit Bitnamen arbeiten wie im Bsp. oder verlinkten Thread. Einfacher gehts nicht und es bleibt für jeden lesbar. Und was der Timer 4 Frequenzmäßig machen soll wäre auch gut zu wissen.

Hi,

nochmals vielen Dank für die schnelle Hilfe.

Ich habe das ganze zum Laufen bekommen, die kleinen Controller sind etwas ungewohnt für mich. Aber nachdem ich mir mal die ganzen Register angeschaut habe, ist mir auch klar warum das ganze so ist.

Was ich komisch finde ist, dass das "Hauptregister" durch das "Shadow Register" verändert werden kann. Laut Datenblatt (Vgl. Figure 15-2) sollte das nicht gehen.

Zur Schreibweise:
Normal mache ich das schon auch, aber für den schnellen Test war das etwas unpraktisch. Schlussendlich ist das Problem durch das Beschreiben von zu vielen (nicht notwendigen) Registern entstanden.

Anbei der aktuelle Code:

  OCR4A = 0;    // Set timer register A = 0
  OCR4B = 0;    // Set timer register B = 0
  TCCR4B = 0;   // Reset timer 4
  TCCR4A = 0;   // Reset timer 4
  TCCR4B = 1;   // Set PWM Frequency to 31,374 kHz
  TCCR4A = 83;  // Config Timer 4 -> Clear on compare match, enable PWM mode on CH A and CH B

Damit lässt sich die H-Brücke jetzt mit 31,374 kHz ansteuern, sobald die Hardware vollständig aufgebaut ist, teste ich es mal ohne Oszilloskop. Laut den Messungen mit dem Oszilloskop sollte es aber kleine Probleme geben. Das beschreiben der OCR4 Register folgt erst später, den restlichen Code dazu schreibe ich erst noch.

Viele Grüße und nochmals vielen Dank!

Hallo,

habe mir nochmal die Mühe gemacht das zu entziffern.

TCCR4B = 1;   // CS40 
TCCR4A = 83;  // COM4A1, COM4B1, PWM4A, PWM4B

das heißt der soll im Fast-PWM Mode mit Prescaler 1 laufen. TOP (OCR4C) muss demzufolge noch von der IDE auf 509 voreingestellt sein.
Sonst würde er nicht mit 31,4kHz takten sondern mit 16MHz.
Wobei mir hier im Manual auffällt das in der Formel der Topwert fehlt. Was nicht sein kann. Das am Rande.
Die Formel sollte eigentlich so lauten. Kannste ja mal mit verschiedenen Topwerten testen.
Takt = CPU Takt / Prescaler / (1 + TOP)
An den Shadow Register muss man laut meinem Verständnis nicht rumfummeln.

Wenn du das so hinbekommst ist doch toll. Dann ist alles geklärt.