2048 Pixel RGB-LED-Matrix: WS2801 Emulator

In diesem Post soll es darum gehen, wie man aus einem Mikrocontroller einen oder mehr WS2801 Pixel „virtualisieren“ kann.

Die Vorteile liegen auf der Hand: Es gibt schon reichlich LED-Controller die dieses Protokoll unterstützen und es werden nur 2 Leitungen (+GND) gebraucht um Daten zu Übertragen. Außerdem geht dies deutlich Flotter als bei den so bliebten WS2811 LEDs. Ws2801 Pixel können theoretisch mit einem Clock von über 20 MHz betrieben werden. Das entspricht einer Pixelanzahl von ca. 33.333 RGB LEDs bei 25 Bildern die Sekunde (die 25 x 500 us Pause zum latchen mal außen vor gelasssen).

20 MHz / 25 Bilder / 8 Bit / 3 Farben = 33.333 RGB LEDs bei 25 FPS

In letzter Zeit sind die WS2811 Pixel sehr viel beliebter, da hier der Clock auf 800 kHz festgelegt ist, spart man sich die Clock Leitung und damit auch beim Pixel etwas Geld. Leider können bei 25 Bilder die Sekunde, nicht annähernd so viele Pixel übertragen werden:

0.8 MHz / 25 Bilder / 8 Bit / 3 Farben = 1.333 RGB LEDs bei 25 FPS

Damit wäre auch geklärt, warum für diese Anwendung eine WS2811 Emulierung nicht in Frage kommt.

Um die Daten zu Empfangen, muss man einen SPI Slave auf seinem Mikrocontroller einrichten.

Der Master, also der LED-Controller, sendet mit jeder steigenden Clock Flanke ein Bit. Meist ändert die Datenleitung ihren Pegel (oder auch nicht) mit der entgegengesetzten Clockflanke. Andere SPI Modis haben hier andere Verhalten zur Folge, WS2801 verhalten sich jedoch so. Begonnen wird also immer mit dem ersten Pixel,der ersten Farbe (rot) und dem höchstwertigstem Bit der 8 Bit großen Farbe.

Normalerweise wird SPI über den Slave select synchronisiert. Das bedeutet, es gibt eine extra Leitung die sagt: Es geht los, es gibt neue Daten. Dies ist nicht unwichtig. Sendet man übere mehrere Stunden SPI Daten, kommt es schnell vor, dass eine Flanke falsch erkannt wird. Die folgen wären fatal. Das erste Bit wäre nur noch das zweite oder eins davor. Damit würden sich alle folgenden Farbwerte verschieben und für den Rest der Betriebszeit stellt sich ein verschobenes Bild ein.

Also wird beim WS2801 automatisch SPI resetet und alle empfangen Daten auf die LED Treiber übernommen (gelatcht), wenn maximal 500 us keine Daten mehr eingespielt wurden. So kann es schlimmstenfalls passieren, dass ein Bild keine korrekten Farben bekommt.

Jetzt stellt sich die Frage: Wie kann man das Ressourcen schonend auf einem µC implementieren? Natürlich könnte man in einem SPI recv Interrupt das Byte entgegen nehmen und eine Timer neu anstoßen. Das wäre aber auch bei langsameren SPI Geschwindigkeiten schon sehr aufwändig. Eine DMA Lösung ist hier angebrachter. Nur leider schiebt der DMA von allein und ohne Interrupt das eingegangen Byte in den passenden Speicher.

Die Lösung ist einfach: Ein Timer wird als Zähler verwendet. Dieser wird damit beauftragt die Flanken an der Clock Leitung zu zählen. Dazu gibt es in manchen µC schon ein recht umfangreiches Eventsystem, in dem man Timer bei bestimmten Ereignissen einfach triggern kann. Leider vermisst man dies noch auf dem Tiva Cortex M4 und muss stattdessen eine Hardwareverbindung zwischen dem Clockeingangs-Pin und dem PIN für das „Flankenereignis“ setzen.

Um den Zähler auszuwerten brauchen wir CPU Unterstützung. So verwenden wir einen zweiten Timer, der aller 250 us einen Interrupt auslösen soll. In diesem Interrupt lesen wir den Counter aus und vergleichen ihn mit dem Wert den wir vorher ausgelesen haben. Ist dieser gleich, hat sich seit mindestens 250 us und maximal seit 500 us nichts am SPI Eingang getan. Wir deaktivieren und aktivieren den SPI Slave gleich wieder um ihn zu synchronisieren. Außerdem wird eine Flag-Variable gesetzt und warten nun darauf das in der Programm-Hauptschleife Programmfunktionen eingeleitet werden, die das neue Bild entgegen nehmen und daraus das Ausgangsbild berechnen. (Dazu später hier im Blog mehr)

WS2801 Timer-Interrupt (250 us)

Jetzt könnte man denken, was ist wenn der Zähler übergelaufen ist und zufälligerweise nach den 250 us wieder am selben Wert angelangt ist?! Nagut, rechnen wir nach: Ich verwende einen 16 Bit Zähler und zähle fallende und steigende Flanken (es geht auch nur eins von beidem). Es braucht eine SPI Frequenz von 1/0,00025 s * 2^16 Zählschritte / 2 Flanken ~ 131 MHz um den Zähler in dieser Zeit zu überrunden. Die Wahrheit ist, dass der Tiva SPI Slave maximal so schnell wie ein zwölftel der CPU Frequenz betrieben werden darf. Also in unserem Fall genau 10 MHz… Das kann der Ws2801 IC also noch deutlich besser (>20 MHz). In der Praxis takten die LED-Controller jedoch viel langsamer. Durch die Kabelkapazitäten und dem maximalen Strom den ein Treiber liefern kann, wird die Frequenz begrenz. Da mit 10 MHz schon weit über 10.000 RGB LEDs betrieben werden können, ist eine so schnelle Taktung überhaupt nicht nötig!

Ws2801 haben eine weitere gute Eigenschaft. Sie verhalten sich nicht wie Schieberegister. Die ersten Daten die gesendet werden, werden also direkt vom ersten Pixel abgespeichert und alle weiteren Daten einfach durchgereicht und die Signalflanken wieder aufgefrischt.

Für unserer Mikrocontroller Programm bedeutet das, wir brauchen noch eine zweite SPI Schnittstelle, die als Master initialisiert wird. Wenn der DMA also die Meldung gibt, dass alle Daten für das Panel empfangen wurden, werden weitere Daten direkt vom DMA vom SPI Slave auf den SPI Master geschoben. Dabei muss natürlich der Master mindestens gleich schnell oder besser schneller als der Slave seine Daten absetzen können. Ein paar Byte können vom Tiva gebuffert werden. Ist der FIFO jedoch voll, gehen hier Daten, die für das nächste Board/Panel bestimmt wurden, verloren.

Bei der Abstimmung ist nicht allein die MHz Zahl des Slaves zum Master entscheidend. Da der DMA sich auf dem schon sehr belasteten Datenbus des Prozessors einen Slot erkämpfen muss, werden nicht alle Eingangsdaten augenblicklich auch auf dem Master ausgegeben. Es entsteht zwischen jedem Ausgangsbyte eine kleine Lücke.

In meinem Fall hat sich dies so ausgewirkt: Der verwendete LED-Controller hat mit 3,3 MHz unterbrechnungsfrei Daten gesendet. Um diese auch schnell genug wieder vom Tiva Board zu bekommen, habe ich die Ausgangs WS2801 Schnittstelle (Master SPI) auf ca. 4-5 MHz gestellt.

Ich denke diese Einstellungen sollten für die meisten LED-Controller ausreichend sein. Solltet ihr Probleme bekommen, könnt ihr an folgender Funktion die Geschwindigkeiten anpassen:

WS2801 Out ist SSI3

SSIConfigSetExpClk(SSI3_BASE, 120000000, SSI_FRF_MOTO_MODE_0,SSI_MODE_MASTER, 5000000, 8);

Bitte nur den vorletzten Parameter hoch (evtl. runter) stellen. Aktuell ist er auf 5 MHz eingestellt.

Ws2801 In ist SSI2

SSIConfigSetExpClk(SSI2_BASE, 120000000, SSI_FRF_MOTO_MODE_0,SSI_MODE_SLAVE, 5000000*12, 8);

Der vorletzte Parameter gibt die maximale SPI Geschwindigkeit an, die euer LED-Controller fahren darf. Es ist aktuell auch auf 5 MHz eingestellt und kann noch bis 10 MHz verstellt werden. Langsamere SPI Geschwindigkeiten sind bei den 5 MHz im Slave natürlich abgedeckt.

Ich hoffe die SPI Basics waren nicht zu verwirrend. Auf die DMA Details wollte ich noch nicht eingehen. Wenn Fragen offen bleiben, kommentiert  einfach meinen Beitrag…

Advertisements
Dieser Beitrag wurde unter Allgemein, LED-Matritzen abgelegt und mit , , , , , , , , , verschlagwortet. Setze ein Lesezeichen auf den Permalink.

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s