Forum: Mikrocontroller und Digitale Elektronik OC0A & OC0B gleichzeitig toggeln?


von Jannik (user_name123)


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

von Falk B. (falk)


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.

von Jannik (user_name123)


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

von Volker B. (Firma: L-E-A) (vobs)


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

: Bearbeitet durch User
von Ingo L. (corrtexx)


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.

: Bearbeitet durch User
Beitrag #7430491 wurde vom Autor gelöscht.
von Volker B. (Firma: L-E-A) (vobs)


Lesenswert?

Ingo L. schrieb:
> 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.

Grüßle,
Volker

Beitrag #7430493 wurde vom Autor gelöscht.
von Ingo L. (corrtexx)


Lesenswert?

Volker B. schrieb:
> 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.
Ja, dass geht ebenfalls.

von Ingo L. (corrtexx)


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

: Bearbeitet durch User
von S. L. (sldt)


Lesenswert?

1
 sbi   DDRD,6
2
 sbi   DDRD,5
3
 puti  TCCR0A,(1<<COM0A0)+(1<<COM0B0)+(1<<WGM01)
4
 puti  OCR0A,123
5
 puti  TCCR0B,(1<<CS00)+(1<<FOC0B)  ; !

von Jannik (user_name123)


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 vom Autor gelöscht.
von S. L. (sldt)


Lesenswert?

an Jannik:

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

Beitrag #7430543 wurde vom Autor gelöscht.
von S. L. (sldt)


Lesenswert?

Was für Hinweise, Volker B.?
  Ich folge den ursprünglichen Anforderungen von Jannik.

von Volker B. (Firma: L-E-A) (vobs)


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

: Bearbeitet durch User
von Volker B. (Firma: L-E-A) (vobs)


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

: Bearbeitet durch User
von S. L. (sldt)


Lesenswert?

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

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

von Jannik (user_name123)


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.

von Jannik (user_name123)


Lesenswert?

S. L. schrieb:
> Natürlich läuft das, ich sehe es doch vor mir.

Also auf meinem Osci siehts auch gut aus :D

von Ingo L. (corrtexx)


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

: Bearbeitet durch User
von Volker B. (Firma: L-E-A) (vobs)


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.

von Ingo L. (corrtexx)


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

: Bearbeitet durch User
von S. L. (sldt)


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.

von Volker B. (Firma: L-E-A) (vobs)


Lesenswert?

S. L. schrieb:
> Volker B.:
>> Nur darf da nichts dazwischenkommen ...
>
> Ist das jetzt nicht etwas an den Haaren herbeigezogen,

Weißt Du was der TO programmiert hat?

von Volker B. (Firma: L-E-A) (vobs)


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!

von S. L. (sldt)


Lesenswert?

Jannik ist zufrieden - das war der Sinn der Übung.
  Guten Tag.

von Peter D. (peda)


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.

von S. L. (sldt)


Lesenswert?

Peter Dannegger schlug vor:
> Du kannst aber einen PWM-Ausgang auf invertiert setzen,
> das geht in allen PWM-Modi.

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

von Falk B. (falk)


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.

von S. L. (sldt)


Lesenswert?

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

> geht aber mit Timer1

Das ist unbestritten; aber schon im Betreff steht Timer0.

von Falk B. (falk)


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.

von S. L. (sldt)


Lesenswert?

... Oder eben die Lösung mit dem 'Force Output Compare' FOC0x.

von Falk B. (falk)


Lesenswert?

S. L. schrieb:
> ... 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.

von S. L. (sldt)


Lesenswert?


von S. L. (sldt)


Lesenswert?

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

von C-hater (c-hater)


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.

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

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

von C-hater (c-hater)


Lesenswert?

C-hater schrieb:

Verdammt, Quoting für die Formel vergessen. Also die nochmal:
1
  16.000.000
2
---------------- = 125.000
3
2 * 1 * (1 + 63)

von Veit D. (devil-elec)


Lesenswert?

Hallo,

den Timer sollte man immer zum Schluss starten. Dann spielt die 
Reihenfolge der Konfiguration keine Rolle und man hat keine negative 
Effekte.

von C-hater (c-hater)


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.

von S. L. (sldt)


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.

: Bearbeitet durch User
von C-hater (c-hater)


Lesenswert?

S. L. schrieb:

>   Zum Zeitpunkt meines Programmes war die Forderung nach 125 kHz noch
> gar nicht bekannt

Stimmt, diese Angabe kam erst im nächsten Posting nach deinem.

> Für Ihre Punkte 2 und 3 bräuchte ich mehr Zeit (und Motivation) -
> vielleicht später.

von S. L. (sldt)


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.

von C-hater (c-hater)


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]

von Harald K. (kirnbichler)


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.

von C-hater (c-hater)


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

von S. L. (sldt)


Angehängte Dateien:

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.

von Harald K. (kirnbichler)


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.

von S. L. (sldt)


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.

von C-hater (c-hater)


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.

von Harald K. (kirnbichler)


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.

von Falk B. (falk)


Lesenswert?

C-hater schrieb:
> Grundprinzip ist: Jede zusätzliche Hardware erhöht die Kosten und die
> Ausfallwahrscheinlichkeit.

In der Theorie und der Massenproduktion. In der Praxis des Bastlers und 
der Kleinstserien ist das bedeutungslos.

"Ich bin dafür, die Dinge so weit wie möglich zu vereinfachen. Aber 
nicht weiter."

Albert Einstein

von C-hater (c-hater)


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

von Peter D. (peda)


Lesenswert?

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

von Maxim B. (max182)


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.

: Bearbeitet durch User
von Georg M. (g_m)


Lesenswert?

Peter D. schrieb:
> Es gibt auch AVRs, die haben extra invertierte Ausgänge
> Und zusätzlich einen Dead-Time Generator

Timer/Counter Type D (TCD)
Generating Complementary Driving Signals

https://ww1.microchip.com/downloads/en/Appnotes/TB3212-Getting-Started-with-TCD-DS90003212.pdf

von Jannik (user_name123)


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

: Bearbeitet durch User
von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Wenns noch um den Mega328 geht, mein FU Projekt hat das vor Jahren schon 
mit 3 Timern gemacht. Jeder Timer hat komplementäre Ausgänge und alle 3 
laufen synchron:
https://www.mikrocontroller.net/articles/3-Phasen_Frequenzumrichter_mit_AVR

von S. L. (sldt)


Lesenswert?

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

von C-hater (c-hater)


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.

von Jannik (user_name123)


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
 }

von S. L. (sldt)


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?

von Veit D. (devil-elec)


Lesenswert?

Jannik schrieb:

> [c]
>
> ISR(TIMER0_COMPA_vect) {
>   uint8_t ui8_sreg = SREG;
>   ...
>   ...
>   SREG = ui8_sreg;
> }

S. L. schrieb:

> Übrigens: Retten von SREG in der ISR - ich dachte, solchen Kleinkram
> nimmt C dem Programmierer ab?

Hallo,

nimmt es auch. Innerhalb einer ISR ist sowas nicht notwendig.

von S. L. (sldt)


Lesenswert?

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.

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.