Best efficient way to handle Interrupt

Dear All, There are different approach to handle IRQ with FreeRTOS, does somebody knows what is the most efficient way in terms of processor use, memory etc.. here both cases : FIRST case : Interrupt function : char cC; cC = LLUSARTReceiveData(Instance); xQueueSendFromISR(xQueueUartRx, &cC, NULL); vTaskNotifyGiveFromISR(uartExtTaskHandle, NULL); //*************************************** Task with uartExtTaskHandle : void uartExttask(void const* argument) { char cChar; while(true) { if (xQueueReceive(xQueueUartRx, &cChar, 0)) { // do somethings } ulTaskNotifyTake(pdTRUE, portMAXDELAY); } SECOND case : Interrupt function : portCHAR cC; cC = LLUSARTReceiveData8(USART6); xQueueSendFromISR(xQueueUartRx,&cC, NULL); //************************************* Task for receiving car : char Ccar; for (;;) { if (xQueueReceivexQueueUartRx,&Ccar, portMAX_DELAY) == pdTRUE) { // do somethings }

Best efficient way to handle Interrupt

Hi David, To summarise your two approaches: FIRST case : ~~~ void Interrupthandler() { char cC; cC = LLUSART_ReceiveData(Instance); xQueueSendFromISR(xQueueUartRx, &cC, NULL); vTaskNotifyGiveFromISR(uartExtTaskHandle, NULL); } void uartExttask(void const* argument) { char cChar; while(true) { if (xQueueReceive(xQueueUartRx, &cChar, 0)) { // do somethings } ulTaskNotifyTake(pdTRUE, portMAXDELAY); } } ~~~ SECOND case : ~~~ void Interrupthandler() { portCHAR cC; cC = LLUSART_ReceiveData8(USART6); xQueueSendFromISR(xQueueUartRx,&cC, NULL); } void Taskforreceiving() { char Ccar; for (;;) { if (xQueueReceive( xQueueUartRx,&Ccar, portMAX_DELAY ) == pdTRUE) { // do somethings } } } ~~~ The second approach looks better to me. In the first approach you are using two wake-up (or notify) mechanisms: both a message queue and a task notification. One method is enough. Note that the second approach is ok for a terminal driver that receives key strokes or so. When the USART is exchanging big amounts of data, it is worth using multiple DMA-buffers. Only when a buffer is full, or when no more data are expected, you send a buffer to the user. After reading it, the user will have to pass back the buffer to the driver. Personally, I like to use circular buffers (see stream_buffer.c), where the driver may write and the user (a single user only) may read from it. This can also be combined with the task-notify mechanism: ~~~ void Interrupthandler() { char cC; BaseTypet xSwitchRequired = pdFALSE;
cC = LL_USART_ReceiveData( Instance );
addByte (&xCircularBuffer, cC);
vTaskNotifyGiveFromISR( uartExtTaskHandle, &( xSwitchRequired ) );
/* Switch context if needed: */
portYIELD_FROM_ISR( xSwitchRequired );
} void Taskforreceiving(void const* argument) { char pcBuffer[ 128 ]; int iCount;
while(true)
{
    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
    /* When waking up, 1 or more bytes have been placed in the
    circular buffer.  Read them in blocks: */
    for( ;; )
    {
        iCount = readBytes ( &xCircularBuffer, pcBuffer, sizeof pcBuffer );
        if( iCount <= 0 )
        {
            break;
        }
        // do somethings
    }
}
} ~~~ Note also that I added a call to portYIELD_FROM_ISR(), to cause a context-switch.

Best efficient way to handle Interrupt

Hi Hein, Thanks for your answer, how you garantee your circular buffer is thread safe ? Regards

Best efficient way to handle Interrupt

The simplest way is to use a mutex for the task side. Normally the ISR side doesn’t have much to worry about, as only 1 ISR will be connected to a given buffer, so it just needs to make sure it updates things such that the task will always see something consistant, and the task need to make sure it keeps things clean for the ISR. One key for this is you move/take the data byte, THEN you update the data pointers. Often I find the task side doesn’t need an explicit mutex for the curcular buffer, as there is a higner level aspect that makes it so that only one task has access to the buffer at any given time.

Best efficient way to handle Interrupt

Thanks Richard, what are you opinion concerning my original question to handle IRQ ? rgds

Best efficient way to handle Interrupt

David wrote:
Thanks for your answer, how you guarantee your circular buffer is thread safe ?
You’re welcome. Richard Damon already answered your question. The method is thread-safe as long as there is only one “giver” and one “taker”. As Richard comments, this is a design thing. If you want to read USART data from several threads (tasks), the circular buffer should be protected with a mutex.

Best efficient way to handle Interrupt

As Hein said, there is no reason that I see to use both a Queue, and then also a direct to task notification (or a semaphore), as you normally only need one interlocking primative. If the baud rate isn’t to high, or the protocal makes it hard for the ISR to figure out the message breaks, just using a Queue can be the simplest, though it does have the overhead of likely causing a task switch in and out for each character. If the data rate is high, the messages are somewhat long, and the ISR can detect message boundries, then having the ISR buffer up a full message and then notify the task can lower the processor load to receive the message. This might be done with a circular buffer, or you might have a group of buffers and indicate which buffer has the message (particularly useful for large messages, to avoid needing to copy it into and out of a circular queue.

Best efficient way to handle Interrupt

Many thanks Hein and Richard for your valuable answer.

Best efficient way to handle Interrupt

FreeRTOS V10.0.0 and on has a thread safe circular buffer, with an example of interrupt to task comms: https://www.freertos.org/RTOS-stream-buffer-example.html