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;
...
}
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?
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
Thanks, I'll look into it.
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;
}
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;
}
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?