How should xQueueSendFromISR and xQueueReceive be used?

adissida wrote on Tuesday, September 15, 2015:

The example projects I have looked at, its simple. To be more shure and understand the xQueue I have read the manual for it and this video guide https://www.youtube.com/watch?v=8lIpI30Tj-g

This is my code for setting up the interrupt handler:


INTC_register_interrupt((int_handler)&trvCLI_UART_ISR, AVR32_USART1_IRQ, AVR32_INTC_INT0);


then from the example project the portENTER_SWITCHING_ISR is needed:


__attribute((naked)) static void trvCLI_UART_ISR( void )
{
portENTER_SWITCHING_ISR();

trvCLI_UART_ISR_Recieve();

portEXIT_SWITCHING_ISR();

}


and at last this function is called after entering switching ISR:


__attribute((noinline)) static portBASE_TYPE trvCLI_UART_ISR_Recieve( void )
{
/* Now we can declare the local variables. */
signed portCHAR cChar = 0;
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
unsigned portLONG ulStatus;
volatile avr32_usart_t *usart = trvCLI_USART;

/* What caused the interrupt? */
ulStatus = usart->csr & usart->imr;

if (ulStatus & AVR32_USART_CSR_RXRDY_MASK)
{
	/* The interrupt was caused by the receiver getting data. */
	cChar = usart->rhr; //TODO

	/* Because FreeRTOS is not supposed to run with nested interrupts, put all OS
	calls in a critical section . */
	portENTER_CRITICAL();
		if (xQueueSendFromISR(xRxedChars, &cChar, &xHigherPriorityTaskWoken))
		{
			gpio_tgl_gpio_pin(trvLED_GPS);
		}
	portEXIT_CRITICAL();
}

usart->csr;

/* The return value will be used by portEXIT_SWITCHING_ISR() to know if it
should perform a vTaskSwitchContext(). */
return ( xHigherPriorityTaskWoken );

}


I have a simple task, to watch the xRxedChars queue:


void trvUART_CLI_RX( void *pvParameters )
{
signed portCHAR receivedChars = 0;
uint8_t str[30];
( void ) pvParameters;

for ( ;; )
{
	if (xQueueReceive(xRxedChars, &receivedChars, comRX_BLOCK_TIME))
	{
		sprintf( str,"%d",receivedChars );
		trvCLI_WriteLine( &str );
	}
}
//vTaskDelete(NULL);

}


As soon as I enter something in the console, everything hangs. If I change the xQueueReceive to xQueueReceiveFromISR it doesent hangs but the value is never copied to receivedChars.

Using ATMEL UC3, FreeRTOS V8.2.2

heinbali01 wrote on Tuesday, September 15, 2015:

From your previous post:

So it has something to do with usart->ier = AVR32_USART_IER_RXRDY_MASK
When I delete that line in the code above, it always works (two LEDs blinking)

When you delete that line there won’t be any RX interrupt.

Your ISR is indeed masking off bits that have not been enabled:

    /* What caused the interrupt? */
    ulStatus = usart->csr & usart->imr;

Because FreeRTOS is not supposed to run with nested interrupts,
put all OS calls in a critical section
portENTER_CRITICAL();
if (xQueueSendFromISR(xRxedChars, &cChar, &xHigherPriorityTaskWoken))
portEXIT_CRITICAL();

I don’t think the critical section is necessary. Interrupts are not enabled (by the global flag) until you enable them.
And ask your self: will there be another ISR that will try to access your xRxedChars? That shouldn’t be.

Note that if you expect lots of data (kilobytes), you better look at other methods like using PDC (DMA) channels.

My guess is that taking away the critical sections will solve the problem.

From trvUART_CLI_RX() you will call xQueueReceive() (without the FromISR), and xQueueReceive() will use critical sections when necessary.

Regards.