PIC2WS2812 Steuerung von WS2812-LEDs mit 8-Bit PIC Microcontroller
Grundlagen
PIC Lösung
Software-Module:
Basis
Patternprozessor
Patternmover
Microstep
Timer
Demo
Defines

Der Patternprozessor

Die grundsätzliche Aufgabe des Patternprozessors ist es, Daten für Leuchtmuster (= "Patterns") aus dem Speicher an einer vorgesehenen Stelle der LED-Kette erscheinen zu lassen. Darüber hinaus unterstützt er die Anwendersoftware mit Funktionen wie automatische Wiederholung von Mustern ("tiling"), Umbruch des Musters am Ende der Kette ("wrapping") oder die Nutzung vom mehreren Ebenen ("Layers"), die miteinander verknüpft werden können.

Funktionsweise

Der Patternprozessor erzeugt nacheinander für jede einzelne LED der Kette die jeweiligen Farbwerte und schreibt sie ins FIFO. Dafür wird das folgende Schema abgearbeitet:
  1. G-R-B Daten auf (0,0,0) oder auf Hintergrundfarbe setzen. 
  2. Pattern-Ebene 0 anwählen
  3. Wenn sich die LED-Nummer innerhalb des angezeigten Patterns auf dieser Ebene befindet: G-R-B Werte aus Sourcedaten lesen und je nach gewähltem Blendmode mit bisherigen G-R-B-Daten verrechnen -> G-R-B aktualisieren.
  4. Falls weitere Ebene vorhanden ist: nächst höhere Ebene wählen, zurück zu Schritt 3.
  5. G-R-B Daten ins FIFO schreiben.
Zur Darstellung benötigt der Patternprozessor zunächst natürlich die Pattern-Daten selbst, die aus einer Reihe von G-R-B Daten (je 3 Bytes für jedes Pixel) bestehen und i.d.R. im Flash-ROM abgelegt sind. Außerdem braucht er zur Verwaltung noch eine Datenstruktur, die u.A. folgende Daten enthält:
  • Zielposition (LED-Nr.), bei der das Pattern erscheinen soll (pdp_startled),
  • Anfangsadresse der Pattern-Daten im Speicher (pdp_srcstart),
  • Endadresse der Pattern-Daten im Speicher (pdp_srcend),
  • Informationen zur Darstellungsart (wrapping, tiling),
  • Farbmischung, d.h. ob und wie die Farbe des aktuellen Patterns mit dem Hintergrund bzw. der Farbmischung der darunter liegenden Ebenen verrechnet wird. 

Adresse Daten


Beispiel:

Daten eines einfachen Patterns im Speicher und Darstellung auf einem kurzen LED-Streifen.
(pdp_srcend) -> 0379 xx



0378
00

3.Pixel

0377 FF

0376 00

0375 00
2.Pixel

0374 00

0373 FF

0372 FF
1.Pixel

0371
00

(pdp_srcstart) -> 0370 00

036F xx


Fiktives Anwendungsbeispiel

Um die Anwendung des Patternprozessors zu veranschaulichen, stellen wir uns ein Beispiel vor: eine Bar-Theke soll als nette Effekt-Beleuchtung mit einem LED-Streifen umrahmt werden (Länge: ein paar Meter, sagen wir mal, es sind 500 LEDs). Im FlashROM gibt es ein Regenbogen-Farbmuster, das über eine Darstellungslänge von 50 LEDs von Violett, über Blau, Türkis, Grün, Gelb, Orange und Rot ein schönes Farbspektrum abbildet. Der ganze LED-Streifen soll als Grundfarbe dezent Himmelblau leuchten, und mittendrin soll unser Regenbogen erscheinen. Die Variablen bckgr_grn, bckgr_red, bckgr_blue werden dafür also mit den Farbwerten für unser Himmelblau geladen (z.B. 8, 6, 20). In der Pattern-Datenstruktur wird als Zielposition für den Regenbogen 300 eingetragen, um den Regenbogen auf die LEDs #300..#349 zu positionieren, und Start- und Endadresse des Regenbogen-Farbmusters im Flash müssen in die entsprechenden Variablen geladen werden. Die Farbmischung setzen wir mal auf BM_OPAQUE (="deckend"). Das bedeutet, daß an der Stelle, wo der Regenbogen erscheint, das dezente Himmelblau brutal durch die kräftigen Farben des Regenbogens ersetzt wird.
Alternativ können wir es z.B. auch mal mit BM_ADD (Pattern-Farbwerte werden auf Grundfarbe addiert) oder BM_MIX (arithmetischer Mittelwert von Grund- und Patternfarbe) probieren, da wirkt der Regenbogen etwas transparenter.
Wenn zusätzlich noch ein anderes Muster, z.B. eine kräftig leuchtende "Sonne" an anderer Stelle erscheinen soll, nehmen wir dafür eine weitere Pattern-Ebene in Betrieb und erstellen ein passendes Pattern mit sonnigen Leuchtwerten. Die Daten der "Sonne" müssen dann entsprechend in die Datenstruktur für die 2. Ebene geschrieben werden.    
Ein Aufruf des Patternprozessors mit dem Befehl "call patternprocessor" sollte schon für die erhoffte Erleuchtung sorgen...

Nun möchten wir den Regenbogen aber vielleicht doch lieber in der linken Ecke haben, zufällig genau dort, wo Anfang (LED #0)  und Ende (LED #499) des LED-Streifens zusammenstoßen, um aus dem Streifen optisch einen geschlossenen Rahmen zu machen. Im Klartext: der erste Teil des Regenbogens muß am Ende des LED-Streifens erscheinen, der Rest soll sich dann aber ab Anfang fortsetzen - alles klar?
Kein Problem! Wenn der "Wrapping"-Mode aktiviert wird, setzt der Patternprozessor automatisch ein Muster, das am Ende des LED-Streifens abgebrochen wird, am Anfang des Streifens fort. Wird unser Regenbogen-Muster z.B. auf LED #490 positioniert, erscheinen die ersten 10 Pixels des Musters auf den LEDs #490..499 und die restlichen 40 Pixels auf LEDs #0..39, wobei natürlich vorausgesetzt wird, daß CHAINLENGTH korrekt auf 500 definiert wurde und der LED-Streifen wirklich aus genau 500 LEDs besteht! 
Nun finden wir einen einzigen Regenbogen auf dem langen LED-Streifen vielleicht noch nicht bunt genug - wie wäre es mit vielen Regenbögen? Dafür ist der Tile-Mode ("tile" = dt.:"Kachel") gedacht! Wenn Tiling aktiviert ist, wird der LED-Streifen mit Regenbögen "zugekachelt", d.h. das Muster wird immer wieder aneinandergehängt. Wenn zwischen den Regenbögen noch ein Stück "Himmel" hervorschauen soll, kann die gewünschte Größe der Lücke in die Pattern-Datenstruktur eingetragen werden (Strukturelement: pdp_gap = Lücke in Pixeln) .  

Blendmodes

BM_OPAQUE GRB-Werte des aktuellen Patterns überdecken den Hintergrund.
BM_ADD GRB-Werte des aktuellen Patterns werden zum Hintergrund addiert.
BM_SUBTRACT GRB-Werte des aktuellen Patterns werden vom Hintergrundwert subtrahiert.
BM_MIX bildet arithmetisches Mittel zwischen aktuellem Pattern und Hintergrund.
BM_MULTIPLY GRB-Werte des aktuellen Patterns (A) und des Hintergrunds (B) werden multipliziert, Formel: X = (A * B)/256
BM_UST_OPAQUE Wie BM_OPAQUE, Microstepping aktiviert.
BM_UST_ADD Wie BM_ADD, Microstepping aktiviert.

Unterprogramm-Aufrufe zur Nutzung des Patternprozessors:

ctrldatfsr0: lädt das FSR0-Register mit der Adresse der Pattern-Datenstruktur für Pattern-Ebene (WREG). Anschließend kann durch "movwi elementname[FSR0]" bzw. "moviw elementname[FSR0]" auf die verschiedenen Elemente der Pattern-Datenstruktur zugegriffen werden,
hier z.B. ein Stück Code, um die Startadresse der Pattern-Quelldaten (pattern_data) für Pattern-Ebene 1 einzutragen:

    movlw    1
   
call        ctrldatfsr0
    movlw    LOW pattern_data
    movwi    pdp_srcstart[FSR0]   
    movlw    HIGH pattern_data
    movwi    pdp_srcstart+1[FSR0]

Der Zugriff auf das Element pdp_flags kann auch direkt über das INDF0-Register erfolgen, da es die Offset-Adresse 0 hat.

patternprocessor: führt die Berechnung der LED-Daten und Ausgabe für die komplette LED-Kette einmal aus.

Variablen:

pp_cltrl0, pp_cltrl1, pp_cltrl2, pp_cltrl3...: Pattern-Datenstrukturen (pro Ebene eine).

Elemente der Datenstruktur, wenn keine Größe angegeben ist, ist es 8 Bit:
pdp_flags: enthält ein paar Steuer- und Statusbits
pm_speed:
(nur bei Patternmover) Bewegungs-Geschwindigkeit des Patterns (-128..+127)
pm_taccu:
(nur bei Patternmover) für internes Timing
pdp_substep:
(nur bei Microstepping) Achtelschritt, 0..7
pdp_startled:
Zielposition des ersten Pattern-Pixels (LED-Nummer), 16 Bit, signed
pdp_gap:
Freiraum zwischen den Patterns im Tile-Modus, 16 Bit, unsigned
pdp_srcstart:
Anfangsadresse der Pattern-Quelldaten, 16 Bit
pdp_srcend: Endadresse+1 der Pattern-Quelldaten, 16 Bit
pdp_srcptr:
Zeiger, wird intern vom Patternproz. verwaltet, 16 Bit
pdp_blendmode:
Blendmodus, es sind nur Werte aus Definitionen "BM_xxx" erlaubt (s.PIC_2_WS281x.asm).

pp_data[N_LAYERS]: Adresse der Pattern-Datenstruktur für die jeweilige Ebene. Es wird nur das niedertige Byte der linearen(!) Adresse gespeichert. Inhalt=0, wenn keine Pattern-Daten für die jeweilige Ebene angezeigt werden sollen.

bckgr_grn, bckgr_red, bckgr_blue: "Hintergrund-Farbe" für alle LEDs. Wenn diese nicht genutzt wird, kann die Definition der drei Variablen gelöscht bzw. auskommentiert werden, um Speicherplatz freizugeben.

Alle anderen pp_??? und temp_grn, temp_red, temp_blue: Arbeitsvariablen, die außerhalb des patternprocessor-Aufrufs auch anderweitig verwendet werden dürfen.


Weiter geht's mit dem Patternmover-Modul.


Kontakt