UPGRADE YOUR BROWSER

We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

cancel
Showing results for 
Search instead for 
Did you mean: 
Visitor angelmaya
Visitor
4,065 Views
Registered: ‎08-20-2013

AXI DMA handshaking issues with custom IP

Jump to solution

Hello, 

 

I'm trying to design an embedded system to capture and process signals from a high-throughput custom IP, which is a time-to-digital converter. My design is being carried out with these features:

 

  • FPGA part: Spartan-6 XC6SLX45T from Spartan-6 SP605 Dev Board
  • Xilinx Design Tools version: 14.1
  • Preferred language: VHDL
  • Main clock frequency: 200 MHz
  • Microblaze frequency: 100 MHz

I'm new to using external Spartan-6 memory resources, so please bear with me. In order to get familiar with DMA services, I made a dummy code snippet which reads 4 slave registers that Microblaze modifies, adds them and then makes a xor operation with a number that changes incrementally.

 

My custom IP was modified so it is interconnected to the following busses:

  • Axi-4 Lite @ 50 MHz
  • Axi-4 Stream @ 50 MHz

This is a capture for my system assembly view, which shows all busses connections:

 

system assembly view in EDK photo system_assembly_view_zps83722b74.png

 

The connected ports between AXI DMA and my custom ip are these:

 

connections between axi dma and custom IP photo ports_zpsb48749aa.png

 

MHS and MPD custom descriptions are below:

 

MHS File

 

BEGIN axi_dma
 PARAMETER INSTANCE = axi_dma_0
 PARAMETER HW_VER = 5.00.a
 PARAMETER C_INCLUDE_MM2S = 0
 PARAMETER C_S2MM_BURST_SIZE = 256
 PARAMETER C_INCLUDE_SG = 0
 PARAMETER C_INTERCONNECT_M_AXI_S2MM_WRITE_FIFO_DEPTH = 512
 PARAMETER C_BASEADDR = 0x41e00000
 PARAMETER C_HIGHADDR = 0x41e0ffff
 BUS_INTERFACE S_AXI_LITE = axi4lite_0
 BUS_INTERFACE M_AXI_S2MM = axi4_0
 BUS_INTERFACE S_AXIS_S2MM = tdc_scdt_prpg_0_S_AXIS
 PORT s_axi_lite_aclk = clk_50_0000MHzPLL0
 PORT m_axi_s2mm_aclk = clk_50_0000MHzPLL0
 PORT s2mm_introut = axi_dma_0_s2mm_introut
END

BEGIN tdc_scdt_prpg
 PARAMETER INSTANCE = tdc_scdt_prpg_0
 PARAMETER HW_VER = 1.00.a
 PARAMETER C_BASEADDR = 0x7ae00000
 PARAMETER C_HIGHADDR = 0x7ae0ffff
 BUS_INTERFACE S_AXI = axi4lite_0
 BUS_INTERFACE S_AXIS_S2MM = tdc_scdt_prpg_0_S_AXIS
 PORT S_AXI_ACLK = clk_50_0000MHzPLL0
 PORT S_AXIS_S2MM_ACLK = clk_50_0000MHzPLL0
 PORT pulso = tdc_scdt_prpg_0_pulso
 PORT dbg_clk = tdc_scdt_prpg_0_dbg_clk_to_chipscope_ila_0
END

 MPD file 

 

BEGIN tdc_scdt_prpg

## Peripheral Options
OPTION IPTYPE = PERIPHERAL
OPTION IMP_NETLIST = TRUE
OPTION HDL = VHDL
OPTION IP_GROUP = MICROBLAZE:USER
OPTION DESC = TDC_SCDT_PRPG
OPTION ARCH_SUPPORT_MAP = (others=DEVELOPMENT)
OPTION RUN_NGCBUILD = TRUE
OPTION STYLE = MIX
OPTION PLATGEN_SYSLEVEL_UPDATE_PROC = run_coregen

## Bus Interfaces
BUS_INTERFACE BUS = S_AXI, BUS_STD = AXI, BUS_TYPE = SLAVE
BUS_INTERFACE BUS=S_AXIS_S2MM, BUS_STD=AXIS, BUS_TYPE=INITIATOR

## Generics for VHDL or Parameters for Verilog
PARAMETER C_S_AXI_DATA_WIDTH = 32, DT = INTEGER, BUS = S_AXI, ASSIGNMENT = CONSTANT
PARAMETER C_S_AXI_ADDR_WIDTH = 32, DT = INTEGER, BUS = S_AXI, ASSIGNMENT = CONSTANT
PARAMETER C_S_AXI_MIN_SIZE = 0x000001ff, DT = std_logic_vector, BUS = S_AXI
PARAMETER C_USE_WSTRB = 0, DT = INTEGER
PARAMETER C_DPHASE_TIMEOUT = 8, DT = INTEGER
PARAMETER C_BASEADDR = 0xffffffff, DT = std_logic_vector, MIN_SIZE = 0x200, PAIR = C_HIGHADDR, ADDRESS = BASE, BUS = S_AXI
PARAMETER C_HIGHADDR = 0x00000000, DT = std_logic_vector, PAIR = C_BASEADDR, ADDRESS = HIGH, BUS = S_AXI
PARAMETER C_FAMILY = virtex6, DT = STRING
PARAMETER C_NUM_REG = 1, DT = INTEGER
PARAMETER C_NUM_MEM = 1, DT = INTEGER
PARAMETER C_SLV_AWIDTH = 32, DT = INTEGER
PARAMETER C_SLV_DWIDTH = 32, DT = INTEGER
PARAMETER C_S_AXI_PROTOCOL = AXI4LITE, TYPE = NON_HDL, ASSIGNMENT = CONSTANT, DT = STRING, BUS = S_AXI
PARAMETER C_S_AXIS_S2MM_PROTOCOL = XIL_AXI_STREAM_ETH_DATA, DT = string, TYPE = NON_HDL, ASSIGNMENT = CONSTANT, BUS = S_AXIS_S2MM
PARAMETER C_S_AXIS_S2MM_TDATA_WIDTH = 32, DT = integer, TYPE = NON_HDL, ASSIGNMENT = CONSTANT, BUS = S_AXIS_S2MM

## Ports
PORT S_AXI_ACLK = "", DIR = I, SIGIS = CLK, BUS = S_AXI
PORT S_AXI_ARESETN = ARESETN, DIR = I, SIGIS = RST, BUS = S_AXI
PORT S_AXI_AWADDR = AWADDR, DIR = I, VEC = [(C_S_AXI_ADDR_WIDTH-1):0], ENDIAN = LITTLE, BUS = S_AXI
PORT S_AXI_AWVALID = AWVALID, DIR = I, BUS = S_AXI
PORT S_AXI_WDATA = WDATA, DIR = I, VEC = [(C_S_AXI_DATA_WIDTH-1):0], ENDIAN = LITTLE, BUS = S_AXI
PORT S_AXI_WSTRB = WSTRB, DIR = I, VEC = [((C_S_AXI_DATA_WIDTH/8)-1):0], ENDIAN = LITTLE, BUS = S_AXI
PORT S_AXI_WVALID = WVALID, DIR = I, BUS = S_AXI
PORT S_AXI_BREADY = BREADY, DIR = I, BUS = S_AXI
PORT S_AXI_ARADDR = ARADDR, DIR = I, VEC = [(C_S_AXI_ADDR_WIDTH-1):0], ENDIAN = LITTLE, BUS = S_AXI
PORT S_AXI_ARVALID = ARVALID, DIR = I, BUS = S_AXI
PORT S_AXI_RREADY = RREADY, DIR = I, BUS = S_AXI
PORT S_AXI_ARREADY = ARREADY, DIR = O, BUS = S_AXI
PORT S_AXI_RDATA = RDATA, DIR = O, VEC = [(C_S_AXI_DATA_WIDTH-1):0], ENDIAN = LITTLE, BUS = S_AXI
PORT S_AXI_RRESP = RRESP, DIR = O, VEC = [1:0], BUS = S_AXI
PORT S_AXI_RVALID = RVALID, DIR = O, BUS = S_AXI
PORT S_AXI_WREADY = WREADY, DIR = O, BUS = S_AXI
PORT S_AXI_BRESP = BRESP, DIR = O, VEC = [1:0], BUS = S_AXI
PORT S_AXI_BVALID = BVALID, DIR = O, BUS = S_AXI
PORT S_AXI_AWREADY = AWREADY, DIR = O, BUS = S_AXI
PORT S_AXIS_S2MM_ACLK = "", DIR=I, SIGIS=CLK, BUS=S_AXIS_S2MM
PORT S_AXIS_S2MM_TREADY = TREADY, DIR=I, BUS=S_AXIS_S2MM
PORT S_AXIS_S2MM_TDATA = TDATA, DIR=O, VEC=[31:0], BUS=S_AXIS_S2MM
PORT S_AXIS_S2MM_TLAST = TLAST, DIR=O, BUS=S_AXIS_S2MM
PORT S_AXIS_S2MM_TKEEP = TKEEP, DIR = O, VEC = [3:0], BUS=S_AXIS_S2MM, ENDIAN = LITTLE
PORT S_AXIS_S2MM_TVALID = TVALID, DIR=O, BUS=S_AXIS_S2MM

PORT pulso = "", DIR=O
PORT dbg_data = "", VEC=[31:0], DIR=O
PORT dbg_trigger = "", VEC=[3:0], DIR=O
PORT dbg_clk = "", SIGIS = CLK, DIR=O
END

 Custom ports such as pulso, dbg_data and dbg_trigger are added to Chipscope in PlanAhead, though some of then don't appear as debuggeable.

 

Hardware description in VHDL and program in C-code

 

User signals declaration

 

  --USER signal declarations added here, as needed for user logic
	
	signal a : integer :=0;
	signal b : integer :=0;
	signal c : integer :=0;
	signal d : integer :=0;
	signal a_temp : unsigned (31 downto 0);
	signal b_temp : unsigned (31 downto 0);
	signal c_temp : unsigned (31 downto 0);
	signal d_temp : unsigned (31 downto 0);
	
	signal word_cnt : integer range 0 to C_PAQUETE-1;
	
	signal suma : integer :=0;
   signal sum          : std_logic_vector(31 downto 0);
	signal sum_temp : unsigned (31 downto 0);
	
	signal data_valid: std_logic;

 User logic implementation

 

  --USER logic implementation added here

   a_temp <= unsigned(slv_reg0);
	b_temp <= unsigned(slv_reg1);
	c_temp <= unsigned(slv_reg2);
	d_temp <= unsigned(slv_reg3);
  
	a <= conv_integer(a_temp);
	b <= conv_integer(b_temp);
	c <= conv_integer(c_temp);
	d <= conv_integer(d_temp);

	suma <= a+b+c+d+word_cnt when (a/=0 and b/=0 and c/=0 and d/=0) else 0;
	sum_temp <= conv_unsigned(suma,32);
	sum <= conv_std_logic_vector(sum_temp,32);

	Dma_Tkeep <= "1111";
	data_valid <= '1' when sum/="00000000000000000000000000000000" else '0';
	Dma_Tdata <= sum;
	Dma_Tvalid <= data_valid;
	Dma_Tlast <= '1' when word_cnt=(C_PAQUETE-1) else '0';

	DMA_Write: process(Dma_Aclk,slv_reg3(31))
	begin
		if slv_reg3(31)='1' then
			word_cnt <= 0;
		elsif rising_edge(Dma_Aclk) then
			if data_valid='1' and Dma_Tready='1' then
				if word_cnt=C_PAQUETE-1 then
					word_cnt <= 0;
				else 
					word_cnt <= word_cnt+1;
				end if;
			end if;
		end if;	
	end process DMA_Write;

 

I'm taking this pic as reference for a simple DMA operation (S2MM mode) between the custom IP and RAM memory:

 

 photo axi4_basic_handshake_zpsb0d154a1.jpg

 

Slave registers are modified by Microblaze below

 

SDK program

 

#include "tdc_scdt_prpg.h"
#include "stdio.h"
#include "xio.h"
#include "xparameters.h"
#include "xil_io.h"
#include "xbasic_types.h"
#include "xuartlite_l.h"


/************************** Constant Definitions ***************************/

#define READ_WRITE_MUL_FACTOR 0x10
#define TDC_SCDT_PRPG_USER_NUM_REG 0x4
#define DDR_BASEADDR  XPAR_MCB_DDR3_S0_AXI_BASEADDR
#define DMA_BASEADDR  XPAR_AXI_DMA_0_BASEADDR
#define UART_BASEADDR XPAR_RS232_UART_1_BASEADDR
#define TDC_BASEADDR XPAR_TDC_SCDT_PRPG_0_BASEADDR
#define databeats 256

void delay(int time){ //1ms delay
	int i=0;
	time=time*1000;
	for (i=0;i<=time;i++) asm ("nop");
}

int main(void){

	u32 datoslectura[databeats];
	char buffer;
	int n=0;

	for (n =0;n<databeats;n++){
		datoslectura[n]= 0;
	}

	xil_printf("Inicio de prueba\n\r");

	TDC_SCDT_PRPG_mWriteSlaveReg0(TDC_BASEADDR,0x0,0x1);
	TDC_SCDT_PRPG_mWriteSlaveReg1(TDC_BASEADDR,0x0,0x2);
	TDC_SCDT_PRPG_mWriteSlaveReg2(TDC_BASEADDR,0x0,0x3);
	TDC_SCDT_PRPG_mWriteSlaveReg3(TDC_BASEADDR,0x0,0x4);
	delay(10);

	Xil_Out32(DMA_BASEADDR+0x30,0); //Clean DMA operations
	Xil_Out32(DMA_BASEADDR+0x30,1); //Start DMA
	Xil_Out32(DMA_BASEADDR+0x48,DDR_BASEADDR+0x120000); //Where data is transferred
// a large offset is added, so data from other peripherals shouldn't get corrupted Xil_Out32(DMA_BASEADDR+0x58,0x400); //Number of bytes to transmit delay(10); for (n =0;n<databeats;n++){ datoslectura[n]= Xil_In32(DDR_BASEADDR+0x120000+(n*4)); } for (n=0;n<databeats;n++){ xil_printf("%x\n\r",datoslectura[n]); } return 0; }

 

I have used more primitive functions to modify DMA register attributes, which appears to be succesful upon looking at memory dumps when running "mrd" in XMD. The specific values in arguments were taken from AXI DMA manual, pages 37-45, 57-58.

 

Issue


Despite of doing what is shown above, I haven't been able to see Dma_Tdata change. It looks like this fragment only changes only once:

 

suma <= a+b+c+d+word_cnt when (a/=0 and b/=0 and c/=0 and d/=0) else 0;

 If a=1, b=2, c=3, d=4, then suma=10 (or A in hex) and this is the only result that appears in the uart console:

 

 photo uart_console_zps32429a71.png

 

 

A look at chipscope shows this result.

 

Then, why Tdata doesn't show a value different from "0" in chipscope? Am I missing something that prevents Tdata get properly changed?

 

Thank you in advance!

 

 

0 Kudos
1 Solution

Accepted Solutions
Xilinx Employee
Xilinx Employee
5,182 Views
Registered: ‎08-02-2011

Re: AXI DMA handshaking issues with custom IP

Jump to solution

Sure, tvalid never goes high :)

 

			if data_valid='1' and Dma_Tready='1' then

 

www.xilinx.com
0 Kudos
2 Replies
Xilinx Employee
Xilinx Employee
5,183 Views
Registered: ‎08-02-2011

Re: AXI DMA handshaking issues with custom IP

Jump to solution

Sure, tvalid never goes high :)

 

			if data_valid='1' and Dma_Tready='1' then

 

www.xilinx.com
0 Kudos
Highlighted
Visitor angelmaya
Visitor
4,050 Views
Registered: ‎08-20-2013

Re: AXI DMA handshaking issues with custom IP

Jump to solution

Like you mentioned, dma_Tvalid never went high. This line isn't good to change a flag state:

 

data_valid <= '1' when sum/="00000000000000000000000000000000" else '0';

Therefore, I suppose it's better to change it to a to one-bit hardware construct that could be either level-sensitive (for example, change a bit of a slave register) or edge-sensitive (registered input). I used the first one:

 

data_valid <= '1' when slv_reg2(31)='1' else '0';

 This way, Dma_Tdata changes accordingly :)

 

 photo uart_console_correct_zpsb31613e8.png

 

0 Kudos