Elektroda.pl
Elektroda.pl
X
PLC Fatek
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

VGA Tetris - projekt na konkurs Gra Retro

ja.czekanski 31 Gru 2011 19:16 21760 23
  • VGA Tetris - projekt na konkurs Gra Retro
    Witam
    Jestem uczniem 2 klasy liceum, z elektroniką łączy mnie tylko hobby. Chciałbym przestawić mój projekt wykonany na konkurs Gra Retro. Jest to remake gry Tetris. Jako wyświetlacz użyłem monitora VGA (w tym wypadku LCD) oraz pada od Pegasusa jako kontroler. Całe oprogramowanie zostało napisane przeze mnie.

    Trochę danych:
    Procesor: Atmega8 (8kB flash, 1kB SRAM)
    Obraz: 104x120px, 16kolorów
    Wejście: Pad od Pegasusa (8 przycisków)
    Dźwięk: Mono, generowany przez PWM (niestety nie ma, brakło czasu)

    Sprzęt
    Procesorem jest znana wszystkim Atmega8 taktowana częstotliwością 20MHz. Wybór tego procesora był złym pomysłem, ale nie miałem już czasu aby to zmienić. Procesor na tej częstotliwości działa bardzo stabilnie. 90% czasu procesora poświęcone jest na generowanie obrazu VGA. Generowanie linii jest bardzo wrażliwe na opóźnienia. Dlatego każda linia generowana jest w przerwaniu timera 16bitowego wywoływanego co dokładnie 636 cykli zegarowych. Tam są ustawiane sygnały synchronizacji oraz kolorów. Z tego powodu nie można korzystać z innych przerwań w konsoli. Obraz jest 16kolorowy, generowany jest za pomocą dzielników rezystorowych. W 10% czasu procesora generowana jest grafika, liczone są kolizje i cała logia gry.
    Urządzenie zasilane jest przez stabilizator 7805 w standardowej konfiguracji.

    Dźwięk
    Niestety brak. Limit czasowy konkursu okazał się zabójczy. Co prawda złącze jest wyprowadzone, razem z filtrem i dzielnikiem, ale konsola nie generuje żadnego dźwięku.

    Oprogramowanie
    Jak wspomniałem całość napisana jest w assemblerze. Dlaczego? Atmega8 ma tylko 1kB ramu, to za mało, aby generować ładny obraz. Dodatkowo pisząc w C nie mamy nad nią wielkiej kontroli i potrzebujemy dużo stosu. Pisząc w assemblerze mam nad tym kontrolę.
    Warto wziąć lepszy procesor i nie męczyć się w assemblerze, po przygodach z nim nie chcę mieć więcej nic wspólnego (mimo, że pisze się całkiem przyjemnie w porównaniu do x86).
    Pisząc grę opierałem się na Tengen Tetris (w którego grałem na Pegasusie lata temu) oraz Tetrisie na Gameboya. Zasady w mojej wersji są praktycznie takie same.
    Pamięć EEPROM została wykorzystana do trzymania najlepszych wyników uzyskanych w grze. Przetwornik ADC został wykorzystany do losowania klocków. Czytam szum z jednego z pinów.
    Źródła załączam w załączniku, jednak nie polecam wzorowania się na nich (wiele rzeczy się powtarza, dużo jest bezsensownego kodu, pierwszy raz pisałem w assemblerze i się spieszyłem dodatkowo :).





    Generowanie obrazu
    Generując obraz VGA (640x480) potrzebujemy częstotliwości 25.175MHz - jeden cykl zegara to jeden piksel. Ale dostanie takiego kwarcu nie jest łatwym zadaniem i może być to częstotliwość za duża do prawidłowego działania procesora. Ja użyłem kwarcu 20.000MHz, który jest łatwo dostępny, ale zmniejszyło to rozdzielczość do 512x480 (a w rzeczywistości jeszcze więcej). Generowanie każdej linii wygląda w ten sposób - przez 512 cykli (dla kwarcu 25.175MHz jest to 640 cykli) wyrzucamy co cykl zegara następny kolor. Niestety w takim mikrokontrolerze jest to niemożliwe, gdyż samo wczytanie danych z pamięci SRAM zajmuje 2 cykle zegara, a instrukcja OUT (wyrzucenie danych na port) 1 cykl. Czyli w najlepszym przypadku dostajemy 512/3~170px. Następnie przez 124 cykle musimy wygenerować sygnały synchronizacji poziomej. Ja w tym miejscu wchodzę w przerwanie, zrzucam rejestry na stos, ustawiam synchronizację sprawdzam, którą linię aktualnie rendeuję - jeżeli większą niż 480 to wychodzę z przerwania i oddaje czas procesorowi na resztę programu. Przez 480 linii obraz jest generowany, potem przez 11 linii wyświetlany jest kolor czarny, potem w ciągu 2 linii ustawiam synchronizację pionową i przez kolejne 31 linii dalej jest ciemność. Daje to 44 linie, przez które nic się nie robi. Daje nam to ( w przybliżeniu) 512*44=22528 wolnych cykli procesora. To właśnie w tym momencie wykonywana jest reszta programu.
    Jednak nie jest tak fajnie, gdyż nie dysponujemy taką ilością ramu. Ze względu na ograniczenia RAMu musiałem wymyślić sposób na generację ładnego obrazu. Najlepszym pomysłem okazało się podzelenie pamięci na bloki (tiles) o wielkości 4x4 piksele. W pamięci mieszczę 28x30 takich bloczków. Jeden bloczek to jedna z 256 grafik zapisanych we flashu. W ten sposób można łatwo rysować klocki oraz czcionki.
    W przerwaniu video wartości poszczególnych bloków zamieniane są na wartości znajdujące się we flashu. Niestety te obliczenia zajmują dużo (aż 19 cykli) co drastycznie zmniejsza rozdzielczość. W wyniku otrzymujemy rozdzielczość 104x120 pikseli.
    Obliczone piksele są wyrzucane na PORTC, gdzie 3 najmłodsze bity to kolory RGB, a 4 bit to bit jasności. Jest on podłączony przez diody i rezystor do każdego z bitów RGB. Gdy nie jest on zaświecony - na każdym bicie jest 0 v, a gdy włączony - 0.35v (czyli szary). Zwiększa to ilość kolorów z 8 do 16.

    Płytkę robiłem termotransferem, miedź nie wygląda najlepiej, jest to wina zużytego tonera w drukarce. Złącze od pada jest podłączone przez goldpiny z głupiego powodu - w sklepie nie mieli złącza do druku, musiałem użyć takiego na kabel.

    Opis wyjść pada, na którym się wzorowałem: http://nesdev.parodius.com/ffpa.txt


    VGA Tetris - projekt na konkurs Gra RetroVGA Tetris - projekt na konkurs Gra RetroVGA Tetris - projekt na konkurs Gra Retro VGA Tetris - projekt na konkurs Gra Retro VGA Tetris - projekt na konkurs Gra Retro
    VGA Tetris - projekt na konkurs Gra RetroVGA Tetris - projekt na konkurs Gra Retro


    Fajne!
  • Semicon
  • #2 31 Gru 2011 22:40
    dan1112
    Poziom 12  

    W plikach znalazłem

    Kod: csharp
    Zaloguj się, aby zobaczyć kod


    Czy to nie przysporzy kłopotów że nie mamy tych plików (patrz: lokalizacja)

    Ja np. nie mam D:\KubX ... Nie powinno się oznaczać poprostu font.asm jako że mamy to właśnie w
    tym folderze??

    Bo tak się raczej robi: (jeżeli mamy np. w tym samym katalogu lub innym)
    Kod: c
    Zaloguj się, aby zobaczyć kod



    Pozdrawiam

    Dodano po 2 [minuty]:

    @edit: Projekt bardzo fajny, wiem że nie zdążyłeś - jeżeli moją wypowiedz zrozumiałeś jako krzyk lub obrazę przepraszam...

  • #3 01 Sty 2012 01:04
    Maticool
    Poziom 19  

    Za to, że całość napisana w assemblerze - prawdziwy szacun.
    Jedyne co może dotknąć purystów to szerokość pola gry - wydaje się większa niż w klasycznym Tetrisie.

  • #4 01 Sty 2012 12:23
    degename
    Poziom 18  

    Długie klocki pojawiają się za często. Gra staje się monotonna na pierwszych poziomach. Chyba że potem jest ich mniej.

  • Semicon
  • #5 01 Sty 2012 13:32
    DmZ
    Poziom 17  

    super projekt. pisane w ASM na kręcona atmege8 to spory jak dla mnie wyczyn. i wszystko chodzi płynie i bez zaciec. ze gra monotonna? to nieistotne, ja na to nie zwrocilem uwagi. poza tym jest tu gra w kolorze. jak dla mnie super.

  • #7 01 Sty 2012 17:41
    ja.czekanski
    Poziom 12  

    W pierwszym poście trochę lepiej opisałem sposób tworzenia obrazu.
    Dziękuję za pozytywną ocenę, postaram się odpowiedzieć na wątpliwości i pytania.

    leonow32 napisał:
    Przyczepić się mogę jedynie tego, że na schemacie złącza nie są opisane - powinno być bardziej sensownie, a nie SV1, SV2 itp, bo nic to nie mówi.

    Masz rację, poprawiłem złącza. Nie używam standardowego KANDA, bo wszystkie projekty robię na płytkach stykowych i takie złącze jest niewygodne. Zamiast tego mam wyprowadzone sygnały od ISP w rzędzie. Na PCB zrobiłem tak samo. Poprawiłem schemat.

    degename napisał:
    Długie klocki pojawiają się za często. Gra staje się monotonna na pierwszych poziomach. Chyba że potem jest ich mniej.

    Klocki losowane są na podstawie odczytu z ADC. Podczas gdy na płytce stykowej układ działał dobrze (dużo szumów, ironia :), to na gotowej PCB losowość się zmniejszyła. Naprawiło to podpięcie izolowanego drutu jako antenę do pinu ADC, film jest chyba kręcony bez tego dodatku.

    Maticool napisał:
    Za to, że całość napisana w assemblerze - prawdziwy szacun.
    Jedyne co może dotknąć purystów to szerokość pola gry - wydaje się większa niż w klasycznym Tetrisie.

    Dziękuje, pisanie z asmem z czasem wchodzi w krew i się nie zastanawiam jak co działa, tylko piszę. Czasami denerwują ograniczenia do korzystania z rejestów (jest ich 32, ale dużo instrukcji może używać tylko od r16 do r31 albo i mniej) oraz brak operacji arytmetycznych (jest mnożenie 2 liczb 8bitowych, tyle dobrze). Przykładowo dzielenie liczb i liczenie reszty z dzielenia musiałem pisać sam (do wyświetlania liczb). Przy takich operacjach dla liczb 16bitowych mózg już mi siada :). Bardzo pomocne okazało się wydrukowanie zestawu instrukcji do AVR z noty Atmela - cały czas korzystałem z niej, są podane czasy wykonywania instrukcji.
    Pole gry jest takie samo, po prostu szerokość "pixeli" powoduje takie wrażenie.

    dan1112 napisał:
    W plikach znalazłem
    Kod: csharp
    Zaloguj się, aby zobaczyć kod


    Czy to nie przysporzy kłopotów że nie mamy tych plików (patrz: lokalizacja)

    Ja np. nie mam D:\KubX ... Nie powinno się oznaczać poprostu font.asm jako że mamy to właśnie w
    tym folderze??

    Widzisz, tutaj mnie masz :) A tak na serio to program pisałem w AVR Studio 4, to jego wina, że używa ścieżek absolutnych. Nie miałem o tym pojęcia, dziękuję za zauważenie tego. Można po prostu stworzyć nowy projekt dla Atmegi8, wrzucić pliki .asm i ustawić main.asm jako startowy i można kompilować. Poprawię to jak najszybciej

    matti1231 napisał:
    Nareszcie ktoś pomyślał:D Zawsze lubiłem w to grać:P

    No cóż, założeniem projektu było generowane obrazu VGA. Pewnie generując obraz PAL mogłem uzyskać lepsze efekty (i rozdzielczość), ale musiałbym pożegnać się z kolorem i wiele takich projektów jest w Internecie. A nie chciałem po prostu skopiować gotowego rozwiązania, a zrobić coś swojego. Pomysł na Tetrisa był pierwszy z brzegu i okazał się nie trudny do implementacji w niskim poziomie. Po napisaniu procedur do sprawdzania kolizji klocków i ich rysowania kodzenie poszło jak z górki :)

  • #8 01 Sty 2012 23:31
    ja.czekanski
    Poziom 12  

    Dodałem zdjęcia w lepszej jakości, poprawiłem schemat, poprawiłem 1szy post, wysłałem jeszcze raz źródła (AVR studio chyba nie obsługuje relatywnych ścieżek, tak wyczytałem).

  • #10 02 Sty 2012 00:31
    ja.czekanski
    Poziom 12  

    misiupan napisał:
    Witaj, jaką funkcję realizuje pin 26 procesora?

    Ze względu na konstrukcję programu nie mogłem użyć całego portu (8bitów), a tylko 4. Związane jest to z czasami wykonywania instrukcji. Wczytanie jednego bajtu z Flasha zajmuje 3 cykle zegara, a jego wyświetlenie 1 cykl. Więc aby wyświetlić 4 piksele potrzebowałbym 16 cykli. To dużo, biorąc pod uwagę, że muszę jeszcze wyliczyć pozycję danych we flashu. Zmniejszając ilość kolorów do 4 bitów może zmieścić 2 piksele w jednym bajcie. Wtedy wczytuje pierwszy bajt z flashu (3 cykle), wyrzucam go na port (1 cykl), zamieniam połówki rejestru (instrukcja SWAP, zamienia bity 0:3 z 3:7) i wyrzucam jeszcze raz. Takim trickiem można zmniejszyć ilość cykli z 16 do 12, a resztę poświęcić na liczenie pozycji.
    Więc gdy zostały mi 4 bity (po jednym na kolor, R, G, B) głupio zostawić jeden bit nie używany. Więc podłączyłem go przez diody do każdego z portu i otrzymałem coś w stylu IRGB. Gdy chcę wyświetlić kolor czerwony, na port wyrzucam 0b0001, a gdy chcę wyświetlić jasny czerwony to wyrzucam 0b1001. Można powiedzieć, że ten 4 bit (pin 26) steruje jasnością piksela.
    Rezystory ustawiają odpowiednie napięcie na liniach. Kolor czarny - 0.0v, kolor czerwony - 3.5v, kolor jasny czerwony - 7.0v

    misiupan napisał:
    Ps. na schemacie nieco literki się nałożyły.

    Racja, poprawiłem.

  • #11 02 Sty 2012 01:16
    xanio
    Poziom 27  

    kubx napisał:

    Klocki losowane są na podstawie odczytu z ADC. Podczas gdy na płytce stykowej układ działał dobrze (dużo szumów, ironia :), to na gotowej PCB losowość się zmniejszyła. Naprawiło to podpięcie izolowanego drutu jako antenę do pinu ADC, film jest chyba kręcony bez tego dodatku.


    Jako innego generatora możesz użyć licznika 0..6 inkrementowanego raz na jakiś czas (raz lub kilka razy na ramkę) i zerowanego po naciśnięciu przycisku na padzie. Wtedy generator nie będzie tak zależny od szumów z zewnątrz a czynnik ludzki wprowadzi wystarczającą losowość.

    Zagadnienie losowania klocków w Tetrisie jest dość ciekawe. "Koszerny" tetris prawdopodobnie wybiera tetromina tak:
    1. weź wszystkie rodzaje (7) klocków dostępnych w grze
    2. ustaw je w dowolnej kolejności
    3. zaserwuj graczowi klocki w tej wylosowanej kolejności
    4. wróć do 1.
    Przy czym, często spotykana jest wersja, że jako pierwszy w grze nigdy nie pojawi się klocek S,Z lub O.

    Przy takim algorytmie maksymalnie 4x z rzędu dostaniemy najmniej korzystne tetromina (S i Z).

  • #12 02 Sty 2012 01:41
    ja.czekanski
    Poziom 12  

    xanio napisał:
    Jako innego generatora możesz użyć licznika 0..6 inkrementowanego raz na jakiś czas (raz lub kilka razy na ramkę) i zerowanego po naciśnięciu przycisku na padzie. Wtedy generator nie będzie tak zależny od szumów z zewnątrz a czynnik ludzki wprowadzi wystarczającą losowość.

    Dobry pomysł, chciałem wykorzystać odczyt przycisków, ale nie miałem pomysłu jak to zrealizować. Myślałem też nad wykorzystaniem timera i liczenia czasu od włączenia gry do naciśnięcia przycisku START, ale nie byłem na siłach napisać algorytmu losującego (operacje 16bitowe, albo - o zgrozo - 32bitowe w assemberze nie są przyjemną sprawą, kiedy trzeba je implementować samodzielnie). Każda próba stworzenia PRNG dawała marne efekty (generator szybko się powtarzał).

  • #13 02 Sty 2012 02:01
    LOTR2
    Poziom 11  

    Jestem pełen podziwu dla autora i gratuluje projektu! Koledzy, studenci elektroniki nie wierzyli, że ktoś jescze pisze w assemblerze. Co do mikroprocesora to nie myślałeś o np. ATmega168 albo ATmega328?

  • #14 02 Sty 2012 02:08
    ja.czekanski
    Poziom 12  

    LOTR2 napisał:
    Jestem pełen podziwu dla autora i gratuluje projektu! Koledzy, studenci elektroniki nie wierzyli, że ktoś jescze pisze w assemblerze. Co do mikroprocesora to nie myślałeś o np. ATmega168 albo ATmega328?

    Oczywiście, bardzo chętnie bym tak zrobił, ale nie było już czasu na zmianę mikrokontrolera. Wtedy wszystko napisałbym w C i obeszło by się bez żadnych problemów. Początkowo cały projekt miał wyglądać całkiem inaczej (avr + pic + zewnętrzny ram, może na feriach się za to zabiorę), ale scalak do programatora przyszedł dopiero po świętach (a zamawiałem na początku grudnia :()
    Każdy program na uC piszę w C, na komputer głównie C++, assemblera staram się nie tykać, ale tutaj musiałem się poświęcić:)

  • #15 02 Sty 2012 09:28
    xanio
    Poziom 27  

    Jeszcze jedno. Jest patent na tekst w wyższej rozdzielczości.
    http://www.linusakesson.net/scene/craft/

    Sekcja Video, drugi akapit:
    In addition to this, I've hooked up a couple of diodes and a PNP transistor in such a way, that when the MOSI pin is low while the OC2B pin is high, the three color signals will be pulled to a high voltage, corresponding to white. This is used to generate high resolution scroll text: The MOSI pin is connected to a shift register internally in the AVR (it is typically used for serial data transmission), and this shift register can be programmed to emit a sequence of 8 bits with a single instruction, thus offloading the CPU.

  • #16 02 Sty 2012 13:22
    mgiro
    Poziom 22  

    Fajny projekt, gratuluję. Jaką największą rozdzielczość można wygenerować za pomocą ATmeg?
    Jak bym chciał wyświetlać na monitorze FULL HD zdjęcia, to jak to najłatwiej zrobić? Trzeba pewnie wykorzystać ARMa, lub FPGA?

  • #17 02 Sty 2012 14:03
    ja.czekanski
    Poziom 12  

    M_Rutkowski78 napisał:
    Czy są jakieś nie dociągnięcia, czy nie, powiem krótko... SZACUNEK!

    Kilka niedociągnieć jest, nie wiem czy widać na filmie, ale po prostu miałem już dość klepania w asmie, a chciałem spędzić sylwestra inaczej niż przy komputerze :)

    xanio napisał:
    Jeszcze jedno. Jest patent na tekst w wyższej rozdzielczości.
    http://www.linusakesson.net/scene/craft/

    Sekcja Video, drugi akapit:
    In addition to this, I've hooked up a couple of diodes and a PNP transistor in such a way, that when the MOSI pin is low while the OC2B pin is high, the three color signals will be pulled to a high voltage, corresponding to white. This is used to generate high resolution scroll text: The MOSI pin is connected to a shift register internally in the AVR (it is typically used for serial data transmission), and this shift register can be programmed to emit a sequence of 8 bits with a single instruction, thus offloading the CPU.

    Tak, widziałem ten projekt, pełen szacunek dla autora, wzorowałem się na nim. Chciałem wykorzystać ten trick, ale niestety brakło już czasu procesora (musiałbym sprawdzać, czy dana komórka to font czy nie, a to już kradnie czas i obniża rozdzielczość). Ale dla grafiki czarno-białej to świetne rozwiązanie - można uzyskać świetne wyniki. A jakby połączyć 3 takie dla każdego koloru? :)

    mgiro napisał:
    Fajny projekt, gratuluję. Jaką największą rozdzielczość można wygenerować za pomocą ATmeg?
    Jak bym chciał wyświetlać na monitorze FULL HD zdjęcia, to jak to najłatwiej zrobić? Trzeba pewnie wykorzystać ARMa, lub FPGA?

    Do takich celów najlepiej nadaje się FPGA, a jeszcze lepiej ARM+FPGA (procesor do streamowania obrazu, a fpga do generacji sygnału). Moim marzeniem jest jakaś płytka z FPGA, ale niestety brak pieniędzy. Zgodnie z tym co jest napisane tutaj: http://www.tinyvga.com/vga-timing to do generowania obrazu o rozdzielczości 1920 x 1200 (wiem, to nie hd, ale bliska rozdzielczość) potrzeba nam częstotliwości 193.16 MHz. Jeden cykl procesora na takim zegarze musi odpowiadać jednemu pikselowi. A procesor musi jeszcze wczytać dane i je zinterpretować. Więc potrzeba zegaru 2, 4 razy większego. ARM taktowany 800MHz do generowania obrazu? Nie najlepszy pomysł :) Lepiej użyć FPGA lub nawet CPLD, który nie robi nic poza generowaniem obrazu z SRAMu (lub DRAMu) i dzieli linie adresowe z mikrokontrolerem.
    A największa rozdzielczość jaką da się wygenerować? Może 320x240 przy dużej ilości pamięci. Taktowanie ATmegi powyżej 20MHz (wogóle powyżej wartości podanej przez producenta) stawia stabilność procesora pod znakiem zapytania. Zobacz tutaj: http://www.linusakesson.net/scene/craft/ Ten pan wycisnął wszystko z tego mikrokontrolera.

  • #18 02 Sty 2012 14:35
    Sputnik8
    Poziom 12  

    kubx napisał:
    W 10% czasu procesora generowana jest grafika, liczone są kolizje i cała logia gry.


    A mógłbyś powiedzieć ile to dokładnie cykli zegarowych?

  • #19 02 Sty 2012 14:53
    ja.czekanski
    Poziom 12  

    Sputnik8 napisał:
    kubx napisał:
    W 10% czasu procesora generowana jest grafika, liczone są kolizje i cała logia gry.


    A mógłbyś powiedzieć ile to dokładnie cykli zegarowych?

    kubx napisał:
    Przez 480 linii obraz jest generowany, potem przez 11 linii wyświetlany jest kolor czarny, potem w ciągu 2 linii ustawiam synchronizację pionową i przez kolejne 31 linii dalej jest ciemność. Daje to 44 linie, przez które nic się nie robi. Daje nam to ( w przybliżeniu) 512*44=22528 wolnych cykli procesora. To właśnie w tym momencie wykonywana jest reszta programu.

    No, może to nie jest 10% :) Mogłem się walnąć w obliczeniach. Jeżeli się nie walnąłem to na klatkę mamy 22528 cykli procesora wolnych dla programu (dużo, niedużo, zależy co piszemy), a 22528*60=1351680cykli na sekundę. Można rysować np. co 2gą klatkę, zmniejszy nam to ilość fps, zyskamy 2x więcej cykli na klatkę i gra nadal będzie płynna. (dla porównania filmy nagrywane są w 24k/s)

  • #20 02 Sty 2012 15:24
    xanio
    Poziom 27  

    A czy klocki narysowane na rogach ekranu są po to, żeby auto-adjust w monitorze dobrze załapał? :)

  • #21 02 Sty 2012 15:44
    ja.czekanski
    Poziom 12  

    xanio napisał:
    A czy klocki narysowane na rogach ekranu są po to, żeby auto-adjust w monitorze dobrze załapał? :)

    Tak, dokładnie. Całe tło jest czarne, więc monitor głupieje przy próbie kalibracji. A gdy testowałem program na CRT, obraz musiałem ustawiać ręcznie.
    To nie jest bug, a znaczniki ekranu.

  • #23 11 Sty 2012 15:53
    And!
    Admin grupy Projektowanie

    Cieszę się że projekt udało się zrealizować mimo zmiany początkowych założeń:
    Link

    Bardzo dobra prezentacja projektu,
    ujęcia przedstawiające model warto wykonywać w świetle dziennym,
    wtedy nawet słabsza kamera lepiej łapie ostrość i odwzorowuje kolory.

    Jak widać warto w prezentacji użyć własnego głosu,
    ew. napisy/opisy + komentarz + podkład muzyczny,
    to zwiększa szansę, że widz dotrwa do końca filmu ;)

  • #24 11 Sty 2012 16:44
    ja.czekanski
    Poziom 12  

    Otrzymałem ostatnio wiadomość z prośbą o lepsze wyjaśnienie generacji obrazu VGA. Postanowiłem się podzielić ze wszystkimi tym co napisałem.
    Od razu informuję, że dla mnie bardzo użyteczne były informacje na tej stronie: http://www.lucidscience.com/pro-vga%20video%20generator-1.aspx . Pisząc tą wiadomość opierałem się o tą stronę i w razie wątpliwości odsyłam do niej.

    Cytat:
    Jeżeli chodzi o generację obrazu - wszystko opiera się o czasy. Najlepiej napisać to w assemblerze, bo mamy kontrolę co do cyklu. No, może nie cały program, ale samo przerwanie do generacji linii. Dobrze jest je stworzyć używając timera. W zależności od kwarcu mamy różną ilość czasu na generację - ja używałem 20MHz, ale obraz generuje się w częstotliwości 25.175MHz i dla takiej wartości będę pisał.

    VGA ma 5 podstawowych sygnałów:
    - Red - zakończone rezystorem 75Ohm w monitorze
    - Green - jw
    - Blue - jw
    - HSYNC (w spoczynku 5v, czyli np. jak wyświetlamy kolory)
    - VSYNC (w spoczynku 5v)


    Jeżeli chodzi o 3 pierwsze to raczej nie ma wątpliwości - 0.0v na jednym z nich to brak tej barwy, a 0.7v (niektóre monitory obsługują 1.0v, ale lepiej nie ryzykować) to pełna barwa. Czyli chcąc wyświetlić czarny mamy pokolei: 0v, 0v, 0v. Dla białego - 0.7v, 0.7v, 0.7v. Dla czerwonego - 0.7v, 0v, 0v, itd. Napięcia łatwo jest wytworzyć dobierając odpowiedni opornik do pinu koloru. Wejście w monitorze jest zakończone rezystorem 75Ohm, więc wystarczy nam policzyć rezystor do dzielnika, aby uzyskać 0.7v dla zasilania 5v (ja użyłem 470Ohm). Jasne? Ok, to lecimy dalej.

    Chcemy generować obraz o rozdzielczości 640x480@60Hz - czyli minimum jakie można osiągnąć na monitorze.
    Dla kwarcu 25.175MHz jeden cykl to jeden piksel. Czyli na jedną linię mamy 640 cykli. Ale na tym się nie kończy, bo monitor musi mieć czas na przemieszczanie działka, którym strzela kolorami (vga było stworzone dla CRT, tam obraz był tworzony inaczej niż w LCD). Dlatego potrzebujemy jeszcze 160 cykli na przemieszczenie działka. Więc jedna linia to 640+160 = 800 cykli.
    Ok, przez 640 cykli procesora co cykl wypluwamy nowy kolor - banał. Następnie, gdy skończymy wyświetlać obraz musimy ustawić kolor czarny. Inaczej monitor nie wie, czy to co wyświetlamy to obraz czy sygnały kontrolne.
    Czyli - 640 cykli - różne kolory, następnie ustawiamy czarny.
    Pozostałe 160 cykli zostało podzielone na 3 fazy: HFP, HSP, HBP. Są to angielskie skróty, nie będę ich rozwijał.
    HFP - 16 cykli
    HSP - 96 cykli
    HBP - 48 cykli

    Przez HFP nie robimy nic. Ja ten czas przeznaczyłem na wyrównanie timera (taka głupota w rdzeniu AVR - aby przerwanie się wykonało to obecna instrukcja musi się wykonać - a to zajmuje różną ilość czasu i rozsynchronizowuje obraz.
    Na początku HSP musimy ustawić HSYNC. Czyli na tą linie wypluwamy 0v. Tyle, dalej nic nie robimy (tutaj robię jakieś obliczenia, nie pamiętam już co).
    Na początku HBP trzeba z powrotem na linię HSYNC podać 5v. To wszystko.
    Tak wygląda generacja jednej linii.
    (dla kwarcu 20MHz, wszystko wygląda tak samo, ale ilość cykli jest odpowiednio przemnożona - 512 cykli na kolory, HFP - 12, HSP - 76, HBP - 36 - tutaj pokazane: http://www.lucidscience.com/projects/VGA%20Video%20Generator/12.jpg )


    Skoro generujemy obraz 640x480 taki proces generowania trzeba powtórzyć 480 razy. Przez 480 takich linii nic się nie zmienia, oczywiście oprócz tego co wyświetlamy. Obliczanie, którą linię wyświetlam obliczam podczas wolnych cykli w HSP i HBP.

    Ale został nam jeszcze sygnał VSYNC - co z nim? Po wygenerowaniu 480 linii musimy poświęcić jeszcze 44 linie na VSYNC. Te 44 linie zostały podzielone również na 3 fazy:
    VFP - 11 linii
    VSP - 2 linie
    VBP - 31 linii

    Przez VFP nie robimy nic. Nie wyświetlamy żadnego koloru, HSYNC generujemy tak jak normalnie. Ja w tym momencie wychodzę z przerwania i zwalniam czas procesora na obliczenia logiki gry.
    VSP - Tutaj na początku trzeba ustawić linię VSYNC na 0v. Na początku czyli w tym momencie gdy zaczęlibyśmy normalnie wyświetlać kolory. Przez resztę czasu nie robimy nic jak w poprzednim przypadku.
    VBP - Na początku ustawiamy VSYNC z powrotem na 5v i reszta jak w poprzednim przypadku.

    Oczywiście tutaj ilość linii będzie inna dla częstotliwości 20MHz i znowu odsyłam tutaj: http://www.lucidscience.com/projects/VGA%20Video%20Generator/12.jpg

    Właściwie to już tyle. Czas wolny podczas generowania linii poświęcam na sprawdzanie, którą linię trzeba wyświetlić oraz miałem tutaj generować dźwięk, ale to nie wypaliło.

    Mam nadzieję, że nie zapomniałem o niczym ważnym, jednak temat ukazałem tylko powierzchniowo. Polecam wczytać się w artykuły które podałem (szczególnie Lucidscience - po lekturze artykułu nie miałem praktycznie żadnych wątpliwości). Pamiętaj również o różnicach w czasach dla różnych kwarców!
    Jakub Czekański