Hallo zusammen,
ich stehe mal wieder irgendwie auf dem Schlauch und komme nicht
runter...
Auf meiner Platine werkelt ein ATmega88 als Frequenzgenerator für eine
Wechselspannung (Per H-Brücke) mit einer Frequenz von wahlweise 25kHz
oder 30kHz. Die beiden Eingänge der H-Brücke hängen an OC1A und OC1B,
sollten sich also prima per Output Compare steuern lassen. Funktioniert
auch recht gut.
Problematisch wird's allerdings, wenn ich die Frequenz ändere. Den Timer
lasse ich im CTC-Modus laufen, OCR1A = OCR1B = F_CPU / (Frequenz 2
8), Prescaler 8. Wenn ich die Frequenz aufdrehe und TCNT1 gerade
oberhalb vom neuen OCR-Wert ist, dann läuft der Timer natürlich komplett
durch -> Lange Verzögerung -> Müll. Ist allerdings mit einer Anweisung à
la
1
if(TCNT1>AC_OCR_MOD)TCNT1=0;
vor der Änderung recht einfach zu beheben. Mehr Probleme bereitet mir
dagegen die Tatsache, dass die beiden Ausgänge teilweise nachher nicht
mehr synchronisiert sind, sie sind dann also nicht mehr gegenläufig und
meine Wechselspannung ist weg. Beim Initialisieren lässt sich das ja
recht gut mit dem Force-Output-Compare-Bit bewerkstelligen, doch im
laufenden Betrieb ist das irgendwie etwas komplizierter.
Daher die Frage: Wie kann ich es möglichst einfach hinkriegen, dass die
beiden Pins mit gleicher Phasenverschiebung und ohne grössere
Unterbrüche toggeln? Irgendwie finde ich da keinen passenden Modus, denn
eigentlich sollte mit einem PWM-Modi doch genau das möglich sein...
Danke und Gruss,
Philipp
Ich habe eben nochmal die diversen PWM-Modi im Datenblatt studiert.
Irgendwie will mir etwas einfach nicht ganz klar werden:
Es gibt ja diverse Modi, in denen die PWM-Frequenz mittels dem
OCR1A-Register eingestellt werden kann. Aber wo muss ich denn dann den
Compare-Wert für den OC1A-Pin ablegen? verwirrtbin
EDIT: Nochwas: Eine Änderung der Hardware möchte ich vermeiden, da die
Platine bereits gemacht ist (Ist schon etwas länger her, da hatte ich
die Verwendung der Hardware-Frequenzerzeugung zwar eingeplant (Signale
entsprechend geroutet), hab's aber dann doch per Software gelöst).
joop
an HW dachte ich als erste einfach ausgang negieren fertig und Port
gesparrt.
variante 2
den 2. ausgan aus der HW PWM herausnehmen und per SW setzen
Igitt was für eine Krücke HW-PWM mit SW Holzbein
nein sowas macht man Per inverter oder Transistor auf der Treiberseite
der Hbrücke aber nicht mit nem Portpin. Das ist viel zu Schade und zu
umständlich noch dazu aus eben dem von dir herausgefundenem Grund ;-)
Schon klar, mit Hacks an der Software oder Hardware würde das schon
funktionieren, aber das muss doch auch so gehen. Es gibt ja extra Modi
für derartige PWM-Erzeugung (Phase and frequency correct zum Beispiel),
aber wenn man OCR1A als TOP verwendet, dann kann man OC1A nicht
verwenden. Na aber hallo?! Das kann's doch wohl nicht sein. Verwende ich
dagegen ICR1 als TOP, ist der Vorteil der Pufferung wieder weg, was in
einem unsauberen Signal resultiert.
Die HW-Lösung funktioniert im Übrigen auch nur, wenn die Pins (Wie in
meinem Fall) IMMER gegenläufig angesteuert werden müssen.
Bäh, der verdammte PDF-Scheiss...
Also, das Datenblatt verstehe ich im Moment irgendwie einfach nicht so
recht. In der Tabelle auf Seite 130 sind ja die diversen
Einstellungsmöglichkeiten der COM1xy-Bits aufgeführt. Für den
Fast-PWM-Mode gibt es da z.B. sowas:
WGM13:0 = 14 or 15: Toggle OC1A on Compare
Match, OC1B disconnected (normal port operation).
For all other WGM1 settings, normal port operation,
OC1A/OC1B disconnected.
Modus 14 verwendet ICR1 als TOP und Modus 15 OCR1A. Angenommen ich
verwende Modus 15 und oben genannte OC-Einstellung, dann wäre also OC1B
unbenutzt und OC1A toggelt jeweils beim Compare-Match. Da sehe ich den
Sinn dieser Einstellung irgendwie nicht wirklich, das ist ja dann etwa
das Gleiche wie CTC...
Kannst du nicht im mit ICR1 als Top (Mode 8, 10 oder 14) die OCR
register in einem Overflow-interrupt updaten, und das ICR1 im nächsten?
Ich interpretiere das mal so ins Datenblatt (Beispiel: Mode 14, ICR1 als
TOP, FastPWM):
- eine Änderung im ICR register wird sofort übernommen
- der Overflow-interrupt kommt bei TOP (= alter ICR1-Wert)
- die OCR register werden bei BOTTOM geupdatet (1xPRESCALER Takte nach
dem Overflow), und man kann man die OCR1n nicht innerhalb von 8 Takten
in einer ISR beschreiben (allein der aufruf dauert 4 + 2(rjmp) +
2(push) Takte)
Also könnte doch es so gehen:
ICR und OCR wert(e) global speichern
flag setzen
Overflow-interrupt aktivieren:
beim ersten Overflow-interrupt werden die OCR register beschrieben
beim nächsten Overflow-interrupt wird das ICR register beschrieben
und
der Overflow-interrupt wieder deaktiviert
hth. Jörg
ps.: alles ungetestet
Könnte man wohl machen, allerdings wär's dann eher einfacher, die
Frequenzerzeugung direkt in die Interrupts auszulagern. Die Verwendung
der Interrupts wollte ich eigentlich komplett vermeiden, da ich das Prog
in C schreibe und dazu Inline-ASM verwenden müsste (Bei C gibt's einen
recht grossen Overhead bei Interrupt-Aufrufen).
Im Moment habe ich es so gelöst, dass ich ICR1 als TOP verwende und
jeweils vor dem ändern TCNT1 auf den neuen TOP-Wert setze, sollte es
denn höher sein. Ist nicht ideal, müsste aber funktionieren.
Naja, ich hatte das so gedacht, dass der Overflow-interrupt nur zum
ändern der Frequenz kurz aktiviert wird, zweimal zuschlägt, und danach
die Hardware weiter PWM machen lässt...
? Jörg
Also, Du willst beide Pins zum gleichen Zeitpunkt entgegengsetzt
togglen.
Dann setz doch einfach OCR1A und OCR1B auf 0 und ICP auf die halbe
Periodendauer.
Und dann setz die Pins per Force.. auf entgegengesetzte Pegel, dann auf
Toggle on Compare und starte den Timer.
Die Frequenz änderst Du dann mit ICP.
Peter
@Peter:
Klar, etwa so wollte ich es ja auch machen. Das Problem ist nur, dass
der Zeitpunkt der Änderung am ICR (Ich nehme an, du meinst ICR und nicht
ICP) nicht definiert ist. Wenn ich den Wert nach unten korrigiere und
der Timer gerade einen höheren Wert hat, dann läuft er komplett durch
und erzeugt einen viel zu langen Impuls. Das ist allerdings nicht so
tragisch, das kann ich mit einer Anpassung von TCNT1 in den Griff
kriegen.
Problematischer ist dabei, dass manchmal die Synchronisation verloren
geht und dann ist die Spannung weg.
Ich muss mir die ganze Sache aber nochmal ansehn, irgendwas ist grade
komisch...
Philipp Burch wrote:
> Klar, etwa so wollte ich es ja auch machen. Das Problem ist nur, dass> der Zeitpunkt der Änderung am ICR (Ich nehme an, du meinst ICR und nicht> ICP) nicht definiert ist. Wenn ich den Wert nach unten korrigiere und> der Timer gerade einen höheren Wert hat, dann läuft er komplett durch> und erzeugt einen viel zu langen Impuls.
Dann mach das neu laden einfach im Interrupt, also direkt nachdem das
letzte Compare erfolgte.
Den Interrupt nur dann enablen, wenn der Wert geändert werden soll
(Interruptflag vorher löschen!).
> Problematischer ist dabei, dass manchmal die Synchronisation verloren> geht und dann ist die Spannung weg.
Wie soll denn das gehen ?
Wenn OCR1B = OCR1A und nie geändert werden, müssen sie auch synchron
bleiben.
Du änderst ja nur ICR.
Peter
Hm, da fällt mir jetzt aber grade was auf. Mit welchem Modus würdest du
das eigentlich lösen? Verwende ich einen PWM-Modus kann ich die Pins
nicht einfach toggeln lassen (Jeweils nur OC1A, OC1B ist dann nicht
angeschlossen), im Normal-Mode läuft der Timer immer komplett durch und
bei CTC kommt er wegen dem "Clear timer on COMPARE" gar nie aus dem
Interrupt bei OCR1A = 0. Setze ich beide OCRs auf die gewünschte
PWM-Frequenz funktioniert's wiederum nicht, da dann eben die
Synchronisation verloren geht :(
So gesehen ist der CTC-Modus mit ICR als TOP eigentlich ziemlich
sinnlos, denn TOP kann ja eigentlich gar nie erreicht werden, ausser OCR
ist höher als TOP...
Philipp Burch wrote:
> Hm, da fällt mir jetzt aber grade was auf. Mit welchem Modus würdest du> das eigentlich lösen? Verwende ich einen PWM-Modus kann ich die Pins> nicht einfach toggeln lassen
PWM geht natürlich nicht.
Mode 12 ist der einzig richtige. Da hast Du immer 50% Tastverhältnis und
mußt nur ICR1 ändern zur Frequenzeinstellung.
Peter
> Mode 12 ist der einzig richtige. Da hast Du immer 50% Tastverhältnis und> mußt nur ICR1 ändern zur Frequenzeinstellung.
Das dachte ich auch. Doch es ist trotzdem ein CTC-Modus, der Timer wird
immer beim Compare gelöscht. kA warum, aber sowohl im Simulator als auch
im realen Controller verhält er sich so und kommt einfach nie mehr aus
dem Interrupt...
Philipp Burch wrote:
> Das dachte ich auch. Doch es ist trotzdem ein CTC-Modus, der Timer wird> immer beim Compare gelöscht.
Das soll er ja auch, damit bestimmst Du doch die Frequenz.
> kA warum, aber sowohl im Simulator als auch> im realen Controller verhält er sich so und kommt einfach nie mehr aus> dem Interrupt...
Du kriegst nur alle 400 Zyklen nen Interupt. Was machst Du darin
solange, daß er nicht mehr rauskommen soll ?
Wozu überhaupt der Interrupt ?
Peter
Ähm, jetzt komme ich aber nicht mehr mit...
Peter Dannegger wrote:
> Philipp Burch wrote:>>> Das dachte ich auch. Doch es ist trotzdem ein CTC-Modus, der Timer wird>> immer beim Compare gelöscht.>> Das soll er ja auch, damit bestimmst Du doch die Frequenz.
Oben schriebst du noch, die Frequenz würde mit ICR bestimmt. Daher ja
auch Modus 12 und nicht Modus 4.
>> kA warum, aber sowohl im Simulator als auch>> im realen Controller verhält er sich so und kommt einfach nie mehr aus>> dem Interrupt...>>> Du kriegst nur alle 400 Zyklen nen Interupt. Was machst Du darin> solange, daß er nicht mehr rauskommen soll ?
Im Interrupt mache ich gar nix, das ist es ja. Das OC-Flag ist einfach
dauernd gesetzt (Durch die Hardware).
> Wozu überhaupt der Interrupt ?
Na zum ändern des ICR-Wertes, hast du doch selbst geschrieben. Den
Interrupt habe ich jetzt mal testweise dauernd aktiviert gelassen, dafür
ist die Routine leer. Aber wie gesagt: Der Controller hängt immer drin.
Philipp Burch wrote:
> Oben schriebst du noch, die Frequenz würde mit ICR bestimmt. Daher ja> auch Modus 12 und nicht Modus 4.
Ja, clear on Compare mit ICR1.
> Im Interrupt mache ich gar nix, das ist es ja. Das OC-Flag ist einfach> dauernd gesetzt (Durch die Hardware).
Durch die Hardware alle 400 Zyklen, also nicht dauernd.
> Na zum ändern des ICR-Wertes, hast du doch selbst geschrieben.
Ich wußte ja nicht, daß Du die Frequenz ständig ändern willst.
> Den> Interrupt habe ich jetzt mal testweise dauernd aktiviert gelassen, dafür> ist die Routine leer. Aber wie gesagt: Der Controller hängt immer drin.
Wenn er leer ist, dann braucht er nur 10 Zyklen, also 390 Zyklen (97,5%)
bist Du nicht drin.
Peter
Ich will dich ja nicht angreifen, aber irgendwie willst du mich einfach
nicht verstehen. Oder wir reden aneinander vorbei.
Mach' doch mal bitte ein neues Projekt (Assembler) für den Mega88 auf
und füge diesen Code ein:
1
.include <m88def.inc>
2
3
.org 0 rjmp RESET
4
.org OC1Aaddr rjmp TIMER1_COMPA_vect
5
6
RESET:
7
8
ldi r16, HIGH(RAMEND)
9
out SPH, r16
10
ldi r16, LOW(RAMEND)
11
out SPL, r16
12
13
14
ldi r16, 1 << WGM13 | 1 << WGM12 | 1 << CS11
15
sts TCCR1B, r16
16
clr r16
17
sts OCR1AH, r16
18
sts OCR1AL, r16
19
sts ICR1H, r16
20
ldi r16, 50
21
sts ICR1L, r16
22
ldi r16, 1 << OCIE1A
23
sts TIMSK1, r16
24
25
sei
26
27
mainloop:
28
29
rjmp mainloop
30
31
32
33
34
TIMER1_COMPA_vect:
35
nop
36
reti
Timer1 wird (Der Einfachheit halber ohne die OC-Pins) in Modus 12 (CTC,
TOP = ICR) initialisiert. Prescaler ist 8, OCR ist 0 und ICR ist 50. Der
Output-Capture-Interrupt A ist aktiviert und macht einfach mal nix.
Wenn du das Prog ausführst (also simulierst) wirst du feststellen, dass
der Controller andauernd im Interrupt hängt.
Wird OCR1A auf einen anderen Wert gelegt (z.B. 3), dann läuft der Timer
eben bis zu diesem Wert und wird dann zurückgesetzt. Der Wert von ICR
scheint ihn überhaupt nicht zu interessieren...
Vielleicht stehe ich ja auch einfach komplett auf dem Schlauch.
Philipp Burch wrote:
> Wenn du das Prog ausführst (also simulierst) ...
Nein, Ausführen und Simulieren sind 2 völlig verschiedene Sachen.
Ich hab schon ewig nichts mehr simuliert, weil nicht alle Funktionen
aller Derivate unterstützt werden.
Lies mal die Doku des Simulators gründlich.
Nur das Ausführen zeigt wirklich, ob etwas funktioniert.
Peter
Philipp_Burch wrote:
>> Nur das Ausführen zeigt wirklich, ob etwas funktioniert.>> Das tut es ja eben NICHT. Ob im Simulator oder auf dem Proz.
Ok, ich nehme alles zurück und behaupte das Gegenteil. Es funktioniert
doch. Anscheinend hab' ich beim letzten Mal irgendwo anders 'nen Hund
vergraben...
Jetzt weiss ich auch wieder, warum ich den Simulator normalerweise nicht
verwende...
Nix für ungut und danke für die Hilfe.
Gruss,
Philipp