repo2/eclaireXL_ITX/hdmi/hdmi.vhd @ 1475
479 | markw | ---------------------------------------------------------------------------
|
|
-- (c) 2016 Alexey Spirkov
|
|||
-- I am happy for anyone to use this for non-commercial use.
|
|||
-- If my verilog/vhdl/c files are used commercially or otherwise sold,
|
|||
-- please contact me for explicit permission at me _at_ alsp.net.
|
|||
-- This applies for source and binary form and derived works.
|
|||
---------------------------------------------------------------------------
|
|||
-- Recommended params:
|
|||
-- N=0x1800 CTS=0x6FD1 (28.625MHz pixel clock -> 48KHz audio clock)
|
|||
-- N=0x1000 CTS=0x6FD1 (28.625MHz pixel clock -> 32KHz audio clock)
|
|||
-- N=0x1000 CTS=0x6978 (27MHz pixel clock -> 32KHz audio clock)
|
|||
-- N=0x1800 CTS=0x6978 (27MHz pixel clock -> 48KHz audio clock)
|
|||
---------------------------------------------------------------------------
|
|||
library IEEE;
|
|||
use IEEE.STD_LOGIC_1164.ALL;
|
|||
use IEEE.STD_LOGIC_UNSIGNED.ALL;
|
|||
483 | markw | entity hdmi is
|
|
479 | markw | generic
|
|
(
|
|||
FREQ: integer := 27000000; -- pixel clock frequency
|
|||
FS: integer := 48000; -- audio sample rate - should be 32000, 41000 or 48000
|
|||
CTS: integer := 27000; -- CTS = Freq(pixclk) * N / (128 * Fs)
|
|||
N: integer := 6144 -- N = 128 * Fs /1000, 128 * Fs /1500 <= N <= 128 * Fs /300
|
|||
-- Check HDMI spec 7.2 for details
|
|||
);
|
|||
port (
|
|||
-- clocks
|
|||
I_CLK_PIXEL : in std_logic;
|
|||
951 | markw | I_RESET : in std_logic;
|
|
479 | markw | ||
-- components
|
|||
I_R : in std_logic_vector(7 downto 0);
|
|||
I_G : in std_logic_vector(7 downto 0);
|
|||
I_B : in std_logic_vector(7 downto 0);
|
|||
I_BLANK : in std_logic;
|
|||
I_HSYNC : in std_logic;
|
|||
I_VSYNC : in std_logic;
|
|||
-- PCM audio
|
|||
I_AUDIO_PCM_L : in std_logic_vector(15 downto 0);
|
|||
I_AUDIO_PCM_R : in std_logic_vector(15 downto 0);
|
|||
977 | markw | -- VIDEO mode
|
|
I_VIDEO_ID_CODE : in std_logic_vector(7 downto 0);
|
|||
483 | markw | -- ENCODED output
|
|
O_R : out std_logic_vector(9 downto 0);
|
|||
O_G : out std_logic_vector(9 downto 0);
|
|||
O_B : out std_logic_vector(9 downto 0));
|
|||
479 | markw | end entity;
|
|
483 | markw | architecture rtl of hdmi is
|
|
479 | markw | ||
component hdmidataencoder
|
|||
generic
|
|||
(
|
|||
FREQ: integer := 27000000;
|
|||
FS: integer := 48000;
|
|||
CTS: integer := 27000;
|
|||
N: integer := 6144
|
|||
);
|
|||
port (
|
|||
i_pixclk : in std_logic;
|
|||
951 | markw | i_reset : in std_logic;
|
|
479 | markw | i_hSync : in std_logic;
|
|
i_vSync : in std_logic;
|
|||
i_blank : in std_logic;
|
|||
i_audioL : in std_logic_vector(15 downto 0);
|
|||
i_audioR : in std_logic_vector(15 downto 0);
|
|||
977 | markw | i_video_id_code : in std_logic_vector(7 downto 0);
|
|
479 | markw | ||
o_d0 : out std_logic_vector(3 downto 0);
|
|||
o_d1 : out std_logic_vector(3 downto 0);
|
|||
o_d2 : out std_logic_vector(3 downto 0);
|
|||
o_data : out std_logic
|
|||
);
|
|||
end component;
|
|||
signal enc0out : std_logic_vector(9 downto 0);
|
|||
signal enc1out : std_logic_vector(9 downto 0);
|
|||
signal enc2out : std_logic_vector(9 downto 0);
|
|||
signal tx_in : std_logic_vector(29 downto 0);
|
|||
signal tmds_d : std_logic_vector(2 downto 0);
|
|||
signal data : std_logic;
|
|||
signal dataPacket0 : std_logic_vector(3 downto 0);
|
|||
signal dataPacket1 : std_logic_vector(3 downto 0);
|
|||
signal dataPacket2 : std_logic_vector(3 downto 0);
|
|||
signal delayLineIn: std_logic_vector(39 downto 0);
|
|||
signal delayLineOut: std_logic_vector(39 downto 0);
|
|||
signal ROut: std_logic_vector(7 downto 0);
|
|||
signal GOut: std_logic_vector(7 downto 0);
|
|||
signal BOut: std_logic_vector(7 downto 0);
|
|||
signal hSyncOut: std_logic;
|
|||
signal vSyncOut: std_logic;
|
|||
signal vdeOut: std_logic;
|
|||
signal dataOut: std_logic;
|
|||
signal vhSyncOut: std_logic_vector(1 downto 0);
|
|||
signal prevBlank: std_logic;
|
|||
signal prevData: std_logic;
|
|||
signal dataPacket0Out : std_logic_vector(3 downto 0);
|
|||
signal dataPacket1Out : std_logic_vector(3 downto 0);
|
|||
signal dataPacket2Out : std_logic_vector(3 downto 0);
|
|||
signal ctl0: std_logic;
|
|||
signal ctl1: std_logic;
|
|||
signal ctl2: std_logic;
|
|||
signal ctl3: std_logic;
|
|||
signal ctl_10: std_logic_vector(1 downto 0);
|
|||
signal ctl_32: std_logic_vector(1 downto 0);
|
|||
-- states
|
|||
type count_state is (
|
|||
videoData,
|
|||
videoDataPreamble,
|
|||
videoDataGuardBand,
|
|||
dataIslandPreamble,
|
|||
dataIslandPreGuard,
|
|||
dataIslandPostGuard,
|
|||
dataIsland,
|
|||
controlData
|
|||
);
|
|||
signal state: count_state;
|
|||
signal clockCounter: integer range 0 to 2047;
|
|||
signal r : std_logic_vector(9 downto 0);
|
|||
signal g : std_logic_vector(9 downto 0);
|
|||
signal b : std_logic_vector(9 downto 0);
|
|||
begin
|
|||
-- data should be delayed for 11 clocks to allow preamble and guard band generation
|
|||
-- delay line inputs
|
|||
delayLineIn(39 downto 32) <= I_R;
|
|||
delayLineIn(31 downto 24) <= I_G;
|
|||
delayLineIn(23 downto 16) <= I_B;
|
|||
delayLineIn(15) <= I_HSYNC;
|
|||
delayLineIn(14) <= I_VSYNC;
|
|||
delayLineIn(13) <= not I_BLANK;
|
|||
delayLineIn(12) <= data;
|
|||
delayLineIn(11 downto 8) <= dataPacket0;
|
|||
delayLineIn(7 downto 4) <= dataPacket1;
|
|||
delayLineIn(3 downto 0) <= dataPacket2;
|
|||
-- delay line outputs
|
|||
ROut <= delayLineOut(39 downto 32);
|
|||
GOut <= delayLineOut(31 downto 24);
|
|||
BOut <= delayLineOut(23 downto 16);
|
|||
hSyncOut <= delayLineOut(15);
|
|||
vSyncOut <= delayLineOut(14);
|
|||
vdeOut <= delayLineOut(13);
|
|||
dataOut <= delayLineOut(12);
|
|||
dataPacket0Out <= delayLineOut(11 downto 8);
|
|||
dataPacket1Out <= delayLineOut(7 downto 4);
|
|||
dataPacket2Out <= delayLineOut(3 downto 0);
|
|||
vhSyncOut <= vSyncOut & hSyncOut;
|
|||
ctl_10 <= ctl1&ctl0;
|
|||
ctl_32 <= ctl3&ctl2;
|
|||
FSA: process(I_CLK_PIXEL) is
|
|||
begin
|
|||
if(rising_edge(I_CLK_PIXEL)) then
|
|||
if(prevBlank = '0' and i_BLANK = '1') then
|
|||
state <= controlData;
|
|||
clockCounter <= 0;
|
|||
else
|
|||
case state is
|
|||
when controlData =>
|
|||
if prevData = '0' and data = '1' then -- ok - data stared - needs data preamble
|
|||
state <= dataIslandPreamble;
|
|||
ctl0 <= '1';
|
|||
ctl1 <= '0';
|
|||
ctl2 <= '1';
|
|||
ctl3 <= '0';
|
|||
clockCounter <= 0;
|
|||
elsif prevBlank = '1' and I_BLANK = '0' then -- ok blank os out - start generation video preamble
|
|||
state <= videoDataPreamble;
|
|||
ctl0 <= '1';
|
|||
ctl1 <= '0';
|
|||
ctl2 <= '0';
|
|||
ctl3 <= '0';
|
|||
clockCounter <= 0;
|
|||
end if;
|
|||
when dataIslandPreamble => -- data island preable needed for 8 clocks
|
|||
if clockCounter = 8 then
|
|||
state <= dataIslandPreGuard;
|
|||
ctl0 <= '0';
|
|||
ctl1 <= '0';
|
|||
ctl2 <= '0';
|
|||
ctl3 <= '0';
|
|||
clockCounter <= 0;
|
|||
else
|
|||
clockCounter <= clockCounter + 1;
|
|||
end if;
|
|||
when dataIslandPreGuard => -- data island preguard needed for 2 clocks
|
|||
if clockCounter = 1 then
|
|||
state <= dataIsland;
|
|||
clockCounter <= 0;
|
|||
else
|
|||
clockCounter <= clockCounter + 1;
|
|||
end if;
|
|||
when dataIsland =>
|
|||
if clockCounter = 11 then -- ok we at the end of data island - post guard is needed
|
|||
state <= dataIslandPostGuard;
|
|||
clockCounter <= 0;
|
|||
elsif prevBlank = '1' and I_BLANK = '0' then -- something fails - no data were detected but blank os out
|
|||
state <= videoDataPreamble;
|
|||
ctl0 <= '1';
|
|||
ctl1 <= '0';
|
|||
ctl2 <= '0';
|
|||
ctl3 <= '0';
|
|||
clockCounter <= 0;
|
|||
elsif data = '0' then -- start count and count only when data is over
|
|||
clockCounter <= clockCounter + 1;
|
|||
end if;
|
|||
when dataIslandPostGuard => -- data island postguard needed for 2 clocks
|
|||
if clockCounter = 1 then
|
|||
state <= controlData;
|
|||
clockCounter <= 0;
|
|||
else
|
|||
clockCounter <= clockCounter + 1;
|
|||
end if;
|
|||
when videoDataPreamble => -- video data preable needed for 8 clocks
|
|||
if clockCounter = 8 then
|
|||
state <= videoDataGuardBand;
|
|||
ctl0 <= '0';
|
|||
ctl1 <= '0';
|
|||
ctl2 <= '0';
|
|||
ctl3 <= '0';
|
|||
clockCounter <= 0;
|
|||
else
|
|||
clockCounter <= clockCounter + 1;
|
|||
end if;
|
|||
when videoDataGuardBand => -- video data guard needed for 2 clocks
|
|||
if clockCounter = 1 then
|
|||
state <= videoData;
|
|||
clockCounter <= 0;
|
|||
else
|
|||
clockCounter <= clockCounter + 1;
|
|||
end if;
|
|||
when videoData =>
|
|||
if clockCounter = 11 then -- ok we at the end of video data - just switch to control
|
|||
state <= controlData;
|
|||
clockCounter <= 0;
|
|||
elsif I_BLANK = '1' then -- start count and count only when video is over
|
|||
clockCounter <= clockCounter + 1;
|
|||
end if;
|
|||
end case;
|
|||
end if;
|
|||
prevBlank <= I_BLANK;
|
|||
prevData <= data;
|
|||
end if;
|
|||
end process;
|
|||
blueout: b <=
|
|||
"1010001110" when (state = dataIslandPreGuard or state = dataIslandPostGuard) and vhSyncOut = "00" else
|
|||
"1001110001" when (state = dataIslandPreGuard or state = dataIslandPostGuard) and vhSyncOut = "01" else
|
|||
"0101100011" when (state = dataIslandPreGuard or state = dataIslandPostGuard) and vhSyncOut = "10" else
|
|||
"1011000011" when (state = dataIslandPreGuard or state = dataIslandPostGuard) and vhSyncOut = "11" else
|
|||
"1011001100" when state = videoDataGuardBand else
|
|||
enc0out;
|
|||
greenout: g <=
|
|||
"0100110011" when state = videoDataGuardBand else
|
|||
"0100110011" when state = dataIslandPreGuard or state = dataIslandPostGuard else
|
|||
enc1out;
|
|||
redout: r <=
|
|||
"1011001100" when state = videoDataGuardBand else
|
|||
"0100110011" when state = dataIslandPreGuard or state = dataIslandPostGuard else
|
|||
enc2out;
|
|||
delay_line: entity work.hdmi_delay_line
|
|||
port map (
|
|||
i_clk => I_CLK_PIXEL,
|
|||
i_d => delayLineIn,
|
|||
o_q => delayLineOut
|
|||
);
|
|||
dataenc: hdmidataencoder
|
|||
generic map (
|
|||
FREQ => FREQ,
|
|||
FS => FS,
|
|||
CTS => CTS,
|
|||
N => N
|
|||
)
|
|||
port map(
|
|||
i_pixclk => I_CLK_PIXEL,
|
|||
951 | markw | i_reset => I_RESET,
|
|
479 | markw | i_blank => I_BLANK,
|
|
i_hSync => I_HSYNC,
|
|||
i_vSync => I_VSYNC,
|
|||
i_audioL => I_AUDIO_PCM_L,
|
|||
i_audioR => I_AUDIO_PCM_R,
|
|||
977 | markw | I_VIDEO_ID_CODE => I_VIDEO_ID_CODE,
|
|
479 | markw | o_d0 => dataPacket0,
|
|
o_d1 => dataPacket1,
|
|||
o_d2 => dataPacket2,
|
|||
o_data => data
|
|||
);
|
|||
483 | markw | enc0: entity work.encoder
|
|
479 | markw | port map (
|
|
CLK => I_CLK_PIXEL,
|
|||
DATA => BOut,
|
|||
C => vhSyncOut,
|
|||
VDE => vdeOut,
|
|||
ADE => dataOut,
|
|||
AUX => dataPacket0Out,
|
|||
ENCODED => enc0out);
|
|||
483 | markw | enc1: entity work.encoder
|
|
479 | markw | port map (
|
|
CLK => I_CLK_PIXEL,
|
|||
DATA => GOut,
|
|||
C => ctl_10,
|
|||
VDE => vdeOut,
|
|||
ADE => dataOut,
|
|||
AUX => dataPacket1Out,
|
|||
ENCODED => enc1out);
|
|||
483 | markw | enc2: entity work.encoder
|
|
479 | markw | port map (
|
|
CLK => I_CLK_PIXEL,
|
|||
DATA => ROut,
|
|||
C => ctl_32,
|
|||
VDE => vdeOut,
|
|||
ADE => dataOut,
|
|||
AUX => dataPacket2Out,
|
|||
ENCODED => enc2out);
|
|||
483 | markw | o_r <= r;
|
|
o_g <= g;
|
|||
o_b <= b;
|
|||
479 | markw | ||
end rtl;
|