cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
bjasionowski
Observer
Observer
1,835 Views
Registered: ‎01-03-2013

uartlite interrupt + lwip problems on baremetal zynq

Jump to solution

I have a baremetal (no-OS) server application I have been using for some time now without issues.

 

I am now trying to integrate some external peripherals that have a UART communication interface. I initially attempted to use the uartlite driver in polling mode, but then realized I needed to use interrupts since the messages were longer than 16 characters and I was dropping parts of the message.

 

However, now that I instrumented the interrupt mechanism, as soon as that initializes, my network interface dies. I can't even ping the IP address of the server.

 

I created a preprocessor directive to toggle between enabling uart interrupts and bypass. When the interrupt setup stuff is bypassed, I can ping and talk to the server just fine. I'm basing my implementation on the uartlite driver example uartlite_intr_tapp_example.c.

 

I also confimed that I can transmit valid characters using the uartlite in interrupt mode.

 

Any ideas are much appreciated.

0 Kudos
1 Solution

Accepted Solutions
bjasionowski
Observer
Observer
1,914 Views
Registered: ‎01-03-2013

I fixed my problem after much trial and error.

 

Originally I was setting up the LWIP before I initialized my xuartlite devices and assigned interrupt handlers. As soon as I moved this LWIP setup code after the xuartlite initialization to support interrupts, things worked fine. Again this was taken from the echo server example. Hopefully this helps someone down the road...

 

        /* initialize LWIP modules */
	lwip_init();

  	/* Add network interface to the netif_list, and set it as default */
	if (!xemac_add(echo_netif, &ipaddr, &netmask,
			&gw, mac->octets,
			PLATFORM_EMAC_BASEADDR)) {
		printf("Error adding N/W interface\n\r");
		return ERR_ADDING_NET_IF;
	}
	netif_set_default(echo_netif);

	/* now enable interrupts */
	platform_enable_interrupts();

	/* specify that the network if is up */
	netif_set_up(echo_netif);

View solution in original post

5 Replies
jmcclusk
Mentor
Mentor
1,833 Views
Registered: ‎02-24-2014

You haven't said if your network interface has an interrupt as well.   If it's simply polled only, then perhaps your ISR for the UART is not completely re-entrant.      If your network uses interrupts, then almost certainly the UART setup on the interrupt controller is overwriting the network interrupt configuration.    You'll have to make sure that setup code doesn't do any damage.  

Don't forget to close a thread when possible by accepting a post as a solution.
0 Kudos
bjasionowski
Observer
Observer
1,812 Views
Registered: ‎01-03-2013

My application was based on the Echo Server application, which is single threaded. It has a polling loop and utilizes callbacks to handle the data. I'm not aware of what else lwip does under the hood:

 

	/* receive and process packets */
	while (1) {
		if (TcpFastTmrFlag) {
			tcp_fasttmr();
			TcpFastTmrFlag = 0;
		}
		if (TcpSlowTmrFlag) {
			tcp_slowtmr();
			TcpSlowTmrFlag = 0;
		}
		xemacif_input(echo_netif);
		transfer_data();
	}

Interestingly if I put a print statement in this loop after transfer_data() it executes continually, so the application still runs - just won't handle new data.

 

I'm using the Zynq's native network interface ETH0. I assume there is some sort of interrupt internally? Also, the only peripherals using the zynq PL-PS interrupt are ones I instantiated.

 

What are you implying you mean the ISR isn't re-entrant? At the moment my interrupt handlers are more or less empty. FWIW, I'm experiencing this issue w/o any uartlite interrupts firing (I see this issue immediately after setting up for interrupt mode). To be safe, I put some print statements in the send/recv callbacks and disconnected the physical uart pins. Nothing.

 

Fundamentally how does the driver work in this single threaded use case? Does the interrupt fire and immediately the program stops where it is and executes the uartlite callback? I'm new to using interrupts at this low level.

 

0 Kudos
jmcclusk
Mentor
Mentor
1,794 Views
Registered: ‎02-24-2014

I guess you need to dig deeper into the echo server code, and look for anything related to interrupts, especially initialization of the interrupt controller.   I'm not familiar with the echo server, so I am really on the edge of my experience here.   Looking at XAPP1026,  they mention interrupts multiple times, so I'm betting that you are hosing the ethernet interrupts when you setup the UART interrupts..    You'll have to dig into that setup routine, and make sure it's compatible with the ethernet interrupts.

Don't forget to close a thread when possible by accepting a post as a solution.
0 Kudos
bjasionowski
Observer
Observer
1,915 Views
Registered: ‎01-03-2013

I fixed my problem after much trial and error.

 

Originally I was setting up the LWIP before I initialized my xuartlite devices and assigned interrupt handlers. As soon as I moved this LWIP setup code after the xuartlite initialization to support interrupts, things worked fine. Again this was taken from the echo server example. Hopefully this helps someone down the road...

 

        /* initialize LWIP modules */
	lwip_init();

  	/* Add network interface to the netif_list, and set it as default */
	if (!xemac_add(echo_netif, &ipaddr, &netmask,
			&gw, mac->octets,
			PLATFORM_EMAC_BASEADDR)) {
		printf("Error adding N/W interface\n\r");
		return ERR_ADDING_NET_IF;
	}
	netif_set_default(echo_netif);

	/* now enable interrupts */
	platform_enable_interrupts();

	/* specify that the network if is up */
	netif_set_up(echo_netif);

View solution in original post

hossam1984
Participant
Participant
355 Views
Registered: ‎02-26-2019

I was looking for a sample code that works with LWIP and UART interrupt and I got the idea how it works.  I am sharing part of the code that may help others.

All interrupts should be initialized in the same place, I used platform_zynq.c to intialize all of my interrupts. 

 

void platform_setup_interrupts(void)
{
	int Status = XST_SUCCESS;
	XScuGic *intc_instance_ptr = &intc;

	XScuGic_Config *IntcConfig; //GIC config

//	Xil_ExceptionInit();

//	XScuGic_DeviceInitialize(INTC_DEVICE_ID);

	//Initialize the GIC
    // get config for interrupt controller
	IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
	if (NULL == IntcConfig) {	xil_printf("IntcConfig FAILURE...\r\n");}
    // initialize the interrupt controller driver
	Status = XScuGic_CfgInitialize(intc_instance_ptr, IntcConfig, IntcConfig->CpuBaseAddress);
	if (Status != XST_SUCCESS) {	xil_printf("XScuGic_CfgInitialize FAILURE...\r\n");

/*############################################################################*/
	/* GPS_PPS_INTR */
	/*############################################################################*/

	// set the priority of IRQ_F2P[0:0] to 0xA0 (highest 0xF8, lowest 0x00) and a trigger for a rising edge 0x3.
	XScuGic_SetPriorityTriggerType(intc_instance_ptr, GPS_PPS_INTR, 0x98, 0x3);

	// connect the interrupt service routine isr0 to the interrupt controller
	Status = XScuGic_Connect(intc_instance_ptr, GPS_PPS_INTR, (Xil_ExceptionHandler)isr0, (void *)&intc);
	if (Status != XST_SUCCESS) {	xil_printf(" GPS_PPS XScuGic_Connect FAILURE...\r\n");}
	// enable interrupts for IRQ_F2P[0:0]
	XScuGic_Enable(intc_instance_ptr, GPS_PPS_INTR);
	/*############################################################################*/
	/* TRIG_ZYNQ_INTR */
	/*############################################################################*/

	// set the priority of IRQ_F2P[1:1] to 0xA8 (highest 0xF8, lowest 0x00) and a trigger for a rising edge 0x3.
	XScuGic_SetPriorityTriggerType(intc_instance_ptr, TRIG_ZYNQ_INTR, 0xA0, 0x3);

	// connect the interrupt service routine isr1 to the interrupt controller
	Status = XScuGic_Connect(intc_instance_ptr, TRIG_ZYNQ_INTR, (Xil_ExceptionHandler)isr1, (void *)&intc);
	if (Status != XST_SUCCESS) {	xil_printf(" TRIG_ZYNQ_INTR XScuGic_Connect FAILURE...\r\n");}
	// enable interrupts for IRQ_F2P[1:1]
	XScuGic_Enable(intc_instance_ptr, TRIG_ZYNQ_INTR);
	/*############################################################################*/
	/* GPIO_DONE_INTR */
	/*############################################################################*/

	// set the priority of IRQ_F2P[1:1] to 0xA8 (highest 0xF8, lowest 0x00) and a trigger for a rising edge 0x3.
	XScuGic_SetPriorityTriggerType(intc_instance_ptr, GPIO_DONE_INTR, 0xA8, 0x3);

	// connect the interrupt service routine isr1 to the interrupt controller
	Status = XScuGic_Connect(intc_instance_ptr, GPIO_DONE_INTR, (Xil_ExceptionHandler)isr2, (void *)&intc);
	if (Status != XST_SUCCESS) {	xil_printf(" TRIG_ZYNQ_INTR XScuGic_Connect FAILURE...\r\n");}
	// enable interrupts for IRQ_F2P[1:1]
	XScuGic_Enable(intc_instance_ptr, GPIO_DONE_INTR);
	/*############################################################################*/
	/* UartLite_GPS */
	/*
	 * Connect the UartLite to the interrupt subsystem such that interrupts
	 * can occur. This function is application specific.
	 */
	/*############################################################################*/
	XScuGic_SetPriorityTriggerType(intc_instance_ptr, UARTLITE_GPS_INTR, 0xB0, 0x3);
	/*
	 * Connect the interrupt handler that will be called when an
	 * interrupt occurs for the device.
	 */
	Status = XScuGic_Connect(intc_instance_ptr, UARTLITE_GPS_INTR, (Xil_ExceptionHandler)XUartLite_InterruptHandler, (void *)&UartLite_GPS);
	if (Status != XST_SUCCESS) {	xil_printf(" UARTLITE_GPS_INTR XScuGic_Connect FAILURE...\r\n");}
	/*
	 * Enable the interrupt for the Timer device.
	 */
	XScuGic_Enable(intc_instance_ptr, UARTLITE_GPS_INTR);


	/*############################################################################*/
	/*############################################################################*/

	Xil_ExceptionInit();
	/*
	 * 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);

	//XScuGic_SetPriorityTriggerType(INTC_DEVICE_ID, TIMER_IRPT_INTR,	0x90, 0x3);


	/*
	 * Enable the interrupt for scu timer.
	 */
	XScuGic_EnableIntr(INTC_DIST_BASE_ADDR, TIMER_IRPT_INTR);

 // enable non-critical exceptions
//	Xil_ExceptionEnable();

	return;
}

void platform_enable_interrupts()
{
	/*
	 * Enable non-critical exceptions.
	 */
	Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);
	XScuTimer_EnableInterrupt(&TimerInstance);
	XScuTimer_Start(&TimerInstance);

	/*
	 * Setup the handlers for the UartLite that will be called from the
	 * interrupt context when data has been sent and received,
	 * specify a pointer to the UartLite driver instance as the callback
	 * reference so the handlers are able to access the instance data.
	 */

	XUartLite_SetRecvHandler(&UartLite_GPS, UartLiteRecvHandler, &UartLite_GPS);
	/*
	 * Enable the interrupt of the UartLite so that interrupts will occur.
	 */
	XUartLite_EnableInterrupt(&UartLite_GPS);
	/*
	 * Enable exceptions.
	 */
	Xil_ExceptionEnable();
	return;
}

 

 

0 Kudos