cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Highlighted
Explorer
Explorer
797 Views
Registered: ‎10-14-2017

Direct mode AXI DMA not working

Jump to solution

I have a simple design where I want to test the direct mode DMA transaction from PL to PS.

I've created a simple sample generator with AXI4 master streaming interface, which essentially is just a counter which, when tready is asserted, counts up to user defined frame size, then toggles tlast and starts counting again. I've included a source code for it below and also a snapshot of simulation waveform which shows it working as it is supposed to.

The sample generator is connected to the AXI DMA input which is configured as direct mode with burts size 16. The block design schematic is given below. I'm using interrupt which is nicely connected to the PS7.

In PS side I have an application code which firstly initializes the system  (AXI DMA, interurpts etc.) and the starts the AXI DMA read transaction. Upon interrupt another AXI DMA read transaction should be started and the values read should always be written to the same address space in DDR (starting from 0xa000000).

The problem is that it is not working. I've implemented the design and tested it on my zynq board by programmign it over JTAG. When I read the DDR registers over JTAG I see random data at the address space although I should be seeing a counting pattern from 0 up to 16: The memory read returns the following:

xsct% mrd 0xa000000 10
 A000000:   12012100
 A000004:   D84688A0
 A000008:   3AED07C5
 A00000C:   0A0EBB68
 A000010:   8E434501
 A000014:   11160A1E
 A000018:   990440A1
 A00001C:   89842569
 A000020:   45031030
 A000024:   11208495

I've double and triple checked everything and have tried all that I can think of, but I'm at the end of my wits and cannot figure out why it's not working. I've tried the simple polling example that comes with SDK and that worked fine, but I've not been able to get anything of my own design to work. Can someone please help me in, because I do not know anyore where I should look for a mistake?

The block design in Vivado looks like this:

block_design.png

Source code for the sample generator is following:

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

entity sample_gen is
	generic (
		C_M_AXIS_TDATA_WIDTH	: integer	:= 32;
		C_M_AXIS_START_COUNT	: integer	:= 32;
		C_M_AXIS_FRAME_SIZE 	: integer	:= 16
	);
	port (
		m_axis_aclk	    : in std_logic;
		m_axis_aresetn	: in std_logic;
		m_axis_tvalid	: out std_logic;
		m_axis_tdata	: out std_logic_vector(C_M_AXIS_TDATA_WIDTH-1 downto 0);
		m_axis_tstrb	: out std_logic_vector((C_M_AXIS_TDATA_WIDTH/8)-1 downto 0);
		m_axis_tlast	: out std_logic;
		m_axis_tready	: in std_logic
	);
end sample_gen;

architecture arch_imp of sample_gen is
    
    type state_type is (start_up, running);
    
    signal state : state_type       := start_up;
    
    signal cnt                      : unsigned (C_M_AXIS_TDATA_WIDTH-1 downto 0) := (others => '0');
    signal start_cnt, tlast_cnt     : integer := 0;
   
begin
    
    m_axis_tstrb <= (others => '1');
    
    main : process (m_axis_aclk, m_axis_aresetn) is
    begin
        if (m_axis_aresetn = '0') then  -- active_low reset
            state <= start_up;  -- clear all the values and assign start_up stage
            m_axis_tvalid <= '0';
            tlast_cnt <= 0;
            start_cnt <= 0;
            m_axis_tlast <= '0';
            cnt <= (others => '0');
        elsif (rising_edge(m_axis_aclk)) then  -- released from reset
            case state is
                when start_up =>  -- wait user specified clk_periods before starting the samples generator
                    m_axis_tvalid <= '0';  
                    tlast_cnt <= 0;
                    m_axis_tlast <= '0';
                    cnt <= (others => '0');
                    if (start_cnt >= C_M_AXIS_START_COUNT) then  -- when user specified clk_periods have elapsed, go into other state which generates the samples
                        state <= running;
                        start_cnt <= 0;
                    else
                        start_cnt <= start_cnt + 1;
                        state <= start_up;
                    end if;
                when running =>
                    m_axis_tvalid <= '1'; -- tvalid continously high
                    start_cnt <= 0;  -- reset the start-up counter for to be used when core is reset
                    m_axis_tlast <= '0';  -- by default tlast is kept low in this state
                    if (m_axis_tready = '1') then  -- only when slave is ready to accept data 
                        m_axis_tdata <= STD_LOGIC_VECTOR(cnt); -- output new data
                        cnt <= cnt + 1; -- increment the data generating counter
                        tlast_cnt <= tlast_cnt + 1; -- increment the tlast counter
                        if (tlast_cnt = C_M_AXIS_FRAME_SIZE-1) then  -- only when tlast counter has counted frame_size of valid output data samples
                            m_axis_tlast <= '1'; -- toggle the tlast signal high
                            tlast_cnt <= 0; -- reset the counter
                            cnt <= (others => '0'); -- reset the data samples generating counter
                        end if;
                    end if;
                when others =>  -- catch-all state
                    m_axis_tvalid <= '0';
                    m_axis_tlast <= '0';
                    start_cnt <= 0;
                    tlast_cnt <= 0;
                    state <= start_up;
            end case;            
        end if;
    end process main;

end arch_imp;

Simulating on a testbench gives the following

testbench_simulation.png

When synthesizing and implementing the design Vivado generates the following warnings. I do not know if those are relevant or not, but I include them anyhow. The warnign about S_AXIS_S2MM interface not being connected is false as I decided to do the connections manually from my IP to the AXI DMA.

[BD 41-1306] The connection to interface pin /axi_dma_0/s_axis_s2mm_tkeep is being overridden by the user. This pin will not be connected as a part of interface connection S_AXIS_S2MM
[IP_Flow 19-474] Invalid Parameter 'Component_Name'
[Synth 8-350] instance 'SI_REG' of module 'axi_register_slice_v2_1_18_axi_register_slice' requires 93 connections, but only 92 given ["c:/Users/User/Documents/Projektid/FPGA/Vivado/axi_dma_v7/axi_dma_v7.srcs/sources_1/bd/design_1/ipshared/7a04/hdl/axi_protocol_converter_v2_1_vl_rfs.v":4392]
[Synth 8-3331] design sc_util_v1_0_4_onehot_to_binary has unconnected port din[0]
[Synth 8-3331] design processing_system7_v5_5_processing_system7 has unconnected port ENET0_GMII_COL
[Synth 8-3331] design s00_couplers_imp_UYSKKA has unconnected port M_ACLK
[Synth 8-3331] design axi_dma_sofeof_gen has unconnected port axi_prmry_aclk
[Synth 8-3332] Sequential element (EXT_LPF/ACTIVE_LOW_EXT.ACT_LO_EXT/GENERATE_LEVEL_P_S_CDC.SINGLE_BIT.CROSS_PLEVEL_IN2SCNDRY_s_level_out_d5) is unused and will be removed from module proc_sys_reset.
[Vivado 12-180] No cells matched 'get_cells -hier -filter {PRIMITIVE_SUBGROUP==LUTRAM || PRIMITIVE_SUBGROUP==dram || PRIMITIVE_SUBGROUP==uram || PRIMITIVE_SUBGROUP==BRAM}'. ["C:/Xilinx/Vivado/2018.3/data/ip/xpm/xpm_memory/tcl/xpm_memory_xdc.tcl":3]
[Synth 8-350] instance 'psr_aclk' of module 'bd_afc3_psr_aclk_0' requires 10 connections, but only 6 given ["c:/Users/User/Documents/Projektid/FPGA/Vivado/axi_dma_v7/axi_dma_v7.srcs/sources_1/bd/design_1/ip/design_1_axi_smc_0/bd_0/synth/bd_afc3.v":486]
[Synth 8-350] instance 'inst' of module 'processing_system7_v5_5_processing_system7' requires 685 connections, but only 672 given ["c:/Users/User/Documents/Projektid/FPGA/Vivado/axi_dma_v7/axi_dma_v7.srcs/sources_1/bd/design_1/ip/design_1_processing_system7_0_0/synth/design_1_processing_system7_0_0.v":489]
[BD 41-927] Following properties on pin /axi_sample_gen_0/m_axis_aclk have been updated from connected ip. They may not be synchronized with cell properties. You can set property on pin directly to confirm the value and resolve the warning.
	CLK_DOMAIN=design_1_processing_system7_0_0_FCLK_CLK0 
[Synth 8-6014] Unused sequential element awaddr_reg was removed.  ["c:/Users/User/Documents/Projektid/FPGA/Vivado/axi_dma_v7/axi_dma_v7.srcs/sources_1/bd/design_1/ipshared/09b0/hdl/axi_dma_v7_1_vh_rfs.vhd":2160]
[Synth 8-3848] Net sg_ctl in module/entity axi_dma_register_s2mm does not have driver. ["c:/Users/User/Documents/Projektid/FPGA/Vivado/axi_dma_v7/axi_dma_v7.srcs/sources_1/bd/design_1/ipshared/09b0/hdl/axi_dma_v7_1_vh_rfs.vhd":4673]
[Synth 8-3848] Net aresetn_out in module/entity clk_map_imp_5Y9LOC does not have driver. ["c:/Users/User/Documents/Projektid/FPGA/Vivado/axi_dma_v7/axi_dma_v7.srcs/sources_1/bd/design_1/ip/design_1_axi_smc_0/bd_0/synth/bd_afc3.v":467]
[xilinx.com:ip:axi_dma:7.1-11] /axi_dma_0
                   #################################### 
                   S_AXIS_S2MM interface is unconnected
                   ####################################
[Synth 8-6104] Input port 'value' has an internal driver ["C:/Xilinx/Vivado/2018.3/data/ip/xpm/xpm_fifo/hdl/xpm_fifo.sv":124]
[Synth 8-3331] design axi_infrastructure_v1_1_0_vector2axi__parameterized0 has unconnected port m_axi_bid[0]
[Synth 8-6014] Unused sequential element state_r1_reg was removed.  ["c:/Users/User/Documents/Projektid/FPGA/Vivado/axi_dma_v7/axi_dma_v7.srcs/sources_1/bd/design_1/ipshared/7a04/hdl/axi_protocol_converter_v2_1_vl_rfs.v":3383]
[Synth 8-5640] Port 'axi_dma_tstvec' is missing in component declaration ["C:/Users/User/Documents/Projektid/FPGA/Vivado/axi_dma_v7/axi_dma_v7.srcs/sources_1/bd/design_1/synth/design_1.vhd":728]
[Designutils 20-3303] unexpected site type 'IOPAD' in HDPYFinalizeIO
[Designutils 20-3303] unexpected site type 'IOPAD' in HDPYFinalizeIO
[Power 33-332] Found switching activity that implies high-fanout reset nets being asserted for excessive periods of time which may result in inaccurate power analysis.
Resolution: To review and fix problems, please run Power Constraints Advisor in the GUI from Tools > Power Constraints Advisor or run report_power with the -advisory option to generate a text report.
[Designutils 20-3303] unexpected site type 'IOPAD' in HDPYFinalizeIO

 The application code on PS is as follows. Most of it is based on a tutorial by Mohammad Sadri (link). I discarded the GPIO part because I'm not using them in my design.

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xil_io.h"
#include "ps7_init.h"
#include "xscugic.h"
#include "xparameters.h"

XScuGic InterruptController;
static XScuGic_Config *GicConfig;
u32 global_frame_counter = 0;

int initAxiDma()
{
	unsigned int tmpVal;

	tmpVal = Xil_In32(XPAR_AXI_DMA_0_BASEADDR + 0x30);  // read from AXI DMA control register
	tmpVal |= 0x1001; // modify the read value with setting the run bit and interrupt_on_complete enable bit
	Xil_Out32(XPAR_AXI_DMA_0_BASEADDR + 0x30, tmpVal); // write the modified value back to AXI DMA register
	tmpVal = Xil_In32(XPAR_AXI_DMA_0_BASEADDR + 0x30); // read the written value
	xil_printf("Value of the DMA control register after the configuration: %x\n\r",tmpVal); // print out the value for user verification

	return 0;
}

void StartDMATransfer(unsigned int dstAddress, unsigned int len)
{
	// write destination address to S2MM_DA register
	Xil_Out32(XPAR_AXI_DMA_0_BASEADDR + 0x48, dstAddress);

	// write length to the S2MM_LENGTH register, this will start the DMA transfer
	Xil_Out32(XPAR_AXI_DMA_0_BASEADDR + 0x58, len);
}

void InterruptHandler(void)
{
	// when you have multiple interrupts the usually first thing to do is to disable interrupts
	u32 tmpVal;

	// clear interrupt; writing 1 on bit 12 in S2MM_DMASR will do that
	tmpVal = Xil_In32(XPAR_AXI_DMA_0_BASEADDR + 0x34);
	tmpVal |= 0x1000;
	Xil_Out32(XPAR_AXI_DMA_0_BASEADDR + 0x34, tmpVal);

	// data should now be in DRAM, do your processing here

	global_frame_counter++;
	if (global_frame_counter > 10000000)
	{
		xil_printf("Frame number: %d\n\r",global_frame_counter);
		return;
	}

	StartDMATransfer(0xa000000, 256);
}

int setUpInterruptSystem(XScuGic *XScuGicInstancePtr)
{
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler, XScuGicInstancePtr);
	Xil_ExceptionEnable();

	return XST_SUCCESS;
}

int initInterruptSystem(deviceID)
{
	int status;

	GicConfig = XScuGic_LookupConfig(deviceID);
	if (NULL == GicConfig)
	{
		return XST_FAILURE;
	}

	status = XScuGic_CfgInitialize(&InterruptController, GicConfig, GicConfig->CpuBaseAddress);
	if (status != XST_FAILURE)
	{
		return XST_FAILURE;
	}

	status = setUpInterruptSystem(&InterruptController);
	if (status != XST_FAILURE)
	{
		return XST_FAILURE;
	}

	status = XScuGic_Connect(&InterruptController,
			XPAR_FABRIC_AXI_DMA_0_S2MM_INTROUT_INTR,
			(Xil_ExceptionHandler)InterruptHandler,
			NULL);
	if (status != XST_FAILURE)
	{
		return XST_FAILURE;
	}

	XScuGic_Enable(&InterruptController, XPAR_FABRIC_AXI_DMA_0_S2MM_INTROUT_INTR);

	return XST_SUCCESS;
}

int main()
{
	xil_printf("Calling init_platform ... \n\r");
    init_platform();

    // enable PL of the ZYNQ device
    ps7_post_config();

    // initialize AXI DMA unit
    xil_printf("Initializing AXI DMA ... \n\r");
    initAxiDma();

    // initialize the interrupt system
    xil_printf("Initializing interrupts ... \n\r");
    initInterruptSystem(XPAR_PS7_SCUGIC_0_DEVICE_ID);

    xil_printf("Starting DMA transfer ... \n\r");
    StartDMATransfer(0xa000000, 16);

    for (;;)
    {
    	// do nothing
    }

    //cleanup_platform();
    return 0;
}

 

0 Kudos
1 Solution

Accepted Solutions
Highlighted
Xilinx Employee
Xilinx Employee
769 Views
Registered: ‎10-04-2016

Hi @ronnu ,

The waveforms coming from your counter look okay to me, but here are a few things you can try.

0. Verify that you don't have a cache coherency issue. The AXI DMA may have written to DRAM, but the processor is reading back stale values from cache. You could test this by disabling the cache for the 1MB region starting at 0xA00_0000. Use the Xil_SetTlbAttributes() function to do this.

1. Add an AXI Protocol Checker between your IP and the S_AXIS_S2MM port on AXI DMA. This can detect subtle protocol errors that tired eyes can't. 

2. Does the IoC IRQ ever fire? Could you add some code to InterruptHandler to see if any of the error bits in the S2MM_DMASR register are set?

3. Does the M_AXI_S2MM ever write to memory? You could add an ILA to this interface and verify that the write transfers to 0xA00_0000 occur.

4. How have you tied off the TKEEP input to AXI DMA?

More details about the AXI Protocol Checker are available here. You will need to instrument the output vector with an ILA to catch the specific protocol violation.

https://www.xilinx.com/support/documentation/ip_documentation/axi_protocol_checker/v2_0/pg101-axi-protocol-checker.pdf

Regards,

Deanna

-------------------------------------------------------------------------
Don’t forget to reply, kudo, and accept as solution.
-------------------------------------------------------------------------

View solution in original post

0 Kudos
2 Replies
Highlighted
Xilinx Employee
Xilinx Employee
770 Views
Registered: ‎10-04-2016

Hi @ronnu ,

The waveforms coming from your counter look okay to me, but here are a few things you can try.

0. Verify that you don't have a cache coherency issue. The AXI DMA may have written to DRAM, but the processor is reading back stale values from cache. You could test this by disabling the cache for the 1MB region starting at 0xA00_0000. Use the Xil_SetTlbAttributes() function to do this.

1. Add an AXI Protocol Checker between your IP and the S_AXIS_S2MM port on AXI DMA. This can detect subtle protocol errors that tired eyes can't. 

2. Does the IoC IRQ ever fire? Could you add some code to InterruptHandler to see if any of the error bits in the S2MM_DMASR register are set?

3. Does the M_AXI_S2MM ever write to memory? You could add an ILA to this interface and verify that the write transfers to 0xA00_0000 occur.

4. How have you tied off the TKEEP input to AXI DMA?

More details about the AXI Protocol Checker are available here. You will need to instrument the output vector with an ILA to catch the specific protocol violation.

https://www.xilinx.com/support/documentation/ip_documentation/axi_protocol_checker/v2_0/pg101-axi-protocol-checker.pdf

Regards,

Deanna

-------------------------------------------------------------------------
Don’t forget to reply, kudo, and accept as solution.
-------------------------------------------------------------------------

View solution in original post

0 Kudos
Highlighted
Explorer
Explorer
756 Views
Registered: ‎10-14-2017

Thank you for the reply!

I actually found out what the mistake was a while ago. I didn't realize that this post eventually got posted as well. I had a problem with xilinx forum marking my first post as spam (guess it was too long), so I made another post where I divided text up to three smaller sections and the posted them as replies.

But, you were right with the first point - it was cache coherency issue.

I'll leave a reference to my other thread here as well - link

0 Kudos