Wymienione elementy są dostępne w postaci wielu gotowych produktów, w tym w łańcuchach świateł połączonych przewodami, sztywnych listwach i matrycach oraz giętkich taśmach. Taśmy mają długość od 1 do 5 m i zawierają od 30 do 144 elementów na metr bieżący. Są one wyposażone w zunifikowane złącza, umożliwiające łączenie ich w dłuższe łańcuchy. Zazwyczaj przy zakupie taśmy otrzymujemy również przewód ze złączem, służący do podłączenia zasilania i sterowania do taśmy.
W opisywanym projekcie świateł choinkowych zastosowano taśmę zwierającą 144 układy na metr. Taśmy o takiej gęstości upakowania elementów umożliwiają uzyskanie szczególnie spektakularnych animacji, dając wrażenie płynności ruchu animowanych obiektów. Oprogramowanie może zostać skonfigurowane do sterowania dowolną liczbą układów; próby przeprowadzono z taśmami o długości od 1, 2, 3 i 4 metrów (odpowiednio 144, 288, 432 i 576 układów).
Zasilanie taśm z WS2812
Projektując oświetlenie efektowe z układami WS2812 należy zwrócić uwagę na moc pobieraną przez układy i wynikające z niej natężenie prądu zasilania oraz sposób doprowadzenia zasilania.
Taśma ze 144 elementami przy wysterowaniu wszystkich diod na pełną jasność pobiera prąd o natężeniu do 10 A. Niezbędna moc zasilacza i sposób doprowadzenia napięcia zasilającego do taśm zależą więc istotnie od z maksymalnej używanej jasności (wartości wypełnienia) diod oraz maksymalnej liczby równocześnie zaświeconych diod.
Praktyka wskazuje, że w przypadku użycia taśm w niewielkim i niezbyt jasno oświetlonym pomieszczeniu maksymalne wypełnienie dla diod nie powinno przekraczać 1/8. Ponieważ efekty świetlne zrealizowane w sterowniku powodują równoczesne świecenie nie więcej niż 1 wszystkich diod, maksymalne natężenie prądu zasilania można szacować na ok. 0.3 A na 144 elementy.
Oznacza to, że sterownik z jedną lub nawet dwiema taśmami może być zasilany podczas prób z interfejsu USB komputera używanego do jego programowania, a sterowane w ten sposób taśmy mogą być zasilane przy użyciu tylko złącz trójstykowych, służących również do transmisji danych.
W przypadku użycia pełnej jasności diod może okazać się konieczne oddzielne doprowadzenie zasilania do każdej taśmy z dwóch stron przy użyciu dodatkowych przewodów, wyprowadzonych standardowo z każdej taśmy.
Jeżeli nie korzystamy z dodatkowych doprowadzeń zasilania, niezbędne jest ich usunięcie lub zaizolowanie w celu wyeliminowania możliwości wystąpienia przypadkowego zwarcia zasilania.
Sterowanie układów WS2812
Opis realizacji transmisji danych do układów WS2812 znajduje się w artykule [EP_WS2812], dostępnym w archiwum EP (numer 3/2014). W projekcie tym dane były transmitowane przy użyciu interfejsu SPI, z kodowaniem danych i obsługą SPI z wykorzystaniem przerwań. Rozwiązanie takie ma jedną istotną zaletę: minimalizuje ono zajętość pamięci RAM mikrokontrolera.
Jego wadami są konieczność pracy z 12-bitowymi ramkami SPI oraz znaczne użycie mocy obliczeniowej procesora związane z obsługą przerwań zgłaszanych z częstotliwością około 200 kHz. Warto podkreślić, że pomimo tak dużej częstotliwości przerwań rozwiązanie takie zużywa znacznie mniejszą część czasu procesora niż całkowicie programowe formowanie strumienia danych dla WS2812, z którego korzysta popularne oprogramowanie dla płytek rodziny Arduino.
Praca z 12-bitowymi ramkami nie jest możliwa w mikrokontrolerach serii STM32F4, w których interfejs SPI używa wyłącznie ramek 8- albo 16-bitowych. Z drugiej strony pojemność pamięci RAM dostępna w serii STM32F4, jak również w większych modelach serii STM32F0, umożliwia przechowywanie całego zakodowanego strumienia danych dla łańcucha WS2812, zajmującego trzykrotnie więcej miejsca niż jego postać wyjściowa, niezakodowana, a dostępny w mikrokontrolerach moduł bezpośredniego dostępu do pamięci (DMA) umożliwia jego transmisję przez interfejs SPI bez udziału procesora.
Rozwiązanie zastosowane w prezentowanym projekcie korzysta więc z transmisji przez SPI wektora przygotowanych wcześniej przez oprogramowanie ramek 16-bitowych przy użyciu DMA. Dzięki temu niemal cała dostępna moc obliczeniowa procesora może być użyta do animacji obiektów i ich rasteryzacji.
W pamięci RAM mikrokontrolera są przechowywane następujące struktury danych:
- Dane animowanych obiektów, zależne od algorytmów animacji, o całkowitym rozmiarze do kilku kB.
- Wartości składowych RGB dla poszczególnych diod - 3 bajty na element, ok. 1700 B przy 576 szt. WS2812.
- Dane zakodowane do transmisji przez SPI - 9 B na element, ok, 5 kB przy 576 szt. WS2812.
Jak wynika z powyższych szacunków, w sterowniku powinien zostać zastosowany model mikrokontrolera wyposażony w min. 16 kB pamięci RAM. Warunki te spełniają m.in. STM32F072, STM32F091 oraz wszystkie modele serii STM32F4.
Sterownik taśm WS2812 - sprzęt
Do realizacji dwóch wersji sterownika użyto płytek STM32 NUCLEO z mikrokontrolerami STM32F091 i STM32F411. Oprogramowanie może zostać łatwo przekonfigurowane dla dowolnego mikrokontrolera serii STM32F0 lub STM32F4 umieszczonego na płytce serii NUCLEO, DISCOVERY lub własnej użytkownika; można je również niezbyt dużym nakładem pracy zaadaptować dla mikrokontrolerów z innych serii rodziny STM32F.
Sterownik jest połączony z taśmą trzema przewodami:, dołączonymi do złącza MORPHO CN10 z prawej strony płytki NUCLEO. Są to linie:
- masy GND (CN10-9),
- zasilania U5V (CN10-8),
- linii danych MOSI/PA7 (CN10-15).
Uwaga: przy takim połączeniu płytka NUCLEO wraz z taśmą LED może być zasilana albo wyłącznie z interfejsu USB komputera albo wyłącznie z zewnętrznego zasilacza, służącego do zasilania taśm. W przypadku użycia zasilacza zewnętrznego, interfejs USB płytki NUCLEO nie może być połączony z komputerem
Struktura oprogramowania sterownika
Całe oprogramowanie składa się z dwóch głównych modułów zapisanych w oddzielnych plikach źródłowych. Pierwszy moduł jest odpowiedzialny za konfigurację peryferiali mikrokontrolera i obsługę transmisji danych do łańcucha układów WS2812. Moduł ten jest specyficzny dla danej serii mikrokontrolerów.
W przedstawionym projekcie użyto dwóch realizacji tego modułu - jednej dla serii STM32F0, drugiej dla STM32F4. Drugi moduł zawiera oprogramowanie sterujące animacją. Jest ono niezależne od typu użytego mikrokontrolera. Moduł animacji nie jest silnie związany z modułem transmisji danych i może zostać łatwo wymieniony na inny, z innymi algorytmami animacji obiektów.
Ponadto w skład projektu wchodzi trzeci plik źródłowy, zawierający procedury wywoływane z modułu animacji i zapewniający zapamiętywanie ostatnio wybranego trybu pracy w pamięci Flash mikrokontrolera przy zaniku zasilania. Podobnie jak w przypadku kodu odpowiedzialnego za transmisję danych, również obsługa pamięci Flash jest specyficzna dla poszczególnych serii mikrokontrolerów.
Pliki
Oprogramowanie zostało przygotowane przy użyciu darmowej wersji środowiska Keil MDK-ARM 5.17. Wszystkie pliki źródłowe projektu są zawarte w pliku archiwum ws2812ctree.zip, dostępnym na serwerze EP. Archiwum składa się z następujących folderów:
- Keil - zawiera foldery z plikami projektów dla obu użytych mikrokontrolerów,
- b_nucleo64 - zawiera pliki definicji zasobów płytki NUCLEO64 oraz plik board.h z parametrami konfiguracji sterownika efektów świetlnych,
- Common - zawiera pomocnicze pliki definicji zasobów mikrokontrolerów STM32F
- WS2812 - zawiera dwie wersje modułu z funkcją main() i obsługą transmisji: WS2812dma-f0.c i WS2812dma-f4.c,
- led-anim - zawiera procedury animacji efektów świetlnych i dwie wersje obsługi pamięci Flash.
W celu skompilowania projektów w środowisku Keil niezbędne jest zainstalowanie przy użyciu Pack Installer trzech pakietów: ARM::CMSIS, Keil::STM32F0_DFP i Keil::STM32F4_DFP.
Plik board.h jest włączany do wszystkich plików źródłowych projektu. Zawiera on dyrektywy #include włączające pliki specyficzne dla użytego w projekcie mikrokontrolera, definicje stałych związanych z taktowaniem wersji z STM32F0 oraz podstawowe parametry sterownika - częstotliwość generowani ramek animacji, liczbę pikseli w łańcuchu i maksymalne wypełnienie dla diod.
Inicjowanie mikrokontrolera i obsługi transmisji
Przy zastosowaniu interfejsu SPI do transmisji danych do układów WS2812, każdy przesyłany oktet musi zostać zakodowany w postaci 24 bitów, a częstotliwość transmisji bitów powinna wynosić około 2.4 MHz [EP_WS2812].
Ponieważ w mikrokontrolerach serii STM32F częstotliwość transmisji SPI jest uzyskiwana przez podział częstotliwości szyny APB mikrokontrolera przez potęgę dwójki z zakresu 2..256, łatwą do uzyskania częstotliwością transmisji jest 2.5 MHz, a w celu jej uzyskania mikrokontroler powinien być taktowany częstotliwością będącą wielokrotnością 20 MHz.
W wersji oprogramowania dla mikrokontrolera STM32F091 główny plik źródłowy nosi nazwę WS2812dma-f0.c. Ponieważ domyślnie włączany do projektu plik system_stm32f0xx.c, pochodzący z pakietu Keil:STM32F0_DFP zawiera funkcję SystemInit() programującą generator zegar w nieodpowiedni dla naszego zastosowania sposób, należało zmienić nazwę tej funkcji w pliku system_stm32f0xx.c i zdefiniować własną funkcję SystemInit() w pliku WS2812dma-f0.c.
W realizacji z STM32F091 użyto częstotliwości rdzenia mikrokontrolera i szyny APB równej 40 MHz, uzyskiwanej z generatora PLL taktowanego wewnętrznym generatorem HSI o częstotliwości ok. 8 MHz.
W wersji oprogramowania dla mikrokontrolera STM32F411 główny plik źródłowy nosi nazwę WS2812dma-f4.c. Źródłem głównego przebiegu zegarowego jest syntezer PLL taktowany wewnętrznym generatorem HSI. Główny zegar mikrokontrolera ma częstotliwość 80 MHz, a zegary szyn APB - 40 MHz.
Kolejnym krokiem po zaprogramowaniu generatora zegara jest zainicjowanie modułów peryferyjnych. Do transmisji danych jest używany moduł SPI1. Aktywne są jedynie dwa wyjścia MOSI tego modułu, wyprowadzone na linie PA7 i PB5 - łańcuch układów WS2812 może być podłączony do jednego z dwóch dostępnych wyjść.
Po zainicjowaniu portów i interfejsu SPI1 jest wywoływana procedura inicjowania modułu animacji app_init(). Następnie jest programowany układ wykrywania spadku napięcia zasilania - włączane jest generowanie przerwań przy spadku napięcia poniżej 2.8 V.
Pseudofunkcja SysTick_Config ustawia timer Systick na zgłaszanie przerwań z częstotliwością 100 Hz, która jest częstotliwością generowania kolejnych faz animacji. Wywołanie to obniża jednocześnie priorytet przerwania SysTick, co jest istotne dla zapewnienia szybkiej reakcji na zanik zasilania. Ostatnią czynnością jest włączenie w procesorze funkcji uśpienia przy wyjściu z obsługi wyjątku i uśpienie procesora w oczekiwaniu na przerwanie.
Wszystkie użyte w projekcie układy peryferyjne są w obu wersjach projektu inicjowane w podobyn sposób. Różnice pomiędzy zawartościami rejetrów sterujących w obu wersjach wynikają z drobnych różnic w budowie peryferiali pomiędzy STM32F0 i STM32F4.
Obsługa transmisji danych
Do inicjowania transmisji danych do WS2812 służy funkcja WS2812, umieszczona w głównym pliku źródłowym wraz z procedurą inicjującą. Obie wersje (dla F0 i F4) są zbudowane analogicznie, a jedyna różnica pomiędzy nimi polega na odmiennym programowaniu modułu DMA, którego implementacje w obu seriach mikrokontrolerów wykazują istotne różnice.
Funkcja WS2812_start zawiera instrukcję warunkową, pomijającą całą transmisję danych w przypadku, gdy poprzednia transmisja nie została zakończona. Dzięki temu w można np. zachować stałą częstotliwość generowania ramek przez moduł animacji, niezależnie od liczby sterowanych elementów - przy większej liczbie elementów nie będą jednak wyświetlane wszystkie wygenerowane ramki.
Działanie funkcji rozpoczyna się od zakodowania danych do transmisji. Zakodowane dane zostają umieszczone w buforze enc_wsdata[]. Pierwsze ramki danych w buforze pozostają niewykorzystane i mają stałą wartość 0 - ich transmisja służy do wygenerowani symbolu RESET dla układów WS2812.
Następnie zostają zainicjowane dwie transmisje DMA - jedna z nich przesyła dane z bufora enc_wsdata[] do interfejsu SPI, a druga służy do wyzerowania bufora zawierającego niezakodowane kolory poszczególnych pikseli. Zerowanie bufora przez DMA jest szybsze niż zerowanie programowe, więc ograniczamy w ten sposób zajętość procesora, zwiększając czas dostępny dla procedury sterowania animacją.
Warto zauważyć, że ze względu na użycie do zerowania bufora kanału DMA o priorytecie arbitrażu wyższym niż kanału używanego do transmisji danych, zachodzi potrzeba programowego podwyższenia priorytetu kanału, z którego korzysta SPI podczas programowania rejestru konfiguracji kanału. W przeciwnym przypadku transmisja SPI mogłaby zostać opóźniona.
Zawartość obu wersji pliku z inicjowaniem mikrokontrolera i obsługą transmisji zamieszczono poniżej
Moduł animacji
Moduł animacji jest niezależny od typu mikrokontrolera i wspólny dla obu wersji projektu. Jest on zapisany w pliku ctree1.c. Na początku pliku są zdefiniowane stałe - parametry animacji. Dwie główne procedury zawarte w tym pliku - to procedura app_init(), wywoływana jednokrotnie podczas inicjowania sterownika oraz procedura obsługi przerwania timera systemowego SysTick.
Moduł animacji umożliwia wyświetlanie czterech rodzajów obiektów należących do dwóch typów - nieruchomych, pojedynczych pikseli o modulowanej jasności oraz zmieniających położenie grup pikseli. Do animacji tych dwóch typów obiektów służą oddzielne fragmenty programu i struktury danych.
Animacja może działać w pięciu trybach. W czterech z nich wyświetlane są obiekty jednego z dostępnych typów, w piątym (domyślnym po zaprogramowaniu sterownika) - wyświetlane są równocześnie obiekty wszystkich czterech typów. Tryb animacji jest przełączany przy użyciu przycisku użytkownika (w kolorze niebieskim) na płytce NUCLEO.
Procedura obsługi przerwania przy zaniku zasilania PVD_IRQHandler() zapamiętuje ostatnio wybrany tryb pracy w pamięci Flash. Procedura app_init() odczytuje z pamięci Flash zapamiętany podczas wyłączania tryb pracy sterownika. Dzięki temu przy kolejnym włączeniu sterownik zachowuje ostatnio ustawiony tryb pracy.
Procedury animacji
Kod odpowiedzialny za animację obiektów jest umieszczony w procedurze obsługi timera SysTick, wywoływanej z częstotliwością określoną w pliku board.h. parametry animacji zdefiniowane na początku pliku ctree1.c zostały obliczone dla częstotliwości generowania ramek animacji równej 100 Hz. Generowanie kolejnych ramek animacji składa się z trzech faz:
- generowania nowych obiektów,
- animowania obiektów,
- rasteryzacji obrazu obiektów.
Warunkiem utworzenia nowego obiektu jest wolne miejsce w strukturze danych opisującej obiekty. Maksymalna liczby obiektów każdego typu jest stała, a wygenerowanie nowego jest możliwe po zakończeniu życia jednego z dotychczas aktywnych obiektów. Ponadto pomiędzy utworzeniem każdego obiektu każdego typu musi upłynąć określony czas.
Zarówno odstęp czasowy generowania obiektów jak i wartości wszelkich parametrów obiektów są wyznaczane przy użyciu generatora liczb pseudolosowych, zrealizowanego w postaci rejestru przesuwającego LFSR.
Losowanie koloru obiektu
Pierwszy krokiem przy tworzeniu nowego obiektu jest losowanie jego koloru. Aglgorytm losowania koloru został opracowany w taki sposób, by zapewnić w miarę kontrastowe kolory kolejnych obiektów. Suma jasności składowych koloru obiektu jest stała. Co drugi kolor obiektu pochodzi z kolejnych odcinków trójkąta barw rgb (jedna ze składowych ma wartość 0).
Tworzenie obiektów
Utworzenie obiektu w postaci nieruchomego piksela polega na wylosowaniu jego położenia. W celu uniknięcia nakładania i sklejania obiektów punktowych obiektów losowanie powtarzane jest do uzyskania pozycji nie zajmowanej przez żaden inny obiekt punktowy ani nie sąsiadującej z nią bezpośrednio.
Poza punktami oprogramowanie może tworzyć dwa typy obiektów ruchomych - piksele porszające się w górę taśmy oraz "fajerwerki" wystrzeliwane w górę taśmy, a następnie "spadające" w dół. Poruszające się piksele z chwilą dotarcia do końca taśmy zamieniają się w "spadające" fajerwerki. Szybkość ruchu pikseli jest stała. Szybkość początkowa fajerwerków jest zmienna w pewnym przedziale, dzięki czemu fajerwerki docierają w pobliże końca taśmy, ale na różne wysokości.
Użycie dobrej jakości generatora pseudolosowego do wyznaczania wartości parametrów obiektów powoduje, że w całej animacji nie daje się zauważyć powtarzalności ani regularności.
Animowanie obiektów nieruchomych
Animowanie nieruchomych pikseli polega na modulacji ich jasności. Dostępne są dwa rodzaje modulacji: piksele "statyczne" zaświecają się płynnie, świecą ze stałą jasnością przez losowy, niezbyt długi czas, a następnie płynie gasną. Piksele "dynamiczne" mają zmienną jasność, przypominającą migotanie świecy. Ich czas życia jest znacznie dłuższy od czasu świecenia pikseli statycznych.
Animowanie obiektów ruchomych
Animowanie obiektów ruchomych polega na zmianie ich pozycji, a w przypadku "fajerwerków" - również na symulacji efektu powolnego wygaszania smugi światła za poruszającym się obiektem. Dzięki temu fajerwerki pozostawiają za sobą ślad o długości zależnej od bieżącej prędkości wznoszenia lub opadania. Smuga za fajerwerkami jest uzyskiwana przez przechowywanie kolorów ciągu pikseli i płynne wygaszanie ich ze stałą szybkością.
Pozycja czoła każdego obiektu ruchomego jest określana z dokładnością 1/256 piksela. Ułamkowa część pozycji jest używana jako parametr do antyaliasingu kolorów pikseli.
Parametry animacji
Poniżej zamieszczono fragment pliku ctree1.c z definicjami stałych sterujących animacją. Przy stałych są umieszczone komentarze opisujące ich znaczenie.
Wszystkie parametry czasowe animacji są wyrażone w jednostkach 1/100 sekundy. Stała MAXFTIME określa maksymalny czas wznoszenia dla fajerwerków, obliczony w taki sposób, by docierały one do końca taśmy. Czas ten zależy od liczby pikseli w sterowanych taśmach. Stała MINFTIME określa pośrednio minimalną wysokość, do której mogą docierać fajerwerki, a stała FTDELTA - różnicę czasu wznoszenia dla kolejnych fajerwerków.
Rasteryzacja obiektów
Ostatnią fazą procedury animacji jest rasteryzacja obiektów. W przypadku obiektów ruchomych odbywa się ona z uwzględnieniem pozycji ułamkowych (obiekt położony "pomiędzy" pikselami), co daje wrażenie większej płynności ruchu, zwłaszcza przy małych prędkościach.
Po rasteryzacji jest wywoływana procedura WS2812_start() enkodująca dane dla WS2812 i inicjująca ich transmisję do łańcucha układów.
Grzegorz Mazur
Bibliografia
1. [EP_WS2812] G. Mazur, 32 bity jak najprościej (3) STM32F0 - płytka eksperymentalna
2. z mikrokontrolerem STM32F030F4, Elektronika Praktyczna 03/2014, s.90..96
3. [WS2812B] WorldSemi, WS2812B Intelligent control LED integrated light source, 2014, www.world-semi.com
4. [UM1724] UM1724 User manual STM32 Nucleo boards, Rev 7, ST Microelectronics 2015
5. [RM0383] RM0383 Reference manual, STM32F411xC/E advanced ARM®-based 32-bit MCUs, Rev 1, ST Microelectronics, July 2014
6. [F411DS] STM32F411xC STM32F411xE Datasheet, Rev 4, ST Microelectronics, February 2015
7. [RM0091] RM0091 Reference manual, STM32F0x1/ STM32F0x2/STM32F0x8 advanced ARM®-based 32-bit MCUs, Rev 8, ST Microelectronics, July 2015
8. [F091DS] STM32F091xB STM32F091xC Datasheet, Rev 2, ST Microelectronics, February 2015