ich möchte mit einem ATmega328 zwei komplementäre Rechtecksignale erzeugen (D=50%). Für ein einzelnes Signal ist der CTC modus mit toggel on compare match natürlich am einfachsten. Jetzt hab ich mir die Frage gestellt ob ich OC0A und OC0B mit dem selben T/C gleichzeitig toggeln kann. Aus dem Datenblatt entnehme ich auf den ersten Blick nichts was dagegen spricht. Wenn ich die Pins gegengleich initialisiere sollte ich so 2 komplementäre Signale haben. Geht das oder lässt sich pro T/C immer nur ein OC0x Pin toggeln?
danke für die Antwort. Habs jetzt mal ausprobiert allerdings bekomme ich zwei identische Signale statt ein invertiertes. Ich wollte das ja realisieren indem ich einen Ausgang initial high und den anderen low setze.
Kann es sein, dass dadurch: "If one or both of the COM0A1:0 bits are set, the OC0A output overrides the normal port functionality of the I/O pin it is connected to". - meine high/low Initialisierung verloren geht?
Habs jetzt mal ausprobiert allerdings bekomme ich
zwei identische Signale statt ein invertiertes. Ich wollte das ja
realisieren indem ich einen Ausgang initial high und den anderen low
setze.
Guck' Dir nochmals den Abschnitt "19.7.3 Fast PWM Mode" im Datenblatt an,
ibs. Figure 19-6. Fast PWM Mode, Timing Diagram.
Ich vermute, dass das nur im Fast PWM Mode funktioniert.
Kann es sein, dass dadurch: "If one or both of the COM0A1:0 bits are
set, the OC0A output overrides the normal port functionality of the I/O
pin it is connected to". - meine high/low Initialisierung verloren geht?
Nein, das heißt nur, dass Du den jeweiligen Pin nicht mehr über DIR oder OUT steuern kannst.
Grüßle,
Volker
P.S.: Wie so oft in diesem Forum wäre es hilfreich wenn Du Deinen Code zeigen würdest, denn das mit dem Hellsehen klappt nur sehr eingeschränkt...
Kann es sein, dass dadurch: "If one or both of the COM0A1:0 bits are
set, the OC0A output overrides the normal port functionality of the I/O
pin it is connected to". - meine high/low Initialisierung verloren geht?
Ja, dass ist so. Entweder nimmst du die Fast-PWM mit Top = 0xff oder mit Timer1 Top = ICR1 und dann Fast-PWM Mode, Duty je 50% und Abfahrt...
Die 8 Bit Timer der alten AVR sind da etwas zäh. Die neuen AVRs können einfach einen IO invertieren, damit wäre das kein Problem.
und dann Fast-PWM Mode, Duty je 50% und Abfahrt...
Lt. Datenblatt Figure 19-7. Phase Correct PWM Mode, Timing Diagram kann auch im Phase Correct PWM Mode ein komplementäres Signal an OC0A und OC0B ausgegeben werden.
Lt. Datenblatt Figure 19-7. Phase Correct PWM Mode, Timing Diagram kann
auch im Phase Correct PWM Mode ein komplementäres Signal an OC0A und
OC0B ausgegeben werden.
Kann es sein, dass dadurch: "If one or both of the COM0A1:0 bits are
set, the OC0A output overrides the normal port functionality of the I/O
pin it is connected to". - meine high/low Initialisierung verloren geht?
Benutze einfach Force Output Compare, dann kannste einen der beiden Ausgänge umschalten, was du vermutlich auch vor hattest ;)
Ob die Initialisierung verloren geht da seid ihr euch offenbar uneinig
Welche Initialisierung denn? Die vom Port.OUT Register? Ja, die hat keine Bedeutung, wie von Dir weiter oben Zitiert.
TCCR0A |= 1 << COM0A0; // Toggle OC0A on compare match
TCCR0A |= 1 << COM0B0; // Toggle OC0B on compare match
OMG! Du willst OC0A setzen und OC0B löschen (und anders herum), also guck' Dir nochmals
Table 19-6. Compare Output Mode, non-PWM an:
COM0B1 COM0B0 Description
0 0 Normal port operation, OC0B disconnected.
0 1 Toggle OC0B on Compare Match.
1 0 Clear OC0B on Compare Match.
1 1 Set OC0B on Compare Match.
Die Bilder Figure 19-6. und Figure 19-7. Phase Correct PWM Mode, Timing Diagram zeigen m.E. genau das Verhalten, das Du haben willst. Warum initialisierst Du dann TCCR0A nicht genau so, wie dort beschrieben?
OMG! Du willst OC0A setzen und OC0B löschen (und anders herum), also
guck' Dir nochmals
Table 19-6. Compare Output Mode, non-PWM an:
Ich will beides setzen weil ich ja beide Pins toggeln will? (PWM modi sind keine Option!)
Der Force Output Compare Einzeiler
1
TCCR0B|=1<<FOC0B;
hat tatsächlich gereicht. Habe jetzt mein gewünschtes Ergebnis.
Um ne kurze Erklärung was der Force Output Compare macht wäre ich trotzdem dankbar. Aus dem kurzen Abschnitt im Datenblatt werde ich mit meinen begrenzten Kenntnissen nicht schlau.
Um ne kurze Erklärung was der Force Output Compare macht wäre ich
trotzdem dankbar. Aus dem kurzen Abschnitt im Datenblatt werde ich mit
meinen begrenzten Kenntnissen nicht schlau.
Es erzwingt einen Compare-Match, was bei deiner Konfiguration ein Pin-Toggle an dem Pin erzwingt. Somit sind die Pins dann automatisch gegenphasig.
OK, der Code von S.L. funktioniert auch. Nur darf da nichts dazwischenkommen, also kein Stop des Timers oder Interrupt bei der Initialisierung. Deshalb würde ich dem TO die Initialisierung gem. der mehrfach erwähnten Diagramme aus dem Handbuch empfehlen.
Nur darf da nichts
dazwischenkommen, also kein Stop des Timers oder Interrupt bei der
Initialisierung. Deshalb würde ich dem TO die Initialisierung gem. der
mehrfach erwähnten Diagramme aus dem Handbuch empfehlen.
1
// 8-bit T/C0 -> toggle OCR0A & OCR0B for 125 kHz constant signal
2
DDRD|=(1<<DDD5)|(1<<DDD6);// Pin 5 6 output
3
TCCR0A=0;
4
TCCR0B=0;
5
TCCR0A|=1<<COM0A0;// Toggle OC0A on compare match
6
TCCR0A|=1<<COM0B0;// Toggle OC0B on compare match
7
TCCR0A|=1<<WGM01;// CTC Mode
8
TCCR0A|=(1<<FOC0A);
9
OCR0A=63;// count 32-1 times to generate 125kHz output, 250kHz
10
//toggle for 125kHz square wave
11
OCR0B=63;// count 32-1 times to generate 125kHz output, 250kHz
Ist das jetzt nicht etwas an den Haaren herbeigezogen, "Stop des Timers"? Und gegen die Unterbrechung während der Initialisierung lässt sich ja vorbeugen, indem man z.B., wie in meinem Programm, TCCR0A auf einen Schlag setzt; oder in cli...sei kapselt.
Habs jetzt mal ausprobiert allerdings bekomme ich
zwei identische Signale statt ein invertiertes. Ich wollte das ja
realisieren indem ich einen Ausgang initial high und den anderen low
setze.
Ne, im PWM-Mode ist das Ausgangsregister wirkungslos.
Du kannst aber einen PWM-Ausgang auf invertiert setzen, das geht in allen PWM-Modi.
Ja, dann kann man die Periodendauer NICHT feingranular einstellen, weil der CTC Mode den Kanal A blockiert. Das geht aber mit Timer1, der hat nicht nur 16 Bit sondern auch noch ICR, mit welchem man den CTC Modus auch nutzen kann und GLEICHZEITIG die beiden OCR1A und OCR1B Kanäle gegenphasig laufen lassen kann. RTFM.
... Oder eben die Lösung mit dem 'Force Output Compare' FOC0x.
???
Wie willst du das bei 125kHz in Software machen? Wenn man denn WIRKLICH zwei komplementäre Ausgänge braucht, kann man einen mittels externem Inverter machen. Fertig.
So ganz verstehe ich die Diskussion jetzt nicht: der Vorschlag kam von Ingo L.,er kam auch von mir, ich sah, dass es funktioniert, Jannik hat das bestätigt, bei ihm läuft es auch - ... ?
Da mit der gewählten Initialisierung jeder Match nur ein Toggeln des Ausgangs bewirkt, beträgt die Frequenz am Ausgang nur die Hälfte der Matchfrequenz. Also nur ca. 65kHz.
Die Flanken der beiden Signale sind um eine Periode des Systemtakts gegeneinander verschoben.
Die Signale toggeln beim Compare-Match (des jeweiligen Kanals!). D.h.: damit das Toggeln gleichzeitig erfolgt, müssen beide OCR0x-Register denselben Wert enthalten.
Während der Initialisierung gibt es eine kurze Periode, in denen die Signale schon aktiv, aber noch nicht invers zueinander sind. Je nachdem, was dran hängt, kann das u.U. tödlich sein.
Ich denke also, das müßte korrekterweise so lauten:
Und dadurch, dass der Match für beide Kanäle gleichzeitig erfolgt (und mittels FOC0B für Kanal B einmal "vorgetoggelt" ist), ist das Signal an OC0B tatsächlich das invertierte Signal von OC0A.
den Timer sollte man immer zum Schluss starten. Dann spielt die
Reihenfolge der Konfiguration keine Rolle und man hat keine negative
Effekte.
Nein, das ist leider falsch. Die Signale sind timerseitig aktiv ab dem Moment, in dem die COM-Bits geschrieben werden, nicht erst ab dem Moment, in dem der Timer gestartet wird.
Am einfachsten läßt sich das Problem umgehen, indem man erst zum Schluß die Pins als Ausgänge schaltet.
Sie lesen den Thread auch nicht erstmal durch, bevor Sie schreiben, wie Falk Brunner oder Peter Dannegger?:
Zum Zeitpunkt meines Programmes war die Forderung nach 125 kHz noch gar nicht bekannt, ich hatte den Wert 123 mehr oder weniger aus der Luft gegriffen, in Anlehnung an Janniks Benutzernamen 'user_name123'.
Für Ihre Punkte 2 und 3 bräuchte ich mehr Zeit (und Motivation) - vielleicht später.
Ursprünglich hatte ich da 200 drinstehen, aber dann fand ich 123 netter.
Nur nebenbei: den Wert kann ohnehin nur Jannik vorgeben, nur er weiß (bislang), wie hoch sein Systemtakt ist - allenfalls aus seinem Halbsatz "da sind die PWM modi zu langsam" könnten wir versuchen, Rückschlüsse zu ziehen; für einen genauen Wert reicht's trotzdem nicht.
Ursprünglich hatte ich da 200 drinstehen, aber dann fand ich 123 netter.
Nur nebenbei: den Wert kann ohnehin nur Jannik vorgeben, nur er weiß
(bislang), wie hoch sein Systemtakt ist - allenfalls aus seinem Halbsatz
"da sind die PWM modi zu langsam" könnten wir versuchen, Rückschlüsse zu
ziehen; für einen genauen Wert reicht's trotzdem nicht.
Stimmt, deswegen habe ich beides in meinem Verbesserungsvorschlag auch variabel ausgelegt. Zur Perfektion fehlt allerdings noch eine Warnung, die "Unzulässigkeit" anzeigt.
Ausserdem war das simple Umkopieren der beiden sbi's zur Pinfreischaltung an's Ende der Initialisierung auch auch noch nicht das Wahre. Wenn man's wirklich richtig machen will, müßte das natürlich auch für beide Kanäle gleichzeitig erfolgen. Also etwa so:
[asm]
in R16, DDRD
ori R16, (1<<DDD6) | (1<<DDD5)
out DDRD, R16
[/asm]
In der Zeit, in der hier herumdiskutiert wird, hätte man das Problem auch mit einem popeligen Inverter lösen können. Bei 125 kHz kann man den mit einem Transistor aufbauen, man kann aber auch einen 74xx04 oder eine Ein-Gatter-Variante davon verwenden.
Aber das wäre vermutlich alles viel zu einfach, oder ist, weil Hardware, vieeeeeeel zu kompliziert.
Aber das wäre vermutlich alles viel zu einfach, oder ist, weil Hardware,
vieeeeeeel zu kompliziert.
Warum zum Taufel sollte man zusätzliche Hardware verbauen, wenn die bereits existierende Hardware die Funktion durchaus bereitstellen kann? Insbesondere: allein durch ihre sachgerechte Nutzung, nicht durch irgendwelche wilden Hacks jenseits ihrer Specs?
Das ergibt doch keinen Sinn. Höchstens für Leute, die halt nicht in der Lage sind, die vorhandene Hardware sachgerecht zu benutzen...
So, also:
Ihr Punkt 2 stimmt natürlich; und gestern hatte ich nachfolgend auch das Gefühl, dass da rein programmsymmetrisch etwas nicht stimmt. Aber bei dem hohen Compare-Wert sah ich den Versatz auf meinem (Analog-)Oszilloskop nicht.
Zu Punkt 3: ich hatte mir bislang keine Gedanken darüber gemacht, wann das TCCR0A bezüglich der Ausgänge greift, war irgendwie naiv davon ausgegangen, dass das erst mit dem Aktivieren des Timers, also mit TCCR0B, erfolgt - danke für den Hinweis.
Und damit ich selbst auch noch etwas Sinnvolles beitrage, im Anhang für Jannik die C-Version (so ungefähr) Ihres Programmes (so gut ich's eben konnte).
an Harald K.:
... oder ist, weil Hardware, vieeeeeeel zu kompliziert.
Sie ist hier schlicht unnötig. Und wenn Ihnen die Diskussion zu langatmig sein sollte, brauchen Sie ja nicht mitzulesen.
Wenn man einen zusätzlichen I/O-Pin zum sinnlosen Verballern freihat, dann kann man das natürlich tun. Andere arbeiten ressourcensparend und versuchen nicht, teure I/Os für Banalitäten zu vergeuden.
Klar, für unbenutzte I/O-Pins bekommt man ebensowenig Geld zurück wie für leergelassenes Flash-ROM, aber das ist halt nicht immer der Fall.
Hier wäre es interessant zu wissen, /wofür/ der Threadstarter das Komplementärsignal zu benötigen meint.
Also was mich betrifft, so versuche ich grundsätzlich so weit wie möglich auf den Fragesteller einzugehen - und da steht nun mal im Betreff "OC0A & OC0B".
Es ist nicht meine Intention, sein Projekt zu verbessern (was ich in meiner Unkenntnis für 'Verbesserung' halte). Ihnen aber steht es natürlich frei, mit Jannik darüber eine längere Diskussion zu beginnen.
Wenn man einen zusätzlichen I/O-Pin zum sinnlosen Verballern freihat,
dann kann man das natürlich tun.
Genau. Deswegen würde ich über einen zusätzlichen Inverter allenfalls dann nachdenken, wenn's mit den Pins knapp wird. Und auch dann vermutlich zuerst darüber, ob man nicht besser andere Pins funktional "sharen" könnte (ohne zusätzliche Hardware verbauen zu müssen).
Grundprinzip ist: Jede zusätzliche Hardware erhöht die Kosten und die Ausfallwahrscheinlichkeit.
Also was mich betrifft, so versuche ich grundsätzlich ...
Das kannst Du gerne tun. Andere hören halt nicht gleich mit dem Denken auf, sondern überlegen, wie man das /eigentliche/ Problem lösen kann. Denn wie die /Erfahrung/ zeigt, die manch einer hier hat (auch ein "C-Hater" hat Erfahrung!), haben viele Fragesteller sich in einer Problemlösung verrannt und versuchen ein Problem zu lösen, das sich entweder mit minimalem Aufwand anders lösen ließe oder letztlich gar nicht besteht, weil an anderer Stelle ein Designfehler vorliegt.
Ein Beispiel dafür sind die verschiedenen Versuche eines einzelnen, das trivale Thema "Tastenabfrage" zu lösen ... dem einen oder anderen mögen die diversen Threads zum Thema noch in Erinnerung sein, ist noch gar nicht so lange her.
Ob das hier der Fall ist, weiß ich natürlich nicht, aber /meiner/ Ansicht nach ist jemandem besser geholfen, wenn ihm nicht nur wortgetreu seine Aufgabe gelöst wird, sondern auch Lösungsalternativen vorgestellt werden und sogar Rückfragen gestellt werden, wozu das ganze überhaupt gut sein soll.
Grundprinzip ist: Jede zusätzliche Hardware erhöht die Kosten und die
Ausfallwahrscheinlichkeit.
In der Theorie
Nein, auch in der Praxis.
und der Massenproduktion.
Nö, da wird es halt nur statistisch unwiderlegbar nachweisbar.
Diese Erkenntnisse aus der Massenproduktion für Einzelstücke zu ignorieren, ist trotzdem nur genau eins: ziemlich idiotisch...
Denn das Gesetz gilt natürlich auch für das Einzelstück. Es ist halt nur nicht nachweisbar, dass es dafür genauso gilt. Es gibt allerdings auch keinerlei logischen Grund, warum es dafür nicht genauso gelten sollte...
Es gibt auch AVRs, die haben extra invertierte Ausgänge, z.B. ATtiny85, ATtiny861. Und zusätzlich einen Dead-Time Generator.
Der ATtiny861 hat sogar 3 OC1x /OC1x Paare (x = A, B, D).
Wenn man einen zusätzlichen I/O-Pin zum sinnlosen Verballern freihat,
dann kann man das natürlich tun.
Wenn eine Platine schon fertig ist, wird es schwieriger, einen 74HC... zu schalten, als das Programm etwas zu ändern.
Wenn ein I/O-Pin unbenutzt bleibt, gibt man 1/28 des Preises von ATMega328 leider nicht zurück :)
Ansonsten plädiere ich als Amateur, der keine Serienfertigung macht, dafür, MK mit mehr Pins als ATMega328 zu wählen. Ich selbst nehme so gut wie immer ATMega1284 oder ab und zu ATMega2560. Die Beschränkung auf 2 MK bringt für Amateur mehrere Vorteile.
ich melde mich auch mal wieder. Ich habe nach den ersten Hinweisen erstmal weiter programmiert und stand jetzt vor dem Problem, dass der FOC0B teilweise aufgibt und wieder das nicht invertierte Signal an PD5 geliefert wird. (So wie Volker B. das denke ich vorhergesehen hat)
Das wäre tatsächlich fatal, da ich mal eine Phase-Shifted-PWM Ansteuerung einer Vollbrücke ausprobieren wollte (mit den Optionen die ich hier habe=>Arduino Nano) und naja wenn beide Mosfets einer Halbbrücke durchschalten gibt's ja bekanntlich nen Kurzschluss.
Wie die Vollbrücke schon vermuten lässt habe ich auch T/C2 genau gleich programmiert. Also insgesamt 4 125kHz Signale. FOC2B funktioniert einwandfrei. OCR2A & OCR2B werden nach dem setup nicht mehr geändert.
Das Problem von FOC0B kommt denke ich daher, dass ich OCR0A & OCR0B in der main des öfteren um 1 erhöhe bzw verringere und in einer Compare Match ISR wieder auf den Ursprungs Wert zurücksetze um die Phasenverschiebung zu Erzeugen.
Eine andere Möglichkeit könnte am ADC liegen, da die Ausgangsspannung am Ende über den Phase-shift geregelt werden soll.
Kann das daran liegen oder hat jemand eine andere Vermutung?
Eigentlich denke ich mir, dass FOC0B den Pin einmal anfangs toggelt und das später keinen Einfluss mehr haben sollte
OCR0A & OCR0B in der main des öfteren um 1 erhöhe bzw verringere
Es muss natürlich sichergestellt sein, dass dies nicht unmittelbar vor Erreichen des Compare-Match geschieht - wie sieht die Stelle in der Main-Schleife denn aus?
Das Problem von FOC0B kommt denke ich daher, dass ich OCR0A & OCR0B in
der main des öfteren um 1 erhöhe bzw verringere und in einer Compare
Match ISR wieder auf den Ursprungs Wert zurücksetze um die
Phasenverschiebung zu Erzeugen.
Ja, das ist natürlich tödlich. Zumal es völlig unmöglich ist, beide Register wirklich gleichzeitig zu schreiben.
Da kann man nicht einfach wild drauflosschreiben, man muss sicherstellen, dass beide Schreibvorgänge abgeschlossen sind, bevor der nächste Compare-Match passiert. Am einfachsten geht das, wenn man ausschließlich in der ISR in diese Register schreibt, denn dann ist relativ sicher, dass der Match eben gerade passiert ist, bis zum nächsten also das Maximum an "Luft" bleibt.
Um dasselbe in Main zu erreichen, ist sehr viel mehr Aufwand nötig.
(Was das Programm genau macht, muss und will ich jetzt nicht verstehen)
Wie bereits geschrieben, und von C-hater näher erläutert, muss gewährleistet sein, dass TCNT0 beim Schreiben von OCR0A hinreichend unter dem alten wie dem neuen Wert von OCR0A liegt. Was bei den verfügbaren 64 Takten (oder noch weniger im Verlauf?) Sorgfalt verlangt.
Übrigens: Retten von SREG in der ISR - ich dachte, solchen Kleinkram nimmt C dem Programmierer ab?
Also, um genau zu sein: die 64 bezog sich auf die Gesamtzeit; wenn das Schreiben von OCR0A im Main erfolgen soll/muss, dann ist/sind die ISR noch abzuziehen - das könnte eng werden.