2

I use the FreeRTOS LPUART library to receive data from an external device. The data I receive looks all fine except every few lines, a character is missing. Been trying to fix this for days but haven't found a reliable solution yet. Has anyone ever had this problem and found a way to fix it?

My latest theory was:

fsl_lpuart_freertos uses an event group for noticing interrupts. This works out fine for buffer overrun interrupts, but my guess is that when data arrives very fast, some interrupts go missing. The FreeRTOS guide says:

Blockquote The deferred interrupt handling task used in Example 16, and shown in Listing 93, is structured so that it only processes one event between each call to xSemaphoreTake(). That was adequate for Example 16, because the interrupts that generated the events were triggered by software, and occurred at a predictable time. In real applications, interrupts are generated by hardware, and occur at unpredictable times. Therefore, to minimize the chance of an interrupt being missed, the deferred interrupt handling task must be structured so that it processes all the events that are already available between each call to xSemaphoreTake()1

This refers to using binary semaphores for deferred interrupt handling - but as event groups are kind of like a group of binary semaphores, I assume the same problem could occur here.

So this is what I tried:

I created a counting semaphore of size 20 in the LPUART_RTOS_Init function. Then, in LPUART_RTOS_Callback, I changed the line

xResult = xEventGroupSetBitsFromISR(handle->rxEvent, RTOS_LPUART_COMPLETE, &xHigherPriorityTaskWoken);

to

xResult = xSemaphoreGiveFromISR( xCountingSemaphore, &xHigherPriorityTaskWoken );

Also, I modified LPUART_RTOS_Receive so that I can define a timeout and so that it reacts to the semaphore and not the event group bit changing.

    /* Non-blocking call */
    LPUART_TransferReceiveNonBlocking(handle->base, handle->t_state, &handle->rxTransfer, &n);
    
    ev = xEventGroupWaitBits(
            handle->rxEvent, RTOS_LPUART_RING_BUFFER_OVERRUN | RTOS_LPUART_HARDWARE_BUFFER_OVERRUN,
            pdTRUE, pdFALSE, 0 );
    /* original code
    *  ev = xEventGroupWaitBits(
    *           handle->rxEvent, RTOS_LPUART_COMPLETE | RTOS_LPUART_RING_BUFFER_OVERRUN | 
    *           RTOS_LPUART_HARDWARE_BUFFER_OVERRUN,
    *           pdTRUE, pdFALSE, atimeout);
    */
    if (ev & RTOS_LPUART_HARDWARE_BUFFER_OVERRUN)
    {
        /* Stop data transfer to application buffer, ring buffer is still active */
        LPUART_TransferAbortReceive(handle->base, handle->t_state);
        /* Prevent false indication of successful transfer in next call of LPUART_RTOS_Receive.
           RTOS_LPUART_COMPLETE flag could be set meanwhile overrun is handled */
        xEventGroupClearBits(handle->rxEvent, RTOS_LPUART_COMPLETE);
        retval         = kStatus_LPUART_RxHardwareOverrun;
        local_received = 0;
    }
    else if (ev & RTOS_LPUART_RING_BUFFER_OVERRUN)
    {
        /* Stop data transfer to application buffer, ring buffer is still active */
        LPUART_TransferAbortReceive(handle->base, handle->t_state);
        /* Prevent false indication of successful transfer in next call of LPUART_RTOS_Receive.
           RTOS_LPUART_COMPLETE flag could be set meanwhile overrun is handled */
        xEventGroupClearBits(handle->rxEvent, RTOS_LPUART_COMPLETE);
        retval         = kStatus_LPUART_RxRingBufferOverrun;
        local_received = 0;
    }
    /*
    * This is what I added
    */
    else if (xSemaphoreTake( xCountingSemaphore, atimeout ) == pdPASS)
    {
        retval          = kStatus_Success;
        local_received  = length;
    }
    else
    {
        retval         = kStatus_LPUART_Timeout;
        local_received = 0;
    }

At first, this seemed to have worked, but taking a closer look I was still missing some characters. Any ideas what else could be the problem?

coding fox
  • 21
  • 1

0 Answers0