Forum: Mikrocontroller und Digitale Elektronik Optimierung Soft-PWM


von Joachim (Gast)


Lesenswert?

Hallo zusammen,

ich bin gerade dabei mir eine 32-Kanal Soft-PWM in C zusammen zu bauen. 
Insgesamt funktioniert der Code auch schon, aber ich hab mir dann mal 
das Assembler-Listing angeguckt und gesehen, daß da noch 
Verbesserungspotenzial ist, nur weiß ich leider nicht, wie ich das 
umsetzen kann.

Insgesamt läuft es ungefähr so, wie in dem Artikel hier zur Soft-PWM:
in der ISR einen Zähler hochzählen, und dann von jedem Kanal den 
PWM-Wert mit dem Zähler vergleichen und ein Bit setzen/löschen.

Das sieht in C (am Beispiel von nur zwei Kanälen) so aus:
1
if(IRQ_Counter < Brightness[1])    Shift_Register[0] |= 0x02;
2
if(IRQ_Counter < Brightness[2])    Shift_Register[0] |= 0x04;
3
...
und in Assembler:
1
lds r24,IRQ_Counter
2
lds r25,Brightness+1
3
cp r24,r25
4
brsh .L49
5
ori r19,lo8(2)
6
sts Shift_Register,r19
7
.L49:
8
9
lds r24,IRQ_Counter
10
lds r25,Brightness+2
11
cp r24,r25
12
brsh .L50
13
ori r19,lo8(4)
14
sts Shift_Register,r19
15
...

Insgesamt "relativ" klar. Aber man sieht ja z.B., daß jedes mal der 
ISR-Zähler in r24 kopiert wird. Es würde doch reichen, das ein einziges 
Mal zu machen.
Auch könnte man den Wert in r19 doch stehen lassen, und erst ganz zum 
Schluß ein einziges mal nach "Shift_Register" kopieren.

Aber ich frag mich, wie ich diese Dinge in mein Programm gebastelt 
kriege o_O . Oder kann man den C-Sourcecode so umstellen, daß der 
Compiler das besser hinkriegt?

Danke schonmal,

Grüße!

von m.n. (Gast)


Lesenswert?

Vielleicht als Anregung: 
http://mino-elektronik.de/AVR_PWM_64/AVR_PWM_64.htm
Die PWM wird etwas anders erzeugt. Du mußt ein bißchen lesen, um es zu 
verstehen.

von Joachim (Gast)


Lesenswert?

m.n. schrieb:
> Vielleicht als Anregung:
> http://mino-elektronik.de/AVR_PWM_64/AVR_PWM_64.htm
> Die PWM wird etwas anders erzeugt. Du mußt ein bißchen lesen, um es zu
> verstehen.

Hi und vielen Dank für die schnelle Antwort!

Das sieht wirklich interessant aus. Das ist ja in der Tat sehr ähnlich 
zu meiner Anwendung :) .

Ich werde mich mal an (Inline-)Assembler versuchen. Ich glaube auf die 
Schnelle ist das das... ähm... schnellste :P .

Danke!

von Detlef (Gast)


Lesenswert?

Sind Shift_Register und/oder IRQ_Counter zufällig global?

Dann eventuell mal sowas probieren:
1
uint8_t tmp = Global;
2
// ...Rechnen mit tmp anstatt Global
3
Global = tmp;

Also temporäre Variablen verwenden. Datentyp natürlich anpassen. avr-gcc 
optimiert Operationen mit globalen Variablen meist nicht wirklich oder 
zumindest sehr unzuverlässig.

von Carl D. (jcw2)


Lesenswert?

Detlef schrieb:
> Sind Shift_Register und/oder IRQ_Counter zufällig global?
>
> Dann eventuell mal sowas probieren:
>
>
1
uint8_t tmp = Global;
2
> // ...Rechnen mit tmp anstatt Global
3
> Global = tmp;
>
> avr-gcc optimiert Operationen mit globalen Variablen meist nicht
> wirklich oder zumindest sehr unzuverlässig.

besonders wenn "Global" als volatile deklariert ist, was man nur 
braucht, wenn Daten von ISR und Hauptprogramm gemeinsam genutzt werden.

Die lokale Variable "entfernt" dieses volatile, was kein Problem ist, 
solange es keine weitere ISR gibt und man innerhalb der beiden ISR die 
Interrupts gesperrt läst.

Noch klarer könnte man Daten, die nur die ISR benutzt, innerhalb dieser 
als "static" deklarieren. Dann kommt auch keiner von außen an so ran.

von Detlef (Gast)


Lesenswert?

Richtig, aber bei volatile sind dem Compiler auch die Hände gebunden. 
Das darf er gar nicht anders.
Trotzdem optimiert avr-gcc auch normale nicht-volatile globale und auch 
static(!) Variablen nur sehr unzuverlässig. Da kommt man oft nicht um 
temporäre Variablen herum. Einfach mal in größeren Projekten testen.

von Joachim (Gast)


Lesenswert?

Hallo nochmal,

vielen Dank für eure Antworten! Das mit den Abhängigkeiten zwischen 
Datentyp und Optimierung wußte ich nicht. Damit werde ich mal ein wenig 
herumexperimentieren.

@Detlef
ja, die Variablen sind leider global. Und so, wie es im Moment ist, 
komme ich da auch nicht drum herum, weil mit den VAriablen außerhalb der 
ISR noch was gemacht wird, was zu zeitfressend ist, als daß ic es mit in 
die IRS packen wollen könnte/möchte.

Ich hab das Ganze jetzt nochmal als Inline-Assembler aufgezogen. Von 
Prinzip her kommt es mir jetzt etwas sinnvoll vor, aber testen konnte 
ich es noch nicht X( . Ich gebe auf jeden Fall Rückmeldung, wie's läuft, 
wenn's läuft.

Danke nochmal!

von Stefan K. (stefan64)


Lesenswert?

Wenn Deine PWM Deinen mc so stark belastet, daß Du optimieren musst, 
würde ich erst einmal den verwendeten Algorithmus unter die Lupe nehmen.

Statt <PWM-Auflösung> mal Interrupts mit jeweils 32 Vergleichen kannst 
Du auch mit zwei vorberechneten Tabellen[32] mit Timer-Offsets und 
Port-Outputs arbeiten. Das braucht mehr RAM für die Tabellen, ist aber 
um Größenordnungen schneller: In einem IRQ gibst Du dann nur den 
nächsten Timer-Offset und 4 Werte auf die PWM-8Bit-Ports aus.

Weiterer Vorteil: mit steigender PWM-Auflösung musst Du mit keiner 
zusätzlichen Rechenzeit rechnen.

Gruß, Stefan

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.