Und hier hat sich jemand ausgiebig mit dem Timing von WS2812 und Co auseinadergesetzt.
MfG Klebwax
Druckbare Version
Und hier hat sich jemand ausgiebig mit dem Timing von WS2812 und Co auseinadergesetzt.
MfG Klebwax
Da in diesem Fall keine gleichzeitige Ansteuerung der vier Stripes nötig ist, die Stripes mit nur drei LEDs sehr kurz und die Schaltfolgen wenig komplex sind, sollte es jede Library tun, mit der du vier verschiedene Pins in wechselnder Folge ansteuern kannst. Wenn du vier lange Stripes "gleichzeitig" mit komplexeren Mustern ansteuern wolltest, wäre das sicher schwieriger und du müsstest die Libraries sorgfältiger unter die Lupe nehmen.
Grundsätzlich erst mal kann der ESP meines Wissens kein Hardware-PWM - das ist alles nur Software-PWM. Letztlich stößt man hinischtlich der Anzahl Kanäle, Frequenz und Auflösung relativ bald an Grenzen. Wie weit PWM hier überhaupt relevant ist, ist ne andere Frage...
@Ceos: Wo ist der Zusammenhang zwischen PWM und WS2812? Der WS wird ja nicht mit PWM angesteuert. Da der ESP sowieso nur SoftPWM kann, erscheint es mir sinnlos, eine Lib auf SoftPWm aufzusetzuen. Die Libs sind, wenn ich das nicht völlig falsch einschätze, doch eher mit Timer-Interrupts programmiert. (Wobei SoftPWM letztlich auch nichts anderes ist als ein Timer Interrupt.) Am Ende läuft das doch eh auf Bitbanging und Timer hinaus, weil es für das Timing des WS2812-Protokolls keine Hardware-Schnittstelle gibt. (Würde mich mal interessieren, wie die eine oben genannte Library die UART-Schnittstelle für den WS-Chip zurechtbiegt...) Ich würde die Begriffe (Hard/Soft)-PWM, Timer und Bitbanging hier jedenfalls nicht so leichtfertig nebeneinander benutzen.
@Klebwax danke für den Hinweis, habe ich in meinem weiter oben ligeenden Post schon erwähnt dass es ihn wohl nicht betrifft es aber trotzdem Einschränkungen gibt, ich wollte hier nur mal einen aus dem Nähkästchen holen um die Grenzen mal zu benennen ... das war einfach nur weiterführend gemeint, falls jemand von 12 LEDs auf 120LEDs hochrüstet und dann hier ein einfaches "Ja geht!" hinein interpretiert
@Gnom67 ich habe einige durchaus funktionierende Implementationen aus (hardware)PWM Ausgängen mit DMA gefunden, bei denen der Timer für jeden bit-Puls per DMA bespielt wird um die nachfolgende Pulsbreite zu variieren für 0 oder 1 ... aber dafür braucht man hohe Basis Taktraten
und zu deiner Frage über UART/SPI habe ich es auch mal selber gebastelt. Du nimmst einfach eine Busfrequenz von 4x800kHz und codierst eine 0 mit binär 0b1000 und eine 1 mit binär 0b1110, bei UART und SPI bekommst du dann einen langen oder kurzen Puls jeweils heraus der gerade so in die Toleranz passt
In der Tat natürlich naheliegend, die Pulsbreite vom PWM machen zu lassen, statt sich ein zweites Timersignal für die zweite Flanke aufzuhalsen. Richtig sinnvoll wird das allerdings erst mit Hardware-PWM. Ein Soft-PWM wird letztlich auch nichts anderes machen, als die Timerabstände entsprechend den duty cycles zu variieren und somit abwechselnd lange Timerzeiten einzustellen.
Mit DMA meinst du sicher, dass die Timergrenzen im Speicher direkt manipuliert werden und nicht über die Funktionen der Library. Das ist wohl auch geboten. Trotzdem wäre es meiner Meinung nach performanter, die Timer gleich in der WS-Lib zu programmieren, als auf eine Soft-PWM-Lib aufzusetzen. Sicher gibts auch verschiedene Libs die es mal so oder mal so machen... Wäre sicher interessant, welche die beste Performance hat.
UART hab ich mir auch genau so vorgestellt, wie du es beschreibst. Etwas rückwärts durch die Brust ins Auge..., aber immerhin nimmt einem dann die Hardware die Arbeit ab - aber wenn nur zwei Pins alternativ zuweisbar sind, ist das hier leider keine Lösung.
nein nein, soft pwm habe ich nie gemeint :) da musst du mich falsch verstanden haben XD
bitbagn mit DMA war hier auf eine etwas kuriose ausnutzung des DMA bezogen, ich glaube dabei wurde die UART und der DMA mit 2 konfigurationen missbraucht und abhängig von dem nächsten bit der eine oder andere wert geladen um das passende bit zu produzieren, aber das ist länger her XD ich bin ein APA jünger geworden :P
Für was steht denn DMA? Da denk ich an direct memory access?
Und was anderes als SoftPWM kann der ESP nicht. Auf was beziehst du dich also?
Hier geht es um Zeiten von 350ns für ein 0-Bit bzw. 700ns für ein 1-Bit. Da geht auf den üblichen µC mit Timern gar nichts. Auch die üblichen HW-PWMs kriegen einen 800kHz PWM-Takt nicht hin. Auf einem PIC16 mit 8MHz Befehlstakt hab ich das so gelöst:
Ich bin hier davon ausgegangen, daß, wie im Link oben gesagt, die Low-Zeit des Signals nicht so wichtig ist. Bisher hat das auch mit allen meinen WS geklappt. Das Ganze muß mit gesperrten Interrupten laufen. Entsprechendes sollte man auf jedem µC hinkriegen. Für viele Pixel mit hoher Framerate taugt das natürlich nicht, aber 4 mal für drei Pixel wird das kein Problem sein.Code:#define NEOPIX LATCbits.LATC4
void SetPIX(uint8_t red, uint8_t green, uint8_t blue) {
uint8_t colorbit;
for (colorbit = 8; colorbit; colorbit--) {
if (green & 0x80) {
NEOPIX = 1;
NEOPIX = 1;
NEOPIX = 1;
NEOPIX = 1;
} else {
NEOPIX = 1;
NEOPIX = 1;
NEOPIX = 0; // !
NEOPIX = 0; // !
}
NEOPIX = 0;
green <<= 1;
}
for (colorbit = 8; colorbit; colorbit--) {
if (red & 0x80) {
NEOPIX = 1;
NEOPIX = 1;
NEOPIX = 1;
NEOPIX = 1;
} else {
NEOPIX = 1;
NEOPIX = 1;
NEOPIX = 0;
NEOPIX = 0;
}
NEOPIX = 0;
red <<= 1;
}
for (colorbit = 8; colorbit; colorbit--) {
if (blue & 0x80) {
NEOPIX = 1;
NEOPIX = 1;
NEOPIX = 1;
NEOPIX = 1;
} else {
NEOPIX = 1;
NEOPIX = 1;
NEOPIX = 0;
NEOPIX = 0;
}
NEOPIX = 0;
blue <<= 1;
}
}
MfG Klebwax
Was spräche denn dagegen, mit "Adafruit_NeoPixel" mehrere Instanzen zu erstellen. Jede mit ihrem eigenen Pin?
(Leider kann ich das nicht ausprobieren.)
MfG
Das stimmt natürlich - bei 8 MHz ist ja ein einziger Zählschritt schon 125 ns lang - da gibts nicht viel zu PWMen... umso weniger versteh ich, warum hier dauernd von PWM die Rede ist.
Die Port-Bits direkt im Prozessortakt mit Befehlen anzusprechen, ist natürlich schneller.
Beim WS2812B ist die Zykluszeit 1250 ns (900 ns high + 350 ns low für 1 und 350 ns high + 900 ns low für 0) - das entspräche 10 Prozessortakten. In deinem Code hätte ich jetzt jeweils 10 Befehle erwartet, die das Portbit auf 1,1,1,1,1,1,1,0,0,0 oder 1,1,1,0,0,0,0,0,0,0 setzen. Stattdessen seh ich nur 1,1,1,1 und 1,1,0,0.
Wird der Pin für die restliche Zeit, die durch Schleifen und Bedingungen verbraucht wird auf 0 gehalten?
Etwas mehr zeit hat man ja - laut Datenblatt bis zu 50 µs Low-Time, bevor ein Reset ausgelöst wird. In meinem Link oben hat das jemand getestet und bekam den Reset bei knapp 9 µs. Na, immerhin sind das ja einige Taktzyklen.
Wie machen das denn die Libraries? Wenn die alle mit solchem Bitgeschubse arbeiten, kann das eigentlich mit einem µC nicht wirklich sauber laufen, oder?
- - - Aktualisiert - - -
Das würd ich auch probieren. Undfalls sie sich in die Quere kommen, kann man sie ja auch immer wieder löschen und für den gewünschten Pin neu erstellen...
Lies erstmal das hier: Neopixel Timing. Und der Code ist aus einem Projekt von mir kopiert, er funktioniert.
Statt 1-1-0-0 und einem 0 am Ende hätte ich auch 1-NOP-0-NOP- NOP schreiben können. Dauert genausolange. Ich fand aber so ist es übersichtlicher. Mit dem Timing, der Anzahl der Takte habe ich mit dem LA und dem Neopixel rumgespielt. Mit drei Takten High für eine Null gehts auch noch, mit nur einem nicht. Hab mich als Kompromiss für 2 entschieden. Die Low-Zeit ist nach Datenblatt zu lang (Shift und Loop), wie im Link beschrieben passt das aber. Und natürlich bleibt ein Portbit so stehen, wie es war.
Der Code in meinem Link macht das ähnlich. Der benutzt ein Macro fürs Timing, der am Ende auch nichts anderes macht, als NOPs einzufügen. Und der Code sieht auch nicht viel anders aus, wenn man I2C, SPI oder Uart mit Bitbanging macht. Alles was schneller als 20-30µs ist, ist für einen Interrupt auf den 8-Bittern zu schnell. Und selbstverständlich kann das so sauber laufen. Code ist deterministisch.Zitat:
Wie machen das denn die Libraries? Wenn die alle mit solchem Bitgeschubse arbeiten, kann das eigentlich mit einem µC nicht wirklich sauber laufen, oder?
MfG Klebwax