Zadanie: Należy wykonać generator figur Lissajous o
następujących właściwościach:
1. Figury rysujemy w kwadratowym obszarze o wymiarach
384 x 384 pixeli.
2. Obraz generujemy na analogowym monitorze VGA (możemy
wykorzystać tryb 640x480).
3. Generator obrazu ustawić tak, aby obraz był
maksymalnie wycentrowany i kwadratowy.
4. Generujemy obraz czarno-biały (wszystkie sygnały RGB
sterujemy równocześnie z tego samego źródła). Figura ma być biała, tło czarne.
5. Częstotliwość obu kanałów (X i Y) i fazę jednego (Y)
ustawiamy za pomocą przełączników SW0-SW7 (zakres 0-255) i przycisków BTN0
(wpis częstotliwości X ustawionej na przełącznikach), BTN1 (wpis częstotliwości
Y ustawionej na przełącznikach), BTN2 (wpis offsetu fazy Y ustawionej na
przełącznikach).
6. Przycisk BTN3 powinien służyć do wyczyszczenia ekranu
i zresetowania generatora DDS (aby rozpoczął rysowanie figur od ustawionej fazy
dla kanału Y i fazy 0 dla kanału X).
7. Kanał X to Channel 0 (patrz opis komponentu DDS
poniżej). Współrzędne ujemne są po lewej stronie ekranu dodatnie po prawej.
Amplituda kanału powinna być tak dobrana aby krzywa w pełni wykorzystała
dostępny ekran.
8. Kanał Y to Channel 1 (patrz opis komponentu DDS
poniżej). Współrzędne ujemne są na dole ekranu dodatnie na górze. Amplituda kanału
powinna być tak dobrana aby krzywa w pełni wykorzystała dostępny ekran.
9. Współrzędne (0,0) są w środku ekranu.
Informacje o figurach
Lissajous:
http://en.wikipedia.org/wiki/Lissajous_curve
Wejścia i wyjścia układu:
clk_i - zegar 50MHz,
rgb_o – wyjście sygnału
RGB do monitora,
hsync_o – wyjście sygnału
synchronizacji poziomej do monitora,
vsync_o – wyjście sygnału
synchronizacji pionowej do monitora,
sw_i – przełączniki do
ustawiania częstotliwości i fazy kanałów,
btn_i – przyciski do wprowadzania częstotliwości i fazy
kanałów ustawionych na przełącznikach.
Informacje o analogowym
sygnale VGA:
http://www.ue.eti.pg.gda.pl/fpgalab/zadania.spartan3/zad_vga_generowanie_sygnalu_vga.html
Przy generacji sygnału wideo
należy pamiętać o zerowaniu sygnałów RGB poza obszarem wyświetlania obrazu.
Do realizacji projektu
potrzebne będą dwa moduły funkcjonalne wygenerowane przez Core Generator.
Dwuportowa pamięć RAM posłuży jako pamięć obrazu, zaś Generator DDS
(Direct Digital Synthesizer) wykorzystany zostanie do wytwarzania cyfrowych
sygnałów sinusoidalnych dla kanału X (poziom) i Y (pion).
Generacja modułu pamięci video:
Wybieramy: Project -> New Source
Następnie otwiera się okienko Select
Source Type w którym wybieramy:
IP (CORE Generator & Architecture Wizard).
Podajemy nazwę pliku dla nowego komponentu (generowanego przez Core Generator),
np. video_mem i klikamy Next:
Następnie otwiera się okienko wyboru
nowego komponentu Select IP:
W okienku tym wybieramy Block Memory
Generator v2.8 oraz klikamy Next. Następnie wyświetla się okienko
podsumowania: New Source Wizard – Summary. Należy potwierdzić naciskając
Finish.
Następnie uruchamia się Core Generator i
otwiera się okienko konfiguracji nowego komponentu:
W tym okienku (1/5) zmieniamy Memory
Type na Simple Dual Port RAM. Pamięć dwuportowa będzie nam
potrzebna, aby można było równocześnie pisać i czytać z dwóch różnych adresów
(zapisujemy pixele wg kształtu krzywej, odczytujemy pixele sekwencyjnie do
monitora).
Znajdujący się w lewym dolnym roku przycisk View Data Sheet otworzy
szczegółową dokumentację projektowanego komponentu.
Następnie klikamy Next.
W tym okienku (2/5) zmieniamy Write
Width na 1 (będziemy zapisywać zawsze jeden pixel – bit na
określonej pozycji - adresie) oraz Write Depth na 147456 (jest
384*384 = 147456 pixeli).
Następnie klikamy Next.
W tym okienku (3/5) zmieniamy Read
Width na 1 (będziemy odczytywać zawsze jeden pixel – bit na
określonej pozycji – adresie) – możliwe jest ustawienie innej szerokości
bitowej magistrali wyjściowej i wejściowej. Liczba adresów jest tym razem
wyliczona automatycznie.
Następnie klikamy Next.
W tym okienku (4/5) nic nie zmieniamy.
Początkowa zawartość pamięci – wszystkie bity zerowe.
Następnie klikamy Next.
W tym okienku (5/5) nic nie zmieniamy.
Okienko pozwala na ustawienie opcji dotyczących modelu symulacyjnego pamięci –
chodzi o wykrywanie kolizji (np. równoczesny zapis z dwóch portów do tej samej
komórki pamięci), i wykrywanie przekroczenia zakresu (np. adresów).
Następnie klikamy Finish.
Spowoduje to rozpoczęcie generacji
komponentu – należy trochę poczekać.
Wygenerowana pamięć posiada dwa wejścia
zegarowe (po jednym dla każdego portu) co może być wykorzystane jeżeli w naszym
systemie są dwie domeny zegarowe, jednak zazwyczaj mamy w projekcie jeden zegar
i wtedy oba wejścia podłączamy do wspólnego zegara.
Należy zwrócić uwagę na definicję
niektórych sygnałów (np. WEA) które są wektorami jednobitowymi – trzeba o tym
pamiętać ponieważ jednobitowy wektor to nie jest to samo co pojedynczy sygnał.
Warto zapamiętać pomocnicze informacje
zawierające podsumowanie właściwości projektowanego komponentu (pole Information)
oraz blokowy schemat połączeń. Szczególnie istotna jest informacja:
Total Port B Read Latency (From Rising Edge of Read Clock): 1 Clock
Cycle(s).
Oznacza to, że odczyt z pamięci odbywa się
z opóźnieniem 1 cyklu zegara w stosunku do zbocza zegarowego zatrzaskującego
odczytywany adres (w przeciwieństwie do zapisu, w którym zapisywana dana
zatrzaskiwana jest równocześnie z adresem). W przypadku wątpliwości proszę
zajrzeć do dokumentacji komponentu (klawisz View Data Sheet).
Po zakończeniu generacji komponent
zostanie dołączony do listy plików projektu.
W celu ułatwienia dołączenia komponentu do
hierarchii aktualnego projektu w katalogu projektu powstają pliki *.vho
zawierające szkielet deklaracji komponentu oraz przykład jego użycia (tworzenia
instancji). Możemy te elementy łatwo przenieść do naszego projektu – wtedy
zaprojektowany komponent zajmie właściwe miejsce w hierarchii.
Przykładowy plik VHO:
--------------------------------------------------------------------------------
-- The following code must appear in the
VHDL architecture header:
------------- Begin Cut here for COMPONENT
Declaration ------ COMP_TAG
component video_mem
port
(
clka:
IN std_logic;
dina:
IN std_logic_VECTOR(0 downto 0);
addra:
IN std_logic_VECTOR(17 downto 0);
wea:
IN std_logic_VECTOR(0 downto 0);
clkb:
IN std_logic;
addrb:
IN std_logic_VECTOR(17 downto 0);
doutb:
OUT std_logic_VECTOR(0 downto 0));
end component;
-- Synplicity black box declaration
attribute syn_black_box : boolean;
attribute syn_black_box of video_mem:
component is true;
-- COMP_TAG_END ------ End COMPONENT
Declaration ------------
-- The following code must appear in the
VHDL architecture
-- body. Substitute your own instance name
and net names.
------------- Begin Cut here for
INSTANTIATION Template ----- INST_TAG
your_instance_name : video_mem
port map (
clka => clka,
dina => dina,
addra => addra,
wea => wea,
clkb => clkb,
addrb => addrb,
doutb => doutb);
-- INST_TAG_END ------ End INSTANTIATION
Template ------------
-- You must compile the wrapper file
video_mem.vhd when simulating
-- the core, video_mem. When compiling the
wrapper file, be sure to
-- reference the XilinxCoreLib VHDL
simulation library. For detailed
-- instructions, please refer to the
"CORE Generator Help".
Tekst zaznaczony na czerwono należy skopiować do obszaru definicji
sygnałów lokalnych. Tekst zaznaczony na niebiesko
(po ustaleniu nazwy instancji komponentu oraz sygnałów podłączonych) należy
skopiować do obszaru opisu systemu. Po dokonaniu powyższych modyfikacji ikona
komponentu powinna zająć właściwe miejsce w hierarchii plików projektu.
Modyfikacja parametrów komponentu i jego
ponowna generacja są możliwe za pomocą ikonek Manage Cores i Regenerate
Core zaznaczonych na poniższym rysunku.
Generacja modułu generatora DDS
W celu wygenerowania modułu generatora DDS
postępujemy podobnie jak poprzednio.
Wybieramy: Project -> New Source
Następnie otwiera się okienko Select
Source Type w którym wybieramy:
IP (CORE Generator & Architecture Wizard).
Podajemy nazwę pliku dla nowego komponentu (generowanego przez Core Generator),
np. singen i klikamy Next:
Następnie otwiera się okienko wyboru
nowego komponentu Select IP:
W okienku tym wybieramy Direct Digital
Synthesizer v5.0 oraz klikamy Next. Następnie wyświetla się okienko
podsumowania: New Source Wizard – Summary. Należy potwierdzić naciskając
Finish.
Następnie uruchamia się Core Generator i
otwiera się okienko konfiguracji nowego komponentu:
W tym okienku (1/6) wybieramy funkcję: Sine
oraz liczbę kanałów: Channels: 2.
(będziemy potrzebować dwóch niezależnych generatorów funkcji sinus do kreślenia
figur Lissajous). Oprócz tego musimy podać częstotliwość zegara systemowego
którym dysponujemy – DDS Clock Rate: 50 MHz.
Konieczne jest także określenie jakości wytwarzanego sygnału (różnica pomiędzy
amplitudą prążka pożądanego, a amplitudą największego spośród prążków
niepożądanych w widmie sygnału podawana w dB) – od tego zależy liczba bitów
użyta do opisu funkcji sinus, a więc także złożoność bloku generatora.
Wybieramy – Spurious Free Dynamic Range: 65 dB
Pozostaje określenie rozdzielczości z którą będziemy ustawiać częstotliwość
sygnału – Frequency Resolution: 500 Hz
Znajdujący się w lewym dolnym roku przycisk View Data Sheet otworzy
szczegółową dokumentację projektowanego komponentu.
Następnie klikamy Next.
W tym okienku (2/6) ustawiamy początkowe
częstotliwości kanałów generatora (częstotliwość podajemy w MHz). Proszę
ustawić częstotliwość obu kanałów na: 0.1953125 MHz
Uwaga - podczas wprowadzania nie widać wprowadzanej wartości.
Phase Increment należy ustawić na: Programmable pozwoli to na
późniejszą zmianę częstotliwości podczas pracy generatora. Częstotliwość
będziemy podawać za pomocą przełączników, których stan możemy wprowadzać
bezpośrednio do najmłodszych bitów wejścia programującego.
Następnie klikamy Next.
W tym okienku (3/6) ustawiamy początkowe
fazy kanałów generatora (fazy podajemy w radianach/2π – tj. np. wielkość
1.0 oznacza 2π radianów). Proszę ustawić fazę kanału 1 na: 0.0 a
kanału 2 na: 0.25 (czyli π/2 radiana).
Uwaga - podczas wprowadzania nie widać wprowadzanej wartości.
Phase Offset należy ustawić na: Programmable pozwoli to na
późniejszą zmianę fazy podczas pracy generatora. Fazę będziemy podawać za
pomocą przełączników, których stan możemy wprowadzać bezpośrednio do najstarszych
bitów wejścia programującego.
Następnie klikamy Next.
W tym okienku (4/6) ustawiamy parametry
pracy oraz dodatkowe opcje generatora DDS.
Proszę włączyć opcję: Clear Options –
SCLR Pin (będzie ona potrzebna do resetowania generatora po wprowadzeniu
zmian i wyczyszczeniu ekranu przyciskiem BTN3) – jest to reset synchroniczny.
Opcję Noise Shaping proszę
pozostawić na None (opcja ta służy do modyfikacji właściwości generatora
w kwestii jakości generowanego sygnału).
Opcję Memory Type proszę ustawić na
Block ROM
W polu Handshaking Options proszę
wyłączyć RFD Pin (jest niepotrzebny) oraz włączyć Channel Pin
(informuje o tym z którego kanału jest wystawiana aktualna próbka).
Opcję Pipelined należy wyłączyć.
W polu Accumulator Latency należy
ustawić One Cycle.
Następnie klikamy Next.
Warto zapamiętać pomocnicze informacje
zawierające posumowanie właściwości projektowanego komponentu (pole Summary)
oraz blokowy schemat połączeń.
Następnie klikamy Next.
Wyświetli się drugie okienko z informacjami
podsumowującymi.
Należy uruchomić syntezę komponentu
naciskając Generate.
Następnie należy trochę poczekać.
Podobnie jak w poprzednim przypadku należy
teraz podłączyć wygenerowany komponent do projektu (można wykorzystać
wygenerowany plik *.vho).
Weryfikacja układu
Należy zweryfikować układ praktycznie
poprzez zaprogramowanie płytki testowej. W razie potrzeby należy wykonać
symulację funkcjonalną. Weryfikacja praktyczna polega na sprawdzeniu działania
systemu poprzez wyświetlenie kilku figur Lissajous dla różnych częstotliwości i
faz. W tym celu należy do wyjścia VGA podłączyć kabelek od małego monitora
znajdującego się na stanowisku laboratoryjnym. Działanie zademonstrować
prowadzącemu. Wyjaśnić kiedy i dlaczego widzimy dyskretną strukturę figur (figura
złożona z pojedynczych kropek).
Informacje dodatkowe o zasadach działania generatorów DDS:
http://en.wikipedia.org/wiki/Direct_digital_synthesizer
http://www.ieee.li/pdf/essay/dds.pdf
Plik ucf do zadania, płytka Digilent Spartan-3, układ Spartan-3 3S200
FT256-4:
# Clock:
NET "clk_i" LOC = "T9"
; # 50 MHz clock
# VGA display:
NET "rgb_o<1>" LOC =
"R12" ; # R
NET "rgb_o<2>" LOC =
"T12" ; # G
NET "rgb_o<0>" LOC =
"R11" ; # B
NET "hsync_o" LOC =
"R9";
NET "vsync_o" LOC =
"T10";
# Slide switches:
NET "sw_i<0>" LOC =
"F12" ; # active high when in UP position
NET "sw_i<1>" LOC =
"G12" ; # active high when in UP position
NET "sw_i<2>" LOC =
"H14" ; # active high when in UP position
NET "sw_i<3>" LOC =
"H13" ; # active high when in UP position
NET "sw_i<4>" LOC =
"J14" ; # active high when in UP position
NET "sw_i<5>" LOC =
"J13" ; # active high when in UP position
NET "sw_i<6>" LOC =
"K14" ; # active high when in UP position
NET "sw_i<7>" LOC =
"K13" ; # active high when in UP position
# Push-buttons:
NET "btn_i<0>" LOC =
"M13" ; # active high
NET "btn_i<1>" LOC =
"M14" ; # active high
NET "btn_i<2>" LOC =
"L13" ; # active high
NET "btn_i<3>" LOC =
"L14" ; # active high
#