Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Elektroda.pl
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

Sterownik matryc LEDowych z interfejsem hub75

Sareph 06 Feb 2021 14:50 2970 15
  • Sterownik matryc LEDowych z interfejsem hub75
    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:

    Sterownik matryc LEDowych z interfejsem hub75

    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
    Log in, to see the code


    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
    Log in, to see the code


    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
    Log in, to see the code


    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.

    Sterownik matryc LEDowych z interfejsem hub75 Sterownik matryc LEDowych z interfejsem hub75 Sterownik matryc LEDowych z interfejsem hub75

    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.

    Sterownik matryc LEDowych z interfejsem hub75 Sterownik matryc LEDowych z interfejsem hub75 Sterownik matryc LEDowych z interfejsem hub75 Sterownik matryc LEDowych z interfejsem hub75 Sterownik matryc LEDowych z interfejsem hub75

    Cool! Ranking DIY
    Can you write similar article? Send message to me and you will get SD card 64GB.
    About Author
    Sareph
    Level 23  
    Offline 
    Sareph wrote 557 posts with rating 306, helped 58 times. Been with us since 2004 year.
  • #2
    piotr_go
    DIY electronics designer
    Sareph wrote:
    jak się człowiek by postarał, to nawet ponad 48bit da się z tych 1bit matryc wydusić

    64pix*16rzędów*50Hz*65536(16b/kolor) = >3GHz !
    Limit dla tych scalaków to 20MHz z tego co pamiętam.
  • #3
    Sareph
    Level 23  
    piotr_go wrote:
    64pix*16rzędów*50Hz*65536(16b/kolor) = >3GHz !
    Źle liczysz: 64px * 16rzędów * 200Hz * 16bit (bo BCM, nie PWM) = 3,3MHz, ledwie.

    Tutaj głównym ograniczeniem jest czas wyświetlania coraz to bardziej znaczących bitów, bo każdy z nich musi w końcu być wyświetlony 2x dłużej niż poprzedni. ;)
  • #4
    piotr_go
    DIY electronics designer
    Nie bardzo wiem jak miało by to działać.
    Rejestr przesuwny w wyświetlaczu nie pozwoli sterować jasnością za pomocą szerokości bitu.
    Poza tym jeżeli bit0 jest 128 razy mniejszy niż bit7 to wymagane częstotliwości są takie same jak w PWMie, a tylko komplikujemy sobie układ.

    Cytat z tej strony którą podałeś dla 8b koloru:
    Quote:
    ON for 1 tick (because bit 0 is 1)
    OFF for 2 ticks (because bit 1 is 0)
    ON for 4 ticks (because bit 2 is 1)
    OFF for 8 ticks (because bit 3 is 0)
    ON for 16 ticks (because bit 4 is 1)
    OFF for 32 ticks (because bit 5 is 0)
    ON for 64 ticks (because bit 6 is 1)
    OFF for 128 ticks (because bit 7 is 0)
  • #5
    Sareph
    Level 23  
    piotr_go wrote:
    Rejestr przesuwny w wyświetlaczu nie pozwoli sterować jasnością za pomocą szerokości bitu.
    Niby nie, ale... Używając BCM żeby mieć 8 bit koloru wystarczy wypchnąć dane do rejestrów tylko 8 razy na rząd. I cały czas potrzebny na te 8 bit to tylko 256 "slotów" zamiast 256 * 8 przy PWM.
  • #7
    eurotips
    Level 37  
    W celach edukacyjnych kupiłem taki panel za 50zł u chińczyka, model P4 full color.
    Nie brałem modułu sterującego bo kosztował drugie tyle i wymaga softu na PC.
    Wysterowałem go z Arduino Nano.
    Jakoś z kolorami nie najlepiej, tylko 8 w zasadzie, prawdopodobnie projekt z Github powstał do sterowania modelu P3 a ja mam P4 i stąd te słabe kolory. Ale wgrywam sobie grafikę do ATMega328, wchodzi bez problemu, szybko się potem ładuje po włączeniu, takie skomplikowane sterowniki to tylko do wyświetlania obrazów ruchomych z dużym odświeżaniem.

    Sterownik matryc LEDowych z interfejsem hub75
  • #8
    piotr_go
    DIY electronics designer
    Próbowałem zasnąć, ale mózg nie dawał mi spokoju. "Coś tu jest jednak nie tak..." :)
    Czy czasem maksymalna jasność nie jest ograniczona do 1/4 (zakładając 8b na kolor) przy tym sposobie sterowania?
    Najstarszy bit dostanie maksymalnie 1/8 czasu zamiast 1/2.
    PWM wypadnie jaśniej kosztem większego transferu.
  • #9
    Sareph
    Level 23  
    piotr_go wrote:
    Próbowałem zasnąć, ale mózg nie dawał mi spokoju. "Coś tu jest jednak nie tak..." :)
    Ooo pewnie wiele rzeczy :D

    piotr_go wrote:
    Czy czasem maksymalna jasność nie jest ograniczona do 1/4 (zakładając 8b na kolor) przy tym sposobie sterowania?
    Dobre pytanie, nie wiem - znaczy nie badałem. Ale wydaje mi się, że powinny być nawet jaśniejsze. Z tego tylko powodu, że czas "obsługi" jednego wiersza jest znacznie krótszy co oznacza, że może być włączany częściej. No ale, ta hipoteza nie uwzględnia tego, że jeszcze po drodze trzeba dane do wierszy wysłać co trochę dodaje przerw, szczególnie przy krótkich impulsach.

    Niestety wycieczka na google, w poszukiwaniu większej liczby wpisów o "Binary Code modulation/Bit Angle Modulation", dała taki rezultat, że nikt jeszcze się nad ta kwestią nie pochylił. ;)
  • #10
    piotr_go
    DIY electronics designer
    Sareph wrote:
    Z tego tylko powodu, że czas "obsługi" jednego wiersza jest znacznie krótszy co oznacza, że może być włączany częściej

    W obydwu przypadkach (pwm i tym twoim) rząd dostanie 1/16 czasu całego wyświetlacza.*

    Sareph wrote:
    No ale, ta hipoteza nie uwzględnia tego, że jeszcze po drodze trzeba dane do wierszy wysłać co trochę dodaje przerw

    Podczas wysyłania można chyba wyświetlać (rejestr z zatrzaskiem)?

    Sareph wrote:
    szczególnie przy krótkich impulsach.

    Właśnie z tego powodu napisałem że tylko 1/4 jasności.

    Jeżeli dane każdego bitu odcienia wyślesz z tą samą prędkością, to bit 0 i bit 7 dostanie 1/8 czasu linii.
    Aby proporcje były zachowane musisz linię bitu 0 zgasić 128 razy szybciej jak linię bitu 7.
    Tym sposobem linia nigdy nie będzie zapalona przez 100% swojego czasu.
    Aby uzyskać 100% musiał byś wysyłać dane linii bitu 0 128 razy szybciej niż linii bitu 7. Tak żeby b7 dostał połowę czasu zamiast 1/8.

    *nie dotyczy TVP :D
  • #11
    Sareph
    Level 23  
    piotr_go wrote:
    W obydwu przypadkach (pwm i tym twoim) rząd dostanie 1/16 czasu całego wyświetlacza.*
    To tak, ale chodzi bardziej o to, że... noo, w wypadku BAM cały rząd jest "załatwiany" w jednym cyklu, w wypadku PWM, popraw mnie jeśli się mylę - nie da się wielobitowego koloru w taki sposób, bo PWM możesz tutaj regulować tylko cały rząd na raz i trzeba by tak obsługiwać po jednym pikselu. Chyba, ze cos mi umyka. Inna sprawa, że w tym konkretnym przypadku PWM reguluje "globalną jasność", a BCM kolory.

    piotr_go wrote:
    Podczas wysyłania można chyba wyświetlać (rejestr z zatrzaskiem)?
    Tak, ale ten kod jest napisany tak a nie inaczej (dopiero po fakcie na to wpadłem), więc działa jak działa, a że działa wystarczająco dobrze jak na to co potrzebuję, to raczej tak zostanie (choć nigdy nie wiadomo). ;)

    piotr_go wrote:
    Aby uzyskać 100% musiał byś wysyłać dane linii bitu 0 128 razy szybciej niż linii bitu 7. Tak żeby b7 dostał połowę czasu zamiast 1/8.
    Nie, czekaj? Dlaczego? Do 100% nigdy nie dojdzie, ale 99% (bo wciąż trzeba odrobinę czasu na zatrzaśniecie i ewentualnie zmianę wiersza)... hm, hm, matematyka na ratunek :D

    Przy 13,5MHz wysłanie danych (64 bitów) trwa 4,17us jeśli dobrze liczę, a dla 200Hz i 8 bit, najmniej znaczący bit będzie trwał 1s / 200Hz / 16wierszy / 255 (bo 8 bit) = 1,22uS. Czyli żeby mieć 99%, to by trzeba podnieść prędkość wysyłki do 25MHz (2,6us) i obniżyć kolor do... 7 bit, albo fps do 100.

    piotr_go wrote:
    *nie dotyczy TVP :D
    Cóż, tam to ponad 100%. :D
  • #12
    piotr_go
    DIY electronics designer
    Sareph wrote:
    PWM możesz tutaj regulować tylko cały rząd na raz

    Zgadza się. Wysyłasz rząd 256 razy (8b odcień)

    Sareph wrote:
    żeby mieć 99%, to by trzeba podnieść prędkość wysyłki do 25MHz (2,6us) i obniżyć kolor do... 7 bit,

    Dla 16bit wyjdą GHz, albo redukcja jasności do 1/8.
  • #13
    Sareph
    Level 23  
    piotr_go wrote:
    Dla 16bit wyjdą GHz, albo redukcja jasności do 1/8.
    W zasadzie tak, na pełnej jasności to będzie ciężko. Ale szczęśliwie one są bardzo jasne, także do wnętrza pomieszczeń to nie problem i tak.

    Chociaż tak się właśnie zastanawiam, jak policzyć liczbę możliwych kolorów jeśli may 8 bitów kolorów + każdy z nich może być regulowany w zakresie 10 bit.
  • #14
    djfarad02
    Level 18  
    Kiedyś siedziałem nad tym tematem. Panele HUB75 i to kilka sztuk można pogonić byle jakim uC korzystając z jednego SPI po DMA dla danych RGB oraz używając jednego timera sterującego linią OE paneli (dla uzyskania BCM).

    Wcale nie trzeba uC z możliwością wystawiania danych przez DMA na kilka pinów.

    Pilnując czasów propagacji można sprowadzić 6 linii danych do jednej, traktując wszystko jako jeden długi rejestr. Schemat łączenia lini HUB-a 75 poniżej

    Sterownik matryc LEDowych z interfejsem hub75

    Film:


    Projekt z filmu zrobiłem na PIC32MX250 przy 48MHz, SPI 8MHz. Panele 32x32 5 sztuk, co daje w sumie 5120 pikseli. FPS 130Hz, kolor RGB444. Przy mniejszej liczbie paneli fps wzrośnie.
    Maksymalna jasność ograniczona jest do 41% tego, na co stać panel. Należy zauważyć, że jest to 41% prądu a nie jasności. Jako, że LED są nieliniowe jasność optycznie będzie większa niż 41% możliwości panela.
    Można wycisnąć parę procent więcej kosztem rezygnacji z korekcji gamma dla czasów BCM.

    ----------------------------------------
    Przy dużych wyświetlaczach (robiłem sterowanie do podłużnej reklamy o szerokości około 8m) sposób z łączeniem linii RGB w jeden rejestr się nie sprawdzi. Reklama składała się z dwóch rzędów starych modułów P16 15x17 pix (bardzo nietypowe), 16320 pikseli. Miały one dwie linie R, jedną G i jedną B oraz jeden sygnał przełączania wierszy.

    W tym przypadku również wykorzystałem pojedyncze SPI, jednak sprzętowo rozszyłem je na 8 linii. Schemat poniżej:
    Sterownik matryc LEDowych z interfejsem hub75
  • #15
    simw
    Level 25  
    djfarad02 wrote:
    Wcale nie trzeba uC z możliwością wystawiania danych przez DMA na kilka pinów.


    Z ciekawości, jak trzymasz dane dot. koloru piksela w buforze?
    Jak tworzysz buforowanie oraz synchronizację wyświetlanego obrazu - na filmie ładnie widać animacje, zatem zakładam, że to jest zrobione porządnie :)
  • #16
    djfarad02
    Level 18  
    simw wrote:

    Z ciekawości, jak trzymasz dane dot. koloru piksela w buforze?
    Jak tworzysz buforowanie oraz synchronizację wyświetlanego obrazu - na filmie ładnie widać animacje, zatem zakładam, że to jest zrobione porządnie :)


    Dzięki :)

    Bufor jest tak zorganizowany, że pojedynczy transfer DMA dotyczy czterech poziomych linii każdego modułu LED, dla wszystkich pięciu modułów jednocześnie. Moduł ma 4 razy po 8 linii, wybieranych binarnie za pomocą sygnałów A,B,C,D (najstarszy bit pozostaje nieużyty). Taki moduł jest oznaczany jako 1/8 scan. Z uwagi na to, że linie kolorów są połączone szeregowo to jeden transfer "zaświeca" wszystkie trzy kolory RGB w dwóch liniach dla dwóch połówek każdego modułu (świecącą 4 linie na jednym module). Po zakończeniu ośmiu kolejnych transferów DMA mamy więc wypełnioną całą matrycę.

    Głębia bitowa koloru realizowana jest poprzez modulację szerokości impulsu wygaszania (lina OE). Bufor zawiera cztery zestawy danych, każdy dla ośmiu transferów DMA. Po wysłaniu każdego zestawu zmieniany jest czas trwania impulsu OE, tak więc poszczególne części bufora mają różny wpływ na optyczną jasność wyświetlanego rastra. Funkcja rysująca piksele ustawia bity w odpowiednich częściach bufora w zależności od tego jaka jest wymagana jasność danego piksela. Np. dla piksela o jasności 0b1001 (9 dec) zostaną ustawione bity w pierwszej części bufora i w ostatniej.

    Funkcja odpowiedzialna za rysowanie pikseli wygląda tak:
    Code: c
    Log in, to see the code


    ONESHIFTSIZE to rozmiar jednego transferu DMA
    appData.bufferOffs mówi o tym, który bufor jest aktualnie roboczy, a który wyświetlany

    Bufory są dwa, jeden wyświetlany i jeden roboczy. Po zakończeniu rysowania pojedynczej klatki animacji ustawiana jest flaga żądania przełączenia buforów. Przełączenie następuje przy najbliższej możliwej sposobności, w przerwaniu generowanym przez zakończony transfer DMA.

    Przerwanie DMA inicjuje kolejny transfer, zatrzaskuje w rejestrach panela uprzednio przesłane dane oraz przełącza linie skanowania i wystawia dla DMA adres części bufora dla kolejnej linii (ustawiając przy okazji timer dla linii OE). Po dojściu do ostatniej linii następuję przeskok w adresowaniu bufora do części odpowiedzialnej za kolejny bit z 4-bitowej głębi koloru. Zmieniany jest też oczywiście czas dla timera sterującego linią OE. Czasy dla OE poddane są korekcji gamma oraz zależą dodatkowo od jasności ustawionej przez użytkownika. Procedura przerwania wygląda tak:

    Code: c
    Log in, to see the code