Zedboard HDMI v2

From Hamsterworks Wiki!

Jump to: navigation, search

This FPGA Project was finished in September 2013.

See Zedboard_VGA_HDMI for an updated project that includes colourspace conversion from RGB

I've finally come to grips with the Zedboard's ADV7511 HDMI transmitter. The pins connected on the Zynq that were labeled D0 through D15 in the schematics are actually D8 through D23 (verified on schematic). The forces the use of the YCrCb colour space, which I knew very little about.

The code below includes the register settings to run in YCbCr 422 mode, and output RGB to the HDMI port, working in DVI-D mode. The code is set up to display red, black, green, white and blue colour bars.

Zed hdmi v2.jpg

The missing ingredient was the register setting for xD0 - without it set to 3C the CbCr components are not captured.

Contents

Source files

This is a small project with only three files.

zedboard_hdmi.vhd

----------------------------------------------------------------------------------
-- Engineer: Mike Field <hamster@snap.net.nz>
-- 
-- Create Date:    06:01:06 10/02/2013 
--
-- Description: 
--      Drive the ADV7511 HDMI encoder directly from the PL fabric
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

Library UNISIM;
use UNISIM.vcomponents.all;

entity zedboard_hdmi is
    Port ( clk_100       : in  STD_LOGIC;
           hdmi_clk      : out  STD_LOGIC;
           hdmi_hsync    : out  STD_LOGIC;
           hdmi_vsync    : out  STD_LOGIC;
           hdmi_d        : out  STD_LOGIC_VECTOR (15 downto 0);
           hdmi_de       : out  STD_LOGIC;
           hdmi_int      : in   STD_LOGIC;
           hdmi_scl      : out  STD_LOGIC;
           hdmi_sda      : inout  STD_LOGIC);
end zedboard_hdmi;

architecture Behavioral of zedboard_hdmi is
   COMPONENT i2c_sender
   PORT(
      clk    : IN std_logic;
      resend : IN std_logic;    
      siod   : INOUT std_logic;      
      sioc   : OUT std_logic
   );
   END COMPONENT;

   signal blanking       : std_logic := '0';
   signal hsync          : std_logic := '0';
   signal vsync          : std_logic := '0';
   signal edge           : std_logic := '0';
   signal colour         : STD_LOGIC_VECTOR (23 downto 0);
   signal Y              : STD_LOGIC_VECTOR (15 downto 0);
   signal Cr             : STD_LOGIC_VECTOR (15 downto 0);
   signal Cb             : STD_LOGIC_VECTOR (15 downto 0);
   signal hdmi_clk_bits  : STD_LOGIC_VECTOR (1 downto 0);
   
   signal   hcounter    : unsigned(10 downto 0) := (others => '0');
   signal   vcounter    : unsigned(10 downto 0) := (others => '0');
   
   constant ZERO        : unsigned(10 downto 0) := (others => '0');
   signal   hVisible    : unsigned(10 downto 0);
   signal   hStartSync  : unsigned(10 downto 0);
   signal   hEndSync    : unsigned(10 downto 0);
   signal   hMax        : unsigned(10 downto 0);
   signal   hSyncActive : std_logic := '1';
   
   signal   vVisible    : unsigned(10 downto 0);
   signal   vStartSync  : unsigned(10 downto 0);
   signal   vEndSync    : unsigned(10 downto 0);
   signal   vMax        : unsigned(10 downto 0);
   signal   vSyncActive : std_logic := '1';
   
   signal clk_vgax2   : std_logic;
   signal clkfb       : std_logic;
   signal clk         : std_logic;
   
   -- Colours converted using The RGB -> YCbCr converter app found on Google Gadgets 
                                                                        --  Y   Cb  Cr
   constant C_BLACK      : std_logic_vector(23 downto 0) := x"108080";  --  16 128 128
   constant C_RED        : std_logic_vector(23 downto 0) := x"515AF0";  --  81  90 240
   constant C_GREEN      : std_logic_vector(23 downto 0) := x"AC2A1B";  -- 172  42  27
   constant C_BLUE       : std_logic_vector(23 downto 0) := x"20F076";  --  32 240 118
   constant C_WHITE      : std_logic_vector(23 downto 0) := x"EA8080";  -- 234 128 128
   
begin   
   -- Set the video mode to 1280x720x60Hz (75MHz pixel clock needed)
   hVisible    <= ZERO + 1280;
   hStartSync  <= ZERO + 1280+72;
   hEndSync    <= ZERO + 1280+72+80;
   hMax        <= ZERO + 1280+72+80+216-1;
   vSyncActive <= '1';

   vVisible    <= ZERO + 720;
   vStartSync  <= ZERO + 720+3;
   vEndSync    <= ZERO + 720+3+5;
   vMax        <= ZERO + 720+3+5+22-1;
   hSyncActive <= '1';

colour_proc: process(hcounter,vcounter)
  begin
   if hcounter < 256 then
      colour <= C_RED;
   elsif hcounter < 512 then
      colour <= C_BLACK;
   elsif hcounter < 768 then
      colour <= C_GREEN;
   elsif hcounter < 1024 then
      colour <= C_WHITE;
   else
      colour <= C_BLUE;
   end if;
  end process;

   -- there is a 16 bit interface into the HDMI transmitter, although I only use 8 bits
   Y   <= colour(23 downto 16) & x"00";
   Cb  <= colour(15 downto  8) & x"00";
   Cr  <= colour( 7 downto  0) & x"00";
      
vga_clkx2_process: process (clk_vgax2)
   begin
      if rising_edge(clk_VGAx2) then 
         ---------------------------------------------------------------------------
         -- signal generation for the HDMI encoder
         --
         -- Transfer on rising edge  of clock Y
         --          on falling edge of clock Either Cr or Cb 
         --
         -- Because I am a wimp I don't use any DDR except for generating the DDR clk.
         ----------------------------------------------------------------------------
         if edge =  '0' then
            edge <= '1';
            hdmi_clk_bits <= "11";
            if blanking = '1' then 
               hdmi_d <= (others => '0');
               hdmi_de <= '0';
            else
               hdmi_d  <= Y;
               hdmi_de <= '1';
            end if;
         else
            edge <= '0';
            hdmi_clk_bits <= "00";
            if blanking = '1' then 
               hdmi_d <= (others => '0');
               hdmi_de <= '0';
            else
               if hcounter(0) = '0' then 
                  hdmi_d <= Cr;
               else
                  hdmi_d <= Cb;
               end if;
               hdmi_de <= '1';
            end if;
         end if;
         hdmi_hsync <= hsync;
         hdmi_vsync <= vsync;


         ------------------------------------------------------------------------
         -- VGA Signal Generation
         -- We only update when the second clock edge has been sent 
         --- to the HDMI encoder
         ------------------------------------------------------------------------
         if edge =  '1' then
            if vcounter >= vVisible then 
               blanking <= '1';
            elsif hcounter >= hVisible then 
               blanking <= '1';
            else
               blanking <= '0';
            end if;
            
            -- Generate the sync Pulses
            if vcounter = vStartSync then 
               vSync <= vSyncActive;
            elsif vCounter = vEndSync then
               vSync <= not(vSyncActive);
            end if;

            if hcounter = hStartSync then 
               hSync <= hSyncActive;
            elsif hCounter = hEndSync then
               hSync <= not(hSyncActive);
            end if;

            -- Advance the position counters
            IF hCounter = hMax  THEN
               -- starting a new line
               hCounter <= (others => '0');
               IF vCounter = vMax THEN
                  vCounter <= (others => '0');
               ELSE
                  vCounter <= vCounter + 1;
               END IF;
            ELSE
               hCounter <= hCounter + 1;
            END IF;
         end if;
      end if;
   end process;
   

   ODDR_inst : ODDR
   generic map(
      DDR_CLK_EDGE => "OPPOSITE_EDGE", INIT => '0',SRTYPE => "SYNC") 
   port map (
      Q => hdmi_clk, 
      C => clk_VGAx2,
      D1 => hdmi_clk_bits(0),
      D2 => hdmi_clk_bits(1),
      CE => '1', R => '0', S => '0'
   );
   
   Inst_i2c_sender: i2c_sender PORT MAP(
      clk => clk,
      resend => '0',
      sioc => hdmi_scl,
      siod => hdmi_sda
   );
   
   -- Generate a 130MHz and 100Mhz clock from the input.
   PLLE2_BASE_inst : PLLE2_BASE
   generic map (
      BANDWIDTH => "OPTIMIZED",  -- OPTIMIZED, HIGH, LOW
      CLKFBOUT_MULT  => 9,       -- Multiply value for all CLKOUT, (2-64)
      CLKFBOUT_PHASE => 0.0,     -- Phase offset in degrees of CLKFB, (-360.000-360.000).
      CLKIN1_PERIOD  => 10.0,    -- Input clock period in ns to ps resolution (i.e. 33.333 is 30 MHz).
      -- CLKOUT0_DIVIDE - CLKOUT5_DIVIDE: Divide amount for each CLKOUT (1-128)
      CLKOUT0_DIVIDE => 9,
      CLKOUT1_DIVIDE => 6,
      CLKOUT2_DIVIDE => 1,
      CLKOUT3_DIVIDE => 1,
      CLKOUT4_DIVIDE => 1,
      CLKOUT5_DIVIDE => 1,
      -- CLKOUT0_DUTY_CYCLE - CLKOUT5_DUTY_CYCLE: Duty cycle for each CLKOUT (0.001-0.999).
      CLKOUT0_DUTY_CYCLE => 0.5,
      CLKOUT1_DUTY_CYCLE => 0.5,
      CLKOUT2_DUTY_CYCLE => 0.5,
      CLKOUT3_DUTY_CYCLE => 0.5,
      CLKOUT4_DUTY_CYCLE => 0.5,
      CLKOUT5_DUTY_CYCLE => 0.5,
      -- CLKOUT0_PHASE - CLKOUT5_PHASE: Phase offset for each CLKOUT (-360.000-360.000).
      CLKOUT0_PHASE => 0.0,
      CLKOUT1_PHASE => 0.0,
      CLKOUT2_PHASE => 0.0,
      CLKOUT3_PHASE => 0.0,
      CLKOUT4_PHASE => 0.0,
      CLKOUT5_PHASE => 0.0,
      DIVCLK_DIVIDE => 1,        -- Master division value, (1-56)
      REF_JITTER1 => 0.0,        -- Reference input jitter in UI, (0.000-0.999).
      STARTUP_WAIT => "FALSE"    -- Delay DONE until PLL Locks, ("TRUE"/"FALSE")
   )
   port map (
      -- Clock Outputs: 1-bit (each) output: User configurable clock outputs
      CLKOUT0  => clk,
      CLKOUT1  => clk_VGAx2,
      CLKOUT2  => open,
      CLKOUT3  => open,
      CLKOUT4  => open,
      CLKOUT5  => open,
      CLKFBOUT => clkfb,   -- 1-bit output: Feedback clock
      LOCKED   => open,    -- 1-bit output: LOCK
      CLKIN1   => clk_100, -- 1-bit input: Input clock
      PWRDWN   => '0',     -- 1-bit input: Power-down
      RST      => '0',     -- 1-bit input: Reset
      CLKFBIN  => clkfb    -- 1-bit input: Feedback clock
   );
end Behavioral;

i2c_sender.vhd

----------------------------------------------------------------------------------
-- Engineer: <mfield@concepts.co.nz
-- 
-- Description: Send register writes over an I2C-like interface
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity i2c_sender is
    Port ( clk    : in    STD_LOGIC;    
           resend : in    STD_LOGIC;
           sioc   : out   STD_LOGIC;
           siod   : inout STD_LOGIC
    );
end i2c_sender;

architecture Behavioral of i2c_sender is
   signal   divider           : unsigned(7 downto 0)  := (others => '0'); 
    -- this value gives nearly 200ms cycles before the first register is written
   signal   initial_pause     : unsigned(22 downto 0) := (others => '0');
   signal   finished          : std_logic := '0';
   signal   address           : std_logic_vector(7 downto 0)  := (others => '0');
   signal   clk_first_quarter : std_logic_vector(28 downto 0) := (others => '1');
   signal   clk_last_quarter  : std_logic_vector(28 downto 0) := (others => '1');
   signal   busy_sr           : std_logic_vector(28 downto 0) := (others => '1');
   signal   data_sr           : std_logic_vector(28 downto 0) := (others => '1');
   signal   tristate_sr       : std_logic_vector(28 downto 0) := (others => '0');
   signal   reg_value         : std_logic_vector(15 downto 0)  := (others => '0');
   constant i2c_wr_addr       : std_logic_vector(7 downto 0)  := x"72";

   type reg_value_pair is ARRAY(0 TO 63) OF std_logic_vector(15 DOWNTO 0);    
   
   signal reg_value_pairs : reg_value_pair := (
            -------------------
            -- Powerup please!
            -------------------
            x"4110", 
            ---------------------------------------
            -- These valuse must be set as follows
            ---------------------------------------
            x"9803", x"9AE0", x"9C30", x"9D61", x"A2A4", x"A3A4", x"E0D0", x"5512", x"F900",
            
            ---------------
            -- Input mode
            ---------------
            x"1506", -- YCbCr 422, DDR, External sync
            x"4810", -- Left justified data (D23 downto 8)
            x"1637", -- 8 bit style 2, 1st half on rising edge - YCrCb clipping
            x"1700", -- output aspect ratio 16:9, external DE 
            x"D03C", -- auto sync data - must be set for DDR modes.
            ---------------
            -- Output mode
            ---------------
            x"AF04", -- DVI mode
            x"4c04", -- Deep colour off (HDMI only?)     - not needed
            x"4000", -- Turn off additional data packets - not needed

       -----------------------------------------------------------------
       -- As a start, here's the identity Matrix a <= A, b <= B, c <= C
       -----------------------------------------------------------------
       --   -- ([R or Cr]* A1 +   [G or Y] * A2   +  [B or Cb] * A3)/4096 +   A4    =  Red or Cr
        --   x"18A8", x"1900",   x"1A00", x"1B00",   x"1C00", x"1D00",   x"1E00", x"1F00",
       --
       --   -- ([R or Cr]* B1 +   [G or Y] * B2   +  [B or Cb] * B3)/4096 +   B4    =  Green or Y
       --   x"2000", x"2100",   x"2208", x"2300",   x"2400", x"2500",   x"2604", x"2700",
       --   
       --   -- ([R or Cr]* C1 +   [G or Y] * C2   +  [B or Cb] * C3)/4096 +   C4    =  Blue or Cb
       --   x"2808", x"2900",   x"2A00", x"2B00",   x"2C08", x"2D00",   x"2E04", x"2F00",

       --------------------------------------------------------------
       -- Here is the YCrCb => RGB conversion, as per programming guide
       -- This is table 57 - HDTV YCbCr (16 to 255) to RGB (0 to 255)
       --------------------------------------------------------------
            -- (Cr * A1       +      Y * A2       +     Cb * A3)/4096 +     A4    =  Red
             x"18E7", x"1934",   x"1A04", x"1BAD",   x"1C00", x"1D00",   x"1E1C", x"1F1B",

            -- (Cr * B1       +      Y * B2       +     Cb * B3)/4096 +     B4    =  Green
            x"201D", x"21DC",   x"2204", x"23AD",   x"241F", x"2524",   x"2601", x"2735",
            
            -- (Cr * C1       +      Y * C2       +     Cb * C3)/4096 +     C4    =  Blue
            x"2800", x"2900",   x"2A04", x"2BAD",   x"2C08", x"2D7C",   x"2E1B", x"2F77",


            -- Extra space filled with FFFFs to signify end of data
            x"FFFF", x"FFFF", x"FFFF", x"FFFF", x"FFFF", x"FFFF", x"FFFF",
            x"FFFF", x"FFFF", x"FFFF", x"FFFF", x"FFFF", x"FFFF", x"FFFF", x"FFFF",
            x"FFFF", x"FFFF", x"FFFF", x"FFFF", x"FFFF", x"FFFF", x"FFFF"
   );
begin

registers: process(clk)
   begin
      if rising_edge(clk) then
         reg_value <= reg_value_pairs(to_integer(unsigned(address)));
      end if;
   end process;

i2c_tristate: process(data_sr, tristate_sr)
   begin
      if tristate_sr(tristate_sr'length-1) = '0' then
         siod <= data_sr(data_sr'length-1);
      else
         siod <= 'Z';
      end if;
   end process;
   
   with divider(divider'length-1 downto divider'length-2) 
      select sioc <= clk_first_quarter(clk_first_quarter'length -1) when "00",
                     clk_last_quarter(clk_last_quarter'length -1)   when "11",
                     '1' when others;
                     
i2c_send:   process(clk)
   begin
      if rising_edge(clk) then
         if resend = '1' then 
            address           <= (others => '0');
            clk_first_quarter <= (others => '1');
            clk_last_quarter  <= (others => '1');
            busy_sr           <= (others => '0');
            divider           <= (others => '0');
            initial_pause     <= (others => '0');
            finished <= '0';
         end if;

         if busy_sr(busy_sr'length-1) = '0' then
            if initial_pause(initial_pause'length-1) = '0' then
               initial_pause <= initial_pause+1;
            elsif finished = '0' then
               if divider = "11111111" then
                  divider <= (others =>'0');
                  if reg_value(15 downto 8) = "11111111" then
                     finished <= '1';
                  else
                     -- move the new data into the shift registers
                     clk_first_quarter <= (others => '0'); clk_first_quarter(clk_first_quarter'length-1) <= '1';
                     clk_last_quarter <= (others => '0');  clk_last_quarter(0) <= '1';
                     
                     --             Start    Address        Ack        Register           Ack          Value         Ack    Stop
                     tristate_sr <= "0" & "00000000"  & "1" & "00000000"             & "1" & "00000000"             & "1"  & "0";
                     data_sr     <= "0" & i2c_wr_addr & "1" & reg_value(15 downto 8) & "1" & reg_value( 7 downto 0) & "1"  & "0";
                     busy_sr     <= (others => '1');
                     address     <= std_logic_vector(unsigned(address)+1);
                  end if;
               else
                  divider <= divider+1; 
               end if;
            end if;
         else
            if divider = "11111111" then   -- divide clkin by 255 for I2C
               tristate_sr       <= tristate_sr(tristate_sr'length-2 downto 0) & '0';
               busy_sr           <= busy_sr(busy_sr'length-2 downto 0) & '0';
               data_sr           <= data_sr(data_sr'length-2 downto 0) & '1';
               clk_first_quarter <= clk_first_quarter(clk_first_quarter'length-2 downto 0) & '1';
               clk_last_quarter  <= clk_last_quarter(clk_first_quarter'length-2 downto 0) & '1';
               divider           <= (others => '0');
            else
               divider <= divider+1;
            end if;
         end if;
      end if;
   end process;
end Behavioral;

zedboard.ucf

NET CLK_100       LOC = Y9   |IOSTANDARD=LVCMOS33;  # "GCLK"
NET "clk_100" TNM_NET = clk_100;
TIMESPEC TS_clk_100 = PERIOD "clk_100" 10 ns HIGH 50%;


NET HDMI_CLK        LOC = W18  | IOSTANDARD=LVCMOS33;  # "HD-CLK"
NET HDMI_D<0>       LOC = Y13  | IOSTANDARD=LVCMOS33;  # "HD-D0"
NET HDMI_D<1>       LOC = AA13 | IOSTANDARD=LVCMOS33;  # "HD-D1"
NET HDMI_D<2>       LOC = AA14 | IOSTANDARD=LVCMOS33;  # "HD-D2"
NET HDMI_D<3>       LOC = Y14  | IOSTANDARD=LVCMOS33;  # "HD-D3"
NET HDMI_D<4>       LOC = AB15 | IOSTANDARD=LVCMOS33;  # "HD-D4"
NET HDMI_D<5>       LOC = AB16 | IOSTANDARD=LVCMOS33;  # "HD-D5"
NET HDMI_D<6>       LOC = AA16 | IOSTANDARD=LVCMOS33;  # "HD-D6"
NET HDMI_D<7>       LOC = AB17 | IOSTANDARD=LVCMOS33;  # "HD-D7"
NET HDMI_D<8>       LOC = AA17 | IOSTANDARD=LVCMOS33;  # "HD-D8"
NET HDMI_D<9>       LOC = Y15  | IOSTANDARD=LVCMOS33;  # "HD-D9"
NET HDMI_D<10>      LOC = W13  | IOSTANDARD=LVCMOS33;  # "HD-D10"
NET HDMI_D<11>      LOC = W15  | IOSTANDARD=LVCMOS33;  # "HD-D11"
NET HDMI_D<12>      LOC = V15  | IOSTANDARD=LVCMOS33;  # "HD-D12"
NET HDMI_D<13>      LOC = U17  | IOSTANDARD=LVCMOS33;  # "HD-D13"
NET HDMI_D<14>      LOC = V14  | IOSTANDARD=LVCMOS33;  # "HD-D14"
NET HDMI_D<15>      LOC = V13  | IOSTANDARD=LVCMOS33;  # "HD-D15"
NET HDMI_DE         LOC = U16  | IOSTANDARD=LVCMOS33;  # "HD-DE"
NET HDMI_HSYNC      LOC = V17  | IOSTANDARD=LVCMOS33;  # "HD-HSYNC"
NET HDMI_VSYNC      LOC = W17  | IOSTANDARD=LVCMOS33;  # "HD-VSYNC"
NET HDMI_INT        LOC = W16  | IOSTANDARD=LVCMOS33;  # "HD-INT"
NET HDMI_SCL        LOC = AA18 | IOSTANDARD=LVCMOS33;  # "HD-SCL"
NET HDMI_SDA        LOC = Y16  | IOSTANDARD=LVCMOS33 | PULLUP;  # "HD-SDA"
#NET HDMI_SPDIF      LOC = U15  | IOSTANDARD=LVCMOS33;  # "HD-SPDIF"
#NET HDMI_SPDIFO     LOC = Y18  | IOSTANDARD=LVCMOS33;  # "HD-SPDIFO"

Test programs

csc.c

I've also written a small test program to verify the Colour Space Conversion register settings. Here is the program's output:

hamster@LogiPi-Dev:~/csc$ ./csc
Constants in hex
0734 04ad 0000 1c1b
1ddc 04ad 1f24 0135
0000 04ad 087c 1b77

Constants as floats
  1.8008   1.1689   0.0000  -0.9736
 -0.5352   1.1689  -0.2148   0.3018
  0.0000   1.1689   2.1211  -1.1338

             Cr     Y     Cb   =>     R     G     B
     Black  0.502  0.063  0.502 =>  0.004  0.000  0.004
       Red  0.941  0.318  0.353 =>  1.000  0.094  0.000
     Green  0.106  0.675  0.165 =>  0.006  0.998  0.004
      Blue  0.463  0.125  0.941 =>  0.006  0.000  1.000
     White  0.502  0.918  0.502 =>  1.000  0.998  1.000

hamster@LogiPi-Dev:~/csc$

And here is the source:

/****************************************************************
* csc.c : testing Colour space conversion settings on the ADV7511
*
* Author : Mike Field [hamster@snap.net.nz]
****************************************************************/

#include <stdio.h>

int main(int c, char *v[])
{

   // These are the register values from the ADV7511 for Colour Space
   // Conversion. I have not paid any attention to the constant's scale
   // bits in Register 18[6:5]
   int reg_values[] = {
   0x18E7, 0x1934, 0x1A04, 0x1BAD, 0x1C00, 0x1D00, 0x1E1C, 0x1F1B,
   0x201D, 0x21DC, 0x2204, 0x23AD, 0x241F, 0x2524, 0x2601, 0x2735,
   0x2800, 0x2900, 0x2A04, 0x2BAD, 0x2C08, 0x2D7C, 0x2E1B, 0x2F77
   };

   struct test_vector {
     char *name;
     int value;
   } test_values[] = {
     {"Black", 0x108080},  //  16 128 128
     {"Red",   0x515AF0},  //  81  90 240  RED
     {"Green", 0xAC2A1B},  // 172  42  27 GREEN
     {"Blue",  0x20F076},  //  32 240 118 BLUE
     {"White", 0xEA8080}   // 234 128 128 WHITE
   };

   unsigned char values[256];
   int csc_int[12];
   float csc_float[12];
   int i;

   for(i =0; i < sizeof(reg_values)/sizeof(int); i++){
     values[reg_values[i]/256] = reg_values[i] & 0xFF;
   }

   for(i = 0; i < 12; i++)
   {
     csc_int[i] =  (values[24+i*2]&0x1f) << 8;
     csc_int[i] += (values[24+i*2+1]);
   }

   printf("Constants in hex\n");
   for(i=0;i<12;i+=4)
     printf("%04x %04x %04x %04x\n",csc_int[i],csc_int[i+1],csc_int[i+2], csc_int[i+3] );
   printf("\n");

   for(i=0;i<12;i+=1) {
     csc_float[i] = csc_int[i]/4096.0;
     if(csc_int[i] & 0x1000)
       csc_float[i] -= 2.0;
     csc_float[i] *= 4.0;
   }
   printf("Constants as floats\n");
   for(i=0;i<12;i+=4)
     printf("%8.4f %8.4f %8.4f %8.4f\n",csc_float[i],csc_float[i+1],csc_float[i+2], csc_float[i+3] );
   printf("\n");

   printf("%10s   Cr     Y     Cb   =>     R     G     B\n","");
   for(i=0; i < sizeof(test_values)/sizeof(struct test_vector); i++) {
      float a ,b,c;
      float A,B,C;
      b = ((test_values[i].value>>16) & 0xFF)/255.0;
      c = ((test_values[i].value>> 8) & 0xFF)/255.0;
      a = ((test_values[i].value>> 0) & 0xFF)/255.0;
      A = a*csc_float[0] + b *csc_float[1] + c * csc_float[2] + csc_float[3];
      B = a*csc_float[4] + b *csc_float[5] + c * csc_float[6] + csc_float[7];
      C = a*csc_float[8] + b *csc_float[9] + c * csc_float[10] + csc_float[11];
      if(A < 0.0) A = 0.0;
      if(B < 0.0) B = 0.0;
      if(C < 0.0) C = 0.0;
      if(A > 1.0) A = 1.0;
      if(B > 1.0) B = 1.0;
      if(C > 1.0) C = 1.0;
      printf("%10s %6.3f %6.3f %6.3f => %6.3f %6.3f %6.3f\n", test_values[i].name, a, b, c, A, B, C);
   }
   return 0;
}

Personal tools