two suggestion for UART driver of KDSK2

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

two suggestion for UART driver of KDSK2

3,248 Views
phantomgz
Contributor III

1. UART_RTOS_Receive() in fsl_uart_freertos.c ,

 

int UART_RTOS_Receive(uart_rtos_handle_t *handle, uint8_t *buffer, uint32_t length, size_t *received)
{   ...
    /* Non-blocking call */
    UART_TransferReceiveNonBlocking(handle->base, handle->t_state, &handle->rxTransfer, &n);

    ev = xEventGroupWaitBits(handle->rxEvent,
                             RTOS_UART_COMPLETE | RTOS_UART_RING_BUFFER_OVERRUN | RTOS_UART_HARDWARE_BUFFER_OVERRUN,
                             pdTRUE, pdFALSE, portMAX_DELAY);
    ...
}

   If a program act as master, it would first send something to the slave, and wait slave respond. but if the packet come from slave occure any error, master can not receive enough data that it want to, the RTOS_UART_COMPLETE event will never be fired, the program will blocked in xEventGroupWaitBits() forever. because the parameter uxBitsToWaitFor is set portMAX_DELAY(it's means to never timeout). I suggest add a timeout parameter for UART_RTOS_Receive() to give a chance for user, to handle if any error occure from incoming data issue.

 

 

2. UART_TransferHandleIRQ()  in fsl_uart.c, do not need to call UART_TransferIsRxRingBufferFull() twice every time. I have make some change as follow.

void UART_TransferHandleIRQ(UART_Type *base, uart_handle_t *handle)
{
    ...
        /* If use RX ring buffer, receive data to ring buffer. */
        if (handle->rxRingBuffer)
        {
            while (count--)
            {
                /* If RX ring buffer is full, trigger callback to notify over run. */
                if (UART_TransferIsRxRingBufferFull(handle))
                {
                    if (handle->callback)
                    {
                        handle->callback(base, handle, kStatus_UART_RxRingBufferOverrun, handle->userData);

                    }
                    /* Move to here */
                          /* If ring buffer is still full after callback function, the oldest data is overrided. */
                          if (UART_TransferIsRxRingBufferFull(handle))
                          {
                              /* Increase handle->rxRingBufferTail to make room for new data. */
                              if (handle->rxRingBufferTail + 1U == handle->rxRingBufferSize)
                              {
                                  handle->rxRingBufferTail = 0U;
                              }
                              else
                              {
                                  handle->rxRingBufferTail++;
                              }
                          }                    
                }

             #if 0  // don't need to call twice every time.
                /* If ring buffer is still full after callback function, the oldest data is overrided. */
                if (UART_TransferIsRxRingBufferFull(handle))
                {
                    /* Increase handle->rxRingBufferTail to make room for new data. */
                    if (handle->rxRingBufferTail + 1U == handle->rxRingBufferSize)
                    {
                        handle->rxRingBufferTail = 0U;
                    }
                    else
                    {
                        handle->rxRingBufferTail++;
                    }
                }
              #endif

                /* Read data. */
                handle->rxRingBuffer[handle->rxRingBufferHead] = base->D;
    ...
}
Labels (1)
6 Replies

2,166 Views
higor
Contributor II

I have a similar situation.
I implemented the modbus protocol in the K64F microcontroller.

However, in some moments the status is occurring: kStatus_UART_RxHardwareOverrun

 

 

It is configured as follows:

baudrate: 115200
parity mode: parity disabled
number of stop bits: one stop bit
buffer size: 256

rt/tx interrupt priority setting
enable priority initialization: checked
priority: 10

 

Can anybody help me?

0 Kudos

2,161 Views
ErichStyger
Senior Contributor V

I had similar problems. I ended up rewriting the interrupt handler, you can see it here:

https://github.com/ErichStyger/McuOnEclipseLibrary/blob/master/lib/src/McuUart485.c

I did not use it with K64F but for K22F and K02F, but I think it would run the same way on a K64F too.

I hope this helps,

Erich

0 Kudos

2,159 Views
higor
Contributor II

Thanks, I'll look into it.

0 Kudos

2,648 Views
hectorgastaminz
Contributor II

I made some modifications to UART_RTOS_Receive() in fsl_uart_freertos.c,

int UART_RTOS_Receive(uart_rtos_handle_t *handle, uint8_t *buffer, uint32_t length, size_t *received)
{
    /* ... */

    /* Non-blocking call */
    UART_TransferReceiveNonBlocking(handle->base, handle->t_state, &handle->rxTransfer, &n);

    ev = xEventGroupWaitBits(handle->rxEvent,
                             RTOS_UART_COMPLETE | RTOS_UART_RING_BUFFER_OVERRUN | RTOS_UART_HARDWARE_BUFFER_OVERRUN,
                             pdTRUE, pdFALSE, 32);
    if (ev & RTOS_UART_HARDWARE_BUFFER_OVERRUN)
    {
        /* ... */
    }
    else if (ev & RTOS_UART_RING_BUFFER_OVERRUN)
    {
        /* ... */
    }
    else if (ev & RTOS_UART_COMPLETE)
    {
        /* ... */
    }
    else
    {
         // Timeout
         if(kStatus_Success == UART_TransferGetReceiveCount(handle->base, handle->t_state, &n))
         {
              if(n > 0)
              {
                        /* Disable UART RX IRQ, protect ring buffer. */
                        UART_DisableInterrupts(handle->base, kUART_RxDataRegFullInterruptEnable);

                        uart_handle_t * pUartDrv = handle->t_state;
                   pUartDrv->rxDataSize = pUartDrv->rxDataSizeAll;
                   pUartDrv->rxData = handle->rxTransfer.data;
                   local_received = n;
                   retval = kStatus_Success;

                        /* Enable UART RX IRQ if previously enabled. */
                        UART_EnableInterrupts(handle->base, kUART_RxDataRegFullInterruptEnable);
              }
         }
    }

    /* ... */

    return retval;
}
0 Kudos

2,648 Views
NicolasP
Contributor IV

The above implementation is erroneous.

Here is my implementation :

/*FUNCTION**********************************************************************
 *
 * Function Name : UART_RTOS_Recv
 * Description   : Receives chars for the application
 *
 *END**************************************************************************/
int UART_RTOS_Receive(uart_rtos_handle_t *handle, uint8_t *buffer, uint32_t length, size_t *received, uint32_t DlyMs)
{
    EventBits_t ev;
    size_t n = 0;
    int retval = kStatus_Fail;
    size_t local_received = 0;
    TickType_t DlyTicks;


    if (NULL == handle->base)
    {
        /* Invalid handle. */
        return kStatus_Fail;
    }
    if (0 == length)
    {
        if (received != NULL)
        {
            *received = n;
        }
        return 0;
    }
    if (NULL == buffer)
    {
        return kStatus_InvalidArgument;
    }

    /* New transfer can be performed only after current one is finished */
    if (pdFALSE == xSemaphoreTake(handle->rxSemaphore, portMAX_DELAY))
    {
        /* We could not take the semaphore, exit with 0 data received */
        return kStatus_Fail;
    }

    handle->rxTransfer.data = buffer;
    handle->rxTransfer.dataSize = (uint32_t)length;

    /* Non-blocking call */
    UART_TransferReceiveNonBlocking(handle->base, handle->t_state, &handle->rxTransfer, &n);

    /* Compute timeout in ticks */
    if (DlyMs < portTICK_PERIOD_MS)
    {
        DlyTicks = 1;
    }
    else
    {
        DlyTicks = DlyMs/portTICK_PERIOD_MS;
    }
    ev = xEventGroupWaitBits(handle->rxEvent,
                             RTOS_UART_COMPLETE | RTOS_UART_RING_BUFFER_OVERRUN | RTOS_UART_HARDWARE_BUFFER_OVERRUN,
                             pdTRUE, pdFALSE, DlyTicks);
    if (ev & RTOS_UART_HARDWARE_BUFFER_OVERRUN)
    {
        /* Stop data transfer to application buffer, ring buffer is still active */
        UART_TransferAbortReceive(handle->base, handle->t_state);
        /* Prevent false indication of successful transfer in next call of UART_RTOS_Receive.
           RTOS_UART_COMPLETE flag could be set meanwhile overrun is handled */
        xEventGroupClearBits(handle->rxEvent, RTOS_UART_COMPLETE);
        retval = kStatus_UART_RxHardwareOverrun;
        local_received = 0;
    }
    else if (ev & RTOS_UART_RING_BUFFER_OVERRUN)
    {
        /* Stop data transfer to application buffer, ring buffer is still active */
        UART_TransferAbortReceive(handle->base, handle->t_state);
        /* Prevent false indication of successful transfer in next call of UART_RTOS_Receive.
           RTOS_UART_COMPLETE flag could be set meanwhile overrun is handled */
        xEventGroupClearBits(handle->rxEvent, RTOS_UART_COMPLETE);
        retval = kStatus_UART_RxRingBufferOverrun;
        local_received = 0;
    }
    else if (ev & RTOS_UART_COMPLETE)
    {
        retval = kStatus_Success;
        local_received = length;
    }
    else
    {
        // Timeout
        uint32_t RxCount;


        /* Disable UART RX IRQ, protect ring buffer. */
        UART_DisableInterrupts(handle->base, kUART_RxDataRegFullInterruptEnable);

        /* Get count received outside ring buffer (directly in buffer) */
        UART_TransferGetReceiveCount(handle->base, handle->t_state, &RxCount);

        /* Stop data transfer to application buffer, ring buffer is still active */
        UART_TransferAbortReceive(handle->base, handle->t_state);

        local_received = RxCount + n;   /* n = Nb bytes received from ring buffer */
        if (local_received)
        {
            retval = kStatus_Success;
        }
        else
        {
            retval = kStatus_Timeout;
        }

        /* Enable UART RX IRQ if previously enabled. */
        UART_EnableInterrupts(handle->base, kUART_RxDataRegFullInterruptEnable);
    }

    /* Prevent repetitive NULL check */
    if (received != NULL)
    {
        *received = local_received;
    }

    /* Enable next transfer. Current one is finished */
    if (pdFALSE == xSemaphoreGive(handle->rxSemaphore))
    {
        /* We could not post the semaphore, exit with error */
        retval = kStatus_Fail;
    }
    return retval;
}


2,648 Views
hectorgastaminz
Contributor II

I agree with you, fsl_uart_freertos doesn't seem to be good enough to be used in a system which need high speed communication through uarts. As I understand there are two ways to work with this driver, using in UART_RTOS_Receive (..., ..., length, ....) a length = 1 but it generates a lot of overhead (hw/sw overrun) or use length = n where the system could be waiting forever if it doesn't receive n bytes.

In KSDK 1.3, I was using MQX and driver UART_DRV_ReceiveDataBlocking(uint32_t instance, uint8_t * rxBuff,  uint32_t rxSize, uint32_t timeout), that way to work was easier.

I couldn't improve this new driver yet. If you made some improvement could you share it?

0 Kudos