UPGRADE YOUR BROWSER

We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

cancel
Showing results for 
Search instead for 
Did you mean: 
Visitor khaledismail
Visitor
354 Views
Registered: ‎02-19-2019

Display image using VGA from BRAM

Jump to solution

Hi everyone,

I am trying to display image pixels stored in block RAM .coe file though VGA on the board BASYS 3.

Description of what I have done so far, Passed this image to MATLAB to create a .coe file:

Kaleidoscope_300_300.jpgIntended image to display

 The image is a 300*300 pixels. The .coe file stores each pixel RGB data scanning from left to right horizontally then moves to the second row, imitating how the VGA code scans the screen. So the .coe file is 300 pixel* 300 pixel=90000 lines long where each line is 12 bits, Red=4 bits followed by Green=4 bits followed by Blue=4 bits.

This is a VHDL code to display the image. summary of code functionality: Divide main 100 MHz clock by four to get 25 MHz clock (required pixel frequency) , establish VGA synchronization and display the image on a 640 x 480 resolution @ 60 Hz. The code is shown below:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.NUMERIC_STD.ALL;

entity vga_driver is
    Port ( clk : in  STD_LOGIC; --100 MHz main clock.
           Hsync : out  STD_LOGIC;
           Vsync : out  STD_LOGIC;
           R,G,B : out  STD_LOGIC_VECTOR (3 downto 0));
end vga_driver;

architecture Behavioral of vga_driver is

signal DFlipFlopOut1: STD_LOGIC;
signal DFlipFlopOut1_NOT: STD_LOGIC;
signal ClockDiv4: STD_LOGIC; -- 25 MHz Clock
signal ClockDiv4_NOT: STD_LOGIC;

constant picture_size : Integer:=90000; -- 300 Pixels* 300 Pixels picture= 90000 Pixels

--Signals for Block RAM
signal wea : STD_LOGIC_VECTOR(0 DOWNTO 0):="0";
signal addra : STD_LOGIC_VECTOR(16 DOWNTO 0):=(others=>'0');
signal dina : STD_LOGIC_VECTOR(11 DOWNTO 0):=(others=>'0');
signal douta : STD_LOGIC_VECTOR(11 DOWNTO 0):=(others=>'0');

	
	constant HD : integer := 639;  --  639   Horizontal Display (640)
	constant HFP : integer := 16;         --   16   Right border (front porch)
	constant HSP : integer := 96;       --   96   Sync pulse (Retrace)
	constant HBP : integer := 48;        --   48   Left boarder (back porch)
	
	constant VD : integer := 479;   --  479   Vertical Display (480)
	constant VFP : integer := 10;       	 --   10   Right border (front porch)
	constant VSP : integer := 2;				 --    2   Sync pulse (Retrace)
	constant VBP : integer := 33;       --   33   Left boarder (back porch)
	
	signal hPos : integer := 0;
	signal vPos : integer := 0;
	
	signal videoOn : std_logic := '0';
	
	component RisingEdge_DFlipFlop is
	   port(
       Q : out std_logic;    
       Clk :in std_logic;   
       D :in  std_logic    
    );
	end component ;

component Picture_Block_RAM is
  PORT (
  clka : IN STD_LOGIC;
  wea : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
  addra : IN STD_LOGIC_VECTOR(16 DOWNTO 0);
  dina : IN STD_LOGIC_VECTOR(11 DOWNTO 0);
  douta : OUT STD_LOGIC_VECTOR(11 DOWNTO 0)
);
end component;

begin

DFlipFlopOut1_NOT<=not DFlipFlopOut1;
ClockDiv4_NOT<= not ClockDiv4;

--Pass Main 100 MHz clock to 2 cascaded DFlipFLops to divide frequency by 4. Result frequency= 25 MHz.
U1: RisingEdge_DFlipFlop Port map (clk=> clk, D=> DFlipFlopOut1_NOT, Q=>DFlipFlopOut1);
U2: RisingEdge_DFlipFlop Port map (clk=> DFlipFlopOut1, D=> ClockDiv4_NOT, Q=>ClockDiv4);

--Block RAM containing picture
U3: Picture_Block_RAM Port map (clka=>ClockDiv4, wea=>wea, addra=>addra, dina=>dina, douta=>douta);

Horizontal_position_counter:process(ClockDiv4)
begin

	if(ClockDiv4'event and ClockDiv4 = '1')then
		if (hPos = (HD + HFP + HSP + HBP)) then
			hPos <= 0;
		else
			hPos <= hPos + 1;
		end if;
	end if;
end process;

Vertical_position_counter:process(ClockDiv4, hPos)
begin

	if(ClockDiv4'event and ClockDiv4 = '1')then
		if(hPos = (HD + HFP + HSP + HBP))then
			if (vPos = (VD + VFP + VSP + VBP)) then
				vPos <= 0;
			else
				vPos <= vPos + 1;
			end if;
		end if;
	end if;
end process;

Horizontal_Synchronisation:process(ClockDiv4, hPos)
begin

	if(ClockDiv4'event and ClockDiv4 = '1')then
		if((hPos <= (HD + HFP)) OR (hPos > HD + HFP + HSP))then
			HSYNC <= '1';
		else
			HSYNC <= '0';
		end if;
	end if;
end process;

Vertical_Synchronisation:process(ClockDiv4, vPos)
begin

	if(ClockDiv4'event and ClockDiv4 = '1')then
		if((vPos <= (VD + VFP)) OR (vPos > VD + VFP + VSP))then
			VSYNC <= '1';
		else
			VSYNC <= '0';
		end if;
	end if;
end process;

video_on:process(ClockDiv4, hPos, vPos)
begin

	if(ClockDiv4'event and ClockDiv4 = '1')then
		if(hPos <= HD and vPos <= VD)then
			videoOn <= '1';
		else
			videoOn <= '0';
		end if;
	end if;
end process;


draw:process(ClockDiv4, hPos, vPos, videoOn)
begin

	if(ClockDiv4'event and ClockDiv4 = '1')then
		if(videoOn = '1')then
            if (unsigned(addra)<picture_size) then
                R<=douta(11 downto 8); G<=douta(7 downto 4); B<=douta(3 downto 0);
                addra<=STD_LOGIC_VECTOR(unsigned(addra)+1);
			else
				R<=(others=>'0');G<=(others=>'0');B<=(others=>'0');
			end if;
		else
			R<=(others=>'0');G<=(others=>'0');B<=(others=>'0');
			addra<=(others=>'0');
		end if;
	end if;
end process;


end Behavioral;

My problem is that the image does not display as expected. I get this displayed on my screen: 

Faulty_image.jpgFaulty displayed image

 

 

As you see, there are 2 problems immediately noticed.

1st: The image is not the same, obviously.

2nd: The image should not take the whole display since it is 300 * 300 pixels while the resolution is 640*480 pixels meaning that some data is being repeated without intention. 

The default display of BASYS 3 is this. I am putting this just for reference so you can know how my screen displays 640*480 resolution:

BASYS3_default_dispaly.jpgBASYS3 default dispaly

 

I tested the VHDL code by printing colors on my screen by direct output assignment and it works as intended. So the problem is probably with accessing the block RAM.

A snippet from my .coe file:

MEMORY_INITIALIZATION_RADIX=2;
MEMORY_INITIALIZATION_VECTOR=
011101010100,
010101110111,
000110011111,
010110101100,
000110111111,
001000100010,
001000100010,
001000100010,
001000100011,
000101100100,
100110100001,
111011010110,
111110110110,
111110000101,
111110010100,
:
:
--it goes on and on until last line, line number 90002, 90000 since 300*300 pixels= 90000. The added two is due to the first 2 lines.
:
:
101100100010;

I am stuck at this point. Where could the problem be?

Tags (3)
0 Kudos
1 Solution

Accepted Solutions
Scholar watari
Scholar
294 Views
Registered: ‎06-16-2013

Re: Display image using VGA from BRAM

Jump to solution

Hi @khaledismail

 

I'm not familiar with VHDL.

But it seems address issue.

So, would you make sure address signal on BRAM by simulation or ILA ?

 

Also I suggest to change polarity of HSYNC and VSYNC if you use analog RGB via connector of D-SUB 15pin to display this picuture.

 

Best regards,

11 Replies
Scholar drjohnsmith
Scholar
312 Views
Registered: ‎07-09-2009

Re: Display image using VGA from BRAM

Jump to solution
imediate features
a) if(ClockDiv4'event and ClockDiv4 = '1')then , use rising_edge
b) dont use integers, use unsigned or signed
c) line up the if and end if's
d) (unsigned(addra)<picture_size) , comparing two different types
e) draw:process(ClockDiv4, hPos, vPos, videoOn) , wrong sensetivity list
0 Kudos
Scholar watari
Scholar
295 Views
Registered: ‎06-16-2013

Re: Display image using VGA from BRAM

Jump to solution

Hi @khaledismail

 

I'm not familiar with VHDL.

But it seems address issue.

So, would you make sure address signal on BRAM by simulation or ILA ?

 

Also I suggest to change polarity of HSYNC and VSYNC if you use analog RGB via connector of D-SUB 15pin to display this picuture.

 

Best regards,

Visitor khaledismail
Visitor
258 Views
Registered: ‎02-19-2019

Re: Display image using VGA from BRAM

Jump to solution

@watari I found out what where the problem was. I was resetting the BRAM address at a wrong point in the code. Which lead to a repeated display of the first row of the image only. Now the image appears like this:

Displayed image.jpgDisplayed image

As seen, it's close to the original image but skewed for some reason.

 

Any idea why the image is skewed?

0 Kudos
Highlighted
Scholar ronnywebers
Scholar
248 Views
Registered: ‎10-10-2014

Re: Display image using VGA from BRAM

Jump to solution

My quick guess, I think you have a timing issue...

In general 'dividing clocks' using a counter or flip-flops is not recommended in FPGAs

I'm not that technical about FPGA, but I believe the Q outputs of a flip-flop or counter 'clock divider' cannot directly drive global clock networks, and therefore you get unreliable clock routing to the rest of your logic working on the divided clock. Only global buffers and special clock dividers (like MMCM can drive these nets).

If you check your synthesis logs you'll probably see some warnings about this.

I know some tutorial books from Digilent (makers of they Basys board) use this 'divide' method a lot, but they should stop doing that. They should even ban these books ... A better book, like the ones from Pong P. Chu use 'ticks' to solve this, more on that below.

One solution would be to use an MMCM to generate a 25MHz clock from your 100Mhz clock, as it will put the 25MHz on a global clock network. But that's a rather 'expensive way' as MMCMs are precious components inside an FPGA, you only have a few of them. But again, you could use an MMCM.

But for this simple case, I'd not use an MMCM, but start by clocking every process with the 100MHz clock. Once you know this method, you'll use it a lot.

Then you create your 25MHz 'ticks'. A 'tick' is a pulse that is active for 1 clock cycle. Do this by creating a 2-bit counter running at 100MHz, and make the tick high when the counter equals '11'. So one out of 4 clock cycles, your tick will be high.

Then use this tick inside all your processes as an 'enable'. That way, your process content will effectively 'process' at 25MHz, altough it is clocked by a 100Mhz clock. So the big difference is that the 100Mhz goes over a global clock network, and arrives at all your logic with approximately '0' skew.

It looks like overkill, but the higher your clock speeds go, the worse will be your issues when you use the wrong method of just dividing a clock with flip-flops or counters, and using the Q output as a clock. It gets even worse if you start mixing processes runnign at 100MHz and 25MHz clocks from the Q outputs. Worse is an understatement :-)

hope my explanation was clear enough to get yo going. I'm interested though in the final code, I always wanted to try the VGA on my Zedboard :-)

side note : I really recommend to get you a book from Pong P. Chu, he writes them for Verilog and VHDL, probably the best practical book I've ever read (and I own a lot of books). To get started, I recommend RTL hardware design using VHDL

The book about Microblaze is newer and looks tempting, but goes less in depth on pure RTL design techniques. You learn to code a UART, PS2, VGA, ... but all that using proper clocking methods. you'll also learn about clock domain crossing and stuff.

 

** kudo if the answer was helpful. Accept as solution if your question is answered **
Explorer
Explorer
226 Views
Registered: ‎05-21-2015

Re: Display image using VGA from BRAM

Jump to solution

To all,

@khaledismailhas made tremendous progress with his design.  You can read about that on Digilent's forums, where he also cross-posted.

Dan

0 Kudos
Scholar watari
Scholar
220 Views
Registered: ‎06-16-2013

Re: Display image using VGA from BRAM

Jump to solution

Hi @khaledismail 

 

What do you mean "skewed" ?

I guess it seems an analog RGB issue. Maybe phase issue of analog RGB.

 

Would you share short movie about this picture ?

I can make sure it whether an analog RGB (phase issue) issue or not.

 

[Added]

I already read the following post.

https://forum.digilentinc.com/topic/17598-display-image-using-vga-from-block-ram/

 

Here is my suggestion. Would you refer it ?

 

If samsung's LCD monitor support scaling function with aspect ratio, it is analog RGB issue. I'm sure that it's a phase issue. You can improve this issue by changing a phase and position on ex. OSD of this LCD monitor.

If this LCD monitor support scaling function without aspect ratio, it is an aspect ratio issue. I suggest you to change original resolution from 640x480 to ex. 1280x720 or 1920x1080.

 

Best regards,

0 Kudos
Scholar ronnywebers
Scholar
176 Views
Registered: ‎10-10-2014

Re: Display image using VGA from BRAM

Jump to solution

@watari it's possible that @khaledismail  is indeed stuk on a phase issue of RGB

but apart from that, the way he clocks his processes is NOT the way to do this, it's a fundamental issue. Digilent should also stop doing this in their text books and examples, I'll send them a mail about that today.

what I'm saying is exactly what D@n is explaining in the very first reply of the forum post you mentioned. This way of clocking is often referred to as FPGA hell ... and it's so simple to fix, that you should not ignore it, learn it, and never ever use that method again. Reason is also that a functional simulation will never detect such issues (timing simulations using the final netlist and properly designed stimuli could discover these though, but then again, you would need to fix it. Also every change you make in your code might cause different issues, what worked before suddenly no longer works, what works in simulation does not work in your device, and so on ...)

** kudo if the answer was helpful. Accept as solution if your question is answered **
Moderator
Moderator
115 Views
Registered: ‎11-09-2015

Re: Display image using VGA from BRAM

Jump to solution

HI @khaledismail ,

Do you have any update on this?


If your question is answered or your issue is solved, please mark the response which helped as solution (click on the button "Accept as solution" below the reply)

If this is not solved/answered, please reply in the topic giving more information on your current status.

Best Regards,


Florent
Product Application Engineer - Xilinx Technical Support EMEA
**~ Don't forget to reply, give kudos, and accept as solution.~**
0 Kudos
Visitor khaledismail
Visitor
105 Views
Registered: ‎02-19-2019

Re: Display image using VGA from BRAM

Jump to solution

I managed to display the picture correctly.

Summary of the changes that helped reach the correct image:

1- Use PLL from (Clocking Wizard) IP to generate the required 25 MHz frequency. This made the testbench output values instead of all outputs being (Undefined). But I don't think that this solved the image display.

2- Changed the code to display from BRAM only in the pixels range of my image.

3- Reset the address of BRAM at the end of the frame. For me it's when (hPos=639 and vPos=479).

4- Start displaying the image from "hPos=1" not "hPos=0". This solved the image skew problem and now it displays correctly. Probably I can't use "hPos=0" due to bad code writing, timing issue, as I am incrementing some signals by the means of other signals treating them like variables in any software language, for example. C, Java, etc.

0 Kudos
Scholar ronnywebers
Scholar
91 Views
Registered: ‎10-10-2014

Re: Display image using VGA from BRAM

Jump to solution

good to hear it's solved now ... using the PLL to generate the 25MHz is a better approach, now you no longer have 'logic generated clocks' :

1- Use PLL from (Clocking Wizard) IP to generate the required 25 MHz frequency. This made the testbench output values instead of all outputs being (Undefined). But I don't think that this solved the image display.
** kudo if the answer was helpful. Accept as solution if your question is answered **
0 Kudos
Scholar ronnywebers
Scholar
90 Views
Registered: ‎10-10-2014

Re: Display image using VGA from BRAM

Jump to solution

you wrote :

Probably I can't use "hPos=0" due to bad code writing, timing issue, as I am incrementing some signals by the means of other signals treating them like variables in any software language, for example. C, Java, etc.

if it's a timing issue - in the sense that your logic became too slow - you could maybe solve this by pipelining some values (re-clocking), and comparing it with 'value minus 1' ?

** kudo if the answer was helpful. Accept as solution if your question is answered **
0 Kudos