Skip to content

Firmware for lighthouse gadgets used on K-SCUK 2019

Notifications You must be signed in to change notification settings

zverinec/kscuk-2019-lighthouse

Repository files navigation

Softwaremodul ws2812.c / ws2812.h
____________________________________________________________________________________________

Text und Software von R. Seelig

Inhaltsverzeichnis:

        - Vorwort
        - WS2812b Leuchtdioden
        - Make
        - WS2812b Header
        - Funktionen von WS2812b

          . rgbfromvalue
          . rgbfromega
          . ws_reset
          . ws_showarray
          . ws_clrarray
          . ws_setrgbcol
          . ws_setegacol
          . ws_blendup_left
          . ws_blendup_right
          . ws_buffer_rl
          . ws_buffer_rr

_______________________________________________

Vorwort
_______________________________________________

Seit geraumer Zeit schon gibt es Leuchtdioden mit "integriertem seriellen Controller". Diese
weerden oft fuer sehr kleines Geld (und absolut haeufig auch aus China auf EBAY) angeboten.

Genausooft (und noch guenstiger) werden Microcontroller der Familie STM8S angeboten und
der zweitpreiswerteste ist ein STM8S103F3P6 (auf EBAY werden 2 Stueck Minimumboards mit
dieser MCU fuer ca. 1,40 Euro angeboten, eigentlich unglaublich.

Leider ist die Unterstuetzung fuer diese MCU im Netz verglichen mit AVR und STM32 relativ
duerftig.

Auch freie Compiler hierfuer sind fast nicht verfuegbar und ausser dem SDCC habe ich
keinen freien (zumindest nicht limitierten) Compiler hierfuer gefunden. Von Cosmic gibt
es zwar einen "no limits compiler" aber ich habe nirgendwo einen Compiler fuer Linux auf
deren Seite entdeckt und so programmiere ich den STM8S eben mit SDCC.

Die Verwendung des Softwaremoduls kann somit mit:

Compiler         :  SDCC (ab Version 3.5.0)
MCU              :  STM8S103F3P6
Taktfrequenz MCU :  16MHz
LEDs             :  WS2812b
Betriebssystem   :  Linux
IDE              :  Make

betrieben werden. Eine IDE ist nicht zwingend notwendig, die Software wird mithilfe eines
Makefiles generiert.

_______________________________________________

WS2812b Leuchtdioden
_______________________________________________

WS2812b LEDs sind Vollfarb-LEDs (gruen / rot / blau) und besitzen einen "integrierten
seriellen Controller". Deren Funktionsweise ist in der Theorie relativ einfach (das
Programmieren fand ich dann doch relativ kniffelig).

Mittels einer einzigen Datenleitung empfaengt innerhalb einer Leuchtdiodenreihe die erste
LED Informationen. Diese sind 3 Bytes, jeweils eines fuer den Farbanteil von gruen, rot
und blau. Treffen nach diesen 3 Bytes weitere Bytes ein, werden die empfangenen Bytes
an den Ausgang der LED geschoben und einer weiteren nachgeschalteten LED uebergeben.

Reist der Datenstrom fuer eine gewisse Zeit ab (in der Regel betraegt diese Zeit
50 uSekunden) wird ein neuer Datenframe als Frame fuer die erste LED gewertet.

Eine WS2812b Leuchtdiode hat somit 4 Anschluesse: +Vcc, GND, Data_in und Data_out.

Beispiel: LED-Strang mit 4 LEDs

       +Vcc
       o------------+--------------+---------------+--------------+---------
                    |Vcc           |Vcc            |Vcc           |Vcc
                    |              |               |              |
       Data    +----+----+    +----+----+     +----+----+    +----+----+
       o-------| in  out |----| in  out |-----| in  out |----| in  out |----
               +----+----+    +----+----+     +----+----+    +----+----+
                    |              |               |              |
       GND       GND|           GND|            GND|           GND|
       o------------+--------------+---------------+--------------+---------

In welcher Form liegen die Daten fuer WS2812 Leuchtdioden vor?

Es ist ein relativ einfaches Protokoll, welches jedoch recht sehr zeitkritisch ist.
Fuer ein Byte muessen 8 Bits uebertragen werden. Nachdem am Data-Input fuer min.
50 uSekunden ein Lo-Signal angelegt wird, beginnt die Datenuebertragung mit der ersten
Lo-Hi Flanke.

Ein Datenbit wird innerhalb einer Zeitspanne von 1,25 uSekunden uebertragen. Betraegt
die Pulsdauer des Signals 350 nSekunden (n= nano !!!) und 900 nSekunden die Pausedauer,
so wertet die WS2812 dieses als eingehende 0.

Betraegt die Pulsdauer 900nS und die Pausedauer 350nS, wird dieses als eingehende 1
gewertet.

Die Informationen werden in die LED in der Folge: gruen, rot und blau und die einzelnen
Bits mit der hoeheren Wertigkeit uebertragen. 3 Byte zu je 8 Bit benoetigen somit 24
Impulse (mit dem oben beschriebenen Timing).

Dieses Timing mit einem STM8S einzuhalten ist nicht ganz einfach und aus diesem Grund
wurde dieses Softwaremodul fuer einen mit 16 MHz betriebenen STM8 geschrieben.

Der Teil, der fuer den Datenstrom in die erste LED zustaendig ist, wurde mittels Bit-
banging in Assembler kodiert.

Das vorliegende ZIP-Archiv, zu dem diese Readme Datei gehoert, enthaellt alle Dateien,
die zum einfachen Uebersetzen des Demoprogrammes notwendig sind (ein installierter
SDCC Compiler wird vorausgesetzt).

_______________________________________________

Make
_______________________________________________

Bei der Programmierung hat es sich mehr oder weniger durchgesetzt, eine Uebersetzung
eines Quellprogramms die Steuerung der Uebersetzung einer sogenannten Make Datei zu
ueberlassen. Auf Betriebssystemebene wird auf einer Kommandozeile

                                      make

in dem Ordner aufgerufen, in dem sich das Quellprogramm befindet. Selbst bei Be-
nutzung einer IDE wird dieses einem Make ueberlassen, welches jedoch haeufig in die
IDE integriert ist und die Makedatei aus Projekteinstelldaten erzeugt wird. Ueber-
sichtlicher finde ich jedoch, wenn die Makedatei im Text vorliegt um entsprechend
direkt mittels Texteingaben die Programmgenerierung steuern zu koennen.

Zu diesem Zwecke wurde hier Make in 2 Dateien aufgeteilt (case sensitiv):

      - Makefile
      - makefile.mk

Das Makefile ist sehr einfach gestaltet und an sich selbsterklaerend. Hier koennen
Angaben gemacht werden, welche Programmmodule zum Hauptprogramm hinzugefuegt werden
sollen, sowie die Pfade, in denen diese Module liegen koennen.

Im Vorliegenden Falle gibt es fuer einen Upload in die MCU zwei Moeglichkeiten, zum
einen mit der Verwendung eines STLINK v2 oder ueber einen selbst geschriebenen
Bootloader.

                                 FLASHERPROG = 1

verwendet einen Bootloader, der an /dev/ttyUSB0 angeschlossen sein muss,

                                 FLASHERPROG = 0

verwendet einen STLINK v2.

Weitere Sourcesoftware kann mittels

                                 SRCS   +=  nocheinedatei.rel

hinzugefuegt werden. Zu beachten, dass es hierfuer eine Datei Namens nocheinedatei.c
in den angegebenen Suchpfaden geben muss. Diese wird zu nocheinedatei.rel uebersetzt.

Makefile inkludiert eine weitere Datei: makefile.mk. Diese wertet die Benutzer-
angaben aus und generiert das Programm im Intel Hex-Format. Innerhalb dieser inkludierten
Datei werden Quelltexte uebersetzt und zu einem Gesamtprogramm zusammengelinkt.

_______________________________________________

WS2812b Header
_______________________________________________


    ws2812b.h
    ---------

      Angaben, die innerhalb ws2812b.h gemacht werden muessen:

           Unter - ledanz - muss angegeben sein, wieviele Leuchtdioden eine
           Leuchtdiodenreihe besitzt

           Ausserdem muss angegeben sein, auf welchem Anschlusspin die Daten fuer
           die WS2812b Leuchtdionden ausgegeben werden.

           Hier sind die moeglichen Ports schon aufgefuehrt und auskommentiert.
           Standardmaessig erfolgt die Datenausgabe auf
                                    PD4
           Soll das geaendert werden, muss der entsprechende Port entkommentiert werden
           und der Pinanschluss unter gpio_pin angegeben werden.

           Bsp.:

           Soll die Ausgabe auf PB5 erfolgen, so sind im Header anzugeben:

                #define ws_portb
                #define gpio_pin  5

    Strukturen, Variable und Funktionen von WS2812b
    -----------------------------------------------

      Das Array - ledbuffer -

        Dieses Array nimmt die RGB-Werte fuer jede einzelene Leuchtdiod im Strang auf,
        welche mittels - ws_showarray - ausgegeben werden kann.

      Das Array -  egapalette - beinhaltet 2 x 16 Farben die den "alten" Farben einer
      EGA Grafikkarte (und den 16 Standardfarben unter Windows) entsprechen. Jede Farbe
      benoetigt 3 Bytes (je eines fuer rot, gruen und blau). Die unteren 16 Farben sind
      die Farben in "dunkel", die oberen 16 Farben sind dieselben Farben mit voller
      Leuchtstaerke


Funktionen von WS2812b
________________________________________________________________________________________


     rgbfromvalue
     --------------------------------------------

     void rgbfromvalue(uint8_t r, uint8_t g, uint8_t b, struct colvalue *f);


     beschreibt eine struct Variable auf die *f zeigt mit einem RGB Farbwert.

     Uebergabe:
                r,g,b   : RGB - Farbwert
                   *f   : Zeiger auf die zu beschreibende
                          struct Variable

     rgbfromega
     --------------------------------------------

     void rgbfromega(uint8_t eganr, struct colvalue *f);


     beschreibt eine struct Variable auf die *f zeigt mit einem Farbwert, der aus der
     EGA-Palette entnommen wird

     Uebergabe:
                  nr   : Farbeintrag der EGA-Palette
                  *f   : Zeiger auf die zu beschreibende
                         struct Variable

     ws_reset
     --------------------------------------------

     void ws_reset(void);

     setzt die Leuchtdiodenreihe (fuer einen ncahfolgenden Datentransfer
     zu den Leuchtdioden) zurueck


     ws_showarray
     --------------------------------------------

     void ws_showarray(uint8_t *ptr, int anz)

     (leider) in Maschinensprache, weil ich keinen anderen Weg gefunden habe, mittels
     SDCC 350 Nanosekundenimpulse zu erzeugen.

     Der SDCC legt seine Parameter auf den Stack in der Reihenfolge von hinten nach
     vorne ab, hier also:

              anz (2 Byte), *ptr (2 Byte), Ruecksprungadresse (2 Byte)

     In wiefern andere Compiler den Stack belegen weiss ich in Ermangelung eines
     anderen Compilers nicht und von daher wird diese Funktion wohl nur mit SDCC
     (Version 3.5 oder hoeher sofern sich am Stackmanagment nichts aendert)
     funktionieren.

     Uebergabe:
               *ptr  : Zeiger auf ein Array, das angezeigt
                       werden soll
               anz   : Anzahl der anzuzeigenden LED's


     ws_clrarray
     --------------------------------------------

     void ws_clrarray(uint8_t *ptr, int anz)

     loescht ein LED Anzeigearray

     Parameter:
                   *ptr : Zeiger auf ein Array, das
                          geloescht werden soll
                    anz : Anzahl der LEDs, die angezeigt
                          werden sollen


     ws_setrgbcol
     --------------------------------------------

     void ws_setrgbcol(uint8_t *ptr, uint16_t nr, struct colvalue *f)

     setzt den Farbwert der in

                   struct colvalue f

     angegeben ist, in ein Array an Stelle nr ein. Dieses Array kann mittels
     ws_showarray auf einen LED-Strang ausgegeben werden kann.

     Parameter:
                   *ptr : Zeiger auf ein Array, das die
                          RGB Farbwerte aufnehmen soll
                     nr : LED-Nummer im Array, welche die
                          Position im Leuchtdiodenstrang
                          repraesentiert
     struct colvalue *f : Zeiger auf einen RGB-Farbwert


     ws_setegacol
     --------------------------------------------

     void ws_setegacol(uint8_t *ptr, uint16_t nr, uint8_t eganr)


     setzt einen Farbwert aus der EGA-Palette in einem Array, das mittels
     showarray auf einem LED-Strang
     ausgegeben werden kann.

     Parameter:
                   *ptr : Zeiger auf ein Array, das die
                          RGB Farbwerte aufnehmen soll
                     nr : LED-Nummer im Array, welche die
                          Position im Leuchtdiodenstrang
                          repraesentiert
                  eganr : Farbwert, der EGA-Palette

                          0..15 dunkle Farben
                         16..31 helle  Farben

     ws_blendup_left
     --------------------------------------------

     void ws_blendup_left(uint8_t *ptr, uint8_t anz, struct colvalue *f, int dtime)


     blendet eine LED-Anzahl anz mit dem Farbwert, der in


                     struct colvalue f

     angegeben ist, links schiebend auf. Hierfuer wird das Array, auf das *ptr
     zeigt mit dem Farbwert aufgefuellt.

     Verzoegerungszeit dtime bestimmt die Dauer eines Einzelschrittes beim Aufbau
     in Millisekunden.

     Parameter:
                   *ptr : Zeiger auf ein Array, das die
                          RGB Farbwerte aufnehmen soll
                    anz : Anzahl der Leuchtdioden im Strang
                    *f  : Zeiger auf RGB-Farbwertstruktur die die Farbe der Auf-
                          blendung enthaellt
                  dtime : Verzoegerungszeit eines Schrittes beim Aufblenden

     ws_blendup_right
     --------------------------------------------

     void ws_blendup_right(uint8_t *ptr, uint8_t anz, struct colvalue *f, int dtime)

     blendet eine LED-Anzahl anz mit dem Farbwert, der in


                      struct colvalue f

     angegeben ist, rechts schiebend auf. Hierfuer wird das Array, auf das *ptr
     zeigt mit dem Farbwert aufgefuellt.

     Verzoegerungszeit dtime bestimmt die Dauer eines  Einzelschrittes beim Aufbau
     in Millisekunden.

     Parameter:
                   *ptr : Zeiger auf ein Array, das die
                          RGB Farbwerte aufnehmen soll
                    anz : Anzahl der Leuchtdioden im Strang
                    *f  : Zeiger auf RGB-Farbwertstruktur die die Farbe der Auf-
                          blendung enthaellt
                  dtime : Verzoegerungszeit eines Schrittes beim Aufblenden


     ws_buffer_rl
     --------------------------------------------

     void ws_buffer_rl(uint8_t *ptr, uint8_t lanz)


     rotiert einen Pufferspeicher der die Leuchtdiodenmatrix enthaelt um eine LED-Position
     nach links (also 3 Bytes) und fuegt hierbei die am Ende anstehende LED am Anfang
     wieder ein.

     Parameter:
                   *ptr : Zeiger auf ein Array, das die
                          RGB Farbwerte aufnehmen soll
                   lanz : Anzahl der Leuchtdioden im Strang


     ws_buffer_rr
     --------------------------------------------

     void ws_buffer_rl(uint8_t *ptr, uint8_t lanz)


     rotiert einen Pufferspeicher der die Leuchtdiodenmatrix enthaelt um eine LED-Position
     nach rechts (also 3 Bytes) und fuegt hierbei die am Anfang anstehende LED am Ende
     wieder ein.

     Parameter:
                   *ptr : Zeiger auf ein Array, das die
                          RGB Farbwerte aufnehmen soll
                   lanz : Anzahl der Leuchtdioden im Strang


________________________________________________________________________________________________________________

Text und Software von R. Seelig

Jegliche Verwendung der Software und des Textes ist ausdruecklich erlaubt. Kommerzielle Nutzung der Software
inklusive dieses Textes insbesondere in gedruckter Form bedarf der Zustimmung des Authors R. Seelig

About

Firmware for lighthouse gadgets used on K-SCUK 2019

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published