Forum: Compiler & IDEs OCR1A aus HIGH Byte und LOW Byte beschreiben


von Hendrik L. (lbd)


Lesenswert?

Hallo zusammen,

ich möchte OCR1A beschreiben

uint8_t  WertL, WertH;
uint16_t Wert;

=>>> Wert = (uint16_t) WertH * 256 + (uint16_t) WertL; <===

OCR1A = Wert;

Ich vermute, OCR1A wird nicht richtig beschrieben.

So funzt es:

OCR1AH = WertH;
OCR1AL = WertL;

Ist obige Zeile

=>>> Wert = (uint16_t) WertH * 256 + (uint16_t) WertL; <===

richtig überlegt ? Ich fürchte nicht ...!

Danke im voraus

von Rolf M. (rmagnus)


Lesenswert?

Hendrik L. schrieb:
> So funzt es:
>
> OCR1AH = WertH;
> OCR1AL = WertL;

Dann lass es doch einfach so. Wenn du OCR1A beschreibst, wird der 
Compiler sowieso deine gerade so kunstvoll zusammengerechneten Bytes 
wieder auftrennen und daraus genau das machen, was die obigen beiden 
Zeilen tun.

> Ist obige Zeile
>
> =>>> Wert = (uint16_t) WertH * 256 + (uint16_t) WertL; <===
>
> richtig überlegt ? Ich fürchte nicht ...!

Sieht aber eigentlich gut aus.

von lbd (Gast)


Lesenswert?

Mit diesem Problem kämpfe ich nun 2 Tage (dachte immer ich hätte die PWM 
Modi nicht verstanden). Offensichtlich liegt das Problem aber in dieser 
Zuweisung.

Ich versuche zu verstehen.

Danke für die Antwort.

von Stone (Gast)


Lesenswert?

Die 16-Bit-Register kannst du ganz normal beschreiben z.b.
1
OCR1A = 4242;

Wenn du willst oder es praktischer ist kann du auch getrennt nach Low 
und High-Byte schreiben.

Ich schreibe eigentlich nur explizit das Low-Byte wenn das High-Byte 
nicht genutzt wird z.b. wenn Timer1 im 8-Bit Mode läuft.

Vielleicht liegt der Fehler ja auch wo anders, poste doch mal deinen 
ganzen Code.


Gruß Matthias

von Hendrik L. (lbd)


Lesenswert?

weitere Details:

Ich verwende im ATTiny 2313 FastPWM (Mode 14) mit ICR1 auf 20.000 
gesetzt

(Entsprechende PWM Frequenz wird am DIGI-Oszilloskop erkannt - stimmt 
mit vorausberechneter PWM Frequenz auf 0.5% überein!)

Aber der Duty Cycle lässt sich hinsichtlich OCR1B nicht verstellen, wohl 
aber vollumfänglich bei OCR1A !

Bei OCR1B wird lediglich der berühmte Spike (bei TOP+1 timer cycle) 
sichtbar.

Für die Experten:

//-----------------
  if (xxxx == 114)
  f8:  80 91 71 00   lds  r24, 0x0071
  fc:  82 37         cpi  r24, 0x72  ; 114
  fe:  49 f4         brne  .+18       ; 0x112 <__stack+0x33>
  {
cli ();
 100:  f8 94         cli
    OCR1B = Wert;
 102:  80 91 69 00   lds  r24, 0x0069
 106:  90 91 6a 00   lds  r25, 0x006A
 10a:  99 bd         out  0x29, r25  ; 41
 10c:  88 bd         out  0x28, r24  ; 40

sei();
 10e:  78 94         sei
 110:  10 c0         rjmp  .+32       ; 0x132 <__stack+0x53>
       TCCR1A &= ~(1 << COM1B1);
    }
*/
  }

//..........................................................

  else if (xxxx == 103)
 112:  87 36         cpi  r24, 0x67  ; 103
 114:  49 f4         brne  .+18       ; 0x128 <__stack+0x49>
  {

cli();
 116:  f8 94         cli
    OCR1AH = WertH;
 118:  80 91 61 00   lds  r24, 0x0061
 11c:  8b bd         out  0x2b, r24  ; 43
    OCR1AL = WertL;
 11e:  80 91 66 00   lds  r24, 0x0066
 122:  8a bd         out  0x2a, r24  ; 42
sei();
 124:  78 94         sei
 126:  05 c0         rjmp  .+10       ; 0x132 <__stack+0x53>
        TCCR1A &= ~(1 << COM1A1);
    }
//---------------------

Der Abfragezweig

  xxxx == 114 funzt NICHT!

hinsichtlich PWM (offensichtlich unveränderbarem OCR1B - Wert)

  xxxx == 103 FUNZT!

hinsichtlich PWM (Vermutung richtiger OCR1A - Wert)

Vertausche ich nun OCR1B und OCR1A in obigem Code - dann jeweils die 
andere PWM falsch, hat also definitiv nix mit A oder B zu tun.

OC1A und OC1B sind disconnected - Ports werden in Interrupt Routinen

  ISR(TIMER1_COMPA_vect)
  ISR(TIMER1_COMPB_vect)

und

  ISR(TIMER1_OVF_vect)

"von Hand" auf HIGH oder LOW gesetzt.

???? Bin völlig ratlos !!!!

von Hmm (Gast)


Lesenswert?

>Für die Experten:

Die "Experten" hätten gerne vollständigen, möglichst compilierbaren 
Quellcode. Keine von Dir redigierten Schnippsel die in der Regel eines 
nicht zeigen: Die Ursache des Problems. :-)

Das ist die Bedeutung der Auffordernung: "... poste doch mal deinen
ganzen Code."

von Hendrik L. (lbd)


Lesenswert?

Hmm schrieb:
>>Für die Experten:
>
> Die "Experten" hätten gerne vollständigen, möglichst compilierbaren
> Quellcode. Keine von Dir redigierten Schnippsel die in der Regel eines
> nicht zeigen: Die Ursache des Problems. :-)
>
> Das ist die Bedeutung der Auffordernung: "... poste doch mal deinen
> ganzen Code."

Danke für Deinen freundlichen Hinweis!

Obiger Code reicht aber völlig aus! Die Logik in meiner Argumentation 
ist ja recht einfach wie schlüssig:

Wenn ich zu Fuss die HByte ond LByte von OCRx beschreibe, funktioniert 
der PWM Mode 14 wie erwartet. Beschreibe ich das 16 Bit Register OCRx 
direkt, geht's nicht.

Vertausche ich OCR1A und OCR1B in obigem Beispiel, dann funzt die 
jeweilige andere PWM (oder eben nicht).

Beschreibe ich beide OCR1x mit 16bit direkt, funzen beide PWMs nicht. 
Beschreibe ich beide getrennt, mit LOW und HIGH-Byte, dann funzen beide 
PWMs.

Nun könnte ich sagen, das Problem ist gelöst -aber bislang habe ich 
verstanden, dass man nur in ASM auf die getrennte Register-Beschreibung 
zu achen hat, bei C sollte der Compiler den Programmierer sorglos 
stellen.

Dennoch, danke für Deine Zeit!

von Hmm (Gast)


Lesenswert?

Da ist ein Widerspruch in Deiner Argumentation: Du weisst nicht was das 
Problem ist, aber weisst, welche Information relevant ist. Umgekehrt 
wird es richtiger sein: Du verwirfst eine Information die, entgegen 
Deiner Einschätzung eben doch relevant ist.

Es im Moment nicht möglich zu sagen, wo genau die Ursache liegt.
Am besten ist es soviel Informationen wie möglich zu geben.

Aber Informationen auszuwählen und nur die zu posten welche Du als 
notwendig erachtest, steht im Widerspruch zu der Tatsache das Du nicht 
in der Lage bist, die nur in Deinem Besitz befindliche Gesamtheit der 
Informationen so zu deuten, das Du Dein Problem alleine lösen kannst.

Die Lösung wird aber eben ein Detail dieser Gesamtheit sein, dessen 
Bedeutung Du falsch einschätzt. Das ist nun weder ungewöhnlich noch 
setzt es Dich herab. Das passiert den Besten und mir und Dir erst recht.

Um es zusammenzufassen: Unter den Informationen, die Du verwirfst und 
hier nicht postest ist genau die, welche das Problem löst.

Sei also so gut und poste alle Informationen.

Und wenn Du mir einen persönlichen Gefallen tun willst, dann benutze 
nicht dieses unsägliche "funzen". Da kräuseln sich mir die Fussnägel.

von Stefan E. (sternst)


Lesenswert?

Hendrik L. schrieb:
> Obiger Code reicht aber völlig aus!

Nö, denn da ist kein Fehler drin, also muss er woanders sein.

Wo ist z.B. der Code, der 'Wert' "zusammenbastelt". Und ich meine nicht 
das, was im ersten Post steht, denn das ist vermutlich was 
"Eingetipptes". Ich meine den realen Code (per Copy&Paste).

von Fabian O. (xfr)


Lesenswert?

Nutzt Du AVR Studio 5? Dann kann es ein Fehler des Compilers sein.

von Hendrik L. (lbd)


Lesenswert?

Stefan Ernst schrieb:
> Hendrik L. schrieb:
>> Obiger Code reicht aber völlig aus!
>
> Nö, denn da ist kein Fehler drin, also muss er woanders sein.
>
> Wo ist z.B. der Code, der 'Wert' "zusammenbastelt". Und ich meine nicht
> das, was im ersten Post steht, denn das ist vermutlich was
> "Eingetipptes". Ich meine den realen Code (per Copy&Paste).


wurde oben schon beschrieben:
//-------------------------------
uint8_t  WertL, WertH;
uint16_t Wert;

=>>> Wert = (uint16_t) WertH * 256 + (uint16_t) WertL; <===

//--------------------------------

WertL und WertH werden über I2C "gefüllt".

Kontroll-Lesen über I2C ergibt, dass WertL und WertH mit den richtigen 
Bytes gefüllt worden sind, um der Berechnung nach den gewünschten Wert 
an OCR1x zu übergeben! zu können

Für den 8bit Timer OCR0A funzt die I2C Mimik einwandfrei - ebenso für 
OCR1B UND OCR1A wenn wie oben beschrieben mit Bytes gearbeitet wird.
An den I2C Routinen liegt es also auch nicht.

Gruß

von csharp (Gast)


Lesenswert?

Hallo Hendrik L.

ohne jetzt alles haarklein durchzugehen, vielleicht hilft dir das 
weiter:

http://www.mikrocontroller.net/articles/AVR_16-Bit-Register

Gruß!

von Hendrik L. (lbd)


Lesenswert?

Fabian O. schrieb:
> Nutzt Du AVR Studio 5? Dann kann es ein Fehler des Compilers sein.

Version 4.19 Built 730!

von Stefan E. (sternst)


Lesenswert?

Hendrik L. schrieb:
> wurde oben schon beschrieben:
> //-------------------------------
> uint8_t  WertL, WertH;
> uint16_t Wert;
>
> =>>> Wert = (uint16_t) WertH * 256 + (uint16_t) WertL; <===
>
> //--------------------------------

Und ich hatte extra dazu geschrieben, dass ich DAS nicht nochmal sehen 
will, sondern den ECHTEN Code per Copy&Paste.

von Bla (Gast)


Lesenswert?

Vertausche mal die Zeilen, die High und Low zuweisen. Eventuell ist die 
Reihenfolge wichtig, weil der Wert gepuffert wird. Sowas sollte aber im 
Datenblatt stehen.

von Hendrik L. (lbd)


Lesenswert?

Bla schrieb:
> Vertausche mal die Zeilen, die High und Low zuweisen. Eventuell ist die
> Reihenfolge wichtig, weil der Wert gepuffert wird. Sowas sollte aber im
> Datenblatt stehen.

Danke für den Hinweis! Es ist aber so, dass die Einzelzuweisung ja 
funktioniert - die Reihenfolge ist also richtig.

Was nicht funktioniert, ist die 16-bit Zuweisung, die der Compiler 
automatisch erstellt. Darum habe ich ja die vom Compiler generierten 
ASM-Zeilen angehängt- weil ich mich in ASM nicht so gut auskenne.

Also, wenn ich die Anweisungen entsprechend Datenblatt "zu Fuss" in C 
programmiere, funzt es.

Nur heisst es in den Tutorials auch, dass GNU-C die 16-bit Zuweisung in 
Maschinencode selbst (richtig) erzeugt.

Dennoch Danke für Deine Hilfe.

Gruß

von Hendrik L. (lbd)


Lesenswert?

Also,

das Problem liegt definitiv in der Umrechnung durch diese Zeile

    Wert = (uint16_t) WertH * 256 + (uint16_t) WertL;
 120:  f3 2e         mov  r15, r19
 122:  ee 24         eor  r14, r14
 124:  c7 01         movw  r24, r14
 126:  82 0f         add  r24, r18
 128:  91 1d         adc  r25, r1

Habe zwischenzeitlich mit union und structure 16 bit und 8 Byte HIGH und 
LOW aufeinander gemapped - und schon funzt die direkte 16 bit Zuweisung 
auf OCRx1.

Gute Nacht!

von Walter S. (avatar)


Lesenswert?

Hendrik L. schrieb:
> Habe zwischenzeitlich mit union und structure 16 bit und 8 Byte HIGH und
> LOW aufeinander gemapped - und schon funzt die direkte 16 bit Zuweisung
> auf OCRx1.

das nennt man den Teufel mit dem Beelzebub austreiben

von Sven P. (Gast)


Lesenswert?

Hendrik L. schrieb:
> Also,
>
> das Problem liegt definitiv in der Umrechnung durch diese Zeile
>
>     Wert = (uint16_t) WertH * 256 + (uint16_t) WertL;
>  120:  f3 2e         mov  r15, r19
>  122:  ee 24         eor  r14, r14
>  124:  c7 01         movw  r24, r14
>  126:  82 0f         add  r24, r18
>  128:  91 1d         adc  r25, r1
Was stimmt daran nicht?

von lbd (Gast)


Lesenswert?

Das ist meine ursprüngliche und immer noch aktuelle Frage!

Wobei mein Programm jetzt funktioniert, indem ich diese Berechnung durch 
ein Speichermapping ersetze (2 Byte auf Word). Das ist erst einmal das 
wichtigste nach stundenlangem Frust.

Vielen Dank an Alle, die mitüberlegt haben.

Gruss

von Walter S. (avatar)


Lesenswert?

lbd schrieb:
> Das ist meine ursprüngliche und immer noch aktuelle Frage!

wenn Du ein Problem hast und möchtest das jemand dir hilft, dann 
solltest du ihm die Informationen zur Verfügung stellen um die er dich 
bittet.

Du behauptest dass du weißt wo das Problem liegt und wirfst den Leuten 
irgendwelche Häppchen zu in denen es liegen soll.

Entweder musst du deine Probleme allein lösen oder du hilfst denen die 
dir helfen sollen.

von Hendrik L. (lbd)


Lesenswert?

Walter S. schrieb:
> lbd schrieb:
>> Das ist meine ursprüngliche und immer noch aktuelle Frage!
>
> wenn Du ein Problem hast und möchtest das jemand dir hilft, dann
> solltest du ihm die Informationen zur Verfügung stellen um die er dich
> bittet.
>
> Du behauptest dass du weißt wo das Problem liegt und wirfst den Leuten
> irgendwelche Häppchen zu in denen es liegen soll.
>
> Entweder musst du deine Probleme allein lösen oder du hilfst denen die
> dir helfen sollen.

Ich bin da gänzlich anderer Meinung!

Offensichtlich gibt es mit obiger Berechnung ein Problem, ersetze ich 
die Zeile, ist das Problem weg.
Es ist zwar unbefriedigend, nicht zu wissen, warum - aber für mich ist 
der Weg nicht (immer) das Ziel. (Interessant ist, dass auf den ersten 
Blick die obige Zeile als korrekt empfunden wird - von mir, wie auch 
anderen).

Im übrigen habe ich die Zeile sowohl im MAIN als auch in Interrupt 
Routinen plaziert - immer das gleiche, es funzte nicht - egal wo im 
gesamten Code die Berechnung eingefügt wurde.

Umgekehrt funzt es jetzt, wenn man LOW und HIGH Byte erst einzeln 
zuweist, die auf eine 16bit Strukur (WORD) mappt und dann dieses WORD 
den Register ICRx1 zuweist. Grundsätzlich funzt also eine 16-bit 
Register Zuweisung bei OCRx1 in GNU C!

Ist doch gut zu wissen - für diejenigen, die auch evtl. einmal in ein 
solches Problem reinlaufen.

Also noch einmal Danke für die Anregungen und Hilfen!

Noch einen schönen Ostermontag wüscht Hendrik.

von Stefan E. (sternst)


Lesenswert?

Hendrik L. schrieb:
> Offensichtlich gibt es mit obiger Berechnung ein Problem, ersetze ich
> die Zeile, ist das Problem weg.

Und schon wieder eine voreilige Schlussfolgerung.

Nein, es gibt kein Problem mit der Berechnung. Das Problem ist immer 
noch irgendwo anders (z.B. Register werden vorher oder nachher irgendwie 
korrumpiert). Und ein Ersetzen der Zeile durch was anderes entfernt 
nicht das Problem, sondern kaschiert es nur.

von Fabian O. (xfr)


Lesenswert?

Ich würde mal eine neuere Compilerversion probieren, wenn Du es wirklich 
auf die eine Zeile eingrenzen kannst. Siehe hier:
Beitrag "Umwandlung von zwei uint8_t in uint16_t erzeugt falschen Code?"

von Peter D. (peda)


Lesenswert?

Das Umstellen des Code kaschiert den Fehler nur, es beseitigt ihn nicht.
Er wird Dir daher bei nächster Gelgenheit wieder auf die Füße fallen.

Wenn Du den fehlerhaften Code partout nicht zeigen willst, Dein Bier.
Deine Annahmen kannst Du Dir sämtlichst sparen, die bringen niemanden 
was.

von Bla (Gast)


Lesenswert?

Wenn du den Code nicht öffentlich machen willst, bau doch einfach mal 
ein Minimal-Beispiel. Vereinfache dein Programm so weit, dass es nur 
noch den Fehler produziert und nichts weiter. Da sollten ja ein paar 
Zeilen reichen. Wichtig ist, dass es fertig kompilierbarer Quelltext 
ist.

Die Assembler-Zeilen sind ok... sofern der korrekte Wert im korrekten 
Register steht.

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.