in hw/mcu/nxp/src/ext/nxp-kinetis-sdk/drivers/fsl_uart.c [1452:1746]
void UART_TransferHandleIRQ(UART_Type *base, uart_handle_t *handle)
{
assert(handle);
uint8_t count;
uint8_t tempCount;
uint32_t status = UART_GetStatusFlags(base);
uint8_t tmpdata;
/* If RX framing error */
if (((uint32_t)kUART_FramingErrorFlag & status) != 0U)
{
/* Read base->D to clear framing error flag, otherwise the RX does not work. */
while ((base->S1 & UART_S1_RDRF_MASK) != 0U)
{
(void)base->D;
}
#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
/* Flush FIFO date, otherwise FIFO pointer will be in unknown state. */
base->CFIFO |= UART_CFIFO_RXFLUSH_MASK;
#endif
handle->rxState = (uint8_t)kUART_RxFramingError;
handle->rxDataSize = 0U;
/* Trigger callback. */
if (handle->callback != NULL)
{
handle->callback(base, handle, kStatus_UART_FramingError, handle->userData);
}
}
/* If RX parity error */
if (((uint32_t)kUART_ParityErrorFlag & status) != 0U)
{
/* Read base->D to clear parity error flag, otherwise the RX does not work. */
while ((base->S1 & UART_S1_RDRF_MASK) != 0U)
{
(void)base->D;
}
#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
/* Flush FIFO date, otherwise FIFO pointer will be in unknown state. */
base->CFIFO |= UART_CFIFO_RXFLUSH_MASK;
#endif
handle->rxState = (uint8_t)kUART_RxParityError;
handle->rxDataSize = 0U;
/* Trigger callback. */
if (handle->callback != NULL)
{
handle->callback(base, handle, kStatus_UART_ParityError, handle->userData);
}
}
/* If RX overrun. */
if (((uint32_t)kUART_RxOverrunFlag & status) != 0U)
{
/* Read base->D to clear overrun flag, otherwise the RX does not work. */
while ((base->S1 & UART_S1_RDRF_MASK) != 0U)
{
(void)base->D;
}
#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
/* Flush FIFO date, otherwise FIFO pointer will be in unknown state. */
base->CFIFO |= UART_CFIFO_RXFLUSH_MASK;
#endif
/* Trigger callback. */
if (handle->callback != NULL)
{
handle->callback(base, handle, kStatus_UART_RxHardwareOverrun, handle->userData);
}
}
/* If IDLE line was detected. */
if ((((uint32_t)kUART_IdleLineFlag & status) != 0U) && ((UART_C2_ILIE_MASK & base->C2) != 0U))
{
#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
/* If still some data in the FIFO, read out these data to user data buffer. */
count = base->RCFIFO;
/* If handle->rxDataSize is not 0, first save data to handle->rxData. */
while ((count != 0U) && (handle->rxDataSize != 0U))
{
tempCount = (uint8_t)MIN(handle->rxDataSize, (uint32_t)count);
/* Using non block API to read the data from the registers. */
UART_ReadNonBlocking(base, handle->rxData, tempCount);
handle->rxData += tempCount;
handle->rxDataSize -= tempCount;
count -= tempCount;
/* If all the data required for upper layer is ready, trigger callback. */
if (0U == handle->rxDataSize)
{
handle->rxState = (uint8_t)kUART_RxIdle;
/* Disable RX interrupt/overrun interrupt/fram error/idle line detected interrupt */
UART_DisableInterrupts(base, (uint32_t)kUART_RxDataRegFullInterruptEnable |
(uint32_t)kUART_RxOverrunInterruptEnable |
(uint32_t)kUART_FramingErrorInterruptEnable);
/* Disable parity error interrupt when parity mode is enable*/
if ((UART_C1_PE_MASK & base->C1) != 0U)
{
UART_DisableInterrupts(base, (uint32_t)kUART_ParityErrorInterruptEnable);
}
if (handle->callback != NULL)
{
handle->callback(base, handle, kStatus_UART_RxIdle, handle->userData);
}
}
}
#endif
/* To clear IDLE, read UART status S1 with IDLE set and then read D.*/
while ((UART_S1_IDLE_MASK & base->S1) != 0U)
{
(void)base->D;
}
#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
/* Flush FIFO date, otherwise FIFO pointer will be in unknown state. */
base->CFIFO |= UART_CFIFO_RXFLUSH_MASK;
#endif
/* If rxDataSize is 0, disable idle line interrupt.*/
if (0U == (handle->rxDataSize))
{
UART_DisableInterrupts(base, (uint32_t)kUART_IdleLineInterruptEnable);
}
/* If callback is not NULL and rxDataSize is not 0. */
if ((handle->callback != NULL) && (handle->rxDataSize != 0U))
{
handle->callback(base, handle, kStatus_UART_IdleLineDetected, handle->userData);
}
}
/* Receive data register full */
if ((((uint32_t)kUART_RxDataRegFullFlag & status) != 0U) && ((UART_C2_RIE_MASK & base->C2) != 0U))
{
/* Get the size that can be stored into buffer for this interrupt. */
#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
count = base->RCFIFO;
#else
count = 1;
#endif
/* If handle->rxDataSize is not 0, first save data to handle->rxData. */
while ((count != 0U) && (handle->rxDataSize != 0U))
{
#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
tempCount = (uint8_t)MIN(handle->rxDataSize, (uint32_t)count);
#else
tempCount = 1;
#endif
/* Using non block API to read the data from the registers. */
UART_ReadNonBlocking(base, handle->rxData, tempCount);
handle->rxData += tempCount;
handle->rxDataSize -= tempCount;
count -= tempCount;
/* If all the data required for upper layer is ready, trigger callback. */
if (0U == handle->rxDataSize)
{
handle->rxState = (uint8_t)kUART_RxIdle;
if (handle->callback != NULL)
{
handle->callback(base, handle, kStatus_UART_RxIdle, handle->userData);
}
}
}
/* If use RX ring buffer, receive data to ring buffer. */
if (handle->rxRingBuffer != NULL)
{
while (0U != count--)
{
/* If RX ring buffer is full, trigger callback to notify over run. */
if (UART_TransferIsRxRingBufferFull(handle))
{
if (handle->callback != NULL)
{
handle->callback(base, handle, kStatus_UART_RxRingBufferOverrun, handle->userData);
}
}
/* If ring buffer is still full after callback function, the oldest data is overridden. */
if (UART_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. */
tmpdata = base->D;
handle->rxRingBuffer[handle->rxRingBufferHead] = tmpdata;
/* Increase handle->rxRingBufferHead. */
if ((size_t)handle->rxRingBufferHead + 1U == handle->rxRingBufferSize)
{
handle->rxRingBufferHead = 0U;
}
else
{
handle->rxRingBufferHead++;
}
}
}
else if (0U == handle->rxDataSize)
{
/* Disable RX interrupt/overrun interrupt/fram error/idle line detected interrupt */
UART_DisableInterrupts(base, (uint32_t)kUART_RxDataRegFullInterruptEnable |
(uint32_t)kUART_RxOverrunInterruptEnable |
(uint32_t)kUART_FramingErrorInterruptEnable);
/* Disable parity error interrupt when parity mode is enable*/
if ((UART_C1_PE_MASK & base->C1) != 0U)
{
UART_DisableInterrupts(base, (uint32_t)kUART_ParityErrorInterruptEnable);
}
}
else
{
}
}
/* If framing error or parity error happened, stop the RX interrupt when use no ring buffer */
if (((handle->rxState == (uint8_t)kUART_RxFramingError) || (handle->rxState == (uint8_t)kUART_RxParityError)) &&
(NULL == handle->rxRingBuffer))
{
UART_DisableInterrupts(
base, (uint32_t)kUART_RxDataRegFullInterruptEnable | (uint32_t)kUART_RxOverrunInterruptEnable |
(uint32_t)kUART_FramingErrorInterruptEnable | (uint32_t)kUART_IdleLineInterruptEnable);
/* Disable parity error interrupt when parity mode is enable*/
if ((UART_C1_PE_MASK & base->C1) != 0U)
{
UART_DisableInterrupts(base, (uint32_t)kUART_ParityErrorInterruptEnable);
}
}
/* Send data register empty and the interrupt is enabled. */
if ((((uint32_t)kUART_TxDataRegEmptyFlag & status) != 0U) && ((base->C2 & UART_C2_TIE_MASK) != 0U))
{
/* Get the bytes that available at this moment. */
#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
count = (uint8_t)FSL_FEATURE_UART_FIFO_SIZEn(base) - base->TCFIFO;
#else
count = 1;
#endif
while ((count != 0U) && (handle->txDataSize != 0U))
{
#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
tempCount = (uint8_t)MIN(handle->txDataSize, (uint32_t)count);
#else
tempCount = 1;
#endif
/* Using non block API to write the data to the registers. */
UART_WriteNonBlocking(base, handle->txData, tempCount);
handle->txData += tempCount;
handle->txDataSize -= tempCount;
count -= tempCount;
/* If all the data are written to data register, TX finished. */
if (0U == handle->txDataSize)
{
/* Disable TX register empty interrupt. */
base->C2 = (base->C2 & ~(uint8_t)UART_C2_TIE_MASK);
/* Enable transmission complete interrupt. */
base->C2 = (base->C2 | (uint8_t)UART_C2_TCIE_MASK);
}
}
}
/* Transmission complete and the interrupt is enabled. */
if ((0U != ((uint32_t)kUART_TransmissionCompleteFlag & status)) && (0U != (base->C2 & UART_C2_TCIE_MASK)))
{
/* Set txState to idle only when all data has been sent out to bus. */
handle->txState = (uint8_t)kUART_TxIdle;
/* Disable transmission complete interrupt. */
base->C2 = (base->C2 & ~(uint8_t)UART_C2_TCIE_MASK);
/* Trigger callback. */
if (handle->callback != NULL)
{
handle->callback(base, handle, kStatus_UART_TxIdle, handle->userData);
}
}
}