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

Moduł generatora VGA - Verilog

26 Paź 2011 23:15 4467 14
  • Poziom 21  
    Witam !

    Proszę o pomoc, bo już nerwy mi puszczają, siedzę nad tym drugi dzień i ciągle to samo, czyli po uruchomieniu programu na płytce testowej monitor przechodzi w stan uśpienia, tak jakby wgl nie reagował na impulsy.

    Układ FPGA taktowany jest zegarem 50 MHz, timingi wziąłem z tąd : (strona 6)
    http://www.xilinx.com/support/documentation/ip_documentation/xps_tft.pdf

    wycinek z timingami :
    Moduł generatora VGA - Verilog

    Problemem jest zegar 50MHz, do którego niby jest tryb 800x600 72Hz, ale w tym trybie również nie działał. W materiale jak wyżej przedstawione są timingi dla zegaru 25MHz tryb 640x480 60Hz.

    Więc podzieliłem częstotliwość 50MHz na 2 i wtedy częstotliwością 25MHz mogłem taktować swój układ.

    Kod :
    Kod: verilog
    Zaloguj się, aby zobaczyć kod


    i wykresy czasowe:
    Moduł generatora VGA - Verilog Moduł generatora VGA - Verilog

    h_video_en i v_video_en to linie, które są 1 gdy kolory pixeli mają być pobierane z bufora.
    Czasy są poprawne. Sam nie wiem co już źle robię , generator z tej strony :
    http://www.fpga4fun.com/PongGame.html

    Działał bez zarzutów, ale nie chcę bezmyślnie kopiować kodu tylko napisać coś samemu.

    Proszę dobrych ludzi o pomoc :)
    Darmowe szkolenie: Ethernet w przemyśle dziś i jutro. Zarejestruj się za darmo.
  • Pomocny post
    Poziom 12  
    Wybacz, ale na razie nie bede Ci sprawdzal wartosci dla case'ow czy sa poprawne, jak pozniej znajde chwilke to na nie lookne. Teraz najbardziej rzucajace sie w oczy:

    Primo:
    Niby ladnie podzililes przez 2, ale czemu go potem nie uzywasz?
    W pierwszym block procesie zamien clock na half_clock i zobacz co wtedy.

    Secundo:
    Synchronizacje v_sync'a ma byc zupelnie inna. v_count powinien byc inkrementowany przez zmiane na h_sync (innymi slowy, v_count jest licznikiem h_sync'ow a nie zegara, jak to jest w Twoim przypadku):
    1. najpierw uklad wystawia kilkaset impulsow h_sync (kazdy wskazuje nowa linie)
    2. v_sync schodzi na 0, ale wystawiane sa jeszcze, o ile dobrze pamietam, 2 h_sync'i
    3. v_sync idzie w gore

    i proces zaczyna sie od nowa.

    Popraw kod, zobacz co sie dzieje, a potem bedziem ywalczyc dalej, bo pewnie to nie jedyne problemy - pozniej jeszcze moga byc kwiatki z kolorami, ale do tego dojdziemy :D

    powodzenia :)
  • Poziom 21  
    Tzn, ja połączyłem te moduły ( dzielnik częstotliwości i generator VGA ) w module testbencha, oto kod testbenchu :
    Kod: verilog
    Zaloguj się, aby zobaczyć kod


    Moduł generatora VGA - Verilog

    Rozumiem, że h_sync jest sygnałem taktującym licznik v_sync, tak też jest u mnie, czas pomiędzy impulsami v_sync (czyli okres ) wynosi 16,8 ms 1 impuls h_sync trwa 32,8 us, a więc tych impulsów h_sync jest 16,8ms / 32,8us = 512 , co się nie zgadza, bo powinno być 800
  • Pomocny post
    Poziom 14  
    Zastąp 'initial' jakimś resetem.
  • Poziom 21  
    Dave_PL napisał:
    Zastąp 'initial' jakimś resetem.


    a ten reset zrobić synchroniczny czy asynchroniczny ?

    Co w tym kodzie jeszcze jest źle ?
  • Pomocny post
    Poziom 21  
    Zrób asynchroniczny aby nie był zależny od zegara
  • Pomocny post
    Poziom 14  
    Asynchroniczny reset to można jedynie do symulacji dać. W przypadku rzeczywistych projektów lepiej dać reset synchroniczny.
  • Pomocny post
    Poziom 21  
    Rozwin temat.... Podaj za przeciw... Na dobra sprawe przy zegarze 25MHz albo w granicach to bez roznicy ale przy mniejszych to jest. Dlatego uzasdnij.
  • Pomocny post
    Poziom 30  
    Może tak. Opis zrób z asynchronicznym resetem. Zamiana z asynchronicznego na synchroniczny to tylko dodanie dodatkowej flagi dla syntezera XST (-async_to_sync), albo w GUI ISE na PPM na Synthesize - XST.

    Pełny synchroniczny reset w systemie to brak resetu jeśli nie ma domeny zegarowej. Jak używasz opisu logiki synchronicznego z asynchronicznym resetem, to wystarczy przefiltrować rejestrem przesuwnym taki reset, aby pozbyć się glitchy, a ścieżka globalna jest na tyle zoptymalizowana, że nie ma co się obawiać jitter'a szczególnie przy tak prostym układzie z niską częstotliwością taktowania.
  • Pomocny post
    Poziom 28  
    lss napisał:
    Rozwin temat.... Podaj za przeciw... Na dobra sprawe przy zegarze 25MHz albo
    w granicach to bez roznicy ale przy mniejszych to jest. Dlatego uzasdnij.

    niebezpieczenstwo asynchronicznego resetu nie jest zalezne
    od czestotliwosci zegara;
    w pewnym skrocie sprawa przedstawia sie tak:
    sygnal reset ustawia sie w stan aktywny [zalozmy ze jest to '0']
    i zeruje rejestry niezaleznie od swej pozycji w czasie wzgledem
    sygnalu zegarowego, po jakims czasie sygnal reset jest de-aktywowany
    i jesli jest rzeczywiscie asynchroniczny wzgledem zegara, to moze
    sie zdarzyc, ze jego [reset] pos. zbocze jest niemal rownoczesne ze
    zboczem sygnalu zegara - w takiej sytuacji zaczynaja odgrywac role
    roznice w propagacji resetu i zegara do poszczegolnych przerzutnikow
    w ukladzie, poniewaz nawet male fpga ma jakies wymiary przestrzenne,
    do jednych przerzutnikow de-aktywacja reset dotrze tuz przed zegarem,
    do innych tuz po, w konsekwencji czesc F-F [przerzutnikow] bedzie
    w danym takcie zegara jeszcze 'zerowana' a inna nie i caly uklad po resecie
    wejdzie w stan nieustalony, przypadkowy, ma to szczegolnie fatalne
    konsekwencje, jesli beda to przerzutniki jakiejs maszyny stanow
    kontrolujacej dzialanie calosci ukladu;

    mimo to asynchroniczne zerowanie jest obecnie dosc czesto
    stosowane, a to z tego powodu, ze podstawowe jednostki architektury
    fpga maja odzielne wejscie zerowania asynchronicznego, wiec
    reset asynchroniczny nie konsumuje jednego z wejsc informacyjnych
    funkcji kombinacyjnej, jak to jest w przypadku zerowania synchronicznego;
    innymi slowy w przypadku rozbudowanej funkcji kombinacyjnej dzieki
    zerowaniu asynchronicznemu funkcja jest realizowana przez mniejsza
    ilosc podstawowych komorek fpga, a przez to calosc jest szybsza;

    mam nadzieje, ze udalo mi sie to opisac w sposob w miare zrozumialy :);

    aby uniknac niebezpieczenstwa ktore opisalem powyzej, stosuje sie
    prosty zabieg, synchronizuje sie asynchroniczny reset do zegara,
    a w przerzutnikach uzywa sie go jako asynchroniczny;

    wyglada to mniej wiecej tak: [przyklad w verilog]

    Code:
    input reset_asynch;
    

    reg reset_synch;

     always @(posedge clk)
        reset_synch <= reset_asynch;

    reg [7:0] registers;
     
     always @(posedge clk or posedge reset_synch)
       if ( reset_synch) registers <= 8'h0; // reset korzystajacy z asynch.
                                               wejscia do komorki fpga
       else              registers <= <jakas funkcja>;


    dzieki temu de-aktywacja zerowania dotrze do wszystkich przerzutnikow
    po aktywnym zboczu zegara;



    tymon_x napisał:
    . Jak używasz opisu logiki synchronicznego z asynchronicznym resetem,
    to wystarczy przefiltrować rejestrem przesuwnym taki reset, aby pozbyć się
    glitchy, a ścieżka globalna jest na tyle zoptymalizowana...


    Panie Tymonie - mam nadzieje, ze nie odbierze Pan to jako jakis osobisty
    przytyk, ale... ma Pan tendencje do wpadania w jakis zamkniety dla wiekszosci
    zargon, przez ktory Panskie wypowiedzi sa trudno zrozumiale, zwlaszcza
    dla poczatkujacych, a tacy przeciez glownie pytaja tu o rade;

    wypowiedzi zwykle trafne merytorycznie, chcialbym zaznaczyc;

    pozdrawiam
    J.A
  • Poziom 21  
    Witam ponownie :)

    Poradziłem sobie już z timingami, mam "goły" generator, bez pamięci , mogę np wyświetlić jakiś kolor.

    Teraz chciałbym dodać pamięć.

    Na początku nie będę wykorzystywał zewnętrznej pamięci SRAM jako buforu. Użyje rejestrów. Trochę pokombinowałem i efekt jest taki :
    Kod: verilog
    Zaloguj się, aby zobaczyć kod


    Zasada zapisu kolorów do bufora jest następująca :
    Przygotowuję dane do wpisu ( data_in) , a następnie zboczem na wejściu data_wr, zapisuję je do pamięci. Aby zapisać pojedynczy piksel najpierw wysyłamy do pamięci zmięnną x_pos, później y_pos, a na końcu kolor.

    Tym sposobem zmniejszam liczbę połączeń, tym bardziej że w przyszłości planuję wrzucić taki sterownik do mniejszego układu abym mógł sobie bez problemu sterować monitorem przez mikrokontroler.

    Może ktoś ma jakiś inny pomysł jak rozwiązać sprawę buforu ?

    Poza tym nie wiem jak zapisywać i odczytywać dane z takiego buforu, bo np
    Kod: verilog
    Zaloguj się, aby zobaczyć kod


    modelsim nie wyrzucił błędu a quatrus wyrzucił, że linie red,gren blue są [2:0].

    Pozdrawiam.
  • Pomocny post
    Poziom 28  
    tu chyba jest blad:
    Code:

       input             data_wr,
       /.../
     always @(posedge clk)
       begin
       case(data_wr)
          1: x_pos_wr <= data_in;
          2: y_pos_wr <= data_in;
          3: begin


    mialo byc case (wr_count) ?

    a te linijki:
    red[2:0] <= buffer[h_count][v_count];
    green[5:3] <= buffer[h_count][v_count];
    blue[8:6] <= buffer[h_count][v_count];

    chyba nalezaloby zapisac:
    {blue,green,red} <= buffer[h_count][v_count];

    dziwne, ze questa przepuscila cos takiego,

    output reg [2:0] green,
    /.../
    green[5:3] <= buffer[h_count][v_count];

    J.A
  • Poziom 21  
    Dzięki za rady. Wpadłem na inny pomysł, żeby zrobić oddzielne moduły tj. oddzielny sam generator i pamięć. Ma to swoje zalety, ponieważ później z łatwością będę mógł zastosować podwójne buforowanie pamięci, zmieniając tylko jeden moduł. Obydwa moduły przedstawiają się tak :

    Moduł generatora

    Wyprowadzone wyjścia h_count i v_count do adresowania pamięci, a także video_on do włączania rysowania kolorów.

    Kod: verilog
    Zaloguj się, aby zobaczyć kod


    Moduł pamięci

    Zapis do pamięci odbywa się równolegle, podajemy na wejścia x_pos i y_pos pozycję zapisu piksela o kolorze RGB {Blue,Green,Red} i zapisujemy impulesm wr.

    Kod: verilog
    Zaloguj się, aby zobaczyć kod



    Do tego postanowiłem zrobić prosty moduł testujący cały układ rysujący kwadrat o kolorze niebieskim i wymiarach 100x100.

    Kod: verilog
    Zaloguj się, aby zobaczyć kod


    Ale problem jest taki, że zamiast prostokąta cały ekran jest niebieski :(

    Gdzie może być błąd ?

    Dołączam jeszcze schemat połączeń między modułami.
    Moduł generatora VGA - Verilog

    Dodano po 33 [minuty]:

    Problem leży w module pamięci, ponieważ robiłem testbench układu testującego i generuje prawidłowe impulsy.
  • Poziom 21  
    Wydaje mi się , żę problem tkwi w źle opisanej pamięci, tzn muszę wykorzystać pamięć SDRAM dostępną na płytce, bo implementując pamięć niby o tej samej pojemności czyli :

    reg [8:0] memory [640*480:0]

    otrzymuję błąd:
    "Error (276003): Cannot convert all sets of registers into RAM megafunctions when creating nodes. The resulting number of registers remaining in design exceeds the number of registers in the device or the number specified by the assignment max_number_of_registers_from_uninferred_rams. This can cause longer compilation time or result in insufficient memory to complete Analysis and Synthesis"