
Po przygodach z matrycami zbudowanymi na max7219, przyszła pora na coś bardziej zaawansowanego. Miałem w planach zrobienie własnej matrycy z 1500 jednokolorowych ledów 0603, 3 rejestrów przesuwnych i paru elementów dyskretnych, ale jak już ją zaprojektowałem, to przypadkiem trafiłem na matryce hub75. Ich głównym zastosowaniem są telebimy, ale wygląda na to, że ze względu na swoją dostępność i cenę (70zł za 64x32 2,5mm pitch), mają także bardziej prozaiczne zastosowania. Minus jest taki, że to tylko LEDy (w dodatku ze słabym dyfuzorem), rejestry i dekoder adresów, więc trzeba nimi samemu sterować, do tego z dużą częstotliwością, ale jak się człowiek by postarał, to nawet ponad 48bit da się z tych 1bit matryc wydusić.
Założenia początkowe były następujące:
* jak najwięcej rzeczy realizowanych w sprzęcie;
* montowane bezpośrednio pod PCB matrycy;
* pomiar prądu pobieranego przez wyświetlacz (do automatycznej kalibracji maksymalnej jasności)
* odświeżanie na poziomie około 200Hz
* kolor RGB444 + 6bit globalnej jasności
* do matryc 64x32, maks 192x64
* komunikacja po SPI, I2C i szeregowym RS485
Po przestudiowaniu tego co jest dostępne w CubeMX i z grubsza posiada co jest potrzebne (dwa timery advanced), pamięć przynajmniej 128kiB (w najgorszym wypadku 2 bufory po 50k każdy), wybór padł na STM32F730. Do tego koszt 12zł, idealnie.
Podstawy sterowania matrycami:

Matryce maja różne kombinacje pinów w zależności od wielkości (i co za tym idzie różny scan-rate), ale generalnie najczęściej występującą kombinacją jest taka jak powyżej. Mamy tutaj 6 pinów danych o kolorze, po dwa na składową (Rx, Gx, Bx), zegar (CLK), zatrzask (LAT), wybór wiersza (A, B, C, D), i Output Enable. Działa to mniej więcej tak:
* Pinami ABCD wybieramy wiersz (no, właściwie dwa), który będzie aktualnie wyświetlony 1-16. Jeśli przykładowo wybierzemy wiersz 0, to wyświetlone po podaniu sygnału niskiego na OE zostaną wiersze 0 i 16 (scan 1/16... choć jak dla mnie to bardziej 2/32);
* Wejścia zatrzasków wierszy z górnej połowy ekranu są podłączone do pinów R/G/B1, dolnej do R/G/B2. Są to rejestry przesuwne, 1bit na LED. Przy matrycy x64 trzeba podać 64 takty zegara na pin CLK i wystawić adekwatną liczbę bitów danych na pinach RGBx;
* Machnąć pinem LAT, przejście niski -> wysoki zatrzaskuje daje w rejestrach;
* Włączyć na jakiś czas pin OE, poczekać chwilę i wrócić do pierwszego punktu;
Niestety żaden STM32 nie ma interfejsu HexSPI o ile taki w ogóle istnieje, dlatego wysyłka danych została zrealizowana na zaawansowanym timerze i DMA. Aby wszystko działało timer musi być połączony z kontrolerem DMA, który ma możliwość zapisywania danych do urządzeń na AHB. W przypadku wielu STMów musi być to timer na APB2, bo te współpracują z DMA2, a tylko DMA2 może wykonywać transfery z/do AHB (gdzie jest GPIO). Dodatkowo timer musi posiadać tryb one pulse i rejestr powtórzeń RCR. Wszystkie warunki spełniają TIM1 i TIM8.
Konfiguracja TIM8 do wysyłki danych:
Code: C
Procedura obsługi jest prosta, CPU przygotowuje dane, które zostana wpakowane do rejestru BSRR portu C. Timer jest ustawiony w trybie OnePulse i 64 (ile pikseli jest w poziomie) powtórzenia. Na kanale CH1 generowany jest sygnał PWM z 50% wypełnieniem, który jest tu sygnałem CLK. Dane wystawiane sa do pinów na porcie C przez DMA, wyzwalane zdarzeniem Capture/Compare kanalu 1. Kiedy DMA zakończy pracę timer wyłączy się sam (dzieki czemu przerwania "komunikacyjne" mogą mieć wyższy priorytet). Eksperymentalnie wyszło, że najszybszym zegarem naszego SPI, przy którym nie następują przekłamania, to około 14MHz. Obliczanie kolejnego pakietu danych jest wykonywane równolegle z ich wysyłką.
Konfiguracja TIM1 (BCM/OE):
Code: C
Kiedy DMA zakończy wysyłkę danych, odpalane jest przerwanie. W tymże uruchamiany jest kolejny timer TIM1 w trybie OnePulse. Ten timer aktywuje sygnał OE, co powoduje wyświetlenie załadowanych wcześniej danych i wyzwolenie kolejnego przerwania gdzie wcześniej przygotowane dane są ładowane do nowego zestawu rejestrów.
Poczałkowo chciałem zrealizować wielobitowy kolor za pomocą PWM, ale po przekopaniu internetu zdecydowałem się na zastosowanie Binary Code Modulation. Dla każdego wiersza przemiatane są wszystkie ustawione bity koloru, a dopiero po ich wyświetleniu wiersz zmieniany jest na kolejny.
Kod przerwań:
Code: C
Sumarycznie przy włączonym DCache, ICache oraz 216MHz da się uzyskać 54bitowy kolor, o ile można tolerować FPS na poziomie 48 klatek na sekundę. Ja nie mogę, więc zostałem przy 12bit kolorze (444) + 10bit globalnej jasności, przy którym FPS wzrasta do 460 klatek. To przy matrycy rozdzielczości 64x32, poszerzenie do 128x32 obniża FPS o około 40.
Sam układ projekt jest względnie prosty, bo to w sumie zasilanie, konwertery poziomów napięć i sam procesor.



Do tego data flash 128Mbit (był najtańszy) dual SPI - na fonty i grafiki, mapowany do pamięci. Software poza tym, ze jest względnie kompatybilny z formatem danych używanym w max7219 to pozwala na rysowanie rzeczy przez kontroler, skoro i tak mam w urządzeniu dwa MCU z czego jeden obsługuje tylko ekran, to może w całości przejąć na siebie zadania rysowania i przechowywania potrzebnych do tego danych (a sam F730 ma tylko 64k flasha... no, w sumie to 512, ale pewne są tylko 64k).
Przy okazji okazało się, że da się uzyskać przerwanie końca transmisji SPI przy niewiadomej ilości danych + w pełni sprzętową obsługa transmisji przez urządzenie, choć konfiguracja jest nietypowa.
Normalnie kiedy pin NSS jest w trybie AF jako NSS ustawienie przerwania na EXTI nic nie daje, przerwanie nie działa. Ale kiedy ustawi się pin z przerwaniem w EXTI, włączy i skonfiguruje SPI i dopiero wtedy zmieni się na AF - to i SPI ma kontrolę nad pinem dzięki czemu samo zarządza transferem/DMA i możemy dostać przerwanie kiedy pin NSS zmienił stan na wysoki bez podłączania go do 2 pinów.





Cool! Ranking DIY