Zynq Ultrascale+, Interrupt handler issue

I am currently testing interrupts using FreeRTOS with Xilinx’s Vitis. I have created an interrupt handler and it should execute when triggered. However, once the handler is activated, all tasks are executed once and do not switch afterwards. It seems like they are hanging or crashing. I haven’t been able to find the reason. Additionally, if the interrupt configuration is set before the scheduler starts, the interrupt handler does not function. I’m sharing my code with you. Please check it out.

Code for setting up the interrupt handler :

void GpioHandler(void *CallbackRef)
{
	XGpioPs *GpioInstancePtr = (XGpioPs *)CallbackRef;
	TaskStatus_t xTaskDetails;
	Int_val = XGpioPs_IntrGetStatusPin(GpioInstancePtr, PS_KEY_MIO);

	XGpioPs_IntrClearPin(GpioInstancePtr, PS_KEY_MIO);

	if (Int_val)
	{
		XGpioPs_WritePin(&GPIO_PTR, PS_LED_MIO, PsLedVal);
		PsLedVal = ~PsLedVal;
		xil_printf("LED run\r\n");
		debugTaskInfo();
	}
}

void PsGpioSetup()
{
	int Status ;
	XGpioPs_Config *GpioCfg ;

	GpioCfg = XGpioPs_LookupConfig(MIO_0_ID) ;
	Status = XGpioPs_CfgInitialize(&GPIO_PTR, GpioCfg, GpioCfg->BaseAddr);

	if (Status != XST_SUCCESS)
	{
		xil_printf("PS GPIO Configuration failed!\r\n") ;
	}
	//set MIO 0 as output
	XGpioPs_SetDirectionPin(&GPIO_PTR, PS_LED_MIO, GPIO_OUTPUT) ;

	//enable MIO 0 output
	XGpioPs_SetOutputEnablePin(&GPIO_PTR, PS_LED_MIO, GPIO_OUTPUT) ;

	XGpioPs_SetDirectionPin(&GPIO_PTR, PS_KEY_MIO, GPIO_INPUT) ;
	XGpioPs_SetIntrTypePin(&GPIO_PTR, PS_KEY_MIO, XGPIOPS_IRQ_TYPE_EDGE_RISING);

	XGpioPs_IntrClearPin(&GPIO_PTR, PS_KEY_MIO);
	XGpioPs_IntrEnablePin(&GPIO_PTR, PS_KEY_MIO);


  	Status = IntrInitFuntion(&INTCInst, MIO_0_ID, &GPIO_PTR);
	if (Status != XST_SUCCESS)
	{
		xil_printf("PS GPIO Configuration failed!\r\n") ;
	}

}

int IntrInitFuntion(XScuGic *InstancePtr, u16 DeviceId, XGpioPs *GpioInstancePtr)
{
	XScuGic_Config *IntcConfig;
	int Status ;

	portDISABLE_INTERRUPTS();
	/* Obtain the configuration of the GIC. */
	IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);

    /* Install a default handler for each GIC interrupt. */

	Status = XScuGic_CfgInitialize(InstancePtr, IntcConfig, IntcConfig->CpuBaseAddress) ;
	if (Status != XST_SUCCESS)
	{
		return XST_FAILURE ;
	}

	XScuGic_SetPriorityTriggerType(InstancePtr, RX_INTR_ID, configMAX_API_CALL_INTERRUPT_PRIORITY , XGPIOPS_IRQ_TYPE_LEVEL_HIGH);

	Status = XScuGic_Connect(InstancePtr, RX_INTR_ID,
			(Xil_ExceptionHandler)GpioHandler, (void *)GpioInstancePtr) ;

	if (Status != XST_SUCCESS)
	{
		return XST_FAILURE ;
	}

	XScuGic_Enable(InstancePtr, RX_INTR_ID) ;

	Xil_ExceptionInit();

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

	Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);

	return XST_SUCCESS ;
}
  1. Task configuration and scheduler start.
  2. Each of the tasks.
int main( void )
{
	xil_printf( "Hello from Freertos example main\r\n" );
	xTaskCreate(CanFdTask, "CanFdTask", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+1, &xCanFdTask);
	xTaskCreate(UartTask, "UartTask", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+1, &xUartTask);
	xTaskCreate(LedTask, "LedTask", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+1, &xLedTask);

	xTimer = xTimerCreate("Timer", pdMS_TO_TICKS(DELAY_1_MS), pdTRUE, (void *) TIMER_ID, vTimerCallback);
	configASSERT( xTimer );
	xTimerStart( xTimer, 0);
	/* Start the tasks and timer running. */
	vTaskStartScheduler();

	for( ;; );
}

static void CanFdTask( void *pvParameters )
{
	xil_printf( "CanFdTask start\r\n" );
	APP_Initialize();
	APP_Tasks(0);
	while (true)
	{

		vTaskDelay(xMS);
	}
}

/*-----------------------------------------------------------*/
static void LedTask( void *pvParameters )
{
	PsGpioSetup();
	xil_printf( "LED On/Off task start   \r\n" );
	while (true)
	{
		vTaskDelay( xMS );
	}
}

static void UartTask( void *pvParameters )
{
	xil_printf( "Uart task start   \r\n" );
	xil_printf( "1: Initial CANFD 2: Start CANFD 3: Result CANFD (q):stop  \r\n" );
	while (true)
	{
		ReceivData = inbyte();
		switch (ReceivData)
		{  ...}
               vTaskDelay( xMS );
       }
}

Can you check if the tick interrupt is firing and xTickCount is incrementing?

Did you try moving the interrupt configuration to after the scheduler starts?

Did you verify that configMINIMAL_STACK_SIZE for all your tasks is sufficient ?
Did you also enable configASSERT besides enabling stack overflow checking ?
Do you have a debugger attached to step through and verify your (setup) code ?
Also is it allowed and safe to use xil_printf in ISRs ?

“After starting the scheduler, only the interrupt operates. I also checked the stack size.”

I also checked the stack size

Status = XScuGic_CfgInitialize(InstancePtr, IntcConfig, IntcConfig->CpuBaseAddress) ;

“It seems that when initialized, all interrupts, including the timer interrupt, are initialized. Therefore, I would like to know a way to only register the handler without initializing the timer interrupt. Do you have any good suggestions?”

Not sure if the right answer has been given already, but I wonder if xil_printf() may be called from an interrupt context.

Yes, that’s right. From what I understand, the current issue is that after the timer interrupt operates once, the tasks are not running due to the initialization of the interrupt

Can you elaborate what you mean by that? Can you share the piece of code where the said initialization happens?

Also, does this post apply to you - interrupts (Zynq) - FreeRTOS

	IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);

	Xil_AssertNonvoid(InstancePtr != NULL);
	Xil_AssertNonvoid(IntcConfig != NULL);

	if(InstancePtr->IsReady != XIL_COMPONENT_IS_READY)
	{

		InstancePtr->IsReady = 0U;
		InstancePtr->Config = IntcConfig;
		InstancePtr->IsReady = XIL_COMPONENT_IS_READY;
	}

	XScuGic_Connect(InstancePtr, RX_INTR_ID,
				(Xil_ExceptionHandler)GpioHandler, (void *)GpioInstancePtr);

	XScuGic_Enable(InstancePtr, RX_INTR_ID);

I resolved it by inserting the same code.

Thank you for reporting back.