Forum: Mikrocontroller und Digitale Elektronik PWM Frequenzhochlauf - Endschrittweite wird nicht erreicht


von Peter A. (elkopeter)


Angehängte Dateien:

Lesenswert?

Hallo in die Runde.
Ich möchte ein sinusförmiges Ausgangssignal (Grundschwingung) an meinen 
beiden PWM-Ausgangspins meines Atmega8A erzeugen.
Ich verwende den Phase-Correct Modus, 8-Bit Timerauflösung, sowie eine 
256-stellige Lookup-Tabelle.

Mein Problem:
Ich möchte innerhalb 1s einen Hochlauf meiner Ausgangsfrequenz auf den 
maximalen Wert erreichen.
Hierzu Teile ich meine max. Schrittweite (für die Indexauswahl der 
Lookup-Tabelle) durch meine PWM Frequenz und erhöhe dann bei jedem 
Timerüberlauf meine Schrittweite bis zum max. Wert.
Leider erreiche ich die max. Schrittweite nicht, d.h. meine 
Ausgangsfrequenz ist deutlich kleiner als gewünscht. Vielleicht erreiche 
ich auch die max. Schrittweite und das Problem liegt an einer anderen 
Stelle.
Leider weiß ich nicht wo der Fehler im Code liegt. (Ich vermute mal, 
dass die Umwandlung von 16-Bit in 32-Bit Variablen und umgekehrt die 
Ursache ist).
Bei fester Schrittweite funktioniert das Ganze einwandfrei.

Variablen i und j bleiben ungenutzt. Ich habe sie im nachhinein 
entfernt.

: Bearbeitet durch User
von Flash Gordon (Gast)


Lesenswert?

Debuggen sollte ein Teil der Entwicklung sein. DH Debuggen muss von 
Begin weg eingeplant werden. Was wurde diesbezueglich unternommen ?

von Peter A. (elkopeter)


Lesenswert?

Ich habe das ganze mit dem Atmel Studio 6 erzeugt.
Mit dem Software Debugger kann ich allerdings nicht feststellen was in 
meiner ISR passiert.
Debug-Maßnahmen habe ich nicht eingeplant.(So tief bin ich nicht in der 
Programmiermaterie drin)

von Peter A. (elkopeter)


Lesenswert?

Kann die niedrige Ausgangsfrequenz auch daran liegen, dass ich mit 
32Bit-Variablen in der ISR rechne?

von Peter A. (elkopeter)


Lesenswert?

Martin Kreiner schrieb im Beitrag #3340776:
> Wo wird denn der phaseaccu hochgezählt?

Am Schluss der ISR am Programmende

von Martin K. (maart)


Lesenswert?

Wenn ich das jetzt richtig gesehen habe:
Der Timer 1 zählt ohne Prescaler von 0 bis 255, dann wieder runter -> 
Dann kommt der Overflow-Interrupt.
(2 * 255) / 3686000 => alle 138 Mikrosekunden.
Um die ISR abzuarbeiten werden schon mal mindesten 186 Mikrosekunden 
gebraucht. Da beißt sich was.

von Karl H. (kbuchegg)


Lesenswert?

Peter A. schrieb:

> Leider weiß ich nicht wo der Fehler im Code liegt. (Ich vermute mal,
> dass die Umwandlung von 16-Bit in 32-Bit Variablen und umgekehrt die
> Ursache ist).

Das denke ich ehrlich gesagt nicht.
Ich denke, du hast dich da irgendwo bei der Mathe verhaut. Einen 
Overflow bei einem Zwischenergebnis nicht bedacht, oder das bei einer 
Integerdivision keine Kommastellen anfallen, oder sowas in der Richtung.

Unglücklicherweise ist der Code etwas ... unübersichtlich und ich hab 
jetzt ehrlich gesagt auch nicht die Nerven und die Lust um den Code erst 
mal soweit aufzudröseln um die hier programmierte Idee erkennen zu 
können, bzw. ob und wenn ja wo bei der Umsetzung der Idee Fehler gemacht 
wurden, bzw. ob und wo da jetzt arithmetische Probleme auftauchen.

Die PWM ist ja nur Nebenschauplatz. Das was dir Sorgen macht, ist doch 
die Veränderung des OCR Wertes. Das kannst du aber mit einem 
Testprogramm auf dem PC genausogut erledigen. Denn letzten Endes geht es 
ja nur darum die Veränderung einiger Kennzahlen nachzuvollziehen.

von Karl H. (kbuchegg)


Lesenswert?

Der Teil hier
1
  highbyte = (samplesize/comparechange)<<8;                          // Highbyte der Variable Stepsizemax
2
  if(samplesize%comparechange>1)                                // Bedingung, nach Schrittweite
3
  {
4
    lowbyte1 = (samplesize%comparechange*100/comparechange);
5
  }
6
  else
7
  {
8
    lowbyte1 = (samplesize*100/comparechange);
9
  }
10
  lowbyte0 =((lowbyte1/10)<<4) | (lowbyte1%10);                        // Zusammensetzen des Lowbytes der stepsizemax Variable
11
  stepsizemax = highbyte|lowbyte0;

erscheint mir zb reichlich suspekt.
Was immer auch hier ausgerechnet wird, das lässt sich doch sicherlich 
auch einfacher berechnen.

von Peter A. (elkopeter)


Lesenswert?

Martin Kreiner schrieb:
> Um die ISR abzuarbeiten werden schon mal mindesten 186 Mikrosekunden
> gebraucht. Da beißt sich was.

Wie kommst du jetzt konkret auf die 186 Mikrosekunden?
In der ISR werden lediglich meine Comparewerte inkrementiert.
Mein Timer braucht 138us je Durchlauf meiner Werte. Die ISR selbst kann 
nicht solange brauchen.

von Martin K. (maart)


Lesenswert?

Peter A. schrieb:

> In der ISR werden lediglich meine Comparewerte inkrementiert.
> Mein Timer braucht 138us je Durchlauf meiner Werte. Die ISR selbst kann
> nicht solange brauchen.

Nun ja, wenn du meinst.....
1
if((stepsizecnt/10000)<(stepsizemax))
Alleine diese in deinen Augen vielleicht lächerliche Abfrage verheizt 
schon mal 163 Mikrosekunden.

> Wie kommst du jetzt konkret auf die 186 Mikrosekunden?

Für soetwas ist der eingebaute Simulator perfekt.

von Peter A. (elkopeter)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Der Teil hier

> erscheint mir zb reichlich suspekt.
> Was immer auch hier ausgerechnet wird, das lässt sich doch sicherlich
> auch einfacher berechnen.

Hier wird meine maximale Schrittweite ausgerechnet. Also konkret der 
Index meiner samples-Werte.
Bsp.: f_pwm = 7200, samples=256-Werte, fout=50:
Schrittweite-Indizes=256/comparechange=3,55555555...
Als Schrittweite definiere ich dann 0x0355.

Aber das Ganze wird nur einmal beim start abgearbeitet und sollte nicht 
das Problem darstellen.

von Peter A. (elkopeter)


Lesenswert?

Martin Kreiner schrieb:
> Nun ja, wenn du meinst.....
1
if((stepsizecnt/10000)<(stepsizemax))
> Alleine diese in deinen Augen vielleicht lächerliche Abfrage verheizt
> schon mal 163 Mikrosekunden.

Ok also ist die 32Bit-Berechnung wohl das Problem. Sind wohl zuviele 
Speicherzugriffe.
Hmm gibt´s da eine sinnvolle alternative? Bitschieberoperanden 
verwenden?

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Peter A. schrieb:

> Bsp.: f_pwm = 7200, samples=256-Werte, fout=50:
> Schrittweite-Indizes=256/comparechange=3,55555555...
> Als Schrittweite definiere ich dann 0x0355.
>
> Aber das Ganze wird nur einmal beim start abgearbeitet und sollte nicht
> das Problem darstellen.

Wenn das Rechenergebnis nicht stimmt, dann ist das schon ein Problem.

> Schrittweite-Indizes=256/comparechange=3,55555555...
> Als Schrittweite definiere ich dann 0x0355.

0x?  (Halte ich jetzt mal wegen stepsizecnt/10000)<(stepsizemax für 
einen Tippfehler:-) )

Warum schreibst du dann die Berechnung nicht einfach genau so hin, 
sondern pfriemelst da mit Einzelbytes rum?

Im übrigen: 32 Bit Rechnerei in der ISR ist auch nicht so ohne.
Da könntest du dir den ganzen Aufwand auch sparen und die 
Prozentrechnerei (denn nichts anderes ist diese Frequenzzunamhe ja) auch 
in 16 Bit direkt in der ISR ausrechnen. Grob geschätzt würde sich das 
nicht um viel reissen.

: Bearbeitet durch User
von Martin K. (maart)


Lesenswert?

Um nochmal zum Anfang zu gehen:
> Leider erreiche ich die max. Schrittweite nicht, d.h. meine
> Ausgangsfrequenz ist deutlich kleiner als gewünscht.

Was meinst du damit?
Wann wäre sie denn erreicht? Wenn diese Codezeile hier ausgeführt wird:
1
else
2
  {
3
    stepsizecntx=stepsizemax;
4
  }

Diese Zeile wird zumindest im Simulator nach 2,723 Sekunden ausgeführt.

von Der (Gast)


Lesenswert?

Allgemeiner Tipp:
Am Anfang der ISR einen Pin auf High setzen und danach auf Low. Damit 
kann man Oszi schön sehen, wann die ISR real aufgerufen wird und wie 
lange sie braucht. Man muss etwas Reserve für die PUSHs am Anfang und 
POPs am Ende rechnen.

von Peter A. (elkopeter)


Lesenswert?

Danke für die vielen Antworten.
Ich komm heut leider nicht mehr dazu das Programm abzuändern.
Aber ich bin mir ziemlich sicher, dass ich irgendwo, wie Herr Buchegger 
bereits erwähnt hat, einen Rechenfehler im Code habe.
Von den 32-Bit Multiplikationen muss ich auch weg. Das kostet zuviel 
Zeit.

Das mit 0x war kein Tippfehler, ich habe mich da von jemand anderem 
Einlullen lassen die Nachkommastellen meiner Indexschrittweite in das 
untere Byte meiner Variable zu schreiben. Das soll den Rundungsfehler 
verkleinern. Von der korrekten Schrittweite ist das aber bei kleinen 
Frequenzen meilenweit entfernt.

von Peter A. (elkopeter)


Lesenswert?

Martin Kreiner schrieb:

> Was meinst du damit?
> Wann wäre sie denn erreicht? Wenn diese Codezeile hier ausgeführt
> wird:else
>   {
>     stepsizecntx=stepsizemax;
>   }
>
> Diese Zeile wird zumindest im Simulator nach 2,723 Sekunden ausgeführt.

Ja korrekt.

von Peter A. (elkopeter)


Angehängte Dateien:

Lesenswert?

Ich scheine die Probleme in den Griff bekommen zu haben.
Der Code ist jetzt deutlich einfacher. Statt multiplikation/division 
verwende ich jetzt Schieberegister. Ich werde das Ganze jetzt mal am 
Oszi begutachten, ob ich denn wirklich alles gelöst habe.

Anbei die Bilder bei einem Hochlauf auf 100Hz.

: Bearbeitet durch User
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.