WS2812 DEMO

China quillt über mit neuen Ideen und innovativer Hardware mit sehr günstigen Preisen. Die Dokumentationen dazu sind sehr oft mehr als dürftig.

Ein interessanter Baustein ist der WS2812 (Internet Suchbegriff ws2812 kaufen), der in das Gehäuse mit drei LED eingebaut ist. Leider gibt das Datenblatt von WorldSemi nicht viel her und verwendet irreführende Begriffe. Damit ist eine Ansteuer-Software nicht realisierbar.

Der WS2812 verfügt über drei Anschlüsse 5 V, Gnd und die Datenleitung Din. Die Datenleitung Din wird nach der nachstehenden Abbildung getaktet. Die Taktlänge sollte 800 ns nicht unterschreiten. Der Takt wird mit der positiven Flanke gestartet. Diese aktiviert das interne RC-Glied des WS2812 mit einer Zeitdauer von ca. 475 ns. Nach Ablauf dieser Zeit wird der Pegel auf der Datenleitung Din im WS2812 in einem temporären 24bit-Schieberegister abgelegt. Zur Übertragung einer 0 muss also Din noch vor Ablauf der 475 ns an Masse gelegt werden, für eine 1 muss diese Zeit überschritten werden. Danach wird das nächste Bit gesendet. Die Zeit zwischen zwei Bit kann durchaus etwas länger sein, da der nächste Schreibvorgang wieder mit einer positiven Flanke gestartet wird. Pro LED müssen 24 Bit gesendet werden in der Reihenfolge GRB (grün, rot, blau) mit dem MSB zuerst.

Timing des WS2812

Die Zeiten in der Abbildung sind die Ergebnisse der nachfolgenden Software-Tests. Beachten Sie bei eigenen Anwendungen, dass es mittlerweile einige Variationen des Cips gibt und das Timing leicht anders sein kann.

Die Pause zwischen 2 Bit sollte allerdings nicht zu lange sein (kürzer als 8 µs = 8000 ns), da sonst der Inhalt des temporären 24bit-Schieberegisters vom PWM (Pulsweitenmodulator) des WS2812 übernommen wird. Nach der Aufnahme von 24 Bit wird das Schieberegister blockiert und alle weiteren eingehende Daten werden konditioniert an den Ausgang Dout weitergegeben. Damit kann die nächste LED (mit anderen Daten) beschrieben werden usw. Auf diese Weise können beliebig lange Ketten von LED mit eigenen Daten versorgt werden. Die Übernahme der Daten für alle LED erfolgt erst mit einem längeren Low-Pegel auf der Datenleitung (> 50 µs, aber auch 9 µs können schon reichen). Der Hersteller nennt diese Phase irreführend RESET. Ein Reset ist ein Rücksetzen des Bausteins auf die Einschaltwerte, was hier eben nicht erfolgt. Als Einschaltwerte weist der WS2812 nur Nullen auf, damit sind alle LED abgeschaltet. Diese Phase sollte als Trigger oder Clock oder sonst wie bezeichnet werden, aber nicht als Reset!

Der High-Pegel zum Schreiben einer Null ist maximal 450 ns, der High-Pegel zum Schreiben einer Eins ist größer/gleich 500 ns. Im Test konnte die nächste Bit-Ausgabe bereits nach 800 ns erfolgen. Das sind für manche Controller kurze Zeiten, muss aber so sein, damit auch bei langen LED-Ketten schnell dynamische Effekte erzielt werden können.

Für eine Kette mit 60 LED werden 60 x 24 = 1440 Bit = 180 Byte benötigt, wenn man sie individuell ansteuern möchte. Das dauert 8 x 800 ns + 400 ns = 6800 ns pro Byte (vgl. nachstehendes Programm). Für 180 Byte ist die Zeit 180 x 6,8 µs = 1224 µs = 1,224 ms = 0,001224 s entspricht 817 Hz Wiederholrate, schnell genug für ein flimmerfreies Erlebnis.

AT89LP4052 Software

Die nachstehende Realisierung benutzt den AT89LP4052, der mit 20 MHz getaktet wird und somit einen Clock Cycle von 50 ns aufweist. Das Beispiel beschreibt drei LED mit den Werten aus einer Tabelle. Diese Werte werden zuvor in das RAM kopiert (um sie später modifizieren zu können) und von dort an die drei LED gesendet.

Programm
#cpu = 89LP4052
#Bit Dout = P1.0
#Const Datalen = 9
; @20 MHz T = 0,00000005s = 50ns = 1 Clock Cycle
clr Dout
P1M0 = #FEh: P1M1 = #01h
acall Tabelle kopieren
; nach Reset sind Eingäng Input only
; P1.0: Output: Push.Pull, Rest Input only
; Timing
; 0: 350:450ns 1: 500:300ns
; 0: ----______ 1: --------___
; Start
r0 = #30h
for r3 = #Datalen
; sendet 9 Byte für 3 LED
a = @r0: inc r0
for r2 = #8
; (150 ns), Byte holen
; (100 ns)
setb Dout
nop
if not bit acc.7 then
; 0, 100 ns
; 1, 50 ns
; 2, 200 ns
clr Dout ; 3, 100 ns, 0: Zeit 350 ns
else ; 4, 150 ns
nop: nop: nop
clr Dout
; 5, 150 ns
; 6, 100 ns, 1: Zeit 500 ns
end if
rl a

; 7, 50 ns
next ; 8, 150 ns
next
end
; (150 ns)
; Zeiten in ns
; 0: 1+2+3+4+7+8+0: 50 + 200 + 100 (350) + 150 + 50 + 150 + 100 = 800 ns
; 1: 1+2+5+6+7+8+0: 50 + 200 + 150 + 100 (500) + 50 + 150 + 100 = 800 ns
; additional time after each byte = 150 + 150 + 100 = 400 ns, no problem
Tabelle kopieren: ; kopiert Tabelle nach 30h bis 38h im IRAM
r0 = #30h + Datalen - 1
for r2 = #Datalen: a = r2: add a, #Tabelle - hier - 4: movc a, @a+pc: @r0 = a: dec r0: next
ret
Tabelle:
DB 10h, 0, 0, 0, 10h, 0, 0, 0, 10h ; für drei LED

Die Software schreibt das betreffende Byte in den Akku (a = @r0) und testet nur Bit 7 (if not bit acc.7). Danach wird der Inhalt nach links rotiert (rl a), das geschieht 8 mal (for r2 = #8). Danach wird das nächste Byte geholt (inc r0). Nach dem Start leuchtet die erste LED grün, die zweite rot, die dritte blau. Wenn Sie zum Testen nur eine LED beschreiben möchten, schreiben Sie for r3 = #3.

Die vorstehende Software läuft in gleicher Weise auch auf dem AT89LP51ED2 im X2 Modus, der große Bruder vom 4052.

AT89S8253 Software

Die nachstehende Realisierung benutzt den AT89S8253, der mit 24 MHz im X2 Modus getaktet wird und somit einen Clock Cycle von 250 ns aufweist. Er ist also 5mal langsamer als der AT89LP4052. Das folgende Beispiel beschreibt drei LED mit den Werten aus einer Tabelle. Diese Werte werden zuvor in das RAM kopiert (um sie später modifizieren zu können) und von dort an die drei LED gesendet.

Programm
#cpu = 89S8253
#Bit Dout = P1.0
#Const Datalen = 9
; @24 MHz T = 0,00000025s = 250ns = 1 Clock Cycle
clr Dout
inc AUXR: inc CLKREG
for r2: next
acall Tabelle kopieren
; ALE abschalten, X2-Modus wählen
; nach Reset ist Dout high, daher
; t(low) > 50 µs
; Start
r0 = #30h
for r3 = #Datalen
; 30h ist die Startadresse der Tabelle.
; sendet 9 Byte für 3 LED
a = @r0: inc r0
for r2 = #8
; (500 ns), Byte holen
; (500 ns)
rlc a
if not bit c then
; 7, 250 ns
; 8, 250 ns
setb Dout
clr Dout
; 0, 250 ns, 0 Start
; 1, 250 ns, Null Zeit 250 ns
else ; 2, 250 ns
setb Dout
nop
clr Dout
; 3, 250 ns, 1 Start
; 4, 250 ns
; 5, 250 ns, Eins
end if
next ; 6, 500 ns
next
end
; (500 ns)
; Zeiten in ns
; 0: 1+2+6+7+8+0 = 250 (=250) + 250 + 500 + 250 + 500 + 250 = 2000 ns
; 1. 4+5+6+7+8+3 = 250 + 250 (=500) + 500 + 250 + 500 + 250 = 2000 ns
; additional time after each byte = 500 + 500 + 500 = 1500 ns, no problem
Tabelle kopieren: ; kopiert Tabelle nach 30h bis 38h im IRAM
r0 = #30h + Datalen - 1
for r2 = #Datalen: a = r2: add a, #Tabelle - hier - 4: movc a, @a+pc: @r0 = a: dec r0: next
ret
Tabelle:
DB 0, 6, 0, 10h, 0, 0, 0, 0, 10h ; für drei LED grün rot blau

Der Write Cycle pro Bit beträgt hier 2000 ns. Ein zusätzliches NOP zwischen den Zeilen 0 und 1, also zwischen setb Dout und clr Dout verlängert die Zeit des High-Pegels von 250 ns auf 500 ns. Das wird vom WS2812 nicht mehr als Null, sondern bereits als eine Eins erkannt.