Dokumentacja.docx

(1090 KB) Pobierz

Wrocław, dnia 25.05.2011r.

Dokumentacja techniczna

Układy cyfrowe i systemy wbudowane 2 – projekt.

Prowadzący: dr inż. Jarosław Sugier

Autorzy: Maciej Siwek, Gwidon Jóźwiak


1.     Temat.

1.1.           Cel i zakres projektu.

Głównym celem projektu jest nawiązanie komunikacji układu Spartan-3E z klawiaturą przez port PS2 przy użyciu środowiska Xilinx i języka opisu sprzętu VHDL. Następnie rozwinięcie projektu do prostej gry video, przypominającej grę samochodową, w której celem gracza jest utrzymanie się w granicach trasy, a jej przekroczenie kończy się przegraną.

1.2.           Opis sprzętu.

Do wykonania zadania dysponowaliśmy zasobami takimi jak: Układ Spartan-3E oraz oprogramowanie Xilinx ISE, natomiast projekt został wykonany w języku VHDL. Wykorzystaliśmy również port PS2, port VGA oraz pamięć ROM zamontowane na płytce z układem. Port PS2 posłużył nam do komunikacji z klawiaturą, która jest kontrolerem gry, port VGA do komunikacji z monitorem, a w pamięci przechowujemy trasę.

Wykaz sprzętu:

- Płytka z układem Spartan-3E (na płytce fabrycznie zamontowany port PS2, VGA oraz pamięć ROM),

- Klawiatura zewnętrzna,

- monitor VGA.

Głównymi źródłami wiedzy są:

- dokumentacja Spartan-3E http://www.xilinx.com/support/documentation/boards_and_kits/ug230.pdf

- strony internetowe:

http://www.networktechinc.com/ps2-prots.html

1.3.           Teoria problemu.

W projekcie napotkaliśmy na następujące problemy: komunikacja z klawiaturą, wyświetlanie obrazu monochromatycznego na monitorze VGA, generacja i obsługa pamięci ROM, silnik gry (czyli połączenie wszystkiego w jednolitą całość i obsługa sterowania „samochodem”). Aby osiągnąć zamierzony cel podzieliliśmy projekt na kolejne etapy. Najpierw realizowaliśmy każdy z problemów stopniowo łącząc je w całość, a na końcu zaprojektowaliśmy silnik. Kolejne etapy projektu to:

1.      Komunikacja z klawiaturą – odczytywanie współrzędnych klawiszy (nie kodów ASCII).

2.      Wyświetlanie jednego koloru na całej powierzchni ekranu VGA.

3.      Wczytywanie trasy z pliku .coe do pamięci Rom i wyświetlanie jej na ekranie.

4.      Silnik gry łączący wszystkie elementy w całość.

2.     Projekt.

2.1.           Opis hierarchii plików źródłowych oraz schematy.

Hierarchia plików źródłowych prezentuje się następująco:

ps2_recive.sch

              PS2_Kbd.sch

                            PS2_Rx.vhd

                            PS2_DataAnalyse.vhd

              VGA.vhd

              GenCol.vhd

              controler.vhd

              mem2.vhd

 

W powyższej hierarchii wymieniono wszystkie napisane przez nas moduły (moduł mem2.vhd został wygenerowany za pomocą narzędzia GenCore). Dwa pliki są schematami łączącymi moduły w całość. Poniżej znajdują się screeny głównego schematu układu (wykonane w całości i z podziałem na części, ponieważ całość jest mało czytelna).

Sch1.png

Rysunek 1: Schemat główny całość

Sch2.png

Rysunek 2: Schemat główny góra

Sch3.png

Rysunek 3: Schemat główny dół

Schemat PS2_Kbd jest jednocześnie modułem dla schematu głównego, dlatego zostanie szczegółowo opisany i przedstawiony w punkcie 2.2. wraz z innymi modułami. Na schemacie można zauważyć jeszcze dwa moduły: REG64b i LCD1x64. Są to moduły gotowe (nie napisane przez nas)  i zostały użyte jedynie w celach testowych (nie są istotne dla działania naszego projektu i mogą być w nim pominięte). Realizują ona wyświetlanie kodu klawisza, odczytanego z portu PS2, na ekranie LCD w systemie szesnastkowym. Z tego powodu moduły te nie będą opisane.

2.2.           Opisy funkcjonalne modułów.

Moduły będą prezentowane w następującej formie. Schemat modułu (porty wejściowe po lewej, wyjściowe po prawej), następnie opis funkcji jaką spełnia moduł w całym układzie oraz szczegóły jego działania i implementacji. Po tym zamieszczony będzie wydruk z symulacji (symulacje Behavioralne),a pod nim lub nad nim ewentualny komentarz.

2.2.1.      PS2_Rx.

PS2_RxSch.png

Rysunek 4: Schemat PS2_Rx

Moduł ten jest odpowiedzialny za odczytanie danych z portu PS2 oraz przesłanie ich dalej po analizie ramki i wyłuskaniu samych danych.

Jego działanie opiera się głównie na próbkowaniu zegara portu (PS2_Clk) z większą częstotliwością zegara wewnętrznego (Clk_50MHz). Detekcja zbocza opadającego zegara PS2_Clk opiera się na dwubitowym rejestrze przesuwnym, który sczytuje stan PS2_Clk. W przypadku gdy stan tego rejestru będzie równy „10” to wykryliśmy zbocze opadające i możemy sczytać kolejny bit danych do 11-bitowego rejestru przesuwnego przechowującego ostatnie 11 sczytanych bitów danych. Jest również licznik zliczający 11 odebranych bitów. Gdy licznik osiągnie wartość 11 to wyjście DR (Data Redy) ustawiamy na 1 (w przeciwnym wypadku na 0), a do wyjścia Data przypisujemy 8-bitowy wektor danych wyłuskany z
11-bitowej ramki. Ramka portu wygląda następująco:

ramka.png

Rysunek 5: Ramka portu PS2

Bit startu powinien być zawsze 0, a bit stopu zawsze 1. Analizę ramki przeprowadzamy za pomocą następującego zapisu w VHDL:

DR <= '1' when

              (

                            cnt = 11

                            and               reg(10) = '0' -- bit startu (zawsze = 0)

                            and               reg(0) = '1' -- bit stopu (zawsze = 1)

and                (not(reg(2) xor reg(3) xor reg(4) xor reg(5) xor reg(6) xor reg(7) xor reg(8) xor reg(9))) = reg(1)

                                          -- bit parzystosci (weryfikacja)

              )

              else '0';

Poniżej znajduje się symulacja tego modułu:

PS2_Rx.png

Rysunek 6: Symulacja PS2_Rx

2.2.2.      PS2_DataAnalyse.

PS2_DataAnalyseSch.png

Rysunek 7: Schemat PS2_DataAnalyse

Głównym zadaniem tego modułu jest analiza odebranych danych pod kątem wystąpień F0 oraz E0. Kod E0 występuje przed niektórymi klawiszami specjalnymi (niektóre z nich potrzebne do projektu to enter oraz klawisze strzałek), natomiast kod F0 oznacza puszczenie klawisza.

Wewnątrz modułu znajduje się bardzo prosta maszyna stanów, składająca się z 3 stanów:

- sidle – gdy moduł znajduje się w tym stanie to oczekuje na nadejście danych
(na enable = 1),

- state – stan oznaczający odczytanie danych, jeżeli odczytane dane to x”E0” lub x”F0” to zostajemy w tym stanie oczekując na nadejście kodu klawisza, w przeciwnym wypadku przechodzimy do stanu sdr,

- sdr – stan oznaczający gotowość do wysłania danych dalej (tutaj ustawiamy DR na 1), zaraz po nim przechodzimy do stanu sidle.

Najprościej maszynę stanów można zobrazować na grafie:

maszyna_stanow.png

Rysunek 8: Maszyna stanów dla PS2_DataAnalyse

Analizowany jest wektor qdata, ponieważ po pojawieniu się na wejściu enable = ‘1’ dane z wektora wejściowego data_in są przepisywane do wektora qdata w celu uniknięcia błędów, gdyby nastąpiła zmiana danych wejściowych przed zakończeniem ich analizy. W przypadku wystąpienia E0 lub F0 lub obu na raz pozostają one ustawione na 1 tak długo aż maszyna nie przejdzie w stan sidle. Na symulacji można zaobserwować dokładne działanie modułu. Nie przedstawiono jedynie sytuacji pojawienia się F0 i E0 jedna po drugiej, ale nie robi to różnicy automat ustawiłby najpierw F0 na jeden potem E0 a następnie przesłał kod klawisza (nie mogą pojawić się w odwrotnej kolejności, czyli E0 i potem F0).

PS2_DataAnalyse.png

Rysunek 9: Symulacja PS2_DataAnalyse

2.2.3.      PS2_Kbd.

PS2_Kbd_sch.png

Rysunek 10: Schemat PS2_Kbd

Moduł ten składa się z połączenia dwóch poprzednich modułów, czyli PS2_Rx i PS2_DataAnalyse. Jego dokładniejszy opis nie jest konieczny, ponieważ opiera się na modułach składowych i realizuje odczyt danych z portu oraz ich analizę (podział na kod klawisza i wystąpienia E0 oraz F0). Poniżej znajduje się schemat połączenia tego układu.

PS2_KbdSch.png

Rysunek 11: Schemat wewnętrzny PS2_Kbd

Symulacja działania tego modułu również jest nieistotna, ponieważ sposób jego działania jest trywialny i wygląda następująco: To co PS2_Rx odczytał z portu PS2 przesyła dalej do PS2DataAnalyse, a ten z kolei analizuje te dane po pojawieniu się na wejściu
enable = 1;

2.2.4.      VGA.

VGASch.png

Rysunek 12: Schemat VGA

Jednym z ważniejszych modułów jest VGA, ponieważ jest odpowiedzialny za wyświetlanie na ekranie monitora rezultatów działania całego układu. Jego działanie opiera się na generowaniu kolejnych współrzędnych pikseli i wysyłanie do portu VGA  danych dotyczących synchronizacji poziomej oraz pionowej i koloru piksela.

Wewnątrz modułu mamy dwa liczniki VCounter oraz HCounter. HCounter zlicza piksele w wierszu i generuje co 1040 pikseli sygnał synchronizacji VGA_HS, natomista VCounter zlicza linie (jest zwiększany gdy przesłano całą linię pikseli) i generuje sygnał synchronizacji VGA_VS co 666 lini. Kolor RGB jest ustalany przez odrębny moduł, VGA ustawia na czarny kolor tylko obszary poza rozdzielczością 800x600, co widać na poniższej symulacji.

VGA.png

Rysunek 13: Symulacja 1 VGA

Na drugiej symulacji można zaobserwować generowanie sygnałów synchronizacji. Dokładny opis działania VGA można znaleźć w dokumentacji Spartan-3E (link na początku dokumentu), jednak opis ten jest dla rozdzielczości 640x480, dlatego w naszym układzie musieliśmy przerobić niektóre liczby.

VGA2.png

Rysunek 14: Symulacja 2 VGA

2.2.5.      GenCol.

GenColSch.png

Rysunek 15: Schemat GenCol

GenCol można nazwać głównym wyświetlaczem, ponieważ jest odpowiedzialny za wyświetlanie obrazów na ekranie oraz ich przewijanie.

Na podstawie otrzymanych od VGA współrzędnych piksela GenCol zwraca odpowiedni kolor. Układ odbiera następujące sygnały:

Data – dane o trasie z pamięci ROM (wsp. X początku i końca trasy),

obj_pos – informacje o aktualnym położeniu górnego lewego rogu prostokąta będącego samochodem (wsp. X),

start – pojedynczy sygnał informujący o tym, czy układ ma rozpocząć przewijanie trasy.

Po otrzymaniu współrzędnych układ oblicza odpowiedni adres w pamięci ROM i na jego podstawie wydostaje z niej dane na temat aktualnego wiersza, dzięki czemu może określić kolor piksela. Jeżeli piksel znajduje się wewnątrz trasy to ma kolor biały, za to piksele należące do samochodu są zielone, a pozostałe mają kolor tła, które jest uzależnione od stanu gry. Gdy y = 500 i samochód nie mieści się w trasie to tło otrzymuje kolor czerwony a przewijanie trasy zostaje zatrzymane, w przeciwnym wypadku tło jest czarne.
Częstotliwość zegara (50 MHz) jest zbyt szybka dla ludzkiego oka i refleksu, dlatego wprowadziliśmy wewnętrzny licznik, który ma za zadanie opóźniać przewijanie trasy. Jest on domyślnie ustawiony na 106 i nie ma możliwości przyśpieszania oraz zwalniania przewijania.
Mapa trasy ma 256 wierszy, dlatego zastosowaliśmy zwiększenie pikseli (1 piksel widoczny to 4 piksele w rzeczywistości). Dokonaliśmy tego za pomocą następujących obliczeń:

cAddr <= y - 44 - ( offset(8 downto 0) & '0');

Addr <= cAddr(8 downto 1);

 

Gdzie Addr to adres w pamięci, y  to współrzędna na ekranie (numer lini), a offset to licznik odpowiedzialny za przewijanie trasy (zlicza od 0 do 255).

Poniższa symulacja pokazuje zwracane kolory dla jednej lini trasy (kolor biały to trasa, a zielony to samochód). Samochód ma szerokość 10 px i na symulacji znajduje się między 400 a 410 pikselem.

GenColgreen.png

Rysunek 16: Symulacja GenCol

2.2.6.      Controler.

controlerSch.png

Rysunek 17: Schemat controler

Controler jest kolejnym obok GenCol głównym silnikiem gry. Analizuje on sygnały otrzymane z klawiatury (od PS2_Kbd) i na ich podstawie wyznacza pozycję samochodu. W przypadku naciśnięcia któregoś z klawiszy strzałek (prawo lub lewo) samochód przesuwa się o 4 piksele w odpowiednią stronę. Moduł generuje również sygnał start rozpoczynający przewijanie trasy po naciśnięciu klawisza ENTER.

Poniżej symulacja na której widać reakcję układu na wciskanie konkretnych klawiszy. Można również zaobserwować, że układ reaguje na naciśnięcie klawisza, a nie na jego puszczenie. W celu łatwiejszego czytania symulacji dane zostały przedstawione w kodzie szesnastkowym.

controler.png

Rysunek 18: Symulacja controler

2.2.7.      Mem2.

mem2Sch.png

Rysunek 19: Schemat mem2

Mem2 to moduł pamięci ROM. Nie został on przez nas napisany, tylko wygenerowany za pomocą narzędzia o nazwie GenCore, które służy do generacji różnego rodzaju pamięci. Do generacji użyliśmy danych zapisanych w pliku .coe. Pliki z tym rozszerzeniem zawierają informacje do inicjalizacji pamięci. Na początku pojawia się informacja o systemie liczbowym, w którym zapisane są dane, a następnie podany jest wektor z danymi. Pamięć można zobrazować jako macierz, gdzie każdy wiersz to kolejne dane. W naszym przypadku mamy 256 wierszy i 16 kolumn. Pamięć na podstawie adresu (addra), który można określić jako numer wiersza zwraca 16 bitów danych.

Poniżej znajduje się symulacja, która przedstawia jak pamięć zwraca kolejne wiersze danych na podstawie adresu. Podobnie jak powyżej w celu łatwiejszego czytania dane w ...

Zgłoś jeśli naruszono regulamin