cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Highlighted
Visitor
Visitor
13,204 Views
Registered: ‎02-26-2015

Digilent Atlys - Spartan 6 - HDMI pixel editing

Jump to solution

Hi,

 

I'm currently working on a project with the Digilent Atlys Spartan 6 FPGA Board. I'm using the DVI encoder and decoder from xapp495, and have sucessfully implemented a throughput of a HDMI signal from my Laptop.

 

Next I want to be able to modify the pixels so i can, for example, alternate the pixels between black and white. Eventually this will lead to using the source input as some of the values, and then replacing the remainder of the pixel data with another source. With the aim to produce a split screen type of effect (like you might see in a video game).

 

 

When simulating the below code it works as i would expect, but when it is placed on the board i am given a blank screen (solid black output), rather than the expected output. I would appreciate any insight you may have into where I am going wrong.

 

Resolution I am working with is 1024x768, so that should explain the numbers used below.

 

I have two processes i have written to achive this, the first calcluate the location of the current pixel:

pixelLocation : process (c100MHz, reset, pclk, pclk_old, de_H)
begin
	if reset = '1' then
		pixelCount <= 0;
		lineCount <= 0;
	elsif rising_edge(c100MHz) and de_H = '1' then
			if pclk_old = '0' and pclk = '1'  then
				if pixelCount < 1024 then
					pixelCount <= pixelCount +1;
					pclk_old <= '1';
				else	
					if lineCount < 768 then
						lineCount <= lineCount+1;
					else
						lineCount <= 0;
					end if;
					pixelCount <= 0;
					pclk_old <= '1';
				end if;
			elsif pclk_old = '1' and pclk = '1'  then
				pclk_old <= '1';
			elsif pclk = '0' then
				pclk_old <= '0';
			end if;
	end if;

end process;

 And a second, which using that data will change the value of the pixel:

-- process to set the data on the falling edge of the input clk, and to set the output clock to 1 to indicate new data.
pixelData &colon; process (pclk, reset, de_H)
variable colourSwitch : integer range 0 to 1 := 0;
begin
	if reset = '1' then
		colourSwitch := 0;
		rgb_data_out <= "000000000000000000000000";
		pclk_out <= '0';
		hsync_out <= '0';
		vsync_out <= '0';
		de_H_out <= '0';
	elsif falling_edge(pclk) and de_H = '1' then
		if colourSwitch = 0 then
			RGB_data_out <= "000000000000000000000000";
			colourSwitch := 1;
		elsif colourSwitch = 1 then
			RGB_data_out <= "111111111111111111111111";
			colourSwitch := 0;
		end if;
		-- update outputs
		hsync_out <= hsync;
		vsync_out <= vsync;
		de_H_out <= de_H;
	end if;
		pclk_out <= pclk;
end process;

 The simulation is shown below:

Simulation

 

If you need any futher information, please let me know, otherwise, thank you for your assistance.

 

Andy

0 Kudos
1 Solution

Accepted Solutions
Highlighted
Teacher
Teacher
22,336 Views
Registered: ‎08-14-2007

Hi Andy,

 so here's how it goes:

 

 

----------------------------------------------------------------------------------
-- Company: 
-- Engineer: Andrew Galpin
-- 
-- Create Date:    11:19:24 03/03/2015 
-- Design Name: 	 HDMI duel input single output
-- Module Name:    Pixel_Mix - Behavioral 
--
-- Additional Comments: 
--      PositionCounter and test processes by eilert (Xilinx user forum)   
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity Pixel_Mix is
    Port ( reset : in  STD_LOGIC;
           c100MHz : in  STD_LOGIC; -- system clock
           rgb_data &colon; in  STD_LOGIC_VECTOR (23 downto 0);
           hsync : in  STD_LOGIC;
           vsync : in  STD_LOGIC;
           pclk : in  STD_LOGIC;
           de_H : in  STD_LOGIC;
           rgb_data_out : out  STD_LOGIC_VECTOR (23 downto 0);
           hsync_out : out  STD_LOGIC;
           vsync_out : out  STD_LOGIC;
           pclk_out : out  STD_LOGIC;
           de_H_out : out  STD_LOGIC);
end Pixel_Mix;

architecture Behavioral of Pixel_Mix is

begin

PositionCounter : process (pclk) is
   variable Hcounter : unsigned (11 downto 0) := to_unsigned(0,12);
   variable Vcounter : unsigned (11 downto 0) := to_unsigned(0,12);
   variable hsync_old : std_logic := '0';
begin
  if rising_edge(pclk) then
    -- count horizontal pixels
    if hsync = '0' then
	   Hcounter  := to_unsigned(0,12);
    else
	  if de_H = '1' then
	   Hcounter  := Hcounter +1; 
     end if; -- de_H
	 end if; -- hsync
	
    if vsync = '0' then
	   Vcounter  := to_unsigned(0,12);
    else
	   if de_H= '0' then
		         -- detect falling edge hsync
		  if hsync_old = '1' and hsync = '0' then  
	       Vcounter  := Vcounter +1;
		  end if; -- detect falling edge hsync
      end if; -- de_H
	  hsync_old := hsync;
	 end if; -- vsync	
	 
	 -- use signal assignment property "last assignment wins" to simplify code
	 RGB_data_out <= rgb_data; -- default assignment
	 if Vcounter > to_unsigned(200,12) and Vcounter < to_unsigned(600,12) then
    	 if Hcounter > to_unsigned(400,12) and Hcounter < to_unsigned(550,12) then
		   RGB_data_out <= rgb_data(23 downto 8) & "11111111";	 
		 end if;   
	 end if;
	  
	  
	 hsync_out <= hsync;
	 vsync_out <= vsync;
	 de_H_out <= de_H;	
	  
  end if; -- pclk
end process;

 -- RGB Throughput working
--		RGB_data_out <= rgb_data;
--		hsync_out <= hsync;
--		vsync_out <= vsync;
--		de_H_out <= de_H;
		pclk_out <= pclk;
		
 -- delayed RGB Throughput  working	
--process(pclk) is
--begin
--  if rising_edge(pclk) then
--		RGB_data_out <= rgb_data;
--		hsync_out <= hsync;
--		vsync_out <= vsync;
--		de_H_out <= de_H;	
--  end if;
--end process;

--process(pclk) is
--  variable rainbow :  STD_LOGIC_VECTOR (23 downto 0) := "000000000000000000001111";
--begin
--  if rising_edge(pclk) then
--		RGB_data_out <= rgb_data(23 downto 8) & "11111111";
--		RGB_data_out <= (others =>'1'); -- white
--		rainbow := rainbow(22 downto 0) & rainbow(23); 
--		rainbow := rainbow(22 downto 0) & (rainbow(23) xor rainbow(7)); -- stable color bars
--		rainbow := rainbow(22 downto 0) & (rainbow(23) xor rainbow(12)); -- noise
--		rainbow := rainbow(22 downto 0) & (rainbow(23) xor rainbow(9)); -- vertical down scrolling stable random
--		rainbow := rainbow(22 downto 0) & (rainbow(23) xor rainbow(12) xor rainbow(7) );-- noise
--		rainbow := rainbow(22 downto 0) & (rainbow(23) xor rainbow(14)); -- vertical up scrolling stable random
--		
--		
--      RGB_data_out <= rainbow;
--		hsync_out <= hsync;
--		vsync_out <= vsync;
--		de_H_out <= de_H;	
--  end if;
--end process;


end Behavioral;

 

This code removes the blue color from a rectangle area.

Of course the assignment can be changed to display any content in that area.

And the area window can be changed to be controlled by external signals etc.

 

Feel free to do your experiments.

 

Have a nice synthesis

  Eilert

 

 

 

 

 

View solution in original post

8 Replies
Highlighted
Teacher
Teacher
13,195 Views
Registered: ‎08-14-2007

Hi Andrew,

doing the HDMI throughput design is already some nice work.

Could you upload that project in a zip file? (sources and tcl script are sufficient)

 

Apart from the clocking I'm missing something in your code.

 

The signal colourSwitch selects wether the data will be all 0's or all 1's.

You are toggling it, so the screen will become some kind of grey, if the timing is ok.

(otherwise it might be solid black or white)

 

But how is this connected to the first code snippet?

 

I'm missing something like:

if line 300 passedthen

  RGB_Data <= black;

else

 RGB_Data <= RGB_DataIn;

end if;

 

So you would see the original picture at the top and everything below line 300 goes black.

 

Besides, are you sure that the HDMI source uses RGB encoding?

check this:

http://www.hardwaresecrets.com/article/Inside-HDMI-High-Definition-Multimedia-Interface/283/2

 

Have a nice synthesis

  Eilert

 

 

Highlighted
Visitor
Visitor
13,180 Views
Registered: ‎02-26-2015

Hi Eilert,

 

Thanks for taking the time to repsond.

 

You are right when you say the processes don't link together - that's a maistake on my part (I've rewritten it too mnay times!). I've updated the code to reflect the end product (like you have outlined in your post), and attached the source files to this post.

 

pixelData &colon; process (pclk, reset, de_H)
begin
	if reset = '1' then
		rgb_data_out <= "000000000000000000000000";
		pclk_out <= '0';
		hsync_out <= '0';
		vsync_out <= '0';
		de_H_out <= '0';
	elsif falling_edge(pclk) and de_H = '1' then
		if linecount <= 400 then
			RGB_data_out <= "000000000000000000000000";
		else
			RGB_data_out <= rgb_data;
		end if;
		-- update outputs
		hsync_out <= hsync;
		vsync_out <= vsync;
		de_H_out <= de_H;
	end if;
		pclk_out <= pclk;
end process;

 In reply to your final question, that's an excellent point. I don't know for sure if the source is RGB encoding (I'm not sure if that can be easily found out?). My assumption that it is is based on the vaibles that the decoder (xapp495) produces from the input signal (rgb_data). In the application note, they don't mention how they decode or encode the images, so i am not sure if it has been written to cope with both RGB, YCbCr (4:4:4) and YCbCr (4:2:2), and the decoding process brings it back to RGB, or if the source I am using (Display Port, from a Laptop running Windows 7) is producing a source that is compatible.

 

XAPP495: http://www.xilinx.com/support/documentation/application_notes/xapp495_S6TMDS_Video_Interface.pdf

 

Andy

0 Kudos
Highlighted
Teacher
Teacher
22,337 Views
Registered: ‎08-14-2007

Hi Andy,

 so here's how it goes:

 

 

----------------------------------------------------------------------------------
-- Company: 
-- Engineer: Andrew Galpin
-- 
-- Create Date:    11:19:24 03/03/2015 
-- Design Name: 	 HDMI duel input single output
-- Module Name:    Pixel_Mix - Behavioral 
--
-- Additional Comments: 
--      PositionCounter and test processes by eilert (Xilinx user forum)   
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity Pixel_Mix is
    Port ( reset : in  STD_LOGIC;
           c100MHz : in  STD_LOGIC; -- system clock
           rgb_data &colon; in  STD_LOGIC_VECTOR (23 downto 0);
           hsync : in  STD_LOGIC;
           vsync : in  STD_LOGIC;
           pclk : in  STD_LOGIC;
           de_H : in  STD_LOGIC;
           rgb_data_out : out  STD_LOGIC_VECTOR (23 downto 0);
           hsync_out : out  STD_LOGIC;
           vsync_out : out  STD_LOGIC;
           pclk_out : out  STD_LOGIC;
           de_H_out : out  STD_LOGIC);
end Pixel_Mix;

architecture Behavioral of Pixel_Mix is

begin

PositionCounter : process (pclk) is
   variable Hcounter : unsigned (11 downto 0) := to_unsigned(0,12);
   variable Vcounter : unsigned (11 downto 0) := to_unsigned(0,12);
   variable hsync_old : std_logic := '0';
begin
  if rising_edge(pclk) then
    -- count horizontal pixels
    if hsync = '0' then
	   Hcounter  := to_unsigned(0,12);
    else
	  if de_H = '1' then
	   Hcounter  := Hcounter +1; 
     end if; -- de_H
	 end if; -- hsync
	
    if vsync = '0' then
	   Vcounter  := to_unsigned(0,12);
    else
	   if de_H= '0' then
		         -- detect falling edge hsync
		  if hsync_old = '1' and hsync = '0' then  
	       Vcounter  := Vcounter +1;
		  end if; -- detect falling edge hsync
      end if; -- de_H
	  hsync_old := hsync;
	 end if; -- vsync	
	 
	 -- use signal assignment property "last assignment wins" to simplify code
	 RGB_data_out <= rgb_data; -- default assignment
	 if Vcounter > to_unsigned(200,12) and Vcounter < to_unsigned(600,12) then
    	 if Hcounter > to_unsigned(400,12) and Hcounter < to_unsigned(550,12) then
		   RGB_data_out <= rgb_data(23 downto 8) & "11111111";	 
		 end if;   
	 end if;
	  
	  
	 hsync_out <= hsync;
	 vsync_out <= vsync;
	 de_H_out <= de_H;	
	  
  end if; -- pclk
end process;

 -- RGB Throughput working
--		RGB_data_out <= rgb_data;
--		hsync_out <= hsync;
--		vsync_out <= vsync;
--		de_H_out <= de_H;
		pclk_out <= pclk;
		
 -- delayed RGB Throughput  working	
--process(pclk) is
--begin
--  if rising_edge(pclk) then
--		RGB_data_out <= rgb_data;
--		hsync_out <= hsync;
--		vsync_out <= vsync;
--		de_H_out <= de_H;	
--  end if;
--end process;

--process(pclk) is
--  variable rainbow :  STD_LOGIC_VECTOR (23 downto 0) := "000000000000000000001111";
--begin
--  if rising_edge(pclk) then
--		RGB_data_out <= rgb_data(23 downto 8) & "11111111";
--		RGB_data_out <= (others =>'1'); -- white
--		rainbow := rainbow(22 downto 0) & rainbow(23); 
--		rainbow := rainbow(22 downto 0) & (rainbow(23) xor rainbow(7)); -- stable color bars
--		rainbow := rainbow(22 downto 0) & (rainbow(23) xor rainbow(12)); -- noise
--		rainbow := rainbow(22 downto 0) & (rainbow(23) xor rainbow(9)); -- vertical down scrolling stable random
--		rainbow := rainbow(22 downto 0) & (rainbow(23) xor rainbow(12) xor rainbow(7) );-- noise
--		rainbow := rainbow(22 downto 0) & (rainbow(23) xor rainbow(14)); -- vertical up scrolling stable random
--		
--		
--      RGB_data_out <= rainbow;
--		hsync_out <= hsync;
--		vsync_out <= vsync;
--		de_H_out <= de_H;	
--  end if;
--end process;


end Behavioral;

 

This code removes the blue color from a rectangle area.

Of course the assignment can be changed to display any content in that area.

And the area window can be changed to be controlled by external signals etc.

 

Feel free to do your experiments.

 

Have a nice synthesis

  Eilert

 

 

 

 

 

View solution in original post

Highlighted
Visitor
Visitor
13,049 Views
Registered: ‎02-26-2015

Eilert,

 

Thanks very much for your assistance, I've got the code you posted working, and started adapting it to achieve the split screen effect.

 

I've attached the final working code source files (based on your above code), for anyone else who may need it. It contains a working version of XAPP495 and the code included in the above post. Tested on the Altys Board.

 

I appreciate your assistance.

 

Andy

 

0 Kudos
Highlighted
Teacher
Teacher
13,038 Views
Registered: ‎08-14-2007

Hi Andy,

good job.

Next thing might be taking the pixel data from the other HDMI-in so you can display parts of both pictures on one screen.

That will not be so difficult.

 

But for a true splitscreen as shown inyour first post you need to compress the images, otherwise you see the top of one screen and then the bottom  of the other screen which is not very useful.

 

This requires some frame buffers, which are too large to be done with internal BRAMs.

So an interface to external ram is required.

And you need to work out a scheme that stores the two incoming frames while at the meantime reads the data of the old frames and does the combination/interpolation of two lines into one for the output.

 

Another method would be to do the compression before storing the data to the frame buffer, so you save memory space and bandwidth.

 

Not an easy task, so think about it very carefully. That will save you a lot of time in the end.

 

Have a nice synthesis

  Eilert

 

0 Kudos
Highlighted
Visitor
Visitor
13,031 Views
Registered: ‎02-26-2015

Hi Eilert,

 

Thanks for the advice - the second HDMI port is next on my list. I was having a few issues with the second HDMI port when using the XAPP495 code - I couldn't get it to work with the input from my laptop like the first HDMI port would. Do you know of anything different between the two ports that I may be missing?

 

I will take a look at interfacing with the external RAM, I've come across some Atlys specific advice for using that on Joel Williams's site: http://www.joelw.id.au/FPGA/XilinxMIGTutorial.

 

I think compressing it before storing it makes the most sense, but I will, as you advise, spend some time research and planning the best approach before moving forward in that direction.

 

Andy

 

 

0 Kudos
Highlighted
Visitor
Visitor
13,021 Views
Registered: ‎02-26-2015

Update on that note:

 

I've fixed the issue i was having with HDMI1 input not working. The jumpers installed next to the port (SDA and SCL) need to be connected. My board came with jumpers on, but they weren't connecting the correct pins together. Fixing this and the first input now works.

 

An explanation of the DDC control signals, which are used for EDID. Looking at the schematics, the PMODA HDMI connector (an output - the unlabelled one on the bottom of the board) has its SDA/SCL connected to JA-SCL/JA-SDA and, if you fit JP2, which is labelled as "SDA" and "SCL" on the PCB, PMOD-SCL/PMOD-SDA.

JA-SCL/JA-SDA go to C13 and A13 (on the FPGA). PMOD-SCL/PMOD-SDA go through the HDMI buffer and to HDMI input J1. This means that the DDC for input 1 is either left floating (if JP2 isn't fitted) or is connected to some FPGA pins and output PMODA.

HDMI OUT J2 has its DDC connected to TMDS-TX-SCL/TMDS-TX-SCL (D9 and C9). If you fit JP6 and JP7, these are connected directly to HDMI IN J3's DDC

 

Ref: http://www.joelw.id.au/FPGA/DigilentAtlysResources

0 Kudos
Highlighted
Visitor
Visitor
11,251 Views
Registered: ‎07-22-2015

Hi all,

 

I am new to the FPGA world. I have the Spartan-6 Atlys board. I am working on Lane reversal for HDMI port. As we know, it has Data2+-, Data1+-, Data0+- and Clk+-. So I want to connect Data0+ to Clk+ and Data2+ to Data1+ and same way for Data- signals. Can somebody help me to achieve this? 

0 Kudos