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 igor_kh
Visitor
1,374 Views
Registered: ‎03-27-2018

VGA controller - memory addressing

Jump to solution

Good day,

 

I am new to the FPGA technology and XILINX products, please give me an advice on the following.

 

Currently, I am trying to implement/repeat implementation of a VGA controller on the SoC Zynq CZ7020 (on Arty Z7 board) in a similar way to the way presented here . The design I am working on is shown in picture below:Design_BD.PNG

In the current, test configuration, the design includes the following components I am interested in:

  • blk_mem_gen_0 - the memory block is configured as a 307200 x 1 single port ROM in order to keep a 640 x 480 binary image and is initialised with a "coe" file representing the image: 

Static.PNG

  • blk_mem_gen_1 - for the purpose of the test, the memory block is configured as a 307200 x 2 single port ROM in order to keep "dynamic data", later this memory block will be replaced with dual port RAM. In the configuration shown on the block diagram, the data stored in this memory block are not used and overwritten by a constant value "00" set by the xlconstant_1 IP.
  • COLOR_CODER - this entity implements functionality to assign R-G-B values to a bit characterized by the two bit value saved in the  blk_mem_gen_1 memory.
    library ieee;
    use ieee.std_logic_1164.all;
    
    entity COLOR_CODER is
    
    	port(
    		 DDATA_IN : in  std_logic_vector(1 downto 0);
    		 SDATA_IN : in  std_logic;
    		 R_OUTPUT : out std_logic_vector(3 downto 0);
    		 G_OUTPUT : out std_logic_vector(3 downto 0);
    		 B_OUTPUT : out std_logic_vector(3 downto 0)
    		 );
    
    end COLOR_CODER;
    
    architecture behavioural of COLOR_CODER is
    	
    	signal sdata : std_logic_vector(11 downto 0); 
    	
    begin
    	
    	with DDATA_IN select
    		R_OUTPUT <= sdata(11 downto 8)when "00",
    					"1111"	   		  when "01",
    					"1111"	   		  when "10",
    					"0000"	   		  when "11",
    					sdata(11 downto 8)when others;
    	
    	
    	with DDATA_IN select
    		G_OUTPUT <= sdata(7 downto 4)when "00",
    					"0000"	   		 when "01",
    					"0011"	   	         when "10",
    					"1101"	   		 when "11",
    					sdata(7 downto 4)when others;
    	
    	with DDATA_IN select
    		B_OUTPUT <= sdata(3 downto 0)when "00",
    					"1101"	   		 when "01",
    					"1111"	   		 when "10",
    					"0000"			 when "11",
    					sdata(3 downto 0)when others;
    					
    	with SDATA_IN select
    		sdata <=(others => '0')when '0',
    				(others => '1')when '1',
    				(others => '1')when others;
    
    end behavioural;	
  • VGA_CONTROLLER - generates synchronisation impulses and sets  up addresses of the of the pixels.
    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
    
    entity VGA_CONTROLLER is
    
        port(
             CLK         : in  std_logic;
             REFRESH     : in  std_logic;
             R_INPUT     : in  std_logic_vector(3 downto 0);
             G_INPUT     : in  std_logic_vector(3 downto 0);
             B_INPUT     : in  std_logic_vector(3 downto 0);
             
             ENABLE      : out std_logic;
             ADDRESS     : out std_logic_vector(18 downto 0);
    	 JA_4_1      : out std_logic_vector(4  downto 1);
    	 JA_10_7     : out std_logic_vector(10 downto 7);
    	 JB_4_1      : out std_logic_vector(4  downto 1);
    	 JB_8_7      : out std_logic_vector(8  downto 7)
    	);
    end VGA_CONTROLLER;
    
    architecture behavioral of VGA_CONTROLLER is
        ATTRIBUTE X_INTERFACE_INFO 	    : STRING;
        ATTRIBUTE X_INTERFACE_PARAMETER : STRING;
        
        ATTRIBUTE X_INTERFACE_INFO of CLK 	   : SIGNAL is "xilinx.com:signal:clock:1.0 CLK CLK";
        ATTRIBUTE X_INTERFACE_PARAMETER of CLK : SIGNAL is "FREQ_HZ 100000000";
        	
        constant VIDEO_PAGE_WIDTH      : unsigned(11 downto 0) := "001010000000";        -- 640
        constant VIDEO_PAGE_HEIGHT     : unsigned(11 downto 0) := "000111100000";        -- 480
        
        constant H_FRONT_PORCH_WIDTH   : unsigned(11 downto 0) := "000000010000";        -- 16
        constant H_SYNCHRO_PULSE_WIDTH : unsigned(11 downto 0) := "000001100000";        -- 96
        constant H_BACK_PORCH_WIDTH	   : unsigned(11 downto 0) := "000000110000";        -- 48
        constant H_TOTAL_PERIOD        : unsigned(11 downto 0) := "001100100000";        -- 800
        
        constant V_FRONT_PORCH_WIDTH   : unsigned(11 downto 0) := "000000001010";        -- 10
        constant V_SYNCHRO_PULSE_WIDTH : unsigned(11 downto 0) := "000000000010";        -- 2
        constant V_BACK_PORCH_WIDTH	   : unsigned(11 downto 0) := "000000100001";        -- 33
        constant V_TOTAL_PERIOD        : unsigned(11 downto 0) := "001000001101"; 	     -- 525
    
        constant MAXIMUM_ADDRESS	   : unsigned(18 downto 0) := "1001010111111111111"; --307199
        
        signal frequency_divider_register : unsigned(1 downto 0):=(others => '0');
        signal divided_clock_register     : std_logic := '0';
        signal pixel_counter_register     : unsigned(11 downto 0):=(others => '0');
        signal line_counter_register      : unsigned(11 downto 0):=(others => '0');
        signal h_synchro_pulse_register   : std_logic := '1';
        signal v_synchro_pulse_register   : std_logic := '1';
        signal line_address               : unsigned(11 downto 0);
        signal pixel_address              : unsigned(11 downto 0);
        signal address_register           : unsigned(18 downto 0):=(others => '0');
        signal active_line                : std_logic;
        signal active_pixel               : std_logic;
        signal active_line_register       : std_logic := '0';
        signal active_pixel_register      : std_logic := '0';
    	 
    begin
        
        frequency_divider:
        process(CLK)
        begin
            if(rising_edge(CLK))then
                if(REFRESH = '1')then
                    frequency_divider_register <= frequency_divider_register + 1;
                    if(frequency_divider_register = "01")then
                        frequency_divider_register <= "00";
                        divided_clock_register <= not(divided_clock_register);
                    end if;
                end if;
            end if;
        end process;         
        
        pixel_counter:
        process(divided_clock_register)
        begin
            if(rising_edge(divided_clock_register))then
                  if(pixel_counter_register = H_TOTAL_PERIOD - 8)then --1
                        pixel_counter_register <= (others => '0');
    			  else
    					pixel_counter_register <= pixel_counter_register + 1;
    			  end if;
            end if;   
        end process;
    	
        line_counter:
        process(divided_clock_register)
        begin
            if(rising_edge(divided_clock_register))then
                if((pixel_counter_register = H_TOTAL_PERIOD - 8) and (line_counter_register = V_TOTAL_PERIOD - 2))then
                    line_counter_register <= (others => '0');
                elsif(pixel_counter_register = H_TOTAL_PERIOD - 8)then
                    line_counter_register <= line_counter_register + 1;
                end if;
            end if;   
        end process;
    	
        horizontal_synchro_pulse_register:
        process(divided_clock_register)
        begin
           if(rising_edge(divided_clock_register))then
              if((pixel_counter_register >= VIDEO_PAGE_WIDTH + H_FRONT_PORCH_WIDTH - 5) and (pixel_counter_register < VIDEO_PAGE_WIDTH + H_FRONT_PORCH_WIDTH + H_SYNCHRO_PULSE_WIDTH - 6))then --0
    	          h_synchro_pulse_register <= '0';
    	       else
    	          h_synchro_pulse_register <= '1';
    	       end if;
    	   end if;
    	end process;
    	
    	vertical_synchro_pulse_register:
    	process(divided_clock_register)
    	begin
    	   if(rising_edge(divided_clock_register))then
    	       if((line_counter_register >= VIDEO_PAGE_HEIGHT + V_FRONT_PORCH_WIDTH - 1) and (line_counter_register < VIDEO_PAGE_HEIGHT + V_FRONT_PORCH_WIDTH + V_SYNCHRO_PULSE_WIDTH - 1))then
    	          v_synchro_pulse_register <= '0';
    	       else
    	          v_synchro_pulse_register <= '1';
    	       end if;
    	   end if;
    	end process;
    	
    	address_logic:
    	active_pixel <= '1' when (pixel_counter_register < VIDEO_PAGE_WIDTH) else '0';
    	active_line  <= '1' when (line_counter_register < VIDEO_PAGE_HEIGHT) else '0';
    
    	process(divided_clock_register, active_line, active_pixel)
    	begin
    		if(rising_edge(divided_clock_register))then
    			if(address_register = MAXIMUM_ADDRESS)then
    			   address_register <= (others => '0');
    			elsif(active_line = '1' and active_pixel = '1')then
    			   address_register <= address_register + 1;
    			else
    			   address_register <= address_register;
    			end if;
    		end if;
    	end process;
    	
    	output_signals_routing:
    	ENABLE  <= not REFRESH;
    	ADDRESS <= std_logic_vector(address_register);
    	JA_4_1  <= R_INPUT when(active_line = '1' and active_pixel = '1') else "0000";
    	JA_10_7 <= G_INPUT when(active_line = '1' and active_pixel = '1') else "0000";
    	JB_4_1  <= B_INPUT when(active_line = '1' and active_pixel = '1') else "0000";
    	JB_8_7  <= v_synchro_pulse_register & h_synchro_pulse_register;
    
    end behavioral;
    The problem is that the static image shown above is not visualized as it is expected to be, the output image is broken off and mixed. I believe that I address the memory in a wrong way, but all my attempts to fix the problem were unsuccessful. I have checked the timing with by simulation and  run the VGA_CONTOLLER with a single colour and it works well. Please advise on the issue.

Best regards.

 

Tags (1)
0 Kudos
1 Solution

Accepted Solutions
Visitor igor_kh
Visitor
1,856 Views
Registered: ‎03-27-2018

Re: VGA controller - memory addressing

Jump to solution

The question is closed. I had a mistake in the bmp-to-coe file conversion script, it mapped an image to the memory address space in a wrong way.

0 Kudos
6 Replies
Scholar jmcclusk
Scholar
1,367 Views
Registered: ‎02-24-2014

Re: VGA controller - memory addressing

Jump to solution

I guess I should ask the obvious question here...   Have you created a timing constraint for your clock?   You should have an XDC file that contains a TCL command of the form:   create_clock  <args>

Don't forget to close a thread when possible by accepting a post as a solution.
Visitor igor_kh
Visitor
1,343 Views
Registered: ‎03-27-2018

Re: VGA controller - memory addressing

Jump to solution

@jmccluskwrote:

I guess I should ask the obvious question here...   Have you created a timing constraint for your clock?   You should have an XDC file that contains a TCL command of the form:   create_clock  <args>


Thank you for your response. Yes, I have created timing constraint for the clock in the xdc file, here it is:

## This file is a general .xdc for the ARTY Z7-20 Rev.B

## To use it in a project:

## - uncomment the lines corresponding to used pins

## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project



## Clock Signal

create_clock -name FCLK_CLK0 -period "20"


## LEDs

set_property -dict { PACKAGE_PIN R14    IOSTANDARD LVCMOS33 } [get_ports { ENABLE_0}]; #IO_L6N_T0_VREF_34 Sch=LED0

## Pmod Header JA

set_property -dict { PACKAGE_PIN Y18   IOSTANDARD LVCMOS33 } [get_ports { JA_4_1_0[1] }]; #IO_L17P_T2_34 Sch=JA1_P

set_property -dict { PACKAGE_PIN Y19   IOSTANDARD LVCMOS33 } [get_ports { JA_4_1_0[2] }]; #IO_L17N_T2_34 Sch=JA1_N

set_property -dict { PACKAGE_PIN Y16   IOSTANDARD LVCMOS33 } [get_ports { JA_4_1_0[3] }]; #IO_L7P_T1_34 Sch=JA2_P

set_property -dict { PACKAGE_PIN Y17   IOSTANDARD LVCMOS33 } [get_ports { JA_4_1_0[4] }]; #IO_L7N_T1_34 Sch=JA2_N

set_property -dict { PACKAGE_PIN U18   IOSTANDARD LVCMOS33 } [get_ports { JA_10_7_0[7] }]; #IO_L12P_T1_MRCC_34 Sch=JA3_P

set_property -dict { PACKAGE_PIN U19   IOSTANDARD LVCMOS33 } [get_ports { JA_10_7_0[8] }]; #IO_L12N_T1_MRCC_34 Sch=JA3_N

set_property -dict { PACKAGE_PIN W18   IOSTANDARD LVCMOS33 } [get_ports { JA_10_7_0[9] }]; #IO_L22P_T3_34 Sch=JA4_P

set_property -dict { PACKAGE_PIN W19   IOSTANDARD LVCMOS33 } [get_ports { JA_10_7_0[10] }]; #IO_L22N_T3_34 Sch=JA4_N



## Pmod Header JB

set_property -dict { PACKAGE_PIN Y14   IOSTANDARD LVCMOS33 } [get_ports { JB_4_1_0[2] }]; #IO_L8N_T1_34 Sch=JB1_N

set_property -dict { PACKAGE_PIN W14   IOSTANDARD LVCMOS33 } [get_ports { JB_4_1_0[1] }]; #IO_L8P_T1_34 Sch=JB1_P

set_property -dict { PACKAGE_PIN T10   IOSTANDARD LVCMOS33 } [get_ports { JB_4_1_0[4] }]; #IO_L1N_T0_34 Sch=JB2_N

set_property -dict { PACKAGE_PIN T11   IOSTANDARD LVCMOS33 } [get_ports { JB_4_1_0[3] }]; #IO_L1P_T0_34 Sch=JB2_P

set_property -dict { PACKAGE_PIN W16   IOSTANDARD LVCMOS33 } [get_ports { JB_8_7_0[8] }]; #IO_L18N_T2_34 Sch=JB3_N

set_property -dict { PACKAGE_PIN V16   IOSTANDARD LVCMOS33 } [get_ports { JB_8_7_0[7] }]; #IO_L18P_T2_34 Sch=JB3_P

but, I am not sure if it is correct. 

0 Kudos
Scholar jmcclusk
Scholar
1,336 Views
Registered: ‎02-24-2014

Re: VGA controller - memory addressing

Jump to solution

That doesn't look right, since you have a period of 20 ns (50 MHz), while your code indicates you have a clock frequency of 100 Mhz..      Try setting the constraint to 10 ns, and rebuild the design..   is it better?

Don't forget to close a thread when possible by accepting a post as a solution.
Visitor igor_kh
Visitor
1,329 Views
Registered: ‎03-27-2018

Re: VGA controller - memory addressing

Jump to solution

@jmccluskwrote:

That doesn't look right, since you have a period of 20 ns (50 MHz), while your code indicates you have a clock frequency of 100 Mhz..      Try setting the constraint to 10 ns, and rebuild the design..   is it better?


I am sorry, I forgot to say this, I also changed the clock frequency from 100 MHz to 50 MHz in my code at that attempt.

By now, I have check it in both configurations:

1. Constraint 50 MHz / Code 50 MHz,

2. Constraint 100 MHz / Code 100 MHz,

in both cases I get the same output on the screen.

0 Kudos
Visitor igor_kh
Visitor
1,857 Views
Registered: ‎03-27-2018

Re: VGA controller - memory addressing

Jump to solution

The question is closed. I had a mistake in the bmp-to-coe file conversion script, it mapped an image to the memory address space in a wrong way.

0 Kudos
Moderator
Moderator
1,245 Views
Registered: ‎11-09-2015

Re: VGA controller - memory addressing

Jump to solution

Hi @igor_kh,

 

As this is solved for you, please kindly close the topic by marking your last reply as accepted solution.

 

You can also give kudos to @jmcclusk to thanks him for his help.

 

Best Regards,


Florent
Product Application Engineer - Xilinx Technical Support EMEA
**~ Don't forget to reply, give kudos, and accept as solution.~**