Hardware-Encoder für NeoPixel (WS2812)/Einleitung: Unterschied zwischen den Versionen
Admin (Diskussion | Beiträge) (Die Seite wurde neu angelegt: „Zurück zum Inhaltsverzeichnis | Projekt:Hardware-Encoder für NeoPixel (WS2812)/Hardware| Weiter zu Hard…“) |
Keine Bearbeitungszusammenfassung |
||
(8 dazwischenliegende Versionen von 2 Benutzern werden nicht angezeigt) | |||
Zeile 1: | Zeile 1: | ||
[[ | [[Hardware-Encoder für NeoPixel (WS2812)|Zurück zum Inhaltsverzeichnis]] | [[Hardware-Encoder für NeoPixel (WS2812)/Hardware| Weiter zu Hardware ->]] | ||
== Das Grobkonzept == | == Das Grobkonzept == | ||
Wir | Wir schreiben einen WS2812-Encoder-Modul, statten es mit einem UART und einer SPI-Schnittstelle aus und verbinden das Ganze über einen kleinen Steuerautomaten. Daraus erzeugen wir eine Konfiguration für ein FPGA und sind fertig. Soweit die Theorie... | ||
[[Datei:WS_Encoder_top.png|right|thumb]] | |||
=== Wofür das Ganze? === | === Wofür das Ganze? === | ||
Wozu nun dieser Aufwand, es gibt doch bereits fertige Software-Bibliotheken? | Wozu nun dieser Aufwand, es gibt doch bereits fertige Software-Bibliotheken? | ||
* | |||
'''Nachteile von Softwarelösungen:''' | |||
* | * Die Timings des WS-Protokolls sind sehr eng und dadurch schwierig auf einem Mikrocontroller einzuhalten. | ||
* Timer mit entsprechenden Routinen sind bereits zu ungenau bzw. | * Wegen der Timings können keine Interrupts während der Ausgabe auf die LEDs benutzt werden. | ||
* Hardware-Timer mit entsprechenden Routinen sind bereits zu ungenau bzw. zu langsam (durch Overhead). | |||
'''Vorteile der Hardwarelösung:''' | |||
* Das Protokoll ist nicht sehr kompliziert, dadurch hat man ein relativ gut durchschaubares Beispiel für die Beschäftigung mit VHDL. | |||
* Die Verwendung von Hardware-Schnittstellen wie SPI oder UART kann Interrupt-gesteuert ablaufen. | * Die Verwendung von Hardware-Schnittstellen wie SPI oder UART kann Interrupt-gesteuert ablaufen. | ||
* Je nach Controller auch unter Verwendung von DMA. | * Je nach Controller auch unter Verwendung von DMA. | ||
Zeile 15: | Zeile 21: | ||
== Der LED-Controller == | == Der LED-Controller == | ||
Wie arbeitet dieser ominöse WS2812 jetzt eigentlich? Der WS2812 steuert eine RGB-LED an und zwar mit 8 Bit pro Farbe bzw. 24 Bit Farbtiefe pro LED. Die Reihenfolge der Farbbytes unterscheidet sich dabei vom gewohnten RGB: Die LEDs erwarten ein GRB-Format, also erst das Byte für Grün, dann Rot und zum Schluss Blau. Das | Wie arbeitet dieser ominöse WS2812 jetzt eigentlich? Der WS2812 steuert eine RGB-LED an und zwar mit 8 Bit pro Farbe bzw. 24 Bit Farbtiefe pro LED. Die Reihenfolge der Farbbytes unterscheidet sich dabei vom gewohnten RGB: Die LEDs erwarten ein GRB-Format, also erst das Byte für Grün, dann Rot und zum Schluss Blau. Das höchstwertige Bit wird zuerst übertragen. | ||
Wenn mehrere NeoPixel hintereinander geschaltet werden, übernimmt der Controller der ersten LED in der Kette die ersten 24 Bit in sein Farbregister, alle weiteren Bits gibt er über seinen Datenausgang an den nächsten Pixel weiter. Angezeigt werden die Farben jedoch erst nach einem RESET-Signal. | Wenn mehrere NeoPixel hintereinander geschaltet werden, übernimmt der Controller der ersten LED in der Kette die ersten 24 Bit in sein Farbregister, alle weiteren Bits gibt er über seinen Datenausgang an den nächsten Pixel weiter. Angezeigt werden die Farben jedoch erst nach einem RESET-Signal. | ||
Zeile 47: | Zeile 53: | ||
Mit eingesetzten Werten: | Mit eingesetzten Werten: | ||
* (16700µs - 50µs) / 30µs = 555 LEDs | * (16700µs - 50µs) / 30µs = 555 LEDs | ||
Die nächstkleinere Zweierpotenz wären 512 LEDs. Halten wir also fest: Mit 512 LEDs erreichen wir unsere 60 FPS, 1024 LEDs können wir immer noch mit 30 FPS ansteuern. Zum Vergleich: Die gängigen LED-Streifen auf Rolle haben 30 oder 60 LEDs / Meter, das wären dann 150 bzw. 300 LEDs pro 5m-Rolle. | Die nächstkleinere Zweierpotenz wären 512 LEDs. Halten wir also fest: Mit 512 LEDs erreichen wir unsere 60 FPS, 1024 LEDs können wir immer noch mit 30 FPS ansteuern. Zum Vergleich: Die gängigen LED-Streifen auf Rolle haben 30 oder 60 LEDs / Meter, das wären dann 150 bzw. 300 LEDs pro 5m-Rolle und damit ca. 17 m bzw 8,5 m gesamtlänge der Streifen. | ||
==== Bleiben noch die Timings ==== | ==== Bleiben noch die Timings ==== | ||
Zeile 67: | Zeile 73: | ||
'''Sequenz 25 50 75 100 125''' | '''Sequenz 25 50 75 100 125''' | ||
RST 1000 2000 3000 4000 5000 | RST 1000 2000 3000 4000 5000 | ||
[[Hardware-Encoder für NeoPixel (WS2812)|Zurück zum Inhaltsverzeichnis]] | [[Hardware-Encoder für NeoPixel (WS2812)/Hardware| Weiter zu Hardware ->]] | |||
[[Kategorie:Projekt]] |
Aktuelle Version vom 22. April 2023, 13:30 Uhr
Zurück zum Inhaltsverzeichnis | Weiter zu Hardware ->
Das Grobkonzept
Wir schreiben einen WS2812-Encoder-Modul, statten es mit einem UART und einer SPI-Schnittstelle aus und verbinden das Ganze über einen kleinen Steuerautomaten. Daraus erzeugen wir eine Konfiguration für ein FPGA und sind fertig. Soweit die Theorie...
Wofür das Ganze?
Wozu nun dieser Aufwand, es gibt doch bereits fertige Software-Bibliotheken?
Nachteile von Softwarelösungen:
- Die Timings des WS-Protokolls sind sehr eng und dadurch schwierig auf einem Mikrocontroller einzuhalten.
- Wegen der Timings können keine Interrupts während der Ausgabe auf die LEDs benutzt werden.
- Hardware-Timer mit entsprechenden Routinen sind bereits zu ungenau bzw. zu langsam (durch Overhead).
Vorteile der Hardwarelösung:
- Das Protokoll ist nicht sehr kompliziert, dadurch hat man ein relativ gut durchschaubares Beispiel für die Beschäftigung mit VHDL.
- Die Verwendung von Hardware-Schnittstellen wie SPI oder UART kann Interrupt-gesteuert ablaufen.
- Je nach Controller auch unter Verwendung von DMA.
- Die Entkopplung der LEDs vom Host ermöglicht, alles als Host zu benutzen, was eine serielle Schnittstelle hat: PCs, Raspberry Pi usw.
Der LED-Controller
Wie arbeitet dieser ominöse WS2812 jetzt eigentlich? Der WS2812 steuert eine RGB-LED an und zwar mit 8 Bit pro Farbe bzw. 24 Bit Farbtiefe pro LED. Die Reihenfolge der Farbbytes unterscheidet sich dabei vom gewohnten RGB: Die LEDs erwarten ein GRB-Format, also erst das Byte für Grün, dann Rot und zum Schluss Blau. Das höchstwertige Bit wird zuerst übertragen.
Wenn mehrere NeoPixel hintereinander geschaltet werden, übernimmt der Controller der ersten LED in der Kette die ersten 24 Bit in sein Farbregister, alle weiteren Bits gibt er über seinen Datenausgang an den nächsten Pixel weiter. Angezeigt werden die Farben jedoch erst nach einem RESET-Signal.
Das Übertragungsprotokoll sieht so aus: Ein Bit wird innerhalb von 1,25µs übertragen. Innerhalb dieser Zeit geht die Signalleitung für eine gewisse Zeit auf High- und anschließend auf Low-Pegel. Für ein "1"-Bit sind es 0,8µs High und 0,45µS Low, für ein "0"-Bit 0,4µs High und 0,85µs Low. Pro Phase sind bis zu 0,15µs Abweichung erlaubt. Liegt die Signalleitung für mehr als 50µs auf Low, wird das als Reset-Signal interpretiert und die übertragenen Farbwerte werden angezeigt.
Hier gibt es das ausführliche Datenblatt[1].
Takte, Timings, LEDs
Ein paar Eckdaten sind noch zu klären:
- Wie viele LEDs kann ich (sinnvoll) hintereinander schalten?
- Wie knapp sind die Timings wirklich?
Rechnen wir mal ein bisschen:
- Für flüssig erscheinende Animationen brauchen wir mindestens 24 Bilder/Sekunde. Dabei flackert es aber noch sichtbar.
- Moderne Computermonitore arbeiten mit 60 Bildern/Sekunde.
In Anlehnung an Monitore werde ich auch hier von FPS (Frames Per Second - Bilder pro Sekunde) sprechen, wenn ich vollständige Übertragungszyklen zu den NeoPixeln meine, auch wenn das vielleicht nicht ganz korrekt ist.
Die erste Frage können wir damit schon mal beantworten: Technisch gesehen können wir beliebig viele LEDs hintereinander schalten, je mehr es werden, desto niedriger wird unsere Bildrate. Interessant ist also vielmehr, wie viele LEDs bei 30 oder 60 FPS hintereinander gehängt werden können. Betrachten wir das Ganze einmal für 60 FPS:
- Wir haben für einen Durchlauf 1/60s Zeit, also 16,7ms.
- Um einen Pixel mit 24 Bit zu übertragen, brauchen wir 24 * 1,25µs = 30µs.
- Pro Durchlauf kommt noch ein Reset mit 50µs dazu.
In eine Formel gegossen könnte das so aussehen:
- T_FRAME = x * T_LED + T_RESET.
Dabei ist x die gesuchte Anzahl der LEDs, T_LED = 30µs und T_RESET = 50µs. T_FRAME = 16,7ms ist die Zeitspanne für einen Durchlauf. Umgestellt nach x erhalten wir:
- x = (T_FRAME - T_RESET) / T_LED
Mit eingesetzten Werten:
- (16700µs - 50µs) / 30µs = 555 LEDs
Die nächstkleinere Zweierpotenz wären 512 LEDs. Halten wir also fest: Mit 512 LEDs erreichen wir unsere 60 FPS, 1024 LEDs können wir immer noch mit 30 FPS ansteuern. Zum Vergleich: Die gängigen LED-Streifen auf Rolle haben 30 oder 60 LEDs / Meter, das wären dann 150 bzw. 300 LEDs pro 5m-Rolle und damit ca. 17 m bzw 8,5 m gesamtlänge der Streifen.
Bleiben noch die Timings
Wie knapp wird es denn jetzt wirklich? Nehmen wir als Beispiel einen ATMega mit 20 MHz Takt, wie er von den Arduinos bekannt ist. Diese Mikrocontroller benötigen für die meisten Befehle einen Takt, für Sprünge zwei.
- Bei 20 MHz dauert ein Takt 1 / 20.000.000 Hz = 0,000.000.050 s oder 50 ns.
- Die kürzeste Schaltdauer sind 400 ns (T0H).
- Diese Zeitspanne entspricht 400 ns / 50 ns = 8 Takten (+-3 Takte Toleranz).
- Ein ganzes Bit entspricht 25 Takten.
Das ist unter Einsatz von taktoptimiertem Assemblercode gerade noch machbar. Wenn wir mit höheren Takten arbeiten können, entspannt sich die ganze Situation ein wenig, allerdings nicht in einem Maße, als daß es uns von handoptimiertem Code erlösen würde.
20MHz 40MHz 60MHz 80MHz 100Mhz T1H 16 32 48 64 80 T1L 9 18 27 36 45 T0H 8 16 24 32 40 T0L 17 34 51 68 85 Sequenz 25 50 75 100 125 RST 1000 2000 3000 4000 5000