Hi, Martin,
I have to say that the api function of usart code based on FreeRtos is corpulent and inefficient, that is why the transfer is slower than you expected. This is the architecture of the USART plus FreeRtos example.
The example use interrupt mechanism, for usart transmitter, after the transmitter has transmitted a character(one Byte), the LPC will enter ISR, I copy the ISR here. In the ISR, it check if the predefined size of message has transmitted, if the message has transmitted, it call a call-back function, in the call-back function, an event is triggered with the code:
You can check the USART_TransferHandleIRQ() ISR code, it is too long, inefficient.
if (status == kStatus_USART_TxIdle)
{
xResult = xEventGroupSetBitsFromISR(handle->txEvent, RTOS_USART_COMPLETE, &xHigherPriorityTaskWoken);
}
If you want to transfer as fast as possible, I suggest you call USART_TransferSendNonBlocking() without using FreeRtos, USART_TransferSendNonBlocking() function uses polling mode, it is the fastest. Secondly, you can call USART_WriteBlocking(), it uses interrupt mode, the transfer speed is middle.
Hope it can help you
BR
XiangJun Rong
void USART_TransferHandleIRQ(USART_Type *base, usart_handle_t *handle)
{
/* Check arguments */
assert((NULL != base) && (NULL != handle));
bool receiveEnabled = ((handle->rxDataSize != 0U) || (handle->rxRingBuffer != NULL));
bool sendEnabled = (handle->txDataSize != 0U);
uint8_t rxdata;
size_t tmpsize;
/* If RX overrun. */
if ((base->FIFOSTAT & USART_FIFOSTAT_RXERR_MASK) != 0U)
{
/* Clear rx error state. */
base->FIFOSTAT |= USART_FIFOSTAT_RXERR_MASK;
/* clear rxFIFO */
base->FIFOCFG |= USART_FIFOCFG_EMPTYRX_MASK;
/* Trigger callback. */
if (handle->callback != NULL)
{
handle->callback(base, handle, kStatus_USART_RxError, handle->userData);
}
}
while ((receiveEnabled && ((base->FIFOSTAT & USART_FIFOSTAT_RXNOTEMPTY_MASK) != 0U)) ||
(sendEnabled && ((base->FIFOSTAT & USART_FIFOSTAT_TXNOTFULL_MASK) != 0U)))
{
/* Receive data */
if (receiveEnabled && ((base->FIFOSTAT & USART_FIFOSTAT_RXNOTEMPTY_MASK) != 0U))
{
/* Receive to app bufffer if app buffer is present */
if (handle->rxDataSize != 0U)
{
rxdata = (uint8_t)base->FIFORD;
*handle->rxData = rxdata;
handle->rxDataSize--;
handle->rxData++;
receiveEnabled = ((handle->rxDataSize != 0U) || (handle->rxRingBuffer != NULL));
if (0U == handle->rxDataSize)
{
if (NULL == handle->rxRingBuffer)
{
base->FIFOINTENCLR = USART_FIFOINTENCLR_RXLVL_MASK | USART_FIFOINTENSET_RXERR_MASK;
}
handle->rxState = (uint8_t)kUSART_RxIdle;
if (handle->callback != NULL)
{
handle->callback(base, handle, kStatus_USART_RxIdle, handle->userData);
}
}
}
/* Otherwise receive to ring buffer if ring buffer is present */
else
{
if (handle->rxRingBuffer != NULL)
{
/* If RX ring buffer is full, trigger callback to notify over run. */
if (USART_TransferIsRxRingBufferFull(handle))
{
if (handle->callback != NULL)
{
handle->callback(base, handle, kStatus_USART_RxRingBufferOverrun, handle->userData);
}
}
/* If ring buffer is still full after callback function, the oldest data is overridden. */
if (USART_TransferIsRxRingBufferFull(handle))
{
/* Increase handle->rxRingBufferTail to make room for new data. */
if ((size_t)handle->rxRingBufferTail + 1U == handle->rxRingBufferSize)
{
handle->rxRingBufferTail = 0U;
}
else
{
handle->rxRingBufferTail++;
}
}
/* Read data. */
rxdata = (uint8_t)base->FIFORD;
handle->rxRingBuffer[handle->rxRingBufferHead] = rxdata;
/* Increase handle->rxRingBufferHead. */
if ((size_t)handle->rxRingBufferHead + 1U == handle->rxRingBufferSize)
{
handle->rxRingBufferHead = 0U;
}
else
{
handle->rxRingBufferHead++;
}
}
}
}
/* Send data */
if (sendEnabled && ((base->FIFOSTAT & USART_FIFOSTAT_TXNOTFULL_MASK) != 0U))
{
base->FIFOWR = *handle->txData;
handle->txDataSize--;
handle->txData++;
sendEnabled = handle->txDataSize != 0U;
if (!sendEnabled)
{
base->FIFOINTENCLR = USART_FIFOINTENCLR_TXLVL_MASK;
handle->txState = (uint8_t)kUSART_TxIdle;
base->INTENSET |= USART_INTENSET_TXIDLEEN_MASK;
}
}
}
/* Tx idle and the interrupt is enabled. */
if ((0U != (base->INTENSET & USART_INTENSET_TXIDLEEN_MASK)) &&
(0U != (base->INTSTAT & USART_INTSTAT_TXIDLE_MASK)) && (handle->txState == (uint8_t)kUSART_TxIdle))
{
/* Disable tx idle interrupt */
base->INTENCLR |= USART_INTENCLR_TXIDLECLR_MASK;
/* Trigger callback. */
if (handle->callback != NULL)
{
handle->callback(base, handle, kStatus_USART_TxIdle, handle->userData);
}
}
/* ring buffer is not used */
if (NULL == handle->rxRingBuffer)
{
tmpsize = handle->rxDataSize;
/* restore if rx transfer ends and rxLevel is different from default value */
if ((tmpsize == 0U) && (USART_FIFOTRIG_RXLVL_GET(base) != handle->rxWatermark))
{
base->FIFOTRIG =
(base->FIFOTRIG & (~USART_FIFOTRIG_RXLVL_MASK)) | USART_FIFOTRIG_RXLVL(handle->rxWatermark);
}
/* decrease level if rx transfer is bellow */
if ((tmpsize != 0U) && (tmpsize < (USART_FIFOTRIG_RXLVL_GET(base) + 1U)))
{
base->FIFOTRIG = (base->FIFOTRIG & (~USART_FIFOTRIG_RXLVL_MASK)) | (USART_FIFOTRIG_RXLVL(tmpsize - 1U));
}
}
}
static void USART_RTOS_Callback(USART_Type *base, usart_handle_t *state, status_t status, void *param)
{
usart_rtos_handle_t *handle = (usart_rtos_handle_t *)param;
BaseType_t xHigherPriorityTaskWoken, xResult;
xHigherPriorityTaskWoken = pdFALSE;
xResult = pdFAIL;
if (status == kStatus_USART_RxIdle)
{
xResult = xEventGroupSetBitsFromISR(handle->rxEvent, RTOS_USART_COMPLETE, &xHigherPriorityTaskWoken);
}
else if (status == kStatus_USART_TxIdle)
{
xResult = xEventGroupSetBitsFromISR(handle->txEvent, RTOS_USART_COMPLETE, &xHigherPriorityTaskWoken);
}
else if (status == kStatus_USART_RxRingBufferOverrun)
{
xResult = xEventGroupSetBitsFromISR(handle->rxEvent, RTOS_USART_RING_BUFFER_OVERRUN, &xHigherPriorityTaskWoken);
}
if (xResult != pdFAIL)
{
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}