Pannon Egyetem, MIK-VIRT, Veszprém Dr. VörösháziZsolt voroshazi.zsolt@virt.uni-pannon.hu Tervezési módszerek programozható logikai eszközökkel 8. VHDL FELADAT VGA vezérlő. Mérnöktovábbképző tanfolyam
2 VHDL Komplex feladat VGA VEZÉRLŐ
3 Felhasznált irodalom [1] Digilent Nexys-2 Board Reference Manual: http://www.digilentinc.com/data/products/nexys2/nexys2_rm.pdf [2] VGA időzítés: http://www.epanorama.net/documents/pc/vga_timing.html [3] VESA Generalized Timing Formula (GTF): http://www.cs.unc.edu/research/stc/faqs/video/gtf_v1r1.xls
Nexys-2 periféria: 8-bit VGA 4
5 Nexys-2: VGA port Nexys-2 kártyán egy 8-bit/pixel-es VGA port található, melyhez két szabványos szinkronizáló jel (HS- horizontális szinkron, VS vertikális szinkron) tartozik. VGA interfész: 8-8 jelszint a RED/GREEN csatornákon, míg 4 jelszint a BLUE csatornákon(emberi szem kevésbé érzékeny a kék szín hiányára) N=8 bit/pixel, azaz 256 különböző színárnyalat jeleníthető meg pixelenként, egyidőben egyetlen színárnyalat, amelyet egy 8-bites minta (RGB color pattern) határoz meg. A VGA kimenetet vezérlő áramkört úgy kell elkészíteni, hogy a HS/VS szinkronizációs jeleket, és a színeket is kezelje, megfelelő időzítéssel ( kijelző ne essen ki a szinkronból ).
6 VGA időzítés VGA időzítését a VESA nevű szervezet specifikálja, és dokumentálja (www.vesa.org). A következőekben egy példán keresztül a VGA szabványon alapuló rendszer időzítési információit adjuk meg: azaz, hogyan vezérelhető egy VGA felbontású monitor (640x480-as képméretet feltételezve)? A pontos időzítési információkért (paraméterek), és frekvencia értékekért a Felhasznált irodalom [2],[3] hivatkozásait használjuk.
CRT katódsugárcsöves rendszer CRT-alapú VGA kijelzők AMamplitúdó modulált mozgó elektronsugarakat használnak (katódsugárcső). LCD kijelzők egy kapcsoló tömböt használnak: a fény(light permittivity) szabályozható a kristályrácson keresztül pixelenként. LCD kijelzőket úgy tervezték, hogy a CRT-khez hasonló időzítési paraméterekkel működjenek. A színes CRT megjelenítők 3 elektronsugarat (RGB ágyút) használnak a kijelző belső felületét borító foszfor gerjesztésére. Gyorsító feszültség (acceleration) >20kV 7
8 VGA időzítési paraméterek Az elekronsugár (nyaláb / beam) folyamatosan pásztázza a kijelző belső falát (balról jobbra, fentről lefelé) történő irányban. A sugár a frame végén (479, 639) visszatér (0,0) pozícióba = retrace, majd újrakezdődik a pásztázás. A megjelenítési idő (display time) egy jelentős részét az ún. blanking periódus teszi ki: ez alatt a pixelek nem kerülnek ugyan megjelenítésre, viszont a szinkronizáció ekkor történik. Horizontális és vertikális szinkr. Frekvencia (f) = pixel órajel: a sugár mérete szabályozható és modulálható a kijelzőn, amely a képfelbontást meghatározza. Raszteres kijelzők: Sorok: horizontális átmenetek száma, Oszlopok: minden sorban azonos pozícióban lévő pixelek
9 VGA 640 480 @ 25MHz pixel órajelen VGA vezérlő áramkör HS és VS időzítő jeleket generál: kép szinkronizációja és megjelenítése adott pixel órajelen(f). VS: kép frissítési frekvenciája (ált. 50 Hz 120 Hz tartományban). Sorok számát adott frissítési frekvencián a horizontális frekvencia(retrace) definiálja: Ált. 640x480-as (pixel x sor) képméret f=25 MHz-es videóórajelenés 60+/-1Hzfrissítésseltörténik. Szinkron jelek impulzus szélessége és a front -, back porch intervallumok megadása: Porch ~ csarnok, olyan intervallumokat definiál, amely a szinkronizációs jel előtti, illetve utáni néhány órajelciklust jelent, amely idő alatt látható információ nem jeleníthető meg a kijelzőn. horizontális-szinkron jel számlálója: minden egyes pixel órajelre lép, és a HS-t generálja. Ez a számláló használható a pixel pontos helyének a meghatározására is egy adott sorban. vertikális-szinkron jel számlálója: minden egyes HS impulzusra inkrementálódik és a VS-t generálja. Ez a számláló használható a kép egy adott sorának meghatározására is. f= 25MHz pixel órajel (40ns)
Feladat 1.) Tervezzen egy VGA 640 480 kijelző időzítő áramkörét VHDL nyelven a mellékelt ábra / táblázat alapján. - Megj: vertikális és horizontális számlálók legyenek 10-bites unsigned típusú signal-ok - Constant-ok : nevük, értékük a Táblázat alapján. - a.) Felezze meg a belső órajelet (50 MHz 25 MHzpixelclock),vagy - példányosítsa a korábbi clkdiv modult a VGA_sync module ( VGA_sync.vhd ).D=? - b.) Készítsen testbench-et ISim-ben, és ( VGA_sync_tb.vhd ): vizsgálja meg a számlálók, szinkron jelek működését. to ensure - c.) Implementálja a terveket FPGA-n. Legyen a top-level modul ( VGA_disp_top.vhd ), példányosítsa a VGA_Synch.vhd-t. /használjon 8 VGA kimenetet (RGB <7:0>).ucf file/ Jelenítse meg pl. a vörös színt CRT/LCD-n (Megj: Red = 111, mialatt a Green és Blue csatorna legyen:= 000 ill 00 értékű). f= 25MHz pixel órajel (40ns) Top-level entitás port listája (megj.): mclk: in rst: in vs: out hs: out (VGA_red/ Bus: 2:0 / out VGA_green/ Bus: 2:0 / out VGA_blue/ Bus: 1:0 / out) 10
11 Megoldás 1/a.) VGA_sync.vhd Használjunk numeric standard csomagot az számlálók inkrementálásához ( + ) use IEEE.NUMERIC_STD.all; Az entitás portlistájában a következők szerepeljenek mclk, rst: in std_logic; hs, vs: out std_logic; video_en : out std_logic; --video_en = 1, ha a counterek az aktív megjeleníthető régióban vannak (mind a horizontális, és vertikális irányokban) Használjunk konstans értékeket a paraméterek megadásához -- VGA 640x480 timing parameters constant C_HDISP : integer:= 640; --horizontal display time constant C_HFP : integer:= 16; --horiz. front porch constant C_HBP : integer:= 48; --horiz. back porch constant C_HPW : integer:= 96; --horiz. pulse width (horiz.retrace time) constant C_VDISP : integer:= 480; --vertical display time constant C_VFP : integer:= 10; --v. front porch constant C_VBP : integer:= 29; --v. back porch -33 constant C_VPW : integer:= 2; --vert. pulse width (vert.retrace time)
Megoldás 1/a.) VGA_sync.vhd (folyt.) mod-2_reg negáltja generálja a 25 MHz belső órajelet mod2_next <= not mod2_reg; clk_25mhz_sig <= '1' when mod2_reg='1' else '0'; Alternatív megoldás: használhatjuk a clkdiv modult is, komponens bejelentése: component clkdiv port( mclk : in STD_LOGIC; clr : in STD_LOGIC; clk_out : out STD_LOGIC); end component; Legyen a következő egy belső órajelet átvivő signal: signal clk_25mhz_sig : std_logic := '0'; Alternatív megoldás: clkdiv példányosítása u1: entity work.clkdiv(behavioral) Generic map (D => 1) port map(mclk => mclk, clr => rst, clk_out => clk_25mhz_sig); 12
13 Megoldás 1/a.) VGA_sync.vhd (folyt.) Definiáljunk néhány belső jelet (regisztereltek legyenek): signal v_count_reg, v_count_next: unsigned(9 downto 0); --521 = TSynch ver signal h_count_reg, h_count_next: unsigned(9 downto 0); --800 = TSynch hor -- kimeneti bufferek signal v_sync_reg, h_sync_reg: std_logic; signal v_sync_next, h_sync_next: std_logic; -- státus jelek, flag-ek (egy horizontális sor végét, vagy egy oszlop végét jelölik) signal h_end, v_end : std_logic;
Megoldás 1/a.) VGA_sync.vhd (folyt.) Minden számlálót aszinkron módon reset-eljünk, és belső regisztereként legyenek kialakítva (D-FF alapúak): process (mclk, rst) begin if rst='1' then --mod2_reg <= '0'; --ha használjuk v_count_reg <= (others=>'0'); h_count_reg <= (others=>'0'); v_sync_reg <= '0'; h_sync_reg <= '0'; elsif (mclk'event and mclk='1') then --mod2_reg <= mod2_next; --ha használjuk v_count_reg <= v_count_next; h_count_reg <= h_count_next; v_sync_reg <= v_sync_next; h_sync_reg <= h_sync_next; end if; end process; 14
15 Megoldás 1/a.) VGA_sync.vhd (folyt.) -- konkurens utasítások -- státus h_end horizontális és v_end vertikális pozíciót jelöl (timing paraméterek, ábra alapján) h_end <= -- end of horizontal counter '1' when h_count_reg=(c_hdisp+c_hfp+c_hbp+c_hpw-1) else --799 '0'; v_end <= -- end of vertical counter '1' when v_count_reg=(c_vdisp+c_vfp+c_vbp+c_vpw-1) else --520 '0'; -- horizontal and vertical sync, bufferelt értékek h_sync_next <= '0' when (h_count_reg >= (C_HDISP+C_HFP)) --656 and (h_count_reg <= (C_HDISP+C_HFP+C_HPW-1)) else --751 '1'; v_sync_next <= '0' when (v_count_reg >= (C_VDISP+C_VFP)) --490 and (v_count_reg <= (C_VDISP+C_VFP+C_VPW-1)) else --491 '1';
16 Megoldás 1/a.) VGA_sync.vhd (folyt.) --h_counter process (szekvenciális utasítások) -- h_end generálása, horizontális szinkron számláló segítségével 0...800-1 h_counter : process (h_count_reg, h_end, clk_25mhz_sig) begin if clk_25mhz_sig = '1' then -- 25 MHz belső clock if h_end = '1' then h_count_next <= (others => '0'); else h_count_next <= h_count_reg + 1; --+ numeric.std!! end if; else h_count_next <= h_count_reg; end if; end process h_counter;
17 Megoldás 1/a.) VGA_sync.vhd (folyt.) --v_counter process (szekvenciális utasítások) -- v_end generálása vertikális számlálóval 0...521-1 v_counter : process (v_count_reg, h_end, v_end, clk_25mhz_sig) begin if clk_25mhz_sig = '1' and h_end = '1' then belső órajel if (v_end = '1') then v_count_next <= (others => '0'); else v_count_next <= v_count_reg + 1; end if; else v_count_next <= v_count_reg; end if; end process; -- 25 MHz
Megoldás 1/a.) VGA_sync.vhd (folyt.) -- konkurens értékadások -- videó engedélyező jel (aktív régión) video_en <= '1' when (h_count_reg < C_HDISP) and (v_count_reg < C_VDISP) else '0'; -- kimenetek VS és HS jeleinek előállításra, VGA interfészre hs <= h_sync_reg; vs <= v_sync_reg; 18
Megoldás 1/b.) VGA_sync_tb.vhd(folyt.) Testbencheredménye: Run simulation(szimulációs idő legyen legalább ~35ms = 1 teljes frame idejű!!) 19
20 Megoldás 1/b.) Új jelek hozzáadása waveform-hoz(folyt.) VGA_sync_tb.vhd *új belső jelek hozzáadása: v_end, h_end, clk_25_mhz_sig, h_sync, v_sync, (reg/next) h_count/v_count (reg/next) Add towavewindow Restart(szimuláció) (szimulációs idő legalább 35ms legyen!!)
Megoldás 1/b.) Waveform VGA_sync_tb.vhd Radix beállítása unsigned decimal 21
library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity vga_disp_top is port( Megoldás 1/c.) VHDL top-modul mclk, rst: in std_logic; sw: in std_logic_vector(7 downto 0); h_sync, v_sync: out std_logic; vgared: out std_logic_vector(2 downto 0); vgagreen: out std_logic_vector(2 downto 0); vgablue: out std_logic_vector(1 downto 0)); end vga_disp_top; architecture Behaviour of vga_disp_top is signal vga_out_reg: std_logic_vector(7 downto 0); signal video_en_sig: std_logic; signal clk_25mhz_sig : std_logic; COMPONENT vga_synch PORT(mclk: IN std_logic; rst: IN std_logic; ); END COMPONENT; hs: OUT std_logic; vs: OUT std_logic; video_en: OUT std_logic (vga_disp_top.vhd) begin uut1: entity work.vga_synch(behavioral) port map (mclk => mclk, rst => rst, hs => h_sync, vs => v_sync, video_en => video_en_sig); --vga output buffer vga_buffer : process (mclk, rst) begin if rst='1' then vga_out_reg <= (others=>'0'); elsif (mclk'event and mclk='1') then -- vga_out_reg <= sw; --use switch to set custom color pattern vga_out_reg <= "11001010"; --custom color pattern end if; end process vga_buffer; -- vga_out_reg dstribution between Red(2:0), Green(2:0), Blue(1:0) as std_vector_logic type vgared <= vga_out_reg(7 downto 5) when video_en_sig='1' else (others => '0'); vgagreen <= vga_out_reg(4 downto 2) when video_en_sig='1' else (others => '0'); vgablue <= vga_out_reg(1 downto 0) when video_en_sig='1' else (others => '0'); end Behaviour; 22
Megoldás 1/c. UCF (Nexys-2) NET "mclk" LOC = "B8"; # Switches NET "sw<0>" LOC = "G18"; NET "sw<1>" LOC = "H18"; NET "sw<2>" LOC = "K18"; NET "sw<3>" LOC = "K17"; NET "sw<4>" LOC = "L14"; NET "sw<5>" LOC = "L13"; NET "sw<6>" LOC = "N17"; NET "sw<7>" LOC = "R17"; # VGA Connector (8-bit + 2 synch bit) NET "vgared<0>" LOC = "R9"; NET "vgared<1>" LOC = "T8"; NET "vgared<2>" LOC = "R8"; NET "vgagreen<0>" LOC = "N8"; NET "vgagreen<1>" LOC = "P8"; NET "vgagreen<2>" LOC = "P6"; NET "vgablue<0>" LOC = "U5"; NET "vgablue<1>" LOC = "U4"; NET "h_sync" LOC = "T4"; NET "v_sync" LOC = "U3"; # Buttons NET "rst" LOC = "B18"; 23
Megoldás 1/c.) Implementáció és teszt FPGA implementáció: (vga_disp_top.vhd) HDL szintaxis ellenőrzése Szintézis és implementáció - XST Bitfile generálás (JTAG CLK) Letöltés és teszt. További feladat: 8 kapcsoló (sw<7:0>) használatával változtassuk a háttér színét a fix színminta helyett Megj: a vga_buffer_procnevű process-tkell módosítani a vga_disp_top.vhd szintjén. 24