Akcelerator grafiki 2D na FPGA i STM32F429

Wykorzystanie zasobów FPGA

Każdy projekt FPGA musi zmieścić się w ograniczeniach na powierzchnię i szybkość pracy układu.  Powierzchnia to maksymalna liczba bramek dostępnych w FPGA, w których muszą zmieścić się wszystkie układy logiczne. W przypadku problemów możliwe są dalsze sztuczki i optymalizacja, ale jeśli nie okażą się one skuteczne, może zajść potrzeba kupna większego układu – a to bywa kosztowne. Poniżej widać uzyskane przeze mnie wykorzystanie układu:

Lubię dostawać to, za co płacę, więc wykorzystanie 103% komórek logicznych przyjąłem za dobrą monetę. Ale czy to nie oznacza przekroczenia dostępnych zasobów? Tak, ale to tylko wstępne oszacowanie narzędzia syntezy xst. Ważne są wyniki narzędzia map, które faktycznie umieszcza skompilowany projekt w fizycznym układzie i próbuje go optymalizować. Użyłem map z flagą oznaczającą maksymalną optymalizację zasobów, co dało następujące rezultaty:

Teraz sytuacja wygląda znacznie lepiej i daje prawdziwy wgląd w rzeczywisty stopień wykorzystania zasobów układu.

Spełnienie wymagań czasowych oznacza, że opóźnienie najwolniejszej ścieżki sygnału musi być krótsze, niż okres między dwoma zboczami zegara. Opóźnienie sygnału wynika z czasów, których potrzebują układy kombinacyjne, a także opóźnień ścieżek wynikających ze skończonej szybkości przepływu prądu w układzie. Próba spełniania wymagań czasowych może być błądzeniem po omacku – czasem z pozoru nieistotne modyfikacje zmieniają końcowy wynik o całe megaherce. Jeśli jednak wymagania czasowe zostaną spełnione, dalsza praca nie ma sensu – nie spowoduje to już żadnej zmiany w działaniu projektu.

Narzędzia Xilinx raportują najgorszy przypadek opóźnienia w zakładce „post-place and route static timing results”. Wymagana częstotliwość pracy mojego projektu to 100 MHz, a wyniki są następujące:

Design statistics:

Minimum period:   9.516ns{1}   (Maximum frequency: 105.086MHz)

Jest to wystarczający margines. Jak wspomniałem wyżej, nie ma sensu poprawiać tego wyniku – projekt będzie pracował dokładnie z taką samą szybkością.

Aplikacje testowe

Pierwsza aplikacja testowa ma na celu sprawdzić, czy poprawnie działa obsługa wyświetlacza LCD w trybie transferu. Aby to sprawdzić, wykorzystam bibliotekę graficzną stm32plus, by wyświetlić pewne testowe kolory. Podsystem grafiki stm32plus jest oparty o hierarchiczną strukturę, która rozdziela odpowiedzialność za algorytmy rysowania wysokiego poziomu od obsługi sterownika LCD. Ten z kolei jest oddzielony od metod zapewniających dostęp do sterownika.

45

Do tej pory używałem trybów dostępu, które polegają albo na wykorzystanie układu peryferyjnego STM32 FSMC, albo użyciu pinów GPIO do sterowania wyświetlaczem LCD. Aby moja własne płytka działała z całą zawartością biblioteki stm32plus, musiałem jedynie napisać klasę trybu dostępu, która realizuje zadanie wysyłania danych na 10-bitową szynę. Nazwałem ją AseAccessMode, gdzie „Ase” oznacza „Andy’s Sprite Engine”.

Przewidywalne zależności czasowe są bardzo istotne, aby zapewnić poprawną pracę trybu transferu. Ważny jest czas włączenia, a szczególnie czas trwania sygnału WR. Układ FPGA wymaga 4 cykli zegara lub 40 ns pomiędzy narastającymi zboczami sygnału WR, aby być gotowym  na odbiór kolejnego narastającego zbocza. Następujący kod assemblera pozwala klasie AseAccessMode na przesłanie polecenia do FPGA:

Instrukcja dsb (Data Synhronization Barrier) jest bardzo ważna, aby zagwarantować przewidywalny czas wykonania. Bez niej zaawansowany rdzeń mikrokontrolera F4 dokonałby optymalizacji potoku instrukcji i doprowadził do rezultatu, który nie spełnia ostrych wymagań czasu wykonania instrukcji podanych w podręczniku użytkownika ARM. Zaprojektowałem tryb transferu tak, aby wymagał jedynie dwóch taktów do przesłania 16-bitowych danych lub treści polecenia do wyświetlacza LCD, albo też mógł w tym czasie przejść w tryb obsługi bitmap.

46

Pierwszy transfer polega na przesłaniu pierwszych 8 bitów 16-bitowej wartości dla wyświetlacza LCD. Jeśli ustawiony jest najstarszy bit portu E, system przejdzie natychmiast w tryb obsługi bitmap i drugi transfer nie nastąpi.

Drugi transfer polega na przesłaniu starszych 8 bitów 16-bitowej wartości. Jeśli ustawiony jest najstarszy bit, wartość ta oznacza wybór linii (register select, RS) wyświetlacza LCD.

47

Kod źródłowy testu transferu jest dostępny na Githubie. Byłem bardzo zadowolony, gdy ten test się powiódł – po raz pierwszy zobaczyłem działający ekran LCD, który wyświetlał dane pod kontrolą FPGA, nawet jeśli całością zarządzał mikrokontroler w trybie transferu.

Manic Knights

Na samym początku artykułu obiecałem demo gry i zamierzam dotrzymać tej obietnicy. Stworzę demo, wykorzystując wysokiej jakości grafiki, które przedstawiają przykładową platformówkę, jaką można zrealizować na tym systemie. Gra będzie wykorzystywać animowane bitmapy, które poruszają się po nieliniowych trajektoriach wykorzystujących funkcje wygładzania. Funkcje te obciążają jednostkę zmiennoprzecinkową (FPU) układu F4, aby płynnie zmieniać szybkość animacji. Gra pozwoli również na przewijanie okna widoku we wszystkich 4 kierunkach, co pozwala graczowi na poruszanie się w świecie znacznie większym od ekranu.

Kafelkowa mapa

Świat gry stanowi matryca kafelków o wymiarach 20 x 30. Każdy kafelek jest kwadratem o boku 64 pikseli. Wykorzystałem darmowy edytor Tiled, aby stworzyć mapę z użyciem zestawu grafik kupionych w serwisie cartoonsmart.com. Dostępne są też darmowe grafiki, ale ich jakość nie jest powalająca. Uznałem, że lepiej będzie wydać kilka dolarów na grafiki komercyjnej jakości.

48

Edytor map Tiled pozwala szybko zbudować świat gry i zapisać go w pliku XML, który następnie można sparsować i przedstawić w dowolnym wymaganym formacie. Głównym problemem jest to, że edytor działa w trybie poziomym (landscape), natomiast silnik gry pracuje w trybie pionowym (portrait). Musi tak być, aby zachować synchronizację z odświeżaniem wyświetlacza, które zawsze przebiega pionowo, niezależnie od logicznej orientacji wyświetlacza.

Aby rozwiązać ten problem, napisałem mały program C#, który eksportuje kafelki do formatu PNG i obraca je przy tym o 90° w kierunku przeciwnym ruchu do wskazówek zegara. To, wraz z kodem Perl łączącym całość, pozwala edytorowi Tiled na tworzenie plików wyjściowych, które można łatwo załadować do pamięci Flash.

49

Powyższy obrazek przedstawia kompletny świat gry, obrócony z powrotem do formatu poziomego na potrzeby artykułu. Ten świat będzie stanowił tło gry. W implementacji gry rezerwuję na początku tablicy bitmap zapas slotów, które są przeznaczone na tło. Gdy gracz porusza się w świecie gry, te zarezerwowane sloty są aktualizowane, dzięki czemu cały czas znajdują się na odpowiedniej siatce tła w danej pozycji. Ponieważ bitmapy są umieszczone na początku tablicy, zawsze będą wyświetlane za innymi bitmapami, które będą rysowane w dalszej kolejności. Konkretnie będą to…

O autorze