vrijdag 6 maart 2020

Software - De list (2: NeoPixels)

Een tweede list voor het minieme aantal ingangen en uitgangen van de ESP32 wordt bedacht voor de aansturing van alle indicatie- en storingslampjes. De dashboardlampjes zouden aangestuurd kunnen worden met de I/O-expanders uit het vorige bericht. Maar dat zou te gemakkelijk zijn ;-). Het idee is om hiervoor NeoPixels te gaan gebruiken.


https://www.adafruit.com/


NeoPixels zijn RGB-leds die via één digitale uitgang van de ESP32 aan te sturen zijn. Over die digitale uitgang wordt een patroon van bits naar de NeoPixel gestuurd. Precies 24 bits; voor elke kleur - rood, groen en blauw - acht bits. Met die acht bits wordt de intensiteit van elke kleur ingesteld (0..255) en kunnen dus 256 x 256 x 256 = ruim 16 miljoen kleuren gekozen worden. Mooi, één digitale uitgang voor 16 miljoen kleuren! Maar het wordt nog mooier, want NeoPixels kunnen in een string achter elkaar geschakeld worden; en ook dan is er nog steeds maar één digitale uitgang nodig. Zijn er twee NeoPixels achter elkaar geschakeld, dan worden niet 24, maar 48 bits naar buiten gestuurd. De eerste 24 bits worden door de eerste NeoPixel 'gebruikt', de resterende bits worden doorgestuurd naar de tweede NeoPixel. Zo kunnen er honderden achter elkaar geschakeld worden waarbij elke NeoPixel telkens 24 bits van het treintje bits afsnoept en de rest doorgeeft. Ik wil (o.a.) gebruik maken van een stick met acht NeoPixels:


https://www.adafruit.com/


Voldoende voor alle indicatielampjes en nog voor andere creatieve uitingen. Zo kan zo'n balkje ledjes ook gebruikt worden ter indicatie van het toerental.

Tot nu toe klinkt het allemaal positief. Maar er zit een addertje onder het gras. De NeoPixels zijn behoorlijk kritisch als het gaat om de timing van de pulsjes die ontvangen worden. Dit komt omdat er maar één pin gebruikt wordt voor het bitpatroon en daarnaast niet net als bij I²C-bus een separaat kloksignaal aanwezig is. Een digitale 0 wordt gevormd door de uitgang van de ESP32 eerst gedurende 300 ns (jawel nanoseconde) hoog te maken en vervolgens 800 ns laag. Een digitale 1 wordt herkend als de uitgang 800 ns hoog en 325 ns laag wordt gemaakt.


WS2812-timing

Als de uitgang enkele tientallen microseconden laag blijft (Treset), dan worden de nieuw ontvangen RGB-waarden van alle NeoPixels gebruikt om gelijktijdig alle leds aan te sturen. De leds houden die kleur totdat er een nieuw treintje met kleurenbits is langsgekomen. Omdat de tijdwaarden zo kort zijn, gaat dit allemaal razendsnel. Dit protocol is vastgelegd in de WS2812-specificatie. Er zijn inmiddels enkele verschillende versies van dit protocol waarbij vooral de timing anders is. En omdat juist die timing een beetje kritisch is, is het belangrijk om te weten welke versie van de WS2812-specificatie bij de gebruikte NeoPixels hoort.

De ESP32 werkt - zoals in het vorige bericht vermeld - met een multitasking besturingssysteem genaamd FreeRTOS. De verschillende taken die hierin draaien moeten zo nu en dan wat tijd gunnen aan de andere taken. Normaliter gebeurt dit door een taak even zogenaamd te pauzeren. In een microcontroller zónder multitasking besturingssysteem (bijvoorbeeld een Arduino UNO) zal een delay-functie de processor eventjes bezig houden (blocking) en vervolgens weer met het programma verder gaan. In een multitasking besturingssysteem is dit uit den boze. Het pauzeren van een taak zal de processor niet blokkeren, maar juist de tijd geven wat aandacht aan een andere taak te geven. In een FreeRTOS-taak wordt hiervoor de functie vTaskDelay() gebruikt. Deze functie accepteert een aantal ticks als argument. Eén tick is de kleinste tijdsduur die te gebruiken is om een taak te pauzeren. De lengte van een tick is afhankelijk van de snelheid waarmee FreeRTOS tussen taken schakelt. En dat doet 'hij' standaard 100 keer per seconde. Zo'n tick is hierdoor ongeveer 10 ms. Je ziet direct dat dit véél te lang is om de WS2812-timing voor elkaar te krijgen. Dit moet dus op een andere manier aangepakt worden.

Bij de I²C-bus hadden we dit probleem niet, omdat de timing en afhandeling van die bus in de hardware van de ESP32 wordt uitgevoerd. Voor het WS2812-protocol is echter geen hardware in de ESP32 aanwezig. Of misschien toch wel...

Zoekende op internet en in de documentatie van Espressif (de maker van de ESP32) kwam ik de Remote Control-hardware (RMT) tegen. Net als de CAN-bus en de I²C-bus een stukje hardware in de ESP32 waarmee het bitpatroon van een afstandsbediening gerealiseerd kan worden. De meeste afstandsbedieningen werken met een infrarood-led. Deze led zendt afhankelijk van de ingedrukte knop op de afstandsbediening (en het merk) een ander treintje bitjes naar de ontvanger (bijv. de tv). Ook dit bitpatroon volgt een strikt tijdschema.

Een klein deel van het RMT-blokschema (Espressif)

De RMT-hardware is net als de CAN-bus en de I²C-hardware vooraf te voorzien van een reeks commando's - hier een serie getalletjes waarmee de tijd van het hoog en laag worden van de digitale uitgang bepaald wordt. Vervolgens krijgt de RMT-hardware vanuit de software de opdracht zijn ding te doen. Daar is de software dan niet meer bij betrokken. De precieze timing wordt volledig afgehandeld door de RMT-hardware zelf. Deze heeft een tijdresolutie overeenkomstig de interne klok van de microcontroller. Die draait op 80 MHz, wat overeenkomt met een tijdresolutie van 12.5 ns. Aangezien de timing van de WS2812 in de grootteorde van 100 ns ligt, is dit nauwkeurig genoeg.

Timing-data

De timing-data wordt aangeboden in een array van 32-bits woorden. Die 32-bits wordt gevuld met twee keer een tijdsduur van 15 bits en de resterende twee bitjes om het niveau van het signaal aan te geven. Als ik het niet zou weten, zou ik denken dat het bedacht is voor het WS2812-protocol. Voor elk bit heb je in dit protocol namelijk een Hoog- en een Laag-tijdsduur (zie hierboven) nodig. Om één NeoPixel aan te sturen zijn precies 24 (3 x 8 voor R, G en B) bits nodig; voor de RMT-hardware komt dit neer op een array van 24 x 32-bits woorden. Voor een stick van acht NeoPixels komt dit uit op 8 x 24 x 32 bits. Da's ruim 6000 bits. Voor een doorsnee computer een druppel op een gloeiende plaat, voor een microcontroller best wel wat geheugen. Gelukkig heeft de ESP32 aardig wat geheugen aan boord, dus dat levert hier geen beperkingen op.

Naast de taken die eerder beschreven zijn (CAN-bus en I²C-bus) is er nu weer een belangrijke taak bijgekomen. Het aansturen van NeoPixels via de RMT-hardware. Drie onafhankelijke taken die netjes door FreeRTOS afgehandeld worden. Er komen er nog meer...

Geen opmerkingen:

Een reactie posten