XUartPs interrupt handler assert fail

Hi Everyone,

I am developing to Xilinx zcu104 board over the Cortex R5 core and I’m trying to figure out why my code fails.

I developed a system with 2 communication channels: Ethernet and UART.
For both of the channels, I am using interrupts in order to detect a message received.
I receive messages from Ethernet every 10 to 40 milliseconds and form the UART every 1 millisecond.

A few seconds (in some cases a few minutes), after I start sending messages through UART to the board (while the Ethernet channel sends and receives messages), I run into an assert error in the “XUuartPs_InterruptHandler(XUartPs *InstancePtr)” function.
For some reason, which I’m trying to figure out, The XUartPs instance pointer, received as the “XUartPs_InterruptHandler(XUartPs *InstancePtr)” parameter, is arriving the function empty and then falls in the Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY) check.

This is how I initialize the UART interrupt system:

main.c:

int main()
{
 	sys_thread_new("main_thread", (void(*)(void*))main_thread, 0, THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);

   	vTaskStartScheduler();
    // should never arrive here
  	while(1);
   	return 0;
}


int main_thread()
{
	int Status;

	// init uart interrupt
	Status = Init_uart_1(&xInterruptController, &UartPs,UART_DEVICE_ID, UART_INT_IRQ_ID); //UART 1 init
	if (Status != XST_SUCCESS)
	{
		return XST_FAILURE;
	}

	FreeRTOS_SetupTickInterrupt(); // enable the tick interrupts in order to get delay


	xil_printf("\n\r\n\r");
	xil_printf("-----lwIP Socket Mode UDP Server Application------\r\n");

	/* initialize lwIP before calling sys_thread_new */
	lwip_init();

	/* any thread using lwIP should be created using sys_thread_new */
	 BaseType_t xTaskCreate(TaskFunction_t pvTaskCode,
	                        const char * const pcName,
	                        configSTACK_DEPTH_TYPE usStackDepth,
	                        void *pvParameters,
	                        UBaseType_t uxPriority,
	                        TaskHandle_t *pxCreatedTask);

	sys_thread_new("nw_thread", network_thread, NULL, THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
    ...
    ...  // some LWIP code
    ...
}

comm.c:

int Init_uart_1(XScuGic *IntcInstPtr, XUartPs *UartInstPtr, u16 DeviceId, u16 UartIntrId)
{
	int Status;
	XUartPs_Config *Config;
	u32 IntrMask;

	/*
	 * Initialize the UART driver so that it's ready to use
	 * Look up the configuration in the config table, then Initialize it.
	 */

	Config = XUartPs_LookupConfig(DeviceId);
	if (NULL == Config)
	{
		return XST_FAILURE;
	}

	Status = XUartPs_CfgInitialize(UartInstPtr, Config, Config->BaseAddress);
	if (Status != XST_SUCCESS)
	{
		return XST_FAILURE;
	}

	/* Check hardware build */
	Status = XUartPs_SelfTest(UartInstPtr);
	if (Status != XST_SUCCESS)
	{
		return XST_FAILURE;
	}

	/*
	 * Connect the UART to the interrupt subsystem such that interrupts
	 * can occur. This function is application specific.
	 */
	Status = SetupInterruptSystem(IntcInstPtr, UartInstPtr, UartIntrId);
	if (Status != XST_SUCCESS)
	{
		return XST_FAILURE;
	}

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

	XUartPs_SetHandler(UartInstPtr, (XUartPs_Handler) Handler_uart_1, UartInstPtr);

	/*
	 * Enable the interrupt of the UART so interrupts will occur, setup
	 * a local loopback so data that is sent will be received.
	 */
	IntrMask = XUARTPS_IXR_RXOVR;


	XUartPs_SetInterruptMask(UartInstPtr, IntrMask);
	XUartPs_SetOperMode(UartInstPtr, XUARTPS_OPER_MODE_NORMAL);

	/*
	 * Set the receiver timeout. If it is not set, and the last few bytes
	 * of data do not trigger the over-water or full interrupt, the bytes
	 * will not be received. By default it is disabled.
	 *
	 * The setting of 8 will timeout after 8 x 4 = 32 character times.
	 * Increase the time out value if baud rate is high, decrease it if
	 * baud rate is low.
	 */
	XUartPs_SetRecvTimeout(UartInstPtr, 8);

	/*
	 * Set RX FIFO threshold to 1
	 */

	XUartPs_SetFifoThreshold(UartInstPtr, 1);

	return XST_SUCCESS;
}


int SetupInterruptSystem(XScuGic *IntcInstancePtr, XUartPs *UartInstancePtr, u16 UartIntrId)
{
	int Status;

	GicConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
	if (NULL == GicConfig)
	{
		return XST_FAILURE;
	}
	Status = XScuGic_CfgInitialize(IntcInstancePtr, GicConfig, GicConfig->CpuBaseAddress);
	if (Status != XST_SUCCESS)
	{
		return XST_FAILURE;
	}
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler) XScuGic_InterruptHandler, IntcInstancePtr);

	Status = XScuGic_Connect(IntcInstancePtr, (u32) UartIntrId, (Xil_InterruptHandler) XUartPs_InterruptHandler, (void *) UartInstancePtr);
	if (Status != XST_SUCCESS)
	{
		return XST_FAILURE;
	}

	Xil_ExceptionEnable();
	XScuGic_Enable(IntcInstancePtr, (u32) UartIntrId);;

	return XST_SUCCESS;
}

Can’t wait to solve this bug.
Thank you!

Do you have configASSERT() defined and configCHECK_FOR_STACK_OVERFLOW set to 2? Also, have you read through the page about running FreeRTOS on A9?

Where is the parameter that gets passed into XUuartPs_InterruptHandler() stored (on the stack? Function scope static?).

Also I’m curious as to why you create main_thread using the lwIP function sys_thread_new(), and what calling FreeRTOS_SetupTickInterrupt() after the scheduler has been started (so presumably the tick interrupt is already set up) does.

Thank you for your replay,

Yes, configASSERT() is defined, and configCHECK_FOR_STACK_OVERFLOW is set to 2.
Not sure I read this page. I will take a look and read it.

The Uart Instance Ptr parameter is a global variable in my system. I declared it at the beginning of the main.c file like this:
XUartPs UartPs; /* Instance of the UART_1 Device */

the parameter is passed through Init_uart_1(XScuGic *IntcInstPtr, XUartPs *UartInstPtr, u16 DeviceId, u16 UartIntrId) function as the second parameter.
I also declared the global variable at the beginning of comm.c file like this:
extern XUartPs UartPs; /* Instance of the UART_1 Device */
I use this variable also at the Uart transmit function.

The system is built over the lwIP UDP echo example, this is why the code includes some code from the example. I used it to create Ethernet interrupts.

I am calling FreeRTOS_SetupTickInterrupt() because I am using taskSuspend() and taskResume() functions. Without this line, it didn’t work. If I got this right, I needed to add it because the scheduler disables it.

Thank you

I think the next thing to determine then is whether the variable itself is getting corrupted (you will be able to see that in the debugger), or whether it is the parameter being passed into the function that is corrupted (in which case it could be a stack issue).

I’m very confused by that. Task suspend/resume don’t even use the tick count as there is no block time. Also, task suspend and resume are very rarely actually needed. FreeRTOS_SetupTickInterrupt() is not a function we provide, so I’m assuming it is a function provided by Xilinx, and I’m also assuming it is the function called by the kernel to configure the tick interrupt when the scheduler starts.