OC0A & OC0B gleichzeitig toggeln?

OP #7426232
Lesenswert?

Hallo,

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?

LG

#7426237
Lesenswert?

Jannik schrieb:

ich möchte mit einem ATmega328 zwei komplementäre Rechtecksignale erzeugen (D=50%).

Dann tu das doch.

Für ein einzelnes Signal ist der CTC modus mit toggel on compare match natürlich am einfachsten.

Das ist egal. CTC ist nur dahin anders, als daß man die Periodendauer feiner einstellen kann.

Jetzt hab ich mir die Frage gestellt ob ich OC0A und OC0B mit dem selben T/C gleichzeitig toggeln kann.

Sicher. Warum nicht?

Aus dem Datenblatt entnehme ich auf den ersten Blick nichts was dagegen spricht. Wenn ich die Pins gegengleich

Gegengleich? Eher invers, invertiert.

initialisiere sollte ich so 2 komplementäre Signale haben. Geht das

Ja.

oder lässt sich pro T/C immer nur ein OC0x Pin toggeln?

Nein. Warum probierst du das nicht einfach aus? Das dauert keine 3 Minuten.

OP #7430474
Lesenswert?

Moin Falk,

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?

LG

(Firma: L-E-A) #7430486
Lesenswert?

Jannik schrieb:

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.

OCnx: (COMnx[1:0] = 0x2) /OCnx: (COMnx[1:0] = 0x3)

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...

#7430488
Lesenswert?

Jannik schrieb:

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.

Beitrag #7430491 wurde von einem Moderator gelöscht.
Beitrag #7430493 wurde von einem Moderator gelöscht.
#7430497
Lesenswert?

Jannik schrieb:

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 ;)

OP #7430537
Lesenswert?

Leider müssen die Signale 125kHz haben, da sind die PWM modi zu langsam.

Force output compare sehe ich mir mal an.

Ob die Initialisierung verloren geht da seid ihr euch offenbar uneinig :D

1
// 8-bit T/C0 -> toggle OCR0A & OCR0B for 125 kHz constant signal
2

3
DDRD |= (1<<DDD5)| (1<<DDD6);  // Pin 5 6 output
4

5
TCCR0A = 0;
6
TCCR0B = 0;
7

8
TCCR0A |= 1 << COM0A0;  // Toggle OC0A on compare match
9
TCCR0A |= 1 << COM0B0;  // Toggle OC0B on compare match
10
TCCR0A |= 1 << WGM01;   // CTC Mode
11

12
TCCR0B |= 1 << CS00;  // no prescaler
13

14
OCR0A = 63;  // count 32-1 times to generate 125kHz output, 250kHz toggle for 125kHz square wave
15
OCR0B = 63;  // count 32-1 times to generate 125kHz output, 250kHz toggle for 125kHz square wave
16

17
PORTD &=~(1 << PD5);  // set pin 5 low OC0B
18
PORTD |= (1<<PD6);    // set pin 6 high OC0A
Beitrag #7430538 wurde von einem Moderator gelöscht.
Beitrag #7430543 wurde von einem Moderator gelöscht.
(Firma: L-E-A) #7430549
Lesenswert?

Jannik schrieb:

Force output compare sehe ich mir mal an.

OMG!

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?

Grüßle, Volker

(Firma: L-E-A) #7430554
Lesenswert?

S. L. schrieb:

an Jannik:

Es sollte kein Problem darstellen, das gezeigte Assemblerprogramm auf C umzusetzen.

...nur dass es auch nicht funktioniert...

Was für Hinweise, Volker B.?

Die Hinweise auf das Datenblatt des mega328 Figure 19-7. Phase Correct PWM Mode, Timing Diagram Figure 19-6. Fast PWM Mode, Timing Diagram

Grüßle, Volker

OP #7430556
Lesenswert?

Volker B. schrieb:

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.

#7430560
Lesenswert?

Jannik schrieb:

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.

Volker B. schrieb:

OMG!

Gleichfalls

Volker B. schrieb:

Warum initialisierst Du dann TCCR0A nicht genau so, wie dort beschrieben?

Weil dann die PWM-Frequenz nicht mehr fein genug eingestellt werden kann, dass hast du offensichtlich nicht bemerkt

(Firma: L-E-A) #7430561
Lesenswert?

Jannik schrieb:

S. L. schrieb:

Natürlich läuft das, ich sehe es doch vor mir.

Also auf meinem Osci siehts auch gut aus :D

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.

Grüßle, Volker.

#7430563
Lesenswert?

Volker B. schrieb:

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 
12
//toggle for 125kHz square wave
13
TCCR0B |= 1 << CS00;  // no prescaler

So sollte das ohne Probleme funktionieren.

Volker B. schrieb:

Deshalb würde ich dem TO die Initialisierung gem. der mehrfach erwähnten Diagramme aus dem Handbuch empfehlen.

Gemäß Diagrammen lässt sich garnichts initialisieren

#7430566
Lesenswert?

Volker B.:

Nur darf da nichts dazwischenkommen ...

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.

(Firma: L-E-A) #7430574
Lesenswert?

Ingo L. schrieb:

Volker B. schrieb:

Deshalb würde ich dem TO die Initialisierung gem. der mehrfach erwähnten Diagramme aus dem Handbuch empfehlen.

Gemäß Diagrammen lässt sich garnichts initialisieren

OK, Punkt für Dich :-)

Also gem. der in Klammern hinter dem jeweiligen Timingdiagramm geschriebenen Hinweisen auf die Initialisierung der COMnx[1:0] Register-Bits.

Hoffe, das war jetzt präszise genug!

#7430602
Lesenswert?

Jannik schrieb:

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.

#7430865
Lesenswert?

S. L. schrieb:

Gefordert sind aber zwei Ausgänge bei 125 kHz - wie geht das auf einem ATmega328 mit Timer0 - Beispielprogramm?

Wurde schon mehrfach geschrieben. Wird nur immer wieder ignoriert.

Beitrag "Re: OC0A & OC0B gleichzeitig toggeln?"

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.

#7430875
Lesenswert?

S. L. schrieb:

Wurde schon mehrfach geschrieben. Wird nur immer wieder ignoriert.

Ich kann rechnen wie ich will, ich erhalte für die 125 kHz einen Systemtakt von 32 MHz.

Stimmt, hab ich nicht beachtet.

geht aber mit Timer1

Das ist unbestritten; aber schon im Betreff steht Timer0.

Dann sind das die Grenzen. Entweder geringere Ausgangsfrequenz oder nur ein Kanal.

#7431140
Lesenswert?

S. L. schrieb:

Beitrag "Re: OC0A & OC0B gleichzeitig toggeln?"

Hmmm...

Im Prinzip richtig, im Detail meiner Meinung nach aber wohl nicht ganz.

Kritikpunkte:

  1. Das erzeugt nur ca. die Hälfte der gewünschten Frequenz von 125kHz (bei angenommenen 16MHz Systemtakt).

Matchfrequenz: 16.000.000 / (123 + 1) = 129.032,...

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.

  1. 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.

  1. 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:

[asm] .EQU F_OUT = 125000

ldi R16, (FCLOCK + F_OUT / 2) / (2 * F_OUT) - 1 ; 63 out OCR0A, R16 out OCR0B, R16

ldi R16,(1<<COM0A0) | (1<<COM0B0) | (1<<WGM01) out TCCR0A,R16

ldi R16, (1<<CS00) | (1<<FOC0B) out TCCR0B, R16

sbi DDRD, 6 sbi DDRD, 5 [/asm]

Damit ergibt sich dann sogar exakt die gewünschte Frequenz lt. Formel aus dem DB (s.S. 100, fast ganz oben):

16.000.000 ---------------- = 125.000 2 * 1 * (1 + 63)

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.

#7431170
Lesenswert?

Veit D. schrieb:

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.

#7431180
Lesenswert?

an C-hater:

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.

#7431206
Lesenswert?

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.

#7431212
Lesenswert?

S. L. schrieb:

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]

#7431222
Lesenswert?

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.

#7431227
Lesenswert?

Harald K. schrieb:

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...

#7431229
Lesenswert?

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.

Angehängte Dateien:
#7431230
Lesenswert?

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.

#7431233
Lesenswert?

an Harald Kirnbichler:

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.

#7431235
Lesenswert?

Harald K. schrieb:

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.

#7431236
Lesenswert?

S. L. schrieb:

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.

#7431246
Lesenswert?

Falk B. schrieb:

C-hater schrieb:

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...

#7434469
Lesenswert?

Harald K. schrieb:

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.

OP #7439653
Lesenswert?

Moin zusammen,

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

#7439908
Lesenswert?

Jannik schrieb:

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.

OP #7440216
Lesenswert?

S. L. schrieb:

wie sieht die Stelle in der Main-Schleife denn aus?

1
// ISR to reset OCR0A/B after the compare match value was reached
2
// -> to keep 125kHz frequency
3
ISR(TIMER0_COMPA_vect) {
4
  uint8_t ui8_sreg = SREG;
5
  OCR0A = OCR0B = 63;
6
  SREG = ui8_sreg;
7
}
8

9
// ISR to count up
10
ISR(TIMER1_COMPA_vect) {
11
    uint8_t ui8_sreg = SREG;
12
    ui32_counter++;
13
    SREG = ui8_sreg;
14
}
15

16
void loop() {
17

18
// Synchronize the signals of the two timer/counters
19
if(syncSig == true) {
20
  TCNT0 = 0;
21
  TCNT2 = 0;
22
  OCR0A = OCR0B = 129;  // 129 for 0° phase shift  // 65 = 0°
23
  syncSig = false;
24
  startUp = true;
25
}
26

27
// PWM hart programmiert langsam hochfahren
28
// 1 count = 3° & 62,5ns delay / 8 counts = 23° & 500ns delay
29
if(startUp == true) {
30
 if(ui32_counter >= 360) {  // wait for 2s increase phase shift 180*2 180 counts = 1s
31
    OCR0A = OCR0B = OCR0A + 1;
32
    ui8_end++;            // count the number of shifts
33
    ui32_counter = 0;     // reset counter
34
  }
35

36
  if(ui8_end >= 8) {      // after 8 shifts (500ns) end the startup
37
    startUp = false;      // end start up
38
    voltReg = true;       // enter regulation via ADC
39
    ui32_counter = 0;     // reset counter
40
    ui8_end = 0;          // reset shift counter
41
  } 
42
}
43

44
// set PWM by ADC voltage
45
 if((voltReg == true)) {           
46

47
  if(ui32_counter >= 180) {
48
    ADCSRA |= (1<<ADSC);              //start conversion
49
    while(ADCSRA&(1<<ADSC));          // wait till conversion is finished
50
    ui16_adcVal = ADCL | (ADCH << 8); // save adc value
51
    Serial.println(ui16_adcVal);
52

53
    if(ui16_adcVal > ui16_adcTop) {   // if voltage is greater than treshold reduce signal shift
54

55
      OCR0A = OCR0B = OCR0A - 1;      // set both in one line
56
    }
57

58
    if(ui16_adcVal < ui16_adcBottom) {  // if voltage is smaller than treshold increase signal shift
59
      
60
      OCR0A = OCR0B = OCR0A + 1;
61
    }
62

63
    ui32_counter = 0;
64
    ui8_end = 0;
65
   }
66
 }
#7440249
Lesenswert?

(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?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren