Electronic – Generating video with ZYNQ, using IP block design

dmafpgavideovivadoxilinx

I am trying to implement a video streamer on Digilent ZYBO board that has Xilinx ZYNQ 7010. By the way, reason of this thing is to test the quality of an encoder board. What I want is to:

  • Generate a RAM Block to store pre-determined video data.
  • Stream out its contents from Pmod connectors (probably using AXI4-Stream Video Out block), using DMA.

Video features are: 1024×768, 720p, 30fps for now. I may have to change them later.

I have found some design on web (please check the figure below). But since it generates random video, I have to modify (I mean, replace it with some other blocks) Test Pattern Generator block, but I have no idea how. What kind of design process should I follow? I have limited time and knowledge about block designing and HDLs, so any help is appreciated.

enter image description here

Best Answer

I wrote this TPG for a project of mine. Maybe it can help you. Create a new Vivado Project. Import the code and generate a IP. Now you can import it into our project.

The output is raw Bayer, but it can easily be adopted to output RBG or YUV.

-------------------------------------------------------------------------------
-- Entity:    testpattern_axi
-- Autor:     Reto Meier [mir3@bfh.ch]
-- Date:      2016.02.03
-- Project:   Gazelle
--
-- Description:
-- This test pattern generator makes a similar pattern as the camera would 
-- generate. It is allmost the same code as camera_testpattern, but as output
-- is not CIF but AXI
-------------------------------------------------------------------------------

library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;   
    use ieee.math_real.all;

package testpattern_axi_pkg is

    component testpattern_axi is
        generic(
            img_height: integer := 480;
            img_width: integer := 640;
            brake_line: integer := 100;
            brake_frame: integer := 500;
            brake_pre_frame: integer := 100;
            data_length: integer := 12
        );

        port(   
            clk: in std_logic;
            o_valid: out std_logic;
            o_user: out std_logic;
            o_last: out std_logic;
            o_ready: in std_logic;
            o_data: out std_logic_vector(data_length-1 downto 0)
        );
    end component testpattern_axi;

end package testpattern_axi_pkg;


-------------------------------------------------------------------------------
library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all; 
    use ieee.math_real.all;   

entity testpattern_axi is
    generic(
        img_height: integer := 480;
        img_width: integer := 640;
        brake_line: integer := 100;
        brake_frame: integer := 500;
        brake_pre_frame: integer := 100;
        data_length: integer := 16
    );

    port(   
        clk: in std_logic;
        o_valid: out std_logic;
        o_user: out std_logic;
        o_last: out std_logic;
        o_ready: in std_logic;
        o_data: out std_logic_vector(data_length-1 downto 0)
    );
end entity testpattern_axi;


-------------------------------------------------------------------------------
architecture rtl of testpattern_axi is

    constant cnt_max: integer := 32000;

    type state_type is (s_frame_brake, s_pre_frame_brake, s_line_brake, s_line);  --type of state machine. 

    type reg_type is record
        cnt: unsigned(integer(floor(log2(real(cnt_max)))) downto 0);
        cnt_lines: unsigned(integer(floor(log2(real(cnt_max)))) downto 0);
        r, g, b: std_logic;
        std_line: std_logic_vector(cnt_lines'range);
        std_cnt: std_logic_vector(cnt'range);
        state: state_type;
    end record reg_type;

    constant init_values: reg_type :=(   
        cnt => (others =>'0'),
        cnt_lines => (others=>'0'),
        r => '0', 
        g => '0',
        b => '0',
        std_line => (others =>'0'),
        std_cnt => (others =>'0'),
        state => s_frame_brake);

    signal r, rin: reg_type := init_values;


begin

    combinational: process(r, o_ready)
        variable v: reg_type;
    begin
        v := r;  

        if o_ready = '1' then
            v.cnt := v.cnt + 1;
        end if;

        -- make the brakes and lines
        case v.state is 
            when s_frame_brake =>
                if v.cnt = to_unsigned(brake_frame, v.cnt'length) then
                    v.state := s_pre_frame_brake;
                    v.cnt := to_unsigned(0, v.cnt'length);
                end if;

            when s_pre_frame_brake => 
                if v.cnt = to_unsigned(brake_pre_frame, v.cnt'length) then
                    v.state := s_line;
                    v.cnt := to_unsigned(0, v.cnt'length); 
                end if;

            when s_line => 
                if v.cnt = to_unsigned(img_width, v.cnt'length) then
                    v.cnt := to_unsigned(0, v.cnt'length);
                    if v.cnt_lines = to_unsigned(img_height-1, v.cnt_lines'length) then
                        v.state := s_frame_brake;
                        v.cnt_lines := to_unsigned(0, v.cnt_lines'length);
                    else
                        v.state := s_line_brake;
                        v.cnt_lines := v.cnt_lines + 1;
                    end if;
                end if;

            when s_line_brake => 
                if v.cnt = to_unsigned(brake_line, v.cnt'length) then
                    v.state := s_line;
                    v.cnt := to_unsigned(0, v.cnt'length);
                end if;

        end case;


        -- generate the color pattern according to the position in the line
        if v.cnt > to_unsigned(img_width/8*7-1,v.cnt'length) then
            v.r := '0';
            v.g := '0';
            v.b := '0';
        elsif v.cnt > to_unsigned(img_width/8*6-1,v.cnt'length) then
            v.r := '0';
            v.g := '0';
            v.b := '1';
        elsif v.cnt > to_unsigned(img_width/8*5-1,v.cnt'length) then
            v.r := '1';
            v.g := '0';
            v.b := '0';
        elsif v.cnt > to_unsigned(img_width/8*4-1,v.cnt'length) then
            v.r := '1';
            v.g := '0';
            v.b := '1';
        elsif v.cnt > to_unsigned(img_width/8*3-1,v.cnt'length) then
            v.r := '0';
            v.g := '1';
            v.b := '0';
        elsif v.cnt > to_unsigned(img_width/8*2-1,v.cnt'length) then
            v.r := '0';
            v.g := '1';
            v.b := '1';
        elsif v.cnt > to_unsigned(img_width/8*1-1,v.cnt'length) then
            v.r := '1';
            v.g := '1';
            v.b := '0';
        else
            v.r := '1';
            v.g := '1';
            v.b := '1';
        end if;

        -- generate the output
        case v.state is 
            when s_line => 
                o_valid <= '1';

                if v.cnt_lines = to_unsigned(0, v.cnt_lines'length) and 
                   v.cnt = to_unsigned(0, v.cnt'length) then
                    o_user <= '1';
                else
                    o_user <= '0';
                end if;

                if v.cnt = to_unsigned(img_width-1, v.cnt'length) then
                    o_last <= '1';
                else
                    o_last <= '0';
                end if;


                v.std_line := std_logic_vector(v.cnt_lines);
                v.std_cnt := std_logic_vector(v.cnt);

                if v.std_line(0) = '0' then
                    if v.std_cnt(0) = '0' then
                        if v.b = '1' then
                            o_data <= (others => '1');
                        else
                            o_data <= (others => '0');
                        end if;
                    else
                        if v.g = '1' then
                            o_data <= (others => '1');
                        else
                            o_data <= (others => '0');
                        end if;
                    end if;
                else
                    if v.std_cnt(0) = '0' then
                        if v.g = '1' then
                            o_data <= (others => '1');
                        else
                            o_data <= (others => '0');
                        end if;
                    else
                        if v.r = '1' then
                            o_data <= (others => '1');
                        else
                            o_data <= (others => '0');
                        end if;
                    end if;                
                end if;

            when others => 
                o_valid <= '0';
                o_user <= '0';
                o_last <= '0';
                o_data <= (others => '0');
        end case;

        rin <= v;
    end process combinational;




    sequential: process(clk) -- sequential process (not need to edit)
    begin
        if rising_edge(clk) then
            r <= rin;
        end if;
    end process sequential;

end architecture rtl;