VHDL-VGA
Problem
[edit | edit source]The beat bearing drum sequencer interface involves a VGA LCD monitor video. The problem is how to drive the monitor without a PC.
Conceive
[edit | edit source]The 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
[edit | edit source]This 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
[edit | edit source]The 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 | edit source]- 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
[edit | edit source]Next Steps
[edit | edit source]- 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)