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: 
Contributor
Contributor
1,384 Views
Registered: ‎03-03-2017

Combination of lwip with adc reading via AXI DMA in interrupt mode

Jump to solution

I have two separated softwares that work perfectly well when they are run separately. One is used to read data from two external ADCs and store it in the RAM via DMA in interrupt mode, and the other one is a modified version of the echo server used to transfer data to a remote PC (modified to send my own data instead of doing echo). However, when I combine both to transfer the data read from the external ADCs and stored in the RAM to a remote PC, the software fails. I have detected the line causing the problem, but I don't know how to solve it. 

 

Let me explain where I think there is a problem. Using the same file 'main.c' obtained when creating a new application project based on the lwIP Echo server, I have added the following code to activate the ADCs just after the 'init_platform()' call:

 

 

// Create ADC object
p_adc_inst = adc_create
(
XPAR_GPIO_0_DEVICE_ID,
XPAR_AXIDMA_0_DEVICE_ID,
XPAR_PS7_SCUGIC_0_DEVICE_ID,
XPAR_FABRIC_AXI_DMA_0_S2MM_INTROUT_INTR,
// XPAR_FABRIC_AXI_DMA_0_MM2S_INTROUT_INTR
0,
sizeof(int)
);
if (p_adc_inst == NULL)
{
xil_printf("ERROR! Failed to create ADC instance.\n\r");
return -1;
}
// Set the desired parameters for the ADC objects
adc_set_bytes_per_sample(p_adc_inst, sizeof(int));
adc_set_samples_per_frame(p_adc_inst, SAMPLES_PER_FRAME);

// Make sure the buffers are clear before we populate it (generally don't need to do this, but for proving the DMA working, we do it anyway)
memset(rcv_buf, 0, SAMPLES_PER_FRAME*NUMBER_OF_FRAMES*sizeof(int));

// Enable/initialize adc
adc_enable(p_adc_inst);

 

 

The problem is in the function 'adc_create', which, at some point calls the function 'Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, p_intc_inst)' (adc_create calls dma_passthrough_create, which calls init_intc, which calls Xil_ExceptionRegisterHandler; the code is not mine but from a tutorial from Xilinx to the DMA in interrupt mode):

 

 

void Xil_ExceptionRegisterHandler(u32 Exception_id,
				    Xil_ExceptionHandler Handler,
				    void *Data)
{
	XExc_VectorTable[Exception_id].Handler = Handler;
	XExc_VectorTable[Exception_id].Data = Data;
}

 

After that, the code output via uart is:

 

-----lwIP TCP echo server ------
TCP packets sent to port 6001 will be echoed back
Start PHY autonegotiation 
Waiting for PHY to complete autonegotiation.
autonegotiation complete 
link speed for phy address 0: 1000

 

As can be seen, the IP is never shown, so the fpga is never registered in the net. However, if I comment the line where the function Xil_ExceptionRegisterHandler is called, then the part of the software related to lwIP runs as expected (see output below), although then the ADC captures never start:

 

-----lwIP TCP echo server ------
TCP packets sent to port 6001 will be echoed back
Start PHY autonegotiation 
Waiting for PHY to complete autonegotiation.
autonegotiation complete 
link speed for phy address 0: 1000
Board IP: 10.30.0.144
Netmask : 255.255.255.0
Gateway : 10.30.0.1
TCP echo server started @ port 7

 

Sometimes, in rare occasions, the complete software runs perfectly well and I can see that everything is working as expected. However, this is very erratic and only happens sometimes, so there is a problem to be solved.

Tags (3)
0 Kudos
0 Solutions
2 Replies
Contributor
Contributor
1,368 Views
Registered: ‎03-03-2017

Re: Combination of lwip with adc reading via AXI DMA in interrupt mode

Jump to solution

Digging a little bit in the code, I've seen that there are two calls to Xil_ExceptionRegisterHandler in two different parts of the code:

 

Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT, (Xil_ExceptionHandler)XScuGic_DeviceInterruptHandler, (void *)INTC_DEVICE_ID);

 

Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, p_intc_inst);

 

It seems the second one affects the first call.

0 Kudos
Contributor
Contributor
1,351 Views
Registered: ‎03-03-2017

Re: Combination of lwip with adc reading via AXI DMA in interrupt mode

Jump to solution

According to this post, "With LwIP example you don't have to write completely new interrupt setup and service as they may conflict with existing. You just need to find original interrupt controller setup and routines (in platform_zynq.c or something like that), insert your handler, add handler registration and irq setup (level-edge etc. if needed) into existing code and it will work fine not blocking LwIP."

 

So, I need to combine the interrupt setup and service of both codes. In the DMA code, this is done in:

 

static int init_intc(XScuGic* p_intc_inst, int intc_device_id, XAxiDma* p_dma_inst, int s2mm_intr_id, int mm2s_intr_id)
{

	// Local variables
	int             status = 0;
	XScuGic_Config* cfg_ptr;

	// Look up hardware configuration for device
	cfg_ptr = XScuGic_LookupConfig(intc_device_id);
	if (!cfg_ptr)
	{
		xil_printf("ERROR! No hardware configuration found for Interrupt Controller with device id %d.\r\n", intc_device_id);
		return DMA_PASSTHROUGH_INTC_INIT_FAIL;
	}

	// Initialize driver
	status = XScuGic_CfgInitialize(p_intc_inst, cfg_ptr, cfg_ptr->CpuBaseAddress);
	if (status != XST_SUCCESS)
	{
		xil_printf("ERROR! Initialization of Interrupt Controller failed with %d.\r\n", status);
		return DMA_PASSTHROUGH_INTC_INIT_FAIL;
	}

	// Set interrupt priorities and trigger type
	XScuGic_SetPriorityTriggerType(p_intc_inst, s2mm_intr_id, 0xA0, 0x3);
	XScuGic_SetPriorityTriggerType(p_intc_inst, mm2s_intr_id, 0xA8, 0x3);

	// Connect handlers
	status = XScuGic_Connect(p_intc_inst, s2mm_intr_id, (Xil_InterruptHandler)s2mm_isr, p_dma_inst);
	if (status != XST_SUCCESS)
	{
		xil_printf("ERROR! Failed to connect s2mm_isr to the interrupt controller.\r\n", status);
		return DMA_PASSTHROUGH_INTC_INIT_FAIL;
	}
	status = XScuGic_Connect(p_intc_inst, mm2s_intr_id, (Xil_InterruptHandler)mm2s_isr, p_dma_inst);
	if (status != XST_SUCCESS)
	{
		xil_printf("ERROR! Failed to connect mm2s_isr to the interrupt controller.\r\n", status);
		return DMA_PASSTHROUGH_INTC_INIT_FAIL;
	}

	// Enable all interrupts
	XScuGic_Enable(p_intc_inst, s2mm_intr_id);
	XScuGic_Enable(p_intc_inst, mm2s_intr_id);

	// Initialize exception table and register the interrupt controller handler with exception table
	Xil_ExceptionInit();
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, p_intc_inst);

	// Enable non-critical exceptions
	Xil_ExceptionEnable();

	return DMA_PASSTHROUGH_SUCCESS;

}

And, in the lwip code:

 

void platform_setup_interrupts(void)
{
	Xil_ExceptionInit();

	XScuGic_DeviceInitialize(INTC_DEVICE_ID);

	/*
	 * Connect the interrupt controller interrupt handler to the hardware
	 * interrupt handling logic in the processor.
	 */
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
			(Xil_ExceptionHandler)XScuGic_DeviceInterruptHandler,
			(void *)INTC_DEVICE_ID);
	/*
	 * Connect the device driver handler that will be called when an
	 * interrupt for the device occurs, the handler defined above performs
	 * the specific interrupt processing for the device.
	 */
	XScuGic_RegisterHandler(INTC_BASE_ADDR, TIMER_IRPT_INTR,
					(Xil_ExceptionHandler)timer_callback,
					(void *)&TimerInstance);
	/*
	 * Enable the interrupt for scu timer.
	 */
	XScuGic_EnableIntr(INTC_DIST_BASE_ADDR, TIMER_IRPT_INTR);

	return;
}

both are called at different times. How is it possible to combine them?

0 Kudos