Interrupt handling in FreeRTOS

barbart1 wrote on Sunday, June 06, 2010:

Hi,

I’m wondering if there is a special mechanism for handling
interrupts in FreeRTOS? I wanted to write a simple interrupt
routine that would toggle a led when I press a button. But sadly,
when I add the interrupt initialization code, the task won’t start.
Here’s the code:

void initInterr()
{
	AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_PIOA, 5, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL,ChangeFlashRate);
	AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_PIOA);
	AT91C_BASE_PIOA->PIO_IER = AT91C_PIO_PA19; // B1
}




void vStartLEDFlashTasks()
{
	initInterr();
	xTaskCreate( vLEDBlink, ( signed char * ) "LEDtaskC", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 2, NULL );
}





void ChangeFlashRate()
{
	int status;
	status = AT91C_BASE_PIOA->PIO_ISR;
	vParTestToggleLED( 0 );
}

As you can see it’s very simple. I’m using SAM7-P64 dev board. Am i doing it wrong?

barbart1 wrote on Sunday, June 06, 2010:

It seems like the line :

AT91C_BASE_PIOA->PIO_IER = AT91C_PIO_PA19;

is the problem. If I comment it, the task is running and everything is ok. How should I handle the interrupt then?

rgrover1 wrote on Sunday, June 06, 2010:

Try enabling your interrupt only after the freeRTOS scheduler gets started.
In your FreeRTOS port, isn’t there a sample serial driver using interrupts which can help as a reference?

barbart1 wrote on Tuesday, June 08, 2010:

Hi, I bought the manual and changed my code, but interrupts still don’t work. Everything seems to be ok. Is the ISR written correctly?

void ToggleLedISR()
{
	int status;
	static portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
	status = AT91C_BASE_PIOA->PIO_ISR;
	xSemaphoreGiveFromISR(xSemafor, &xHigherPriorityTaskWoken);
	if(xHigherPriorityTaskWoken == pdTRUE) {
		AT91C_BASE_AIC->AIC_EOICR = 0xFA;
		portYIELD_FROM_ISR();
	}
}

Here’s the task that takes the semaphore:

void ToggleLedTask(void *pvParameters) {
	while(1) {
		xSemaphoreTake(xSemafor, portMAX_DELAY);
		vParTestToggleLED( 0 );
	}
}

richard_damon wrote on Tuesday, June 08, 2010:

Not familiar with this processor, but the line
AT91C_BASE_AIC->AIC_EOICR = 0xFA;
would be my guess at the error. I presume this is an end of interrupt control, and probably doesn’t want to be conditioned on xHigherPriorityTaskWoken. I would suggest placing it before the if statement.

barbart1 wrote on Tuesday, June 08, 2010:

I got it working. It seems that an interrupt handler that gives a token to a semaphore needs to be called from a wrapper that copies the context. I got it working with:

void vLed_ISR_Wrapper( void )
{
	/* Save the context of the interrupted task. */
	portSAVE_CONTEXT();
	/* Call the handler itself.  This must be a separate function as it uses
	the stack. */
	__asm volatile ("bl vLed_ISR_Handler");
	/* Restore the context of the task that is going to
	execute next. This might not be the same as the originally
	interrupted task.*/
	portRESTORE_CONTEXT();
}

Now, correct me if I’m wrong, but that is the only way I managed to get it done. Without the wrapper the processor “hangs” itself. And of course both the wrapper and the handler must be compiled in ARM mode. Or is there a way without using a wrapper?

rtel wrote on Tuesday, June 08, 2010:

If your interrupt is wanting to cause a context switch, or wanting to call a FreeRTOS API function, then the wrapper is required - as per the documentation and examples.

Regards.