Hardware-Encoder für NeoPixel (WS2812)/Hardware: Unterschied zwischen den Versionen

Aus Hackerspace Bielefeld Wiki
Zur Navigation springen Zur Suche springen
K (Admin verschob die Seite Projekt:Hardware-Encoder für NeoPixel (WS2812)/Hardware nach Hardware-Encoder für NeoPixel (WS2812)/Hardware, ohne dabei eine Weiterleitung anzulegen)
KKeine Bearbeitungszusammenfassung
 
(4 dazwischenliegende Versionen von einem anderen Benutzer werden nicht angezeigt)
Zeile 1: Zeile 1:
== Wir werden konkret ==
[[Hardware-Encoder für NeoPixel (WS2812)|Zurück zum Inhaltsverzeichnis]]
Bevor wir loslegen können, müssen wir uns noch ein paar darüber machen, was unsere Schaltung tun und wie sie arbeiten soll. Da I/O-Pins an einem µController immer Mangelware sind, bieten sich für die Datenübertragung zu unserem Encoder serielle Schnittstellen an. Eigentlich immer vorhanden sind UARTs und SPI-Schnittstellen.


SPI braucht zwar mehr Leitungen als ein UART, ist dafür aber schneller und man kann, sofern die restliche Schaltung das zulässt, mehrere Geräte an ein und derselben Schnittstelle betreiben. UART hat vor allem den Vorteil, daß praktisch jeder Microcontroller einen oder mehrere davon an Bord hat. Dazu kommt, daß sich die Schaltung auch an einem normalen PC oder Mac betreiben lässt. Falls dort keine echte Schnittstelle mehr vorhanden ist, kann man einfach einen USB-Adapter verwenden.
Unser Grobkonzept steht, jetzt geht es in die Details. Dazu machen wir uns zuerst Gedanken darüber, wie unser Encoder-System grundsätzlich arbeiten soll. Daraus ergeben sich erste Funktionsblöcke, die zur Gesamtschaltung verbunden werden. Bei Bedarf werden diese Blöcke noch weiter unterteilt, bis wir auf einem Level angekommen sind, daß wir gut beschreiben und '''testen''' können.


Da selbst kleine FPGAs (Spartan 6 LX 4 z.B.) mehr als genug Ressourcen für unser Projekt bieten, können wir einfach beide Schnittstellen implementieren.
== Der Weg der Daten ==
[[Datei:WS_Encoder_grob.png|right|thumb]]
Beginnen wir bei den Eingabedaten und verfolgen ihre Verarbeitung. Im einfachsten Fall werden wir ein RGB-Farbtripel an den Encoder schicken, daß in das WS-Protokoll überführt und ausgegeben wird. Egal, welche unserer seriellen Schnittstellen wir benutzen, das übertragene Datum steht nach dem erfolgreichen Empfang in einem Register und kann parallel weiter verarbeitet werden. Unsere ersten Funktionsblöcke werden also einmal ein '''UART-Modul''' und ein '''SPI-Modul'''.


Die ankommenden Bytes könnten wir jetzt direkt in den Pixel-Encoder stecken. Allerdings müssen wir dann immer alle Daten neu übertragen und die zeitliche Entkopplung der Ausgabe an den Encoder ist auch nicht gegeben. Das können wir durch einen Pufferspeicher lösen. Wir benötigen für 512 LEDs je 3 Bytes, also 1,5KiB RAM.  
Damit die Datenübertragung zum Encoder die Ausgabe an die LEDs nicht beeinflusst, brauchen wir einen Pufferspeicher zur Entkopplung, in den die empfangenen Daten geschrieben werden. Wir benötigen also ein Modul, daß RAM implementiert und ansteuert, also einen '''VRAM-Controller'''.


Jetzt können wir die Daten per UART oder SPI in das RAM schreiben und der Encoder kann sie auslesen, wie es ihm passt, und sie zur Anzeige bringen. Sind wir fertig? Noch nicht ganz. Neben Zugriff auf den Speicher wäre es sinnvoll, verschiedene Einstellungen bei Bedarf anpassen zu können. Z.B. gibt es vom WS2812 zwei Varianten mit leicht abweichenden Timings. Dann kann es sein, daß deine Hardware eine andere ist, ein anderes FPGA, anderer Takt - kurzum: Wir wollen Zugriff auf Konfigurationsregister.  
Aus diesem Video-RAM holt sich der eigentliche '''WS2812-Encoder''' die Daten, wandelt sie und gibt sie aus.


Damit wird die Sache noch ein bisschen komplexer: Wir müssen festlegen können, wann wir LED-Daten senden und wann wir auf ein Register zugreifen wollen, und auf welches. Wir brauchen ein Protokoll! Und einen Automaten, der es versteht. Also einen Protokoll-Interpreter.
== Das Konfigurations-Interface ==
Dinge ändern sich. Zum Beispiel die Timings von einer Version des WS2812 zur anderen. Oder dein FPGA-Board wird mit einem anderen Takt betrieben als meins. Lange Rede, kurzer Sinn: Wir wollen bestimmte Parameter einstellen können. Und dazu brauchen wir neben der reinen Datenverarbeitung ein Konfigurationsinterface.
 
Das Konfigurationsinterface besteht aus Registern, der Hardware-Entsprechung zu Variablen in der Programmierung. Hier können wir Parameter hinterlegen, die die Datenverarbeitung steuern, z.B. die Anzahl der LEDs auf einem angeschlossenen Streifen oder die Dauer des Reset-Signals. In meinem aktuellen Entwurf habe ich 12 solcher Register vorgesehen. Es lohnt sich also, darüber nachzudenken, wie man den Zugriff auf diese Register regeln kann, ohne daß die Modulschnittstelle überfrachtet wird.
 
Ein weiteres Thema ist Wiederverwendbarkeit. Dir passen die seriellen Schnittstellen nicht, du willst lieber ein paralleles Interface? Je nachdem, wie die Schnittstelle des Encoder-Moduls aussieht kann das simpel sein oder zu einem Schreikrampf führen. Ziel ist also eine möglichst einheitliche, übersichtliche Modulschnittstelle. Das führt uns zu Bussen.
 
== Wir nehmen den Bus ==
Ein Bus besteht aus Daten-, Adress-, und Steuerleitungen. Die Adresse legt fest, auf welches Register wir zugreifen wollen, die Daten sind die Daten, die wir schreiben oder lesen wollen und die Steuerleitungen sind dafür da, die Abläufe zu koordinieren.
 
Es gibt eine ganze Menge verschiedenster Busse, parallele, serielle, schnelle für kurze Distanzen, langsamere für groß, whatever. Für uns interessant sind vor allem Busse, die sich dazu eignen, Systeme aus Modulen auf einem FPGA zusammenzuschalten. Da gibt es selbstverständlich auch mehrere, AXI oder AMBA zum Beispiel. Ich favorisiere in diesem Zusammenhang den [http://opencores.org/opencores,wishbone "Wishbone-Bus"], eine offene Busspezifikation, frei verwendbar und sehr leistungsfähig und flexibel.
 
== Infrastrukturmaßnahmen ==
[[Datei:WS_Encoder_WB.png|right|thumb]]
Strukturieren wir das Projekt also nach unseren neuesten Erkenntnissen um:
* Das WS2812-Encodermodul bekommt ein Wishbone-Slave-Interface.
* Das Modul umfaßt die Buslogik, den VRAM und den eigentlichen Encoder
 
Um die Daten von den seriellen Schnittstellen in den Encoder zu bekommen, müssen diese über ein Wishbone-Master-Interface verfügen. Hier könnten wir jetzt jeder Schnittstelle ein solches Interface verpassen oder ein kleines Hilfsmodul bauen, daß Daten von den Schnittstellen abholt und über den Wishbone-Bus an das WS2812-Modul überträgt. Diese Lösung hat darüber hinaus den Vorteil, daß es nur einen Master gibt. Gäbe es mehrere, müssten diese untereinander aushandeln, wer gerade übertragen darf. Diese zusätzliche Komplexität würde ich mir gerne schenken.
 
Das Abholen der Daten von den externen Schnittstellen kann natürlich auch wieder per Wishbone erfolgen. Ein weiterer Vorteil dabei ist, daß man einfach Schnittstellen austauschen oder hinzufügen kann, in dem man sie an den Bus koppelt.
 
Erweitern wir unsere Liste von oben also noch ein wenig:
* Wir bauen einen kleinen Steuercontroller, der das Wishbone-Master-Interface steuert
* Die seriellen Schnittstellen erhalten, wie das WS-Modul, ein Wishbone-Slave-Interface.
 
== Die Komponenten im Detail ==
Da die Besprechung der einzelnen Blöcke umfangreich wird, habe ich entsprechende Unterseiten eingerichtet:
* Zum [[/Wishbone|Wishbone-Bus ->]]
* Zum [[/SPI|SPI-Modul ->]]
* Zum [[/UART|UART-Modul ->]]
* Zum [[/WS_Encoder|WS2812-Encoder ->]]
 
[[Hardware-Encoder für NeoPixel (WS2812)|Zurück zum Inhaltsverzeichnis]]
 
[[Kategorie:Projekt]]

Aktuelle Version vom 22. April 2023, 13:31 Uhr

Zurück zum Inhaltsverzeichnis

Unser Grobkonzept steht, jetzt geht es in die Details. Dazu machen wir uns zuerst Gedanken darüber, wie unser Encoder-System grundsätzlich arbeiten soll. Daraus ergeben sich erste Funktionsblöcke, die zur Gesamtschaltung verbunden werden. Bei Bedarf werden diese Blöcke noch weiter unterteilt, bis wir auf einem Level angekommen sind, daß wir gut beschreiben und testen können.

Der Weg der Daten

Beginnen wir bei den Eingabedaten und verfolgen ihre Verarbeitung. Im einfachsten Fall werden wir ein RGB-Farbtripel an den Encoder schicken, daß in das WS-Protokoll überführt und ausgegeben wird. Egal, welche unserer seriellen Schnittstellen wir benutzen, das übertragene Datum steht nach dem erfolgreichen Empfang in einem Register und kann parallel weiter verarbeitet werden. Unsere ersten Funktionsblöcke werden also einmal ein UART-Modul und ein SPI-Modul.

Damit die Datenübertragung zum Encoder die Ausgabe an die LEDs nicht beeinflusst, brauchen wir einen Pufferspeicher zur Entkopplung, in den die empfangenen Daten geschrieben werden. Wir benötigen also ein Modul, daß RAM implementiert und ansteuert, also einen VRAM-Controller.

Aus diesem Video-RAM holt sich der eigentliche WS2812-Encoder die Daten, wandelt sie und gibt sie aus.

Das Konfigurations-Interface

Dinge ändern sich. Zum Beispiel die Timings von einer Version des WS2812 zur anderen. Oder dein FPGA-Board wird mit einem anderen Takt betrieben als meins. Lange Rede, kurzer Sinn: Wir wollen bestimmte Parameter einstellen können. Und dazu brauchen wir neben der reinen Datenverarbeitung ein Konfigurationsinterface.

Das Konfigurationsinterface besteht aus Registern, der Hardware-Entsprechung zu Variablen in der Programmierung. Hier können wir Parameter hinterlegen, die die Datenverarbeitung steuern, z.B. die Anzahl der LEDs auf einem angeschlossenen Streifen oder die Dauer des Reset-Signals. In meinem aktuellen Entwurf habe ich 12 solcher Register vorgesehen. Es lohnt sich also, darüber nachzudenken, wie man den Zugriff auf diese Register regeln kann, ohne daß die Modulschnittstelle überfrachtet wird.

Ein weiteres Thema ist Wiederverwendbarkeit. Dir passen die seriellen Schnittstellen nicht, du willst lieber ein paralleles Interface? Je nachdem, wie die Schnittstelle des Encoder-Moduls aussieht kann das simpel sein oder zu einem Schreikrampf führen. Ziel ist also eine möglichst einheitliche, übersichtliche Modulschnittstelle. Das führt uns zu Bussen.

Wir nehmen den Bus

Ein Bus besteht aus Daten-, Adress-, und Steuerleitungen. Die Adresse legt fest, auf welches Register wir zugreifen wollen, die Daten sind die Daten, die wir schreiben oder lesen wollen und die Steuerleitungen sind dafür da, die Abläufe zu koordinieren.

Es gibt eine ganze Menge verschiedenster Busse, parallele, serielle, schnelle für kurze Distanzen, langsamere für groß, whatever. Für uns interessant sind vor allem Busse, die sich dazu eignen, Systeme aus Modulen auf einem FPGA zusammenzuschalten. Da gibt es selbstverständlich auch mehrere, AXI oder AMBA zum Beispiel. Ich favorisiere in diesem Zusammenhang den "Wishbone-Bus", eine offene Busspezifikation, frei verwendbar und sehr leistungsfähig und flexibel.

Infrastrukturmaßnahmen

Strukturieren wir das Projekt also nach unseren neuesten Erkenntnissen um:

  • Das WS2812-Encodermodul bekommt ein Wishbone-Slave-Interface.
  • Das Modul umfaßt die Buslogik, den VRAM und den eigentlichen Encoder

Um die Daten von den seriellen Schnittstellen in den Encoder zu bekommen, müssen diese über ein Wishbone-Master-Interface verfügen. Hier könnten wir jetzt jeder Schnittstelle ein solches Interface verpassen oder ein kleines Hilfsmodul bauen, daß Daten von den Schnittstellen abholt und über den Wishbone-Bus an das WS2812-Modul überträgt. Diese Lösung hat darüber hinaus den Vorteil, daß es nur einen Master gibt. Gäbe es mehrere, müssten diese untereinander aushandeln, wer gerade übertragen darf. Diese zusätzliche Komplexität würde ich mir gerne schenken.

Das Abholen der Daten von den externen Schnittstellen kann natürlich auch wieder per Wishbone erfolgen. Ein weiterer Vorteil dabei ist, daß man einfach Schnittstellen austauschen oder hinzufügen kann, in dem man sie an den Bus koppelt.

Erweitern wir unsere Liste von oben also noch ein wenig:

  • Wir bauen einen kleinen Steuercontroller, der das Wishbone-Master-Interface steuert
  • Die seriellen Schnittstellen erhalten, wie das WS-Modul, ein Wishbone-Slave-Interface.

Die Komponenten im Detail

Da die Besprechung der einzelnen Blöcke umfangreich wird, habe ich entsprechende Unterseiten eingerichtet:

Zurück zum Inhaltsverzeichnis