| Author |
Message
|
^Rachel Poziom 18

Joined: 19 Nov 2010 Posts: 540 Location: Częstochowa
|
#1
26 Oct 2011 23:15 Generator VGA - Verilog |
|
|
|
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 :
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 :
module vga_generator(input wire clk, output reg h_sync,v_sync,h_video_en,v_video_en); reg [9:0] h_count; reg [9:0] v_count; initial begin h_sync = 0; v_sync = 0; h_video_en = 0; v_video_en = 0; h_count = 0; v_count = 0; end always @(posedge clk) begin h_count <= h_count+1; case(h_count) 95: h_sync <= 1; 143: h_video_en <= 1; 783: h_video_en <= 0; 799: begin h_sync <= 0; h_count <= 0; v_count <= v_count+1; end endcase case(v_count) 1: v_sync <= 1; 32: v_video_en <= 1; 512:v_video_en <= 0; 524: begin v_sync <= 0; v_count <= 0; end endcase end endmodule module div_2(input wire clock,output reg half_clock); initial begin half_clock = 0; end always @(posedge clock) half_clock <= ~half_clock; endmodule
i wykresy czasowe:
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 :)
|
|
| Back to top |
|
 |
KonusiK Poziom 9

Joined: 04 Nov 2007 Posts: 33 Location: Kraków
|
#2
27 Oct 2011 09:31 Re: Generator VGA - Verilog |
|
|
|
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 :)
|
|
| Back to top |
|
 |
Google

|
#
27 Oct 2011 09:31 |
|
|
|
|
|
| Back to top |
|
 |
^Rachel Poziom 18

Joined: 19 Nov 2010 Posts: 540 Location: Częstochowa
|
#3
27 Oct 2011 17:49 Re: Generator VGA - Verilog |
|
|
|
Tzn, ja połączyłem te moduły ( dzielnik częstotliwości i generator VGA ) w module testbencha, oto kod testbenchu :
module engine_tb; reg clk; wire h_sync,v_sync,h_video_en,v_video_en,clk2; initial begin clk = 0; end div_2 u2(clk,clk2); vga_generator u1(clk2,h_sync,v_sync,h_video_en,v_video_en); always #10 clk <= ~clk; endmodule
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
|
|
| Back to top |
|
 |
Dave_PL Poziom 9

Joined: 15 Sep 2010 Posts: 40 Location: Kraków
|
#4
28 Oct 2011 00:26 Re: Generator VGA - Verilog |
|
|
|
Zastąp 'initial' jakimś resetem.
|
|
| Back to top |
|
 |
Google

|
#
28 Oct 2011 00:26 |
|
|
|
|
|
| Back to top |
|
 |
^Rachel Poziom 18

Joined: 19 Nov 2010 Posts: 540 Location: Częstochowa
|
#5
28 Oct 2011 09:34 Re: Generator VGA - Verilog |
|
|
|
| Dave_PL wrote: |
| Zastąp 'initial' jakimś resetem. |
a ten reset zrobić synchroniczny czy asynchroniczny ?
Co w tym kodzie jeszcze jest źle ?
|
|
| Back to top |
|
 |
lss Poziom 17

Joined: 14 Dec 2008 Posts: 352 Location: Warszawa
|
#6
28 Oct 2011 14:49 Re: Generator VGA - Verilog |
|
|
|
Zrób asynchroniczny aby nie był zależny od zegara
|
|
| Back to top |
|
 |
Google

|
#
28 Oct 2011 14:49 |
|
|
|
|
|
| Back to top |
|
 |
Dave_PL Poziom 9

Joined: 15 Sep 2010 Posts: 40 Location: Kraków
|
#7
28 Oct 2011 21:08 Re: Generator VGA - Verilog |
|
|
|
Asynchroniczny reset to można jedynie do symulacji dać. W przypadku rzeczywistych projektów lepiej dać reset synchroniczny.
|
|
| Back to top |
|
 |
lss Poziom 17

Joined: 14 Dec 2008 Posts: 352 Location: Warszawa
|
#8
28 Oct 2011 23:46 Re: Generator VGA - Verilog |
|
|
|
Rozwin temat.... Podaj za przeciw... Na dobra sprawe przy zegarze 25MHz albo w granicach to bez roznicy ale przy mniejszych to jest. Dlatego uzasdnij.
|
|
| Back to top |
|
 |
Dave_PL Poziom 9

Joined: 15 Sep 2010 Posts: 40 Location: Kraków
|
|
| Back to top |
|
 |
tymon_x Poziom 20

Joined: 17 Jun 2010 Posts: 814 Location: Gdańsk
|
#10
01 Nov 2011 17:52 Re: Generator VGA - Verilog |
|
|
|
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.
|
|
| Back to top |
|
 |
J.A Poziom 17

Joined: 06 Sep 2007 Posts: 417 Location: Krakow
|
#11
02 Nov 2011 01:48 Re: Generator VGA - Verilog |
|
|
|
| lss wrote: |
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 wrote: |
. 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
|
|
| Back to top |
|
 |
^Rachel Poziom 18

Joined: 19 Nov 2010 Posts: 540 Location: Częstochowa
|
#12
04 Feb 2012 00:41 Re: Generator VGA - Verilog |
|
|
|
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 :
module vga_controller( input clk, input reset, input data_wr, input [9:0] data_in, output reg [1:0] wr_count, output reg h_sync, output reg v_sync, output reg [2:0]red, output reg [2:0]green, output reg [2:0]blue); reg clk_div2; reg video_h,video_v; reg [9:0] h_count; reg [9:0] v_count; reg [9:0] buffer [9:0][8:0]; reg [8:0] color_wr; reg [9:0] x_pos_wr; reg [8:0] y_pos_wr; initial //tylko do symulacji begin h_sync=0; v_sync=0; red=0; green=0; blue=0; clk_div2=0; video_h=0; video_v=0; h_count=0; v_count=0; color_wr=0; x_pos_wr=0; y_pos_wr=0; wr_count=0; end always @(posedge data_wr) wr_count<=wr_count+1; always @(posedge clk) begin case(data_wr) 1: x_pos_wr <= data_in; 2: y_pos_wr <= data_in; 3: begin color_wr <= data_in; buffer[x_pos_wr][y_pos_wr]<= color_wr; wr_count <= 0; end //impuls data_good przez 2 cykle czyli 40ns endcase end always @(posedge clk) begin if(!reset) clk_div2 <= 1'b0; else clk_div2 <= ~clk_div2; end always @(posedge clk) begin if(!reset) h_count <= 10'd0; else if(clk_div2) begin if(h_count != 10'd799) h_count <= h_count + 1'b1; else h_count <= 10'd0; end end always @(posedge clk) begin if(!reset) v_count <= 10'd0; else if(clk_div2) begin if(h_count == 10'd799) begin if(v_count != 10'd524) v_count <= v_count + 1'b1; else v_count <= 10'd0; end end end always @(posedge clk) begin if(!reset) h_sync <= 1'b0; else if(clk_div2) begin if(h_count >= 10'd656 && h_count< 10'd752) h_sync <= 1'b0; else h_sync <= 1'b1; end end always @(posedge clk) begin if(!reset) v_sync <= 1'b0; else if(clk_div2) begin if(v_count >= 10'd490 && v_count < 10'd492) v_sync <= 1'b0; else v_sync <= 1'b1; end end always @(posedge clk) begin if(!reset) {red,green,blue} <= 3'b000; else if(clk_div2) begin if(h_count < 10'd640 && v_count < 10'd480) begin // tutaj musze wstawic obsluge wyrzucania kolorow z pamieci // moge tez zapelnic caly obraz jednym kolorem // uzywajac red <= 7; red[2:0] <= buffer[h_count][v_count]; green[5:3] <= buffer[h_count][v_count]; blue[8:6] <= buffer[h_count][v_count]; end else //bez tego elsa widzielibysmy tylko czarny obraz ;/ begin red <= 0; green<=0; blue <=0; end end end endmodule
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
red[2:0] <= buffer[h_count][v_count]; green[5:3] <= buffer[h_count][v_count]; blue[8:6] <= buffer[h_count][v_count];
modelsim nie wyrzucił błędu a quatrus wyrzucił, że linie red,gren blue są [2:0].
Pozdrawiam.
|
|
| Back to top |
|
 |
J.A Poziom 17

Joined: 06 Sep 2007 Posts: 417 Location: Krakow
|
#13
04 Feb 2012 17:29 Re: Generator VGA - Verilog |
|
|
|
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
|
|
| Back to top |
|
 |
^Rachel Poziom 18

Joined: 19 Nov 2010 Posts: 540 Location: Częstochowa
|
#14
06 Feb 2012 19:39 Re: Generator VGA - Verilog |
|
|
|
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.
module vga_controller( input clk, input reset, output reg video_on, output reg [9] h_count, output reg [9] v_count, output reg h_sync, output reg v_sync); reg clk_div2; initial //tylko do symulacji begin video_on=0; h_sync=0; v_sync=0; clk_div2=0; h_count=0; v_count=0; end always @(posedge clk) begin if(!reset) clk_div2 <= 1'b0; else clk_div2 <= ~clk_div2; end always @(posedge clk) begin if(!reset) h_count <= 10'd0; else if(clk_div2) begin if(h_count != 10'd799) h_count <= h_count + 1'b1; else h_count <= 10'd0; end end always @(posedge clk) begin if(!reset) v_count <= 10'd0; else if(clk_div2) begin if(h_count == 10'd799) begin if(v_count != 10'd524) v_count <= v_count + 1'b1; else v_count <= 10'd0; end end end always @(posedge clk) begin if(!reset) h_sync <= 1'b0; else if(clk_div2) begin if(h_count >= 10'd656 && h_count< 10'd752) h_sync <= 1'b0; else h_sync <= 1'b1; end end always @(posedge clk) begin if(!reset) v_sync <= 1'b0; else if(clk_div2) begin if(v_count >= 10'd490 && v_count < 10'd492) v_sync <= 1'b0; else v_sync <= 1'b1; end end always @(posedge clk) begin if(!reset) video_on<=1'b0; // {red,green,blue} <= 3'b000; else if(clk_div2) begin if(h_count < 10'd640 && v_count < 10'd480) begin video_on<=1'b1; end else //bez tego elsa widzielibysmy tylko czarny obraz ;/ begin video_on<=1'b0; end end end endmodule
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.
module single_buffering_memory( input clk, input wr, input video_on, input [8]RGB, input [9]x_pos, input [9]y_pos, input [9]h_count, input [9]v_count, output reg [2]red, output reg [2]green, output reg [2]blue); reg [9] buffer [9][8]; initial begin red=0; green=0; blue=0; end always @(posedge clk) ////////////zapis do pamieci , najpierw dane, a zapisujemy impulsem wr begin if(wr) buffer [x_pos][y_pos] <= RGB; end always @(posedge clk) /////////// wyswietlanie begin if(video_on) begin {blue,green,red} <= buffer[h_count][v_count]; end else begin red <= 0; green<=0; blue <=0; end end endmodule
Do tego postanowiłem zrobić prosty moduł testujący cały układ rysujący kwadrat o kolorze niebieskim i wymiarach 100x100.
module test( input clk, output reg wr, output reg [8]RGB, output reg [9]x_pos, output reg [9]y_pos); reg [9] x; reg [9] y; always @(posedge clk) begin if(x>100)x<=0; else x<= x+1'b1; if(y>100)y<=0; else y<= y+1'b1; end always @(posedge clk) begin wr <= ~wr; if(wr) begin x_pos <= x; y_pos <= y; RGB <= 9'b111000000; end end endmodule
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.
Dodano po 33 [minuty]:
Problem leży w module pamięci, ponieważ robiłem testbench układu testującego i generuje prawidłowe impulsy.
|
|
| Back to top |
|
 |
Google

|
#
06 Feb 2012 19:39 |
|
|
|
|
|
| Back to top |
|
 |
^Rachel Poziom 18

Joined: 19 Nov 2010 Posts: 540 Location: Częstochowa
|
#15
07 Feb 2012 12:48 Re: Moduł generatora VGA - Verilog |
|
|
|
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"
|
|
| Back to top |
|
 |