Ich wundere mich gerade ein wenig, den Artikel über Soft-PWM hier habe
ich gelesen.
timer1, 1 Kanal direkt via OCR1A, top OCR1C, 3 Kanäle via Software
Sortieren, Masken, nächsten PWM-Kanal via OCR1B-Interrupt etc, alles
gemacht, funktioniert auch - bis auf einen Fall: 2 Werte unterscheiden
sich nur um ein LSB, dann werden die folgenden Kanäle nicht bedient
Probeweise den Vorteiler erhöht - änderte nichts.
unsigned char OCR1B_reload[3]={10,20,30}; //klappt
unsigned char OCR1B_reload[3]={10,11,30}; //Kanal 1 ok, 2 und 3 nicht
Die Software hatte auf einem Mega88 funktioniert (denke ich zumindest,
vielleicht ist es auch nur nicht aufgefallen, habe aber leider keinen
hier um das mal zu testen). In der Simulation funktionert es aber mit
dem 88er, mit dem Tiny25 aber auch nicht.
Man kann das Problem eigentlich auf folgendes herabbrechen:
// Timer1 output compare B interrupt service routine
interrupt [TIM1_COMPB] void timer1_compb_isr(void)
{
OCR1B++; //eigentlich kommt der neue Wert aus einem sortierten array
}
In Wirklichkeit passiert natürlich noch ein bisschen mehr, aber diese
eine Zeile zeigt das Problem. Der Interrupt mit OCR1B+1 kommt nicht.
Den Mega88-Timer hatte ich auch nur mit 8bit laufen, top on ICR1.
{ OCR1B++; }
Als ASM-Doof-ling kann ich nur beisteuern, dass OCR1B kein
Standard-Register, sondern ein I/O-Register ist.
Fürs Inkrementieren muss es in ein Standard-Register gelesen
werden, dieses inkrementieren und den neuen Inhalt wieder nach
OCR1B schreiben.
Ist ja eine tolle Erleichterung, wenn die Libraries bei Tiny
und Mega nicht vergleichbar arbeiten!
Dann lieber gleich ASM.
Daran liegt es nicht, das macht der Compiler schon richtig
; 0000 0045 OCR1B++;
000059 b5eb IN R30,0x2B
00005a 5fef SUBI R30,-LOW(1)
00005b bdeb OUT 0x2B,R30
Und genau in der Art muss man es in Assembler auch machen.
Hat auch mit libraries überhaupt nichts zu tun. Ich incrementiere auch
nicht wirklich, sondern laden den nächsten OCR-Wert aus einem array
nach. Das mit OCR1B++ ist nur der Einfachheit halber (nächster Wert soll
wieder einen OCR1B-Int auslösen.
Ich habe im Datenblatt keinen Hinweis gefunden, dass das nicht gehen
sollte. Erste Vermutung, dass der Interrupt zu lange dauert und deshalb
den nächsten nicht erwischt. Ist aber auch nicht das Problem. Vorteiler
original ist 64, ISR dauert um die 30 Takte. Mit Vorteiler 128 dasselbe.
Erhöhe ich OCR1B nur um eins, funktioniert das beim Tiny25-Timer1
offensichtlich nicht. Und das ist Mist. Das Problem müsste eigentlich
schon mal jemand gehabt haben, wenn es denn tatsächlich eins ist.
Gefunden habe ich darüber nichts, deswegen denke ich, dass ich das
Problem bin und nicht der arme kleine Tiny. Nur fällt mir nichts mehr
ein, da habe ich schon ein paar Stunden draufrumgekaut :-(
Falls niemand sonst helfen will - erklär mir doch mal "auf
ASM", was SW-PWM mit
> unsigned char OCR1B_reload[3]={10,20,30}; //klappt> unsigned char OCR1B_reload[3]={10,11,30}; //Kanal 1 ok, 2 und 3 nicht
bedeuten soll.
Manchmal wird einem beim Erklärungsversuch schon klar, was
man sich vorher nicht selbst klar gemacht hat. ;-)
Auch das hat mit meinem eigentlichen Problem nichts zu tun.
Assembler kann ich aber nicht.
Grober Ablauf:
-der timer1_ov setzt alle Ausgänge, deren PWM-Wert grösser 0 ist
-ins OCR1B-Register wird der kleinste PWM-Wert aller Kanäle geschrieben
-der folgende OCR1B-Interrupt setzt den (oder die Ausgänge, falls
gleiche Werte), die diesem PWM-Wert entsprechen zurück und lädt den
nächstgrösseren PWM-Wert usw und irgendwann ganz von vorne
Funktioniert auch alles prächtig, solange sich 2 PWM-Werte um min. 2
unterscheiden. Unterscheiden sie sich aber nur um 1, wird der eigentlich
nächste auszuführende OCR1B-Int nicht ausgeführt. Damit entfällt dann
sowohl das Abbrechen des zweiten Kanals und logischerweise damit auch
das Nachladen des 3.Kanals.
PWM1_Sollwert 10
PWM2_Sollwert 20
PWM3_Sollwert 30 -> alles ist gut
PWM1_Sollwert 10 -> funktioniert
PWM2_SOllwert 11 -> funktioniert nicht, Kanal bleibt bei 100%
PWM3_Sollwert egal -> auch 100%
Es spucken auch keine anderen Interrupts dazwischen, ich habe alles
andere rausgeschmissen - Problem bleibt.
Und wenn man dann sowas macht (Pseudocode)
pwm[0]=50;
pwm[1]=80;
test:
for (loop=0;loop<255;loop++)
{pwm[2]=loop;
set_pwm(); //sortieren, Masken setzen etc
delay_ms(100); //nein, nicht wirklich
}
goto test; //auch nicht wirklich
entstehen lustige Sachen bei loop=49, 51 79 und 81
Gerhard schrieb:> PWM3_Sollwert 30 -> alles ist gut>> PWM1_Sollwert 10 -> funktioniert> PWM2_SOllwert 11 -> funktioniert nicht, Kanal bleibt bei 100%> PWM3_Sollwert egal -> auch 100%>> Es spucken auch keine anderen Interrupts dazwischen, ich habe alles> andere rausgeschmissen - Problem bleibt.>> Und wenn man dann sowas macht (Pseudocode)> delay_ms(100); //nein, nicht wirklich> goto test; //auch nicht wirklich>> entstehen lustige Sachen bei loop=49, 51 79 und 81
Das komplette Programm liegt nicht vor. Durch subjektive Kommentare, die
aber nur für den OP bestimmt sinnvoll sind und viel Bla Bla, die den
Programmcode anscheinend ersetzten sollen, ist es mir einfach zu mühsam
dem OP zu folgen und dem Problem näher zu rücken.
Jakob schrieb:> Dann lieber gleich ASM.
Das hat nichts mit ASM zu tun, daß Atmel die Timerfunktionen bei jedem
AVR-Derivat neu gemischt hat. Mich hat das auch schon aufgeregt, daß es
keine einheitlichen Timer gibt.
Lieber jedeZweite,
danke für den äusserst wertvollen und kurzweiligen Kommentar, den rahme
ich mir ein!
Mit der einen Zeile war eigentlich alles wichtige gesagt.
Es ist tasächlich so: der Timer1 bekommt es nicht gebacken, 2 direkt
aufeinanderfolgende OCR1x-Werte zu verarbeiten. Immerhin ist der
Simulator so nett und macht es wie der reale Prozessor. Gerade mit den
Timern habe ich mit AVR-Studio schon nette Sachen erlebt
Mit dem Timer0 klappt es wie erwartet, da müsste ich allerdings alle 4
Kanäle via Soft-PWM bedienen, da der wiederum im fast-PWM-Mode OCR0A/B
wohl erst bei Überlauf übernimmt, auch wenn nur einer als Hardware-PWM
arbeitet
OCR1A dasselbe Verhalten wie OCR1B.
// Timer1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
OCR1A+=2;
PORTB.0=!PORTB.0;
}
arbeitet völlig korrekt,
mit +1 passiert gar nichts. Jetzt werde ich noch mal tief in der Kiste
graben, ob ich noch ein paar andere AVRs finde. Ein NET-I/O habe ich auf
jeden Fall noch mit Mega644. Und Tiny2313 müsste auch noch da sein.
Interessiert mich jetzt.
Gerhard schrieb:> Mit der einen Zeile war eigentlich alles wichtige gesagt.
Zeig trotzdem mal einen compilierfähigen Code, d.h. mit Init und Main.
Niemand hat Lust, erstmal rumprobieren zu müssen.
Gerhard schrieb:> mit +1 passiert gar nichts.
Wirklich nichts oder erst nach 257 Timerzyklen?
Peter D. schrieb:> Gerhard schrieb:>> Mit der einen Zeile war eigentlich alles wichtige gesagt.>> Zeig trotzdem mal einen compilierfähigen Code, d.h. mit Init und Main.
Mach ich gleich mal, Mnimalvariante.
> Niemand hat Lust, erstmal rumprobieren zu müssen.
Es sollte ja auch niemand probieren. Ich hatte auf Erfahrungen gehofft
-Ne, geht nicht weil xyz oder
-muss gehen, bei mir hat es funktioniert
So exotisch schien mir die Aufgabe nicht
> Gerhard schrieb:>> mit +1 passiert gar nichts.>> Wirklich nichts oder erst nach 257 Timerzyklen?
Nichts mehr, da beim Überlauf eh wieder der kleinste OCR-Wert geladen
wird.
Vermutlich benutzt Du den PWM-Mode, dann gilt das hier:
"Note that in PWM mode, writing to the Output Compare Registers OCR1A or
OCR1B, the data value is first transferred to a temporary location. The
value is latched into OCR1A or OCR1B when the Timer/Counter reaches
OCR1C."
D.h. der neue OCR1B wird erst beim Erreichen von OCR1C übernommen.
Das ist das Problemchen, dass ich im Moment mit dem Timer0 habe. Sobald
da einer von beiden als Hardware-PWM-arbeitet, wird auch der zweite erst
beim Überlauf übernommen.
Beim Timer1 ist es anders, es gilt nur für den, der auch an die
PWM-Einheit gekoppelt ist. Der andere wird direkt geschrieben (sonst
würde das folgende ja auch nicht funktionieren)
Setzt man OCR1B_reload[0] auf 19, ist Kanal 2 tot (bzw. 100%).
Ganze Aufbereitung/Sortierung habe ich jetzt mal weggelassen.
Und nein, an evtl. fehlendem volatile liegt es nicht.
Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.
Wichtige Regeln - erst lesen, dann posten!
Groß- und Kleinschreibung verwenden
Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang