07-30-2019 06:57 AM
I created a video IP using Vivado HLS 2018.3. It has AXI4-Stream data interfaces.
This IP works correctly when added to a block design (Vivado 2018.3)
It receives AXI4-Stream input video and transfers it to a VDMA without error.
Now, I want to include my IP in a block design free project which has no AXI4-Stream communication at all.
My idea was to create a custom module to emulate a AXI4-Stream protocol given that I know hsize and vsize. Here's my code:
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use IEEE.std_logic_unsigned.ALL; entity data_to_axis_v2_0_M00_AXIS is generic ( -- Users to add parameters here -- User parameters ends -- Do not modify the parameters beyond this line -- Width of S_AXIS address bus. The slave accepts the read and write addresses of width C_M_AXIS_TDATA_WIDTH. C_M_AXIS_TDATA_WIDTH : integer := 32; -- Start count is the number of clock cycles the master will wait before initiating/issuing any transaction. C_M_START_COUNT : integer := 32 ); port ( -- Users to add ports here dataIn : in STD_LOGIC_VECTOR (C_M_AXIS_TDATA_WIDTH-1 downto 0); M_AXIS_TUSER : out std_logic_vector(0 downto 0); HSIZE : in std_logic_vector(31 downto 0); VSIZE : in std_logic_vector(31 downto 0); -- User ports ends -- Do not modify the ports beyond this line -- Global ports M_AXIS_ACLK : in std_logic; -- M_AXIS_ARESETN : in std_logic; -- Master Stream Ports. TVALID indicates that the master is driving a valid transfer, A transfer takes place when both TVALID and TREADY are asserted. M_AXIS_TVALID : out std_logic; -- TDATA is the primary payload that is used to provide the data that is passing across the interface from the master. M_AXIS_TDATA : out std_logic_vector(C_M_AXIS_TDATA_WIDTH-1 downto 0); -- TSTRB is the byte qualifier that indicates whether the content of the associated byte of TDATA is processed as a data byte or a position byte. M_AXIS_TSTRB : out std_logic_vector((C_M_AXIS_TDATA_WIDTH/8)-1 downto 0); -- TLAST indicates the boundary of a packet. M_AXIS_TLAST : out std_logic; -- TREADY indicates that the slave can accept a transfer in the current cycle. M_AXIS_TREADY : in std_logic ); end data_to_axis_v2_0_M00_AXIS; architecture implementation of data_to_axis_v2_0_M00_AXIS is -- Total number of output data signal i_hsize : integer; signal i_vsize : integer; signal NUMBER_OF_IMAGE_DATA : integer; -- AXIS signal axis_tvalid : std_logic; signal axis_tdata : std_logic_vector(C_M_AXIS_TDATA_WIDTH-1 downto 0); signal axis_tlast : std_logic; signal axis_tuser : std_logic_vector(0 downto 0); -- Data counters signal line_counter : unsigned(31 downto 0); signal data_counter : unsigned(31 downto 0); -- Reset counter signal reset_counter : unsigned(7 downto 0); signal reset_disabled : std_logic; begin -- Integer values i_hsize <= to_integer(unsigned(HSIZE)); i_vsize <= to_integer(unsigned(VSIZE)); NUMBER_OF_IMAGE_DATA <= i_hsize*i_vsize; -- I/O Connections assignments M_AXIS_TVALID <= axis_tvalid; M_AXIS_TDATA <= axis_tdata; M_AXIS_TLAST <= axis_tlast; M_AXIS_TUSER <= axis_tuser; M_AXIS_TSTRB <= (others => '1'); -- TDATA tdata_p: process(M_AXIS_ACLK) begin if (rising_edge(M_AXIS_ACLK)) then if (M_AXIS_ARESETN = '0') then axis_tdata <= (others => '0'); else if ((axis_tvalid='1') and (M_AXIS_TREADY='1')) then axis_tdata <= dataIn; end if; end if; end if; end process tdata_p; -- Count number of cycles after reset reset_p: process (M_AXIS_ACLK) begin if (rising_edge(M_AXIS_ACLK)) then if (M_AXIS_ARESETN = '0') then reset_disabled <= '0'; reset_counter <= (others => '0'); else reset_counter <= reset_counter + 1; if (reset_counter = C_M_START_COUNT) then reset_disabled <= '1'; end if; end if; end if; end process reset_p; -- TVALID tvalid_p: process(M_AXIS_ACLK) begin if (rising_edge(M_AXIS_ACLK)) then if (M_AXIS_ARESETN = '0') then axis_tvalid <= '0'; else if (reset_disabled = '1') then axis_tvalid <= '1'; end if; end if; end if; end process tvalid_p; -- TLAST and TUSER tlast_tuser_p: process(M_AXIS_ACLK) begin if (rising_edge(M_AXIS_ACLK)) then if (M_AXIS_ARESETN = '0') then line_counter <= (others => '1'); data_counter <= (others => '1'); else if ((axis_tvalid='1') and (M_AXIS_TREADY='1')) then if (data_counter = NUMBER_OF_IMAGE_DATA - 2) then data_counter <= (others => '1'); axis_tuser <= (others => '1'); else data_counter <= data_counter + 1; axis_tuser <= (others => '0'); end if; if (line_counter = i_hsize - 2) then line_counter <= (others => '1'); axis_tlast <= '1'; else line_counter <= line_counter + 1; axis_tlast <= '0'; end if; end if; end if; end if; end process tlast_tuser_p; end implementation;
I have two major issues:
Where should I look?
08-07-2019 06:41 AM
08-07-2019 05:38 AM
You might want to check the output value of you IP using an ILA to check it is correct.
If this is correct, you might want to check if you processor is not using the same memory region as the one use by your VDMA. You can do this in you linker script. I have done (and explained) this in my Video Series 24: Using the AXI VDMA in Triple Buffer Mode.
08-07-2019 05:55 AM
I noticed that you accept a new piece of data on every clock cycle, and that there's really no way for the downstream video generator to tell your upstream pixel generator that its generating a pixel during a blanking interval. Your logic only uses the TREADY line for this purpose, yet does nothing to communicate teh TREADY information upstream.
I might suggest you rethink your approach.
If it helps at all, you can find an open source video example here that doesn't use block design at all. It does include a simulator, so that you can see the image as its being created on a window on your screen, as well as then being able to see a full trace of everything going on within the design. You can read about it more here if you are interested. The example is for VGA, although I do have some HDMI examples lying around as well.
08-07-2019 06:41 AM