2
\$\begingroup\$

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: 1024x768, 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

\$\endgroup\$
  • \$\begingroup\$ The simple answer is to replace the video sample generator with your own module, generating a simple image, for that you need to know the format of the streaming video which is well documented. I am afraid there is no other way than finding another module that does the exact same thing you want to do. \$\endgroup\$ – FarhadA Apr 8 '16 at 6:43
  • \$\begingroup\$ Check out xilinx.com/products/intellectual-property/tpg.html it has exactly what you are looking for \$\endgroup\$ – FarhadA Apr 8 '16 at 6:46
  • \$\begingroup\$ @FarhadA I have just checked what you suggested. But I don't have a full license and it seems that it is obligatory to use Video Test Pattern Generator. \$\endgroup\$ – ddyn Apr 8 '16 at 6:55
  • \$\begingroup\$ Are you using WebPack? because this is what it says in the license section of the IP: Licensing and Ordering Information This Xilinx® LogiCORE™ IP module is provided at no cost under the terms of the Xilinx Core License Agreement. The module is shipped as part of the Vivado Design Suite. For full access to all core functionalities in simulation and in hardware, you must request a free license for the core. Contact your local Xilinx sales representative for information about pricing and availability. \$\endgroup\$ – FarhadA Apr 8 '16 at 9:48
  • \$\begingroup\$ Just checked my WEBPACK Vivado 2015.01 and it has the "Test Pattern Generator" module (that you have in your block) included in the license. If you double click on the IP, you will be able to modify the parameters of the IP and get what you are looking for. \$\endgroup\$ – FarhadA Apr 8 '16 at 11:31
2
\$\begingroup\$

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;
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.