Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

VGA input to FPGA to light LEDs

Status
Not open for further replies.

Simon2

Junior Member level 2
Joined
Jul 25, 2012
Messages
20
Helped
1
Reputation
2
Reaction score
1
Trophy points
1,283
Activity points
1,614
Hi everyone,

I am quite a beginner in the FPGA-world, and I'm learning this as a hobby. And now I have the following problem.
I have connected a VGA input (another PC) to my FPGA (virtex 5 ml507) and i'm trying to light some LEDs depending on the color of a pixel somewhere in the middle of a frame. I am using 800 X 600 @ 72 Hz resolution. I have read about VGA and I know I think I need 1040 pixels on a row and 666 pixelrows on a frame. (The pixelfrequency is 50 MHz. )

The VGA input on my FPGA delivers 8 bit for blue, 8 bit for red and 8 bit for green. a horizontal and vertical synchronisation signal. However when I make a colored frame (for example in 'paint' opening a black screen) , input this to VGA and assign for example the blue 8 bit vector on a specific pixel of the frame to the 8 LEDs, I get always '0' on my LEDs, even when I input a white or a blue frame.

I use the following principle: the first data that enters is a vertical blanc signal, followed by a horizontal blanc signal, followed by a row of screen-pixels, followed by a horizontal blanc signal, followed by a horizontal synchronisation signal (end of row 1). Then again a horizontal blanc signal, a row of screen pixels, a horizontal blanc signal and a horizontal sync (end of row 2),... etc. Every frame is concluded by a vertical blanc signal and a vertical synchronisation.

The specific timings for the signals, I found on this website: http://tinyvga.com/vga-timing/800x600@72Hz

Is this the correct way to do it? Or should you start with a synchronisation signal? Or start with the row of screen-pixels?

Could someone give me some help with this?
Thanks in advance,

Simon
 

you need to work out the vertical and horizontal blanking so you can ignore these data values. You should only be scanning the 800x600 pixels, not the 1040x666. Create a v_valid and h_valid signal, then when both are one, you know you're in the visible region. Then you can start the counters and find the correct pixel.
 

From the ML507 it seems that the VGA input uses a Codec IC (the AD9980). You should use the timing information described in the AD9880 datasheet (these are afterall the signals connected to the FPGA). These are not necessarily 1:1 ith the VGA signals on it's input.
Furthermore, although I have not read the datasheet completely, you might have to setup this codec first, before it operates correctly. You will then have to control it using it's I2C bus (at I2C address $4C according to the ML507 schematic).
 

I interfaces the Kopin AMLCD to VGA 640x480, so I am familiar with the synchronization.. YOu want to look after the back porch .

If using 800 X 600 then you have 800 pixels across. by 600 = 480,000 pixels of RGB.

You need to have a sample & hold for each LED for memory and refresh each frame. Since analog does not show pixels in the signal, you can scale it . Vertical scaling is a little harder as you would need 2 sample & holds. This is easy for LCD since the charge layer is built in. But for LED's it becomes impractical.. So without digital memory, you must scan by multiplexing each LED for one pixel per line at 800x the peak current or use memory with many S&H with buffers.

LED monitors sound so simple but the economy of scaling a couple million LEDs is not so easy. SONY's Jumbotron used to start @ 4million $



How many LEDs? 80x60? in RGB?

If this were a make vs buy decision.. it would definitely be cheaper to buy.
 

For the VGA timings, see reply to your other other post, Mr Spread Stuff Across Threads. :p
 

you need to work out the vertical and horizontal blanking so you can ignore these data values. You should only be scanning the 800x600 pixels, not the 1040x666. Create a v_valid and h_valid signal, then when both are one, you know you're in the visible region. Then you can start the counters and find the correct pixel.

How does the FPGA know when the v_valid and h_valid need to be one? What signal would you use for that instead of a counter then?

greetz,
Simon

- - - Updated - - -

From the ML507 it seems that the VGA input uses a Codec IC (the AD9980). You should use the timing information described in the AD9880 datasheet (these are afterall the signals connected to the FPGA). These are not necessarily 1:1 ith the VGA signals on it's input.
Furthermore, although I have not read the datasheet completely, you might have to setup this codec first, before it operates correctly. You will then have to control it using it's I2C bus (at I2C address $4C according to the ML507 schematic).

Hmm, damn. And it looked so easy ;)
 

I think I don't have to setup the IIC bus, the default values of the AD9980 look fine to me.
However about the timing diagrams of the AD9980, in 4:4:4 timing mode (see page 19 of the datasheet of the AD9980 : https://www.xilinx.com/products/boards/ml505/datasheets/464471350AD9980_0.pdf) there is some kind of delay between the HS_in and HS_out, and between the DATA_in and DATA_out. I don't really know how to take this into account. Does this delay occur every new pixel-line, or only at the first line of a frame --> the 6 clock cycles delay between HS_out and DATA_out remains constant for the whole frame?
Does this delay occur for the vertical synchronisation aswell?

Thanks in advance,
Simon

- - - Updated - - -

Here is the VHDL code of the design I made, it's very basic, but still won't work. The resolution I use is 800 x 600 @ 75 Hz.
It should take a pixel somewhere in the middle of a frame, in the middle of a pixelline, and store the value of blue [7 downto 0] in the 8 LED's.
When I program this in the FPGA, I expect the same LED's on '1' the whole time when I use the same screen as input. However the LED's change the whole time. This is probably because the VGA input signal of an image on the screen is not in 1 color. But still, it should take the same pixel every time so the LED's should not change.
There should be something wrong with the timing, but according to the testbench, it should work...


Here is a screenshot of the waveform result I get from the testbench. http://i.imgur.com/QVGAq.jpg

This is the VHDL code for the design, the testbench code is below.
Could someone help me with this?

Thanks in advance,
Simon


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Virtex 5 ml507
-- Using the AD9980 8 bit display interface

entity circuit1 is
port(
reset : in std_logic; -- active high
data_clk : in std_logic; -- data clock aligned with hs and green, red, blue
hs : in std_logic; -- has delay of 2 clock cycles
vs : in std_logic;
--green : in std_logic_vector(0 to 7); not used
--red : in std_logic_vector(0 to 7); not used
blue : in std_logic_vector(0 to 7);
led : out std_logic_vector(0 to 7)
);
end circuit1;

architecture Behavioral of circuit1 is
signal starter : std_logic := '0';
signal pixelcount : integer range 0 to 1055 := 0;
signal linecount : integer range 0 to 624 := 0;
constant maxpixelcount : integer := 1055;
constant maxlinecount : integer := 624;
signal verticalsynchcounter : integer := 0;



begin


-- startup process, only start when you reach a full vertical synchronisation signal, this is protection against starting in middle of line or frame
process(vs, reset, data_clk) -- because we need to find the start of the frame first.
begin
if reset = '0' then
starter <= '0';
else
if rising_edge(data_clk) and vs = '1' then
if verticalsynchcounter < 3167 then
verticalsynchcounter <= verticalsynchcounter + 1;
elsif verticalsynchcounter = 3167 then
verticalsynchcounter <= 0;
starter <= '1';
end if;
end if;
end if;
end process;

process(data_clk, starter, reset)
begin
if reset = '0' then
pixelcount <= 0;
linecount <= 0;
else
if starter = '0' then
pixelcount <= 0;
linecount <= 0;

else

if rising_edge(data_clk) and starter = '1' then
if pixelcount < maxpixelcount then
pixelcount <= pixelcount + 1;
else -- when row is complete
pixelcount <= 0;
if linecount < maxlinecount then
linecount <= linecount + 1;
else -- when frame is complete
linecount <= 0;
end if;
end if;
end if;
end if;
end if;



end process;


process(pixelcount, blue, reset, linecount)
begin
if reset = '0' then
led <= "00000000";
else
if linecount = 300 and pixelcount = 500 then -- take a pixel somewhere in the middle of a line, in the middle of a frame
led <= blue ; -- ask the data in blue in that pixel
end if;
end if;
end process;


end Behavioral;








This is the testbench code I made,


LIBRARY ieee;
USE ieee.std_logic_1164.ALL;


use IEEE.STD_LOGIC_ARITH.ALL; -- nodig om alle getallen arith te maken,
use IEEE.STD_LOGIC_UNSIGNED.ALL; -- alles unsigned, geen negatieve getallen dus


ENTITY tester IS
END tester;

ARCHITECTURE behavior OF tester IS


COMPONENT circuit1
PORT(
reset : IN std_logic;
data_clk : IN std_logic;
vs : IN std_logic;
hs : IN std_logic;
blue : IN std_logic_vector(0 to 7);
led : OUT std_logic_vector(0 to 7)
);
END COMPONENT;



signal reset : std_logic := '0';
signal data_clk : std_logic := '0';
signal vs : std_logic := '0';
signal hs : std_logic := '0';
signal blue : std_logic_vector(0 to 7) := (others => '0');
signal led : std_logic_vector(0 to 7);
signal consta : std_logic_vector(0 to 7) := "00000000";
constant data_clk_period : time := 20.202020 ns;

BEGIN


uut: circuit1 PORT MAP (
reset => reset,
data_clk => data_clk,
vs => vs,
hs => hs,
blue => blue,
led => led
);

-- Clock process definitions
data_clk_process :process
begin
data_clk <= '0';
wait for data_clk_period/2;
data_clk <= '1';
wait for data_clk_period/2;
end process;


-- Stimulus process
stim_proc: process

begin
reset <= '1'; -- zonder verticale synchronisatie

vs <= '0';
for i in 1 to 625 loop
hs <= '1';
wait for 1.6161616161 us; --
hs <= '0';
wait for 3.35353535 us; -- because of delay of the AD9980, was 3.232323 us
consta <= consta +1;
blue <= consta;
wait for 16.1616161616 us;
blue <= "00000000";
wait for 0.20202020 us; -- because of delay of the AD9980, was 0.32323232 us
end loop;
wait for 0.02133333333 ms;

for j in 1 to 1000 loop -- 1000 frames
consta <= "00000000";
vs <= '1';
wait for 0.064 ms;
vs <= '0';
wait for 0.448 ms;

hs <= '1';
wait for 1.6161616161 us;
hs <= '0';
wait for 3.35353535 us;
consta <= "00000001";
blue <= consta;
wait for 16.161616166 us;
wait for 0.20202020 us;


for i in 2 to 600 loop
hs <= '1';
wait for 1.616161616161 us;
hs <= '0';
wait for 3.35353535 us;
consta <= consta +1;
blue <= consta;
wait for 16.161616161616 us;
wait for 0.20202020 us;
end loop;
consta <= "00000000";
wait for 0.02133333333 ms;

end loop;
end process;

END;
 

I think it maybe has to do someting with the AD9980. However in the datasheets of the AD9980, I can't that there is somekind of setup necessary to activate it or to activate the default values of the registers of the adresses.
I thought the default values mentioned in the datasheet were OK to use in this case.
However: when I check the period of the data_clk comming out of the AD9980, this is always 20 ns. This is the case when I input a VGA signal with pixel frequency of 150 or 40 MHz.
Is that normal? Shouldn't the AD9980 set his output data_clk to the pixel frequency of the incomming signal?

Thanks in advance
 

I gave the datasheet a quick glance. And your assumptions do seem reasonable. However in case of "it doesn't work" you could do the following.
Include a small i2c master so you can read and write to it. First read out registers to check if you get the powerup default as a sanity check. And then write the PLL registers so it conforms to the recommended settings for your input vga signal.

Or right now you can put a scope on the sync outputs and see if that's reasonable. Or add some counters to it to check frequency.
 

You need to debug your hardware to make sure it is noise free on the analog side and that the clock recovery is stable.
ALso view a pixel sampling clock output for each pixel digitized. This MUST be sync'd to VS and HS when viewing. Use a DSO or Logic Analyzer.
Then once it appears to be stable get an analog test pattern generated. I recommend DPT.exe (free for windows) It has dozens of test patterns.

Remember grey is RGB all equal levels from 0~255. You ought to be able to detect the level within +/1bit of error in 256.

Any digital noise in your ADC analog ground or reference voltage will cause dead bit zones. ( values that do not exist with apparent hysteresis).
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top