Forum: Mikrocontroller und Digitale Elektronik WS2811 Lib (optimierungen)


von Tobias N. (silberkristall)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe mir mal eine WS2811 Library geschrieben. Nunja, diese verstehe 
ich wenigstens. Klappen tut auch alles soweit aber ich würde diese noch 
ein wenig optimieren.

Mir geht es hautpsächlich darum das man das ganze noch mit der Frequenz 
machen kann. Also anhand der F_CPU.

Mit der berrechnung habe ich leider noch nicht soviele erfahrungen.

Derzeit habe ich das Fix auf 8Mhz erstellt. Ein Takt dauert demnach 
125ns aber wenn ich nun berechne z.b.

takttime = (((1 / F_CPU) * 1000) * 1000) * 1000

dann habe ich in takttime die taktzeit, bei 8Mhz also 125ns, aber wie 
geht es dann weiter?

Wenn ich das wiederrum mit einer berrechne und das wiederrum durch eine 
Schleife laufen lasse habe ich ja wieder ein timing problem was 
angepasst werden muss.

Ich hoffe ihr könnt mir da weiter helfen.

von Tobias N. (silberkristall)


Lesenswert?

Habe mal was angepasst.

ws2811.h
1
int takttime = (((1 / F_CPU) * 1000) * 1000) * 1000;
2
3
int onehightakte = (1250 / takttime) - 1;
4
int onelowtakte =  (1250 / takttime) - 1;
5
int zerohightakte = (500 / takttime) - 1;
6
int zerolowtakte = (2000 / takttime) - 1;
ws2811.c
1
void wswrite_zero(void)
2
{
3
  // 500ns +- 150ns high
4
  WSPORT |= (1<<WSPIN); // 125ns
5
  for (int i=0; i<zerohightakte; i++)
6
  {
7
    nop();
8
  }
9
  // 2000ns +- 150ns low
10
  WSPORT &= ~(1<<WSPIN); // 125ns
11
  for (int i=0; i<zerolowtakte; i++)
12
  {
13
    nop();
14
  }
15
16
}
17
18
void wswrite_one(void)
19
{
20
  // 1200ns +- 150ns high
21
  WSPORT |= (1<<WSPIN); // 125ns
22
  for (int i=0; i<onehightakte; i++)
23
  {
24
    nop();
25
  }
26
  // 1300ns +- 150ns low
27
  WSPORT &= ~(1<<WSPIN); // 125ns
28
  for (int i=0; i<onelowtakte; i++)
29
  {
30
    nop();
31
  }
32
}

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Tobias N. schrieb:
> Habe mal was angepasst.
>
> ws2811.h
>
1
> int takttime = (((1 / F_CPU) * 1000) * 1000) * 1000;
2
> 
3
> int onehightakte = (1250 / takttime) - 1;
4
> int onelowtakte =  (1250 / takttime) - 1;
5
> int zerohightakte = (500 / takttime) - 1;
6
> int zerolowtakte = (2000 / takttime) - 1;
7
>

Da dieses Werte alle konstant sind, rate ich Dir, sie mit 
Preprocessor-Konstanten zu erschlagen. Dann kann die Berechnung durch 
den Compiler erfolgen und muß nicht mühselig vom µC erledigt werden.

Also:
1
#define TAKTTIME (((1 / F_CPU) * 1000) * 1000) * 1000

bzw. kürzer:
1
#define TAKTTIME (1000000000UL / F_CPU)

Rest:
1
#define ONEHIGHTAKTE  ((1250 / TAKTTIME) - 1)
2
#define ONELOWTAKTE   ((1250 / TAKTTIME) - 1)
3
#define ZEROHIGHTAKTE (( 500 / TAKTTIME) - 1)
4
#define ZEROLOWTAKTE  ((2000 / TAKTTIME) - 1)

Dieser Mischmasch aus deutsch und Englisch sieht aber schon irgendwie 
beknackt aus, oder? ;-)

Was meinst Du, was der Compiler daraus macht:
1
> for (int i=0; i<onelowtakte; i++)
2
> {
3
>     nop();
4
> }

Neben Initialisierung und ständigem Vergleich mit einer Variablen bzw. 
einem festen Wert auch noch "nebenbei" mal ein NOP. Deine Schleifen 
verbrauchen ein Vielfaches!

Mein Tipp: Benutze besser _delay_us(), das kann das wesentlich besser. 
Damit kannst Du dann Deine ganze Taktberechnungen bzw. Schleifen wieder 
rausschmeissen.

: Bearbeitet durch Moderator
von Tobias N. (silberkristall)


Lesenswert?

Hallo,

cool, danke :)

Ja sieht schon ein wenig komisch aus :) Kann man ja noch ändern g

Jetzt muss ich noch noch das Timing der Schleifen anpassen, richtig?

Und ggf. wenn eine "krumme" zahl raus kommt anpassen, richtig?

von Tobias N. (silberkristall)


Lesenswert?

_delay_us() bringt mir nichts da ich das ganze ja im NS bereich brauche.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Tobias N. schrieb:
> Ja sieht schon ein wenig komisch aus :) Kann man ja noch ändern *g*

Solltest Du auch, wenn Du es nochmal brauchst. Aber Du brauchst die 
Dinger gar nicht, s.u.

> Jetzt muss ich noch noch das Timing der Schleifen anpassen, richtig?

Schmeiss die Schleifen raus und ersetze sie durch delay_us (), also:
1
...
2
#include <util/delay.h>        // einfügen! Hier muss F_CPU bekannt sein!
3
...
4
void wswrite_zero(void)
5
{
6
  // 500ns +- 150ns high
7
  WSPORT |= (1<<WSPIN); // 125ns
8
  _delay_us (500);
9
10
  // 2000ns +- 150ns low
11
  WSPORT &= ~(1<<WSPIN); // 125ns
12
  _delay_us (2000);
13
}
14
15
void wswrite_one(void)
16
{
17
  // 1200ns +- 150ns high
18
  WSPORT |= (1<<WSPIN); // 125ns
19
  _delay_us (1200);
20
21
  // 1300ns +- 150ns low
22
  WSPORT &= ~(1<<WSPIN); // 125ns
23
  _delay_us (1300);
24
}

Dann kannst Du Dir den ganzen Takte-Heckmeck mit den Schleifen sparen.

: Bearbeitet durch Moderator
von wurg (Gast)


Lesenswert?

och nö. so funktioniert c nicht. eine hochsprache ist einfach nicht 
dafür gedacht, taktzyklengenaues timing zu erzeugen.

versuche doch einen der hundert anderen ansätze hier auf dem board zu 
verstehen. da ist deine zeit besser investiert. --> wS2812

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Tobias N. schrieb:
> _delay_us() bringt mir nichts da ich das ganze ja im NS bereich brauche.

Du hast recht, mein Fehler. Sorry. Ich bin erstaunt, dass das mit den 
Schleifen überhaupt klappt.

von wurg (Gast)


Lesenswert?

meine güte, ich sehe gerade dass das bereits dein dritter thread mit 
diesem fehlgeleiteten ansatz ist...

von Tobias N. (silberkristall)


Lesenswert?

die nop(); sind ja asm. ein nop = 1 takt, 1 takt = 125ns :)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Tobias N. schrieb:
> die nop(); sind ja asm. ein nop = 1 takt, 1 takt = 125ns :)

und Dein for(...) verbraucht nichts an CPU-Takten? Wenn Dein µC 10 NOPs 
machen soll, dann macht er auch noch mindestens 10 Vergleiche (Variable 
i mit einem Wert). Und das kostet bei jedem(!) Vergleich ein Vielfaches 
eines NOPs.

Deshalb schrieb ich: Wundert mich, dass es überhaupt mit Deinen 
Schleifen funktioniert.

von Tobias N. (silberkristall)


Lesenswert?

ich hatte ja schonmal was fertiges o.O

Beitrag "Re: WS2812 Timing"

von Icke ®. (49636b65)


Lesenswert?

wurg schrieb:
> versuche doch einen der hundert anderen ansätze hier auf dem board zu
> verstehen. da ist deine zeit besser investiert. --> wS2812

Richtig. Man kann einfach die geniale, kaum noch zu verbessernde 
WS2812-LightweightLib von Tim benutzen oder das Rad eckig machen.

Beitrag "Lightweight WS2811/WS2812 Library"

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.