VHDL-VGA
Problem
editThe beat bearing drum sequencer interface involves a VGA LCD monitor video. The problem is how to drive the monitor without a PC.
Conceive
editThe goal is to design a beat boarding board with out a PC, without software. The concept is to use FPGA technology to create a circuit that displays only what is necessary for the beat bearing project.
Design
editThis design started off with this hardware:
- Papilo Spartan3E 250K FPGA
- VGA connector on a logic start board
- initial VGA VHDL Project that this was started from
vga_generator VHDL code
|
---|
-------------------------------------------------------------------------------- ---- Howard Community College Spring 2014 ENES-245 ---- ---- This file is part of the Chapter 19 lab ---- ---- Description: ---- Date: 3/20/14 ---- ---- Current Status: Complete ---- ---- Original Author: unknown ---- -------------------------------------------------------------------------------- ---- Modification Description: Edited SwitchesLinkedToColor project to include ---- ---- all 256 colors (controlled by the 8 switches); displays a ---- ---- 50x50 px box on a screen, move the box across the screen ---- ---- with the joystick ---- ---- Date: 3/27/14 ---- ---- Author: King Carmichael III ---- -------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; entity vga_generator is port( ext_CLK, reset: in std_logic; SWITCH: in std_logic_vector(7 downto 0); VGA_HSYNC, VGA_VSYNC: out std_logic; JOY_RIGHT, JOY_LEFT, JOY_UP, JOY_DOWN: in STD_LOGIC; rgb: out std_logic_vector(7 downto 0) ); end vga_generator; architecture arch of vga_generator is -- vga clock component dcm_32_to_50p35 port( clkin_in : in std_logic; clkfx_out : out std_logic; clkin_ibufg_out : out std_logic; clk0_out : out std_logic ); end component; signal clk: std_logic; signal rgb_reg: std_logic_vector(7 downto 0); signal video_on, antisquare: std_logic; begin inst_dcm_32_to_50p35: dcm_32_to_50p35 port map( clkin_in => ext_CLK, clkfx_out => clk, clkin_ibufg_out => open, clk0_out => open ); vga_sync_unit: entity work.vga_sync port map( clk => clk, reset => reset, hsync => VGA_HSYNC, vsync => VGA_VSYNC, video_on => video_on, antivid => antisquare, right => JOY_RIGHT, left => JOY_LEFT, up => JOY_UP, down => JOY_DOWN, p_tick => open, pixel_x => open, pixel_y => open ); process(clk, reset) begin if reset = '1' then rgb_reg <= (others => '0'); elsif clk'event and clk = '1' then rgb_reg <= SWITCH(7 downto 0); end if; end process; rgb <= rgb_reg when video_on = '1' and antisquare = '0' else NOT rgb_reg when video_on = '1' and antisquare = '1' else "00000000"; end arch; |
VGA sync VHDL code
|
---|
-------------------------------------------------------------------------------- ---- Howard Community College Spring 2014 ENES-245 ---- ---- This file is part of the Chapter 19 lab ---- ---- Description: VGA sync - tells determines when the video will be on, syncs ---- ---- timing of pixel ticks (when to scan horizontally/vertically ---- ---- and when to restart), etc. ---- Date: 3/20/14 ---- ---- Current Status: Complete ---- ---- Original Author: unknown ---- -------------------------------------------------------------------------------- ---- Modification Description: Move the box across the screen with the joystick. ---- ---- Second block element on (second video_on) when ---- ---- block is at the end of pixel range. ---- ---- Date: 3/27/14 ---- ---- Author: King Carmichael III Email: ---- -------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity vga_sync is port( clk, reset: in std_logic; hsync, vsync: out std_logic; video_on, antivid, p_tick: out std_logic; right, left, up, down: in std_logic; pixel_x, pixel_y: out std_logic_vector(9 downto 0) ); end vga_sync; architecture arch of vga_sync is -- VGA 640x480 -- horizontal timings, in pixels constant h_display_area: integer := 640; constant h_front_porch: integer := 16; constant h_sync: integer := 96; constant h_back_porch: integer := 48; -- vertical timings, in lines constant v_display_area: integer := 480; constant v_front_porch: integer := 10; constant v_sync: integer := 2; constant v_back_porch: integer := 33; -- derived horizontal constants constant hsync_start: integer := h_display_area + h_front_porch; constant hsync_end: integer := hsync_start + h_sync; constant end_of_line: integer := hsync_end + h_back_porch - 1; -- derived vertical constants constant vsync_start: integer := v_display_area + v_front_porch; constant vsync_end: integer := vsync_start + v_sync; constant end_of_frame: integer := vsync_start + v_back_porch - 1; -- mod-2 counter signal mod2_reg, mod2_next: std_logic; -- sync counters signal v_count_reg, v_count_next: unsigned(9 downto 0); signal h_count_reg, h_count_next: unsigned(9 downto 0); -- output buffer signal v_sync_reg, h_sync_reg: std_logic; signal v_sync_next, h_sync_next: std_logic; -- status signals signal h_end, v_end, pixel_tick: std_logic; --30 bit counter signal count: std_logic_vector(29 downto 0) := (others => '0'); --pixel region to display signal pixx, pixy: unsigned(10 downto 0);-- := (others => '0'); --Need at least 10 bits to have decimal number 799 signal neg: std_logic; -- constant pixx_set: integer := 424; --initial test to display rectangle -- constant pixy_set: integer := 286; --initial test to display rectangle begin -- registers process(clk, reset) begin if reset = '1' then mod2_reg <= '0'; v_count_reg <= (others => '0'); h_count_reg <= (others => '0'); v_sync_reg <= '0'; h_sync_reg <= '0'; elsif clk'event and clk = '1' then mod2_reg <= mod2_next; 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; -- mod-2 circuit to generate 25.125MHz enable tick mod2_next <= not mod2_reg; -- 25.125MHz pixel tick pixel_tick <= '1' when mod2_reg = '1' else '0'; -- status h_end <= '1' when h_count_reg = end_of_line else '0'; v_end <= '1' when v_count_reg = end_of_frame else '0'; -- mod-800 horizontal sync counter process(h_count_reg, h_end, pixel_tick) begin if pixel_tick = '1' then if h_end = '1' then h_count_next <= (others => '0'); else h_count_next <= h_count_reg + 1; end if; else h_count_next <= h_count_reg; end if; end process; -- mod-525 vertical sync counter process(v_count_reg, h_end, v_end, pixel_tick) begin if pixel_tick = '1' and h_end = '1' then 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; -- hsync and vsync, buffered to avoid glitch h_sync_next <= '1' when hsync_start <= h_count_reg and h_count_reg < hsync_end else '0'; v_sync_next <= '1' when vsync_start <= v_count_reg and v_count_reg < vsync_end else '0'; --Block controls process(clk)--pixel_tick) begin if rising_edge(clk) then count <= count + 1; if count = 200000 then --change value to change how fast block moves count <= (others => '0'); if right = '0' and pixx < 591 then pixx <= pixx + 1; elsif left = '0' and pixx > 0 then pixx <= pixx - 1; elsif up = '0' and pixy > 0 then pixy <= pixy - 1; elsif down = '0' and pixy < 431 then pixy <= pixy + 1; end if; end if; end if; end process; -- video on/off video_on <= '1' when h_count_reg < 50 + pixx and h_count_reg > pixx --pixx and pixy +51 because rectangle is 50x50 pixels and v_count_reg < 50 + pixy and v_count_reg > pixy else '0'; --original code - displayed a rectangle the size of the screen -- '1' when h_count_reg < h_display_area and v_count_reg < v_display_area else -- '0'; neg <= '1' when pixx = 0 else '1' when pixx = 591 else '1' when pixy = 0 else '1' when pixy = 431 else '0'; -- output signals hsync <= h_sync_reg; vsync <= v_sync_reg; antivid <= neg; pixel_x <= std_logic_vector(h_count_reg); pixel_y <= std_logic_vector(v_count_reg); p_tick <= pixel_tick; end arch; |
The constraints file being used with the logic start board
|
---|
NET ext_CLK LOC="P89" | IOSTANDARD=LVTTL | PERIOD=31.25ns; # CLK NET VGA_VSYNC LOC="P85" | IOSTANDARD=LVTTL; # B0 NET VGA_HSYNC LOC="P83" | IOSTANDARD=LVTTL; # B1 NET "rgb<7>" LOC = "P78" | IOSTANDARD=LVTTL; NET "rgb<6>" LOC = "P71" | IOSTANDARD=LVTTL; NET "rgb<5>" LOC = "P68" | IOSTANDARD=LVTTL; NET "rgb<4>" LOC = "P66" | IOSTANDARD=LVTTL; NET "rgb<3>" LOC = "P63" | IOSTANDARD=LVTTL; NET "rgb<2>" LOC = "P61" | IOSTANDARD=LVTTL; NET "rgb<1>" LOC = "P58" | IOSTANDARD=LVTTL; NET "rgb<0>" LOC = "P54" | IOSTANDARD=LVTTL; NET SWITCH(0) LOC="P91" | IOSTANDARD=LVTTL; # C0 NET SWITCH(1) LOC="P92" | IOSTANDARD=LVTTL; # C1 NET SWITCH(2) LOC="P94" | IOSTANDARD=LVTTL; # C2 NET SWITCH(3) LOC="P95" | IOSTANDARD=LVTTL; # C3 NET SWITCH(4) LOC="P98" | IOSTANDARD=LVTTL; # C4 NET SWITCH(5) LOC="P2" | IOSTANDARD=LVTTL; # C5 NET SWITCH(6) LOC="P3" | IOSTANDARD=LVTTL; # C6 NET SWITCH(7) LOC="P4" | IOSTANDARD=LVTTL; # C7 |
Implement
editThe goal is to simulate this video with out using a PC running some program like processing or visual basic. So the switches on the logic start board are used to simulate one row of the beat bearing board.
The switches add a white explosion underneath the blue squares.
Squares are used instead of circles because implementing a circuit that does the math would not fit on such a small FPGA.
Operate
edit- Connect a papilo 250K FPGA with a logic start circuit board to a USB file to a computer that has the papilo boot loader installed.
- Connect a VGA cable from the logic start board to a monitor.
- Apply power to both.
- Download this bit file.
- Right mouse on the bit file and send it to the papilo.
Demo
editNext Steps
edit- Turn squares off totally and have an two step explosion of color
- Create test program to test and exercise each row
- Use putty through usb cable to configure speed of bar, colors of squares
- Connect to arduino serial out to change configuration
- Physically connect to beat bearing board and read column of four switches
(need 6 pins free on Papilio)