Cortex A9/Zynq ISR hangs on xSemaphoreGiveFromISR

raymadigan wrote on Wednesday, June 01, 2016:

I have been trying to solve this problem for too long now. There is clearly something I don’t quite get yet. Any pointers would be helpful.

I have a DMA program that runs on the Zynq without FreeRTOS, and it runs on FreeRTOS if I use a callback function from the ISR. The problem is, it can’t be a FreeRTOS task. So I followed the example in Mastering the FreeRTOS Kernel in the interrupt section and I can’t understand why the application hangs in the call to xSemaphoreGiveFromISR.

There are three tasks running and the isr handler task has the highest priority

#define mainHANDLE_TASK_PRIORITY		    ( tskIDLE_PRIORITY + 3 )
#define mainQUEUE_RECEIVE_TASK_PRIORITY		( tskIDLE_PRIORITY + 2 )
#define	mainQUEUE_SEND_TASK_PRIORITY		( tskIDLE_PRIORITY + 1 )

The semaphore is defined as

static SemaphoreHandle_t xBinarySemaphore = NULL;

main is very simple

int main( void )
{
	prvSetupHardware();
	prvSetupDMA();

	xBinarySemaphore = xSemaphoreCreateBinary();

	if (xBinarySemaphore != NULL )
	{
		xTaskCreate (vHandleTask, "Handler", 
                                configMINIMAL_STACK_SIZE, NULL, mainHANDLE_TASK_PRIORITY, NULL);
	}

	/* Create the queue. */
	xQueue = xQueueCreate( mainQUEUE_LENGTH, sizeof( uint32_t ) );

	if( xQueue != NULL )
	{
		xTaskCreate( prvQueueReceiveTask,
					"Rx",
					configMINIMAL_STACK_SIZE,
					NULL, 
					mainQUEUE_RECEIVE_TASK_PRIORITY,
					NULL );							

		xTaskCreate( prvQueueSendTask, "TX",
                               configMINIMAL_STACK_SIZE, NULL, mainQUEUE_SEND_TASK_PRIORITY, NULL );
	}
	if ( (xQueue != NULL) && (xBinarySemaphore != NULL))
		vTaskStartScheduler();
	}
}

The handler task, just to get it will do processing later

static void vHandleTask (void *pvParameters)
{
	for ( ;; )
	{
		printf("Before Take Interrupt Handler \r\n");
		xSemaphoreTake (xBinarySemaphore, portMAX_DELAY);
		printf("Interrupt Handler \r\n");
	}
}

The interrupt service routine

static void RxIntrHandler(void *Callback)
{
	XAxiDma_BdRing *RxRingPtr = (XAxiDma_BdRing *) Callback;
	u32 IrqStatus;
	int TimeOut;

	BaseType_t xHigherPriorityTaskWoken;

	IrqStatus = XAxiDma_BdRingGetIrq(RxRingPtr);
	XAxiDma_BdRingAckIrq(RxRingPtr, IrqStatus);
	if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {
		return;
	}

	if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {

		XAxiDma_BdRingDumpRegs(RxRingPtr);
		XAxiDma_Reset(&AxiDma);
		TimeOut = RESET_TIMEOUT_COUNTER;
		while (TimeOut) {
			if(XAxiDma_ResetIsDone(&AxiDma)) {
				break;
			}
			TimeOut -= 1;
		}
		return;
	}

    // The following to wake up the FreeRTOS handler task
	xHigherPriorityTaskWoken = pdFALSE;
    /// This print statment always happens
	printf("Interrupt 1: \r\n");
	xSemaphoreGiveFromISR(xBinarySemaphore, &xHigherPriorityTaskWoken);
    /// This print statement never happens
	printf("Interrupt 2: \r\n");
	portYIELD_FROM_ISR( xHigherPriorityTaskWoken );

    // If completion interrupt is asserted, call RX call back function
	// to handle the processed BDs and then raise the according flag.
	//if ((IrqStatus & (XAXIDMA_IRQ_DELAY_MASK | XAXIDMA_IRQ_IOC_MASK))) {
	//	RxCallBack(RxRingPtr);
	//}
	printf("Interrupt Out: \r\n");
}

the output looks like

Before Take Interrupt Handler
Interrupt 1:

The isr handle task is waiting for the semaphore and the isr hangs attempting to deliver it.

Any help would be appreciated.

heinbali01 wrote on Thursday, June 02, 2016:

Hi Sting,

I don’t know how your printf() is implemented, but the standard implementation is normally not interrupt-proof. I would try to debug it by setting some volatile variables and log those from a normal task.

raymadigan wrote on Thursday, June 02, 2016:

It hangs when I comment out the printf statements. It doesn’t hang with the printf statements when I use the callback. The only time it hangs is when I use the BinarySemaphore to wake up the handler.

This interrupt is an AXI interrupt generated by the logic in the fpga. Maybe the handling has to be different. The handling of memory has to be different for the buffer descriptors because the interconnects in the fpga address memory fro 0x100000 to 0x1FFFFF.

Since the callback mechanism seems to work I will temporarily move the wakeup of the handler to the callback routine so I can handle the data management in a task until I figure out how to debug this.

rtel wrote on Thursday, June 02, 2016:

I would agree with Hein, calling printf() from an interrupt is going to cause more problems that it solves. I would suggest placing a breakpoint on the xSemaphoreGiveFromISR() call and stepping through the code to see what it does, how far it gets, etc.

The Cortex-A port has specific requirements for how interrupts are installed. Are you using the FreeRTOS interrupt handler, and installing the interrupts as described on the following page: http://www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html

Regards.

raymadigan wrote on Thursday, June 02, 2016:

I got the board late last night and found the problem. I do wonder why it works bare metal, but I did have a defect.

//defined in FreeRTOSConfig.h
#define configMAX_API_CALL_INTERRUPT_PRIORITY	18

// Setting the interrupt priority
XScuGic_SetPriorityTriggerType(&xInterruptController, XFER_INTR_ID, 0x10, 0x3);
// Should have been
XScuGic_SetPriorityTriggerType(&xInterruptController, XFER_INTR_ID, 0xA0, 0x3);

raymadigan wrote on Thursday, June 02, 2016:

I just reread the post and:

Are you using the FreeRTOS interrupt handler?

I have to answer this question with a NO! Not that I wouldn’t, I just can’t find the reference to a call that would, and I looked at

void vApplicationIRQHandler( uint32_t ulICCIAR );

in FreeRTOS_tick_config and it looks to call the functions from the XScuGic interrupt table so I figured that just registering them was all I needed to do.