2 * Copyright (c) 2016, Freescale Semiconductor, Inc.
\r
3 * Copyright 2016-2019 NXP
\r
4 * All rights reserved.
\r
6 * SPDX-License-Identifier: BSD-3-Clause
\r
9 #include "fsl_usart.h"
\r
10 #include "fsl_device_registers.h"
\r
11 #include "fsl_flexcomm.h"
\r
13 /*******************************************************************************
\r
15 ******************************************************************************/
\r
17 /* Component ID definition, used by tools. */
\r
18 #ifndef FSL_COMPONENT_ID
\r
19 #define FSL_COMPONENT_ID "platform.drivers.flexcomm_usart"
\r
23 * @brief Used for conversion from `flexcomm_usart_irq_handler_t` to `flexcomm_irq_handler_t`
\r
25 typedef union usart_to_flexcomm
\r
27 flexcomm_usart_irq_handler_t usart_master_handler;
\r
28 flexcomm_irq_handler_t flexcomm_handler;
\r
29 } usart_to_flexcomm_t;
\r
33 kUSART_TxIdle, /* TX idle. */
\r
34 kUSART_TxBusy, /* TX busy. */
\r
35 kUSART_RxIdle, /* RX idle. */
\r
36 kUSART_RxBusy /* RX busy. */
\r
39 /*******************************************************************************
\r
41 ******************************************************************************/
\r
43 /*! @brief IRQ name array */
\r
44 static const IRQn_Type s_usartIRQ[] = USART_IRQS;
\r
46 /*! @brief Array to map USART instance number to base address. */
\r
47 static const uint32_t s_usartBaseAddrs[FSL_FEATURE_SOC_USART_COUNT] = USART_BASE_ADDRS;
\r
49 /*******************************************************************************
\r
51 ******************************************************************************/
\r
53 /* Get the index corresponding to the USART */
\r
54 /*! brief Returns instance number for USART peripheral base address. */
\r
55 uint32_t USART_GetInstance(USART_Type *base)
\r
59 for (i = 0; i < (uint32_t)FSL_FEATURE_SOC_USART_COUNT; i++)
\r
61 if ((uint32_t)base == s_usartBaseAddrs[i])
\r
67 assert(i < FSL_FEATURE_SOC_USART_COUNT);
\r
72 * brief Get the length of received data in RX ring buffer.
\r
74 * param handle USART handle pointer.
\r
75 * return Length of received data in RX ring buffer.
\r
77 size_t USART_TransferGetRxRingBufferLength(usart_handle_t *handle)
\r
81 /* Check arguments */
\r
82 assert(NULL != handle);
\r
83 uint16_t rxRingBufferHead = handle->rxRingBufferHead;
\r
84 uint16_t rxRingBufferTail = handle->rxRingBufferTail;
\r
86 if (rxRingBufferTail > rxRingBufferHead)
\r
88 size = (size_t)rxRingBufferHead + handle->rxRingBufferSize - (size_t)rxRingBufferTail;
\r
92 size = (size_t)rxRingBufferHead - (size_t)rxRingBufferTail;
\r
97 static bool USART_TransferIsRxRingBufferFull(usart_handle_t *handle)
\r
101 /* Check arguments */
\r
102 assert(NULL != handle);
\r
104 if (USART_TransferGetRxRingBufferLength(handle) == (handle->rxRingBufferSize - 1U))
\r
116 * brief Sets up the RX ring buffer.
\r
118 * This function sets up the RX ring buffer to a specific USART handle.
\r
120 * When the RX ring buffer is used, data received are stored into the ring buffer even when the
\r
121 * user doesn't call the USART_TransferReceiveNonBlocking() API. If there is already data received
\r
122 * in the ring buffer, the user can get the received data from the ring buffer directly.
\r
124 * note When using the RX ring buffer, one byte is reserved for internal use. In other
\r
125 * words, if p ringBufferSize is 32, then only 31 bytes are used for saving data.
\r
127 * param base USART peripheral base address.
\r
128 * param handle USART handle pointer.
\r
129 * param ringBuffer Start address of the ring buffer for background receiving. Pass NULL to disable the ring buffer.
\r
130 * param ringBufferSize size of the ring buffer.
\r
132 void USART_TransferStartRingBuffer(USART_Type *base, usart_handle_t *handle, uint8_t *ringBuffer, size_t ringBufferSize)
\r
134 /* Check arguments */
\r
135 assert(NULL != base);
\r
136 assert(NULL != handle);
\r
137 assert(NULL != ringBuffer);
\r
139 /* Setup the ringbuffer address */
\r
140 handle->rxRingBuffer = ringBuffer;
\r
141 handle->rxRingBufferSize = ringBufferSize;
\r
142 handle->rxRingBufferHead = 0U;
\r
143 handle->rxRingBufferTail = 0U;
\r
144 /* ring buffer is ready we can start receiving data */
\r
145 base->FIFOINTENSET |= USART_FIFOINTENSET_RXLVL_MASK | USART_FIFOINTENSET_RXERR_MASK;
\r
149 * brief Aborts the background transfer and uninstalls the ring buffer.
\r
151 * This function aborts the background transfer and uninstalls the ring buffer.
\r
153 * param base USART peripheral base address.
\r
154 * param handle USART handle pointer.
\r
156 void USART_TransferStopRingBuffer(USART_Type *base, usart_handle_t *handle)
\r
158 /* Check arguments */
\r
159 assert(NULL != base);
\r
160 assert(NULL != handle);
\r
162 if (handle->rxState == (uint8_t)kUSART_RxIdle)
\r
164 base->FIFOINTENCLR = USART_FIFOINTENCLR_RXLVL_MASK | USART_FIFOINTENCLR_RXERR_MASK;
\r
166 handle->rxRingBuffer = NULL;
\r
167 handle->rxRingBufferSize = 0U;
\r
168 handle->rxRingBufferHead = 0U;
\r
169 handle->rxRingBufferTail = 0U;
\r
173 * brief Initializes a USART instance with user configuration structure and peripheral clock.
\r
175 * This function configures the USART module with the user-defined settings. The user can configure the configuration
\r
176 * structure and also get the default configuration by using the USART_GetDefaultConfig() function.
\r
177 * Example below shows how to use this API to configure USART.
\r
179 * usart_config_t usartConfig;
\r
180 * usartConfig.baudRate_Bps = 115200U;
\r
181 * usartConfig.parityMode = kUSART_ParityDisabled;
\r
182 * usartConfig.stopBitCount = kUSART_OneStopBit;
\r
183 * USART_Init(USART1, &usartConfig, 20000000U);
\r
186 * param base USART peripheral base address.
\r
187 * param config Pointer to user-defined configuration structure.
\r
188 * param srcClock_Hz USART clock source frequency in HZ.
\r
189 * retval kStatus_USART_BaudrateNotSupport Baudrate is not support in current clock source.
\r
190 * retval kStatus_InvalidArgument USART base address is not valid
\r
191 * retval kStatus_Success Status USART initialize succeed
\r
193 status_t USART_Init(USART_Type *base, const usart_config_t *config, uint32_t srcClock_Hz)
\r
197 /* check arguments */
\r
198 assert(!((NULL == base) || (NULL == config) || (0U == srcClock_Hz)));
\r
199 if ((NULL == base) || (NULL == config) || (0U == srcClock_Hz))
\r
201 return kStatus_InvalidArgument;
\r
204 /* initialize flexcomm to USART mode */
\r
205 result = FLEXCOMM_Init(base, FLEXCOMM_PERIPH_USART);
\r
206 if (kStatus_Success != result)
\r
211 if (config->enableTx)
\r
213 /* empty and enable txFIFO */
\r
214 base->FIFOCFG |= USART_FIFOCFG_EMPTYTX_MASK | USART_FIFOCFG_ENABLETX_MASK;
\r
215 /* setup trigger level */
\r
216 base->FIFOTRIG &= ~(USART_FIFOTRIG_TXLVL_MASK);
\r
217 base->FIFOTRIG |= USART_FIFOTRIG_TXLVL(config->txWatermark);
\r
218 /* enable trigger interrupt */
\r
219 base->FIFOTRIG |= USART_FIFOTRIG_TXLVLENA_MASK;
\r
222 /* empty and enable rxFIFO */
\r
223 if (config->enableRx)
\r
225 base->FIFOCFG |= USART_FIFOCFG_EMPTYRX_MASK | USART_FIFOCFG_ENABLERX_MASK;
\r
226 /* setup trigger level */
\r
227 base->FIFOTRIG &= ~(USART_FIFOTRIG_RXLVL_MASK);
\r
228 base->FIFOTRIG |= USART_FIFOTRIG_RXLVL(config->rxWatermark);
\r
229 /* enable trigger interrupt */
\r
230 base->FIFOTRIG |= USART_FIFOTRIG_RXLVLENA_MASK;
\r
232 /* setup configuration and enable USART */
\r
233 base->CFG = USART_CFG_PARITYSEL(config->parityMode) | USART_CFG_STOPLEN(config->stopBitCount) |
\r
234 USART_CFG_DATALEN(config->bitCountPerChar) | USART_CFG_LOOP(config->loopback) |
\r
235 USART_CFG_SYNCEN((uint32_t)config->syncMode >> 1) | USART_CFG_SYNCMST((uint8_t)config->syncMode) |
\r
236 USART_CFG_CLKPOL(config->clockPolarity) | USART_CFG_ENABLE_MASK;
\r
238 /* Setup baudrate */
\r
239 result = USART_SetBaudRate(base, config->baudRate_Bps, srcClock_Hz);
\r
240 if (kStatus_Success != result)
\r
244 /* Setting continuous Clock configuration. used for synchronous mode. */
\r
245 USART_EnableContinuousSCLK(base, config->enableContinuousSCLK);
\r
247 return kStatus_Success;
\r
251 * brief Deinitializes a USART instance.
\r
253 * This function waits for TX complete, disables TX and RX, and disables the USART clock.
\r
255 * param base USART peripheral base address.
\r
257 void USART_Deinit(USART_Type *base)
\r
259 /* Check arguments */
\r
260 assert(NULL != base);
\r
261 while (0U == (base->STAT & USART_STAT_TXIDLE_MASK))
\r
264 /* Disable interrupts, disable dma requests, disable peripheral */
\r
265 base->FIFOINTENCLR = USART_FIFOINTENCLR_TXERR_MASK | USART_FIFOINTENCLR_RXERR_MASK | USART_FIFOINTENCLR_TXLVL_MASK |
\r
266 USART_FIFOINTENCLR_RXLVL_MASK;
\r
267 base->FIFOCFG &= ~(USART_FIFOCFG_DMATX_MASK | USART_FIFOCFG_DMARX_MASK);
\r
268 base->CFG &= ~(USART_CFG_ENABLE_MASK);
\r
272 * brief Gets the default configuration structure.
\r
274 * This function initializes the USART configuration structure to a default value. The default
\r
276 * usartConfig->baudRate_Bps = 115200U;
\r
277 * usartConfig->parityMode = kUSART_ParityDisabled;
\r
278 * usartConfig->stopBitCount = kUSART_OneStopBit;
\r
279 * usartConfig->bitCountPerChar = kUSART_8BitsPerChar;
\r
280 * usartConfig->loopback = false;
\r
281 * usartConfig->enableTx = false;
\r
282 * usartConfig->enableRx = false;
\r
284 * param config Pointer to configuration structure.
\r
286 void USART_GetDefaultConfig(usart_config_t *config)
\r
288 /* Check arguments */
\r
289 assert(NULL != config);
\r
291 /* Initializes the configure structure to zero. */
\r
292 (void)memset(config, 0, sizeof(*config));
\r
294 /* Set always all members ! */
\r
295 config->baudRate_Bps = 115200U;
\r
296 config->parityMode = kUSART_ParityDisabled;
\r
297 config->stopBitCount = kUSART_OneStopBit;
\r
298 config->bitCountPerChar = kUSART_8BitsPerChar;
\r
299 config->loopback = false;
\r
300 config->enableRx = false;
\r
301 config->enableTx = false;
\r
302 config->txWatermark = kUSART_TxFifo0;
\r
303 config->rxWatermark = kUSART_RxFifo1;
\r
304 config->syncMode = kUSART_SyncModeDisabled;
\r
305 config->enableContinuousSCLK = false;
\r
306 config->clockPolarity = kUSART_RxSampleOnFallingEdge;
\r
310 * brief Sets the USART instance baud rate.
\r
312 * This function configures the USART module baud rate. This function is used to update
\r
313 * the USART module baud rate after the USART module is initialized by the USART_Init.
\r
315 * USART_SetBaudRate(USART1, 115200U, 20000000U);
\r
318 * param base USART peripheral base address.
\r
319 * param baudrate_Bps USART baudrate to be set.
\r
320 * param srcClock_Hz USART clock source frequency in HZ.
\r
321 * retval kStatus_USART_BaudrateNotSupport Baudrate is not support in current clock source.
\r
322 * retval kStatus_Success Set baudrate succeed.
\r
323 * retval kStatus_InvalidArgument One or more arguments are invalid.
\r
325 status_t USART_SetBaudRate(USART_Type *base, uint32_t baudrate_Bps, uint32_t srcClock_Hz)
\r
327 uint32_t best_diff = (uint32_t)-1, best_osrval = 0xf, best_brgval = (uint32_t)-1;
\r
328 uint32_t osrval, brgval, diff, baudrate;
\r
330 /* check arguments */
\r
331 assert(!((NULL == base) || (0 == baudrate_Bps) || (0 == srcClock_Hz)));
\r
332 if ((NULL == base) || (0U == baudrate_Bps) || (0U == srcClock_Hz))
\r
334 return kStatus_InvalidArgument;
\r
337 /* If synchronous master mode is enabled, only configure the BRG value. */
\r
338 if ((base->CFG & USART_CFG_SYNCEN_MASK) != 0U)
\r
340 if ((base->CFG & USART_CFG_SYNCMST_MASK) != 0U)
\r
342 brgval = srcClock_Hz / baudrate_Bps;
\r
343 base->BRG = brgval - 1U;
\r
349 * Smaller values of OSR can make the sampling position within a data bit less accurate and may
\r
350 * potentially cause more noise errors or incorrect data.
\r
352 for (osrval = best_osrval; osrval >= 8U; osrval--)
\r
354 brgval = (((srcClock_Hz * 10U) / ((osrval + 1U) * baudrate_Bps)) - 5U) / 10U;
\r
355 if (brgval > 0xFFFFU)
\r
359 baudrate = srcClock_Hz / ((osrval + 1U) * (brgval + 1U));
\r
360 diff = baudrate_Bps < baudrate ? baudrate - baudrate_Bps : baudrate_Bps - baudrate;
\r
361 if (diff < best_diff)
\r
364 best_osrval = osrval;
\r
365 best_brgval = brgval;
\r
369 /* value over range */
\r
370 if (best_brgval > 0xFFFFU)
\r
372 return kStatus_USART_BaudrateNotSupport;
\r
375 base->OSR = best_osrval;
\r
376 base->BRG = best_brgval;
\r
379 return kStatus_Success;
\r
383 * brief Writes to the TX register using a blocking method.
\r
385 * This function polls the TX register, waits for the TX register to be empty or for the TX FIFO
\r
386 * to have room and writes data to the TX buffer.
\r
388 * param base USART peripheral base address.
\r
389 * param data Start address of the data to write.
\r
390 * param length Size of the data to write.
\r
392 void USART_WriteBlocking(USART_Type *base, const uint8_t *data, size_t length)
\r
394 /* Check arguments */
\r
395 assert(!((NULL == base) || (NULL == data)));
\r
396 if ((NULL == base) || (NULL == data))
\r
400 /* Check whether txFIFO is enabled */
\r
401 if (0U == (base->FIFOCFG & USART_FIFOCFG_ENABLETX_MASK))
\r
405 for (; length > 0U; length--)
\r
407 /* Loop until txFIFO get some space for new data */
\r
408 while (0U == (base->FIFOSTAT & USART_FIFOSTAT_TXNOTFULL_MASK))
\r
411 base->FIFOWR = *data;
\r
414 /* Wait to finish transfer */
\r
415 while (0U == (base->STAT & USART_STAT_TXIDLE_MASK))
\r
421 * brief Read RX data register using a blocking method.
\r
423 * This function polls the RX register, waits for the RX register to be full or for RX FIFO to
\r
424 * have data and read data from the TX register.
\r
426 * param base USART peripheral base address.
\r
427 * param data Start address of the buffer to store the received data.
\r
428 * param length Size of the buffer.
\r
429 * retval kStatus_USART_FramingError Receiver overrun happened while receiving data.
\r
430 * retval kStatus_USART_ParityError Noise error happened while receiving data.
\r
431 * retval kStatus_USART_NoiseError Framing error happened while receiving data.
\r
432 * retval kStatus_USART_RxError Overflow or underflow rxFIFO happened.
\r
433 * retval kStatus_Success Successfully received all data.
\r
435 status_t USART_ReadBlocking(USART_Type *base, uint8_t *data, size_t length)
\r
437 uint32_t statusFlag;
\r
438 status_t status = kStatus_Success;
\r
440 /* check arguments */
\r
441 assert(!((NULL == base) || (NULL == data)));
\r
442 if ((NULL == base) || (NULL == data))
\r
444 return kStatus_InvalidArgument;
\r
447 /* Check whether rxFIFO is enabled */
\r
448 if ((base->FIFOCFG & USART_FIFOCFG_ENABLERX_MASK) == 0U)
\r
450 return kStatus_Fail;
\r
452 for (; length > 0U; length--)
\r
454 /* loop until rxFIFO have some data to read */
\r
455 while ((base->FIFOSTAT & USART_FIFOSTAT_RXNOTEMPTY_MASK) == 0U)
\r
458 /* check rxFIFO statusFlag */
\r
459 if ((base->FIFOSTAT & USART_FIFOSTAT_RXERR_MASK) != 0U)
\r
461 base->FIFOCFG |= USART_FIFOCFG_EMPTYRX_MASK;
\r
462 base->FIFOSTAT |= USART_FIFOSTAT_RXERR_MASK;
\r
463 status = kStatus_USART_RxError;
\r
466 /* check receive statusFlag */
\r
467 statusFlag = base->STAT;
\r
468 /* Clear all status flags */
\r
469 base->STAT |= statusFlag;
\r
470 if ((statusFlag & USART_STAT_PARITYERRINT_MASK) != 0U)
\r
472 status = kStatus_USART_ParityError;
\r
474 if ((statusFlag & USART_STAT_FRAMERRINT_MASK) != 0U)
\r
476 status = kStatus_USART_FramingError;
\r
478 if ((statusFlag & USART_STAT_RXNOISEINT_MASK) != 0U)
\r
480 status = kStatus_USART_NoiseError;
\r
483 if (kStatus_Success == status)
\r
485 *data = (uint8_t)base->FIFORD;
\r
497 * brief Initializes the USART handle.
\r
499 * This function initializes the USART handle which can be used for other USART
\r
500 * transactional APIs. Usually, for a specified USART instance,
\r
501 * call this API once to get the initialized handle.
\r
503 * param base USART peripheral base address.
\r
504 * param handle USART handle pointer.
\r
505 * param callback The callback function.
\r
506 * param userData The parameter of the callback function.
\r
508 status_t USART_TransferCreateHandle(USART_Type *base,
\r
509 usart_handle_t *handle,
\r
510 usart_transfer_callback_t callback,
\r
514 assert(!((NULL == base) || (NULL == handle)));
\r
516 uint32_t instance = 0;
\r
517 usart_to_flexcomm_t handler;
\r
518 handler.usart_master_handler = USART_TransferHandleIRQ;
\r
520 if ((NULL == base) || (NULL == handle))
\r
522 return kStatus_InvalidArgument;
\r
525 instance = USART_GetInstance(base);
\r
527 (void)memset(handle, 0, sizeof(*handle));
\r
528 /* Set the TX/RX state. */
\r
529 handle->rxState = (uint8_t)kUSART_RxIdle;
\r
530 handle->txState = (uint8_t)kUSART_TxIdle;
\r
531 /* Set the callback and user data. */
\r
532 handle->callback = callback;
\r
533 handle->userData = userData;
\r
534 handle->rxWatermark = (uint8_t)USART_FIFOTRIG_RXLVL_GET(base);
\r
535 handle->txWatermark = (uint8_t)USART_FIFOTRIG_TXLVL_GET(base);
\r
537 FLEXCOMM_SetIRQHandler(base, handler.flexcomm_handler, handle);
\r
539 /* Enable interrupt in NVIC. */
\r
540 (void)EnableIRQ(s_usartIRQ[instance]);
\r
542 return kStatus_Success;
\r
546 * brief Transmits a buffer of data using the interrupt method.
\r
548 * This function sends data using an interrupt method. This is a non-blocking function, which
\r
549 * returns directly without waiting for all data to be written to the TX register. When
\r
550 * all data is written to the TX register in the IRQ handler, the USART driver calls the callback
\r
551 * function and passes the ref kStatus_USART_TxIdle as status parameter.
\r
553 * note The kStatus_USART_TxIdle is passed to the upper layer when all data is written
\r
554 * to the TX register. However it does not ensure that all data are sent out. Before disabling the TX,
\r
555 * check the kUSART_TransmissionCompleteFlag to ensure that the TX is finished.
\r
557 * param base USART peripheral base address.
\r
558 * param handle USART handle pointer.
\r
559 * param xfer USART transfer structure. See #usart_transfer_t.
\r
560 * retval kStatus_Success Successfully start the data transmission.
\r
561 * retval kStatus_USART_TxBusy Previous transmission still not finished, data not all written to TX register yet.
\r
562 * retval kStatus_InvalidArgument Invalid argument.
\r
564 status_t USART_TransferSendNonBlocking(USART_Type *base, usart_handle_t *handle, usart_transfer_t *xfer)
\r
566 /* Check arguments */
\r
567 assert(!((NULL == base) || (NULL == handle) || (NULL == xfer)));
\r
568 if ((NULL == base) || (NULL == handle) || (NULL == xfer))
\r
570 return kStatus_InvalidArgument;
\r
572 /* Check xfer members */
\r
573 assert(!((0 == xfer->dataSize) || (NULL == xfer->data)));
\r
574 if ((0U == xfer->dataSize) || (NULL == xfer->data))
\r
576 return kStatus_InvalidArgument;
\r
579 /* Return error if current TX busy. */
\r
580 if ((uint8_t)kUSART_TxBusy == handle->txState)
\r
582 return kStatus_USART_TxBusy;
\r
586 handle->txData = xfer->data;
\r
587 handle->txDataSize = xfer->dataSize;
\r
588 handle->txDataSizeAll = xfer->dataSize;
\r
589 handle->txState = (uint8_t)kUSART_TxBusy;
\r
590 /* Enable transmiter interrupt. */
\r
591 base->FIFOINTENSET |= USART_FIFOINTENSET_TXLVL_MASK;
\r
593 return kStatus_Success;
\r
597 * brief Aborts the interrupt-driven data transmit.
\r
599 * This function aborts the interrupt driven data sending. The user can get the remainBtyes to find out
\r
600 * how many bytes are still not sent out.
\r
602 * param base USART peripheral base address.
\r
603 * param handle USART handle pointer.
\r
605 void USART_TransferAbortSend(USART_Type *base, usart_handle_t *handle)
\r
607 assert(NULL != handle);
\r
609 /* Disable interrupts */
\r
610 USART_DisableInterrupts(base, (uint32_t)kUSART_TxLevelInterruptEnable);
\r
612 base->FIFOCFG |= USART_FIFOCFG_EMPTYTX_MASK;
\r
614 handle->txDataSize = 0U;
\r
615 handle->txState = (uint8_t)kUSART_TxIdle;
\r
619 * brief Get the number of bytes that have been written to USART TX register.
\r
621 * This function gets the number of bytes that have been written to USART TX
\r
622 * register by interrupt method.
\r
624 * param base USART peripheral base address.
\r
625 * param handle USART handle pointer.
\r
626 * param count Send bytes count.
\r
627 * retval kStatus_NoTransferInProgress No send in progress.
\r
628 * retval kStatus_InvalidArgument Parameter is invalid.
\r
629 * retval kStatus_Success Get successfully through the parameter \p count;
\r
631 status_t USART_TransferGetSendCount(USART_Type *base, usart_handle_t *handle, uint32_t *count)
\r
633 assert(NULL != handle);
\r
634 assert(NULL != count);
\r
636 if ((uint8_t)kUSART_TxIdle == handle->txState)
\r
638 return kStatus_NoTransferInProgress;
\r
641 *count = handle->txDataSizeAll - handle->txDataSize;
\r
643 return kStatus_Success;
\r
647 * brief Receives a buffer of data using an interrupt method.
\r
649 * This function receives data using an interrupt method. This is a non-blocking function, which
\r
650 * returns without waiting for all data to be received.
\r
651 * If the RX ring buffer is used and not empty, the data in the ring buffer is copied and
\r
652 * the parameter p receivedBytes shows how many bytes are copied from the ring buffer.
\r
653 * After copying, if the data in the ring buffer is not enough to read, the receive
\r
654 * request is saved by the USART driver. When the new data arrives, the receive request
\r
655 * is serviced first. When all data is received, the USART driver notifies the upper layer
\r
656 * through a callback function and passes the status parameter ref kStatus_USART_RxIdle.
\r
657 * For example, the upper layer needs 10 bytes but there are only 5 bytes in the ring buffer.
\r
658 * The 5 bytes are copied to the xfer->data and this function returns with the
\r
659 * parameter p receivedBytes set to 5. For the left 5 bytes, newly arrived data is
\r
660 * saved from the xfer->data[5]. When 5 bytes are received, the USART driver notifies the upper layer.
\r
661 * If the RX ring buffer is not enabled, this function enables the RX and RX interrupt
\r
662 * to receive data to the xfer->data. When all data is received, the upper layer is notified.
\r
664 * param base USART peripheral base address.
\r
665 * param handle USART handle pointer.
\r
666 * param xfer USART transfer structure, see #usart_transfer_t.
\r
667 * param receivedBytes Bytes received from the ring buffer directly.
\r
668 * retval kStatus_Success Successfully queue the transfer into transmit queue.
\r
669 * retval kStatus_USART_RxBusy Previous receive request is not finished.
\r
670 * retval kStatus_InvalidArgument Invalid argument.
\r
672 status_t USART_TransferReceiveNonBlocking(USART_Type *base,
\r
673 usart_handle_t *handle,
\r
674 usart_transfer_t *xfer,
\r
675 size_t *receivedBytes)
\r
678 /* How many bytes to copy from ring buffer to user memory. */
\r
679 size_t bytesToCopy = 0U;
\r
680 /* How many bytes to receive. */
\r
681 size_t bytesToReceive;
\r
682 /* How many bytes currently have received. */
\r
683 size_t bytesCurrentReceived;
\r
684 uint32_t regPrimask = 0U;
\r
686 /* Check arguments */
\r
687 assert(!((NULL == base) || (NULL == handle) || (NULL == xfer)));
\r
688 if ((NULL == base) || (NULL == handle) || (NULL == xfer))
\r
690 return kStatus_InvalidArgument;
\r
692 /* Check xfer members */
\r
693 assert(!((0 == xfer->dataSize) || (NULL == xfer->data)));
\r
694 if ((0U == xfer->dataSize) || (NULL == xfer->data))
\r
696 return kStatus_InvalidArgument;
\r
699 /* How to get data:
\r
700 1. If RX ring buffer is not enabled, then save xfer->data and xfer->dataSize
\r
701 to uart handle, enable interrupt to store received data to xfer->data. When
\r
702 all data received, trigger callback.
\r
703 2. If RX ring buffer is enabled and not empty, get data from ring buffer first.
\r
704 If there are enough data in ring buffer, copy them to xfer->data and return.
\r
705 If there are not enough data in ring buffer, copy all of them to xfer->data,
\r
706 save the xfer->data remained empty space to uart handle, receive data
\r
707 to this empty space and trigger callback when finished. */
\r
708 if ((uint8_t)kUSART_RxBusy == handle->rxState)
\r
710 return kStatus_USART_RxBusy;
\r
714 bytesToReceive = xfer->dataSize;
\r
715 bytesCurrentReceived = 0U;
\r
716 /* If RX ring buffer is used. */
\r
717 if (handle->rxRingBuffer != NULL)
\r
719 /* Disable IRQ, protect ring buffer. */
\r
720 regPrimask = DisableGlobalIRQ();
\r
721 /* How many bytes in RX ring buffer currently. */
\r
722 bytesToCopy = USART_TransferGetRxRingBufferLength(handle);
\r
723 if (bytesToCopy != 0U)
\r
725 bytesToCopy = MIN(bytesToReceive, bytesToCopy);
\r
726 bytesToReceive -= bytesToCopy;
\r
727 /* Copy data from ring buffer to user memory. */
\r
728 for (i = 0U; i < bytesToCopy; i++)
\r
730 xfer->data[bytesCurrentReceived++] = handle->rxRingBuffer[handle->rxRingBufferTail];
\r
731 /* Wrap to 0. Not use modulo (%) because it might be large and slow. */
\r
732 if ((size_t)handle->rxRingBufferTail + 1U == handle->rxRingBufferSize)
\r
734 handle->rxRingBufferTail = 0U;
\r
738 handle->rxRingBufferTail++;
\r
742 /* If ring buffer does not have enough data, still need to read more data. */
\r
743 if (bytesToReceive != 0U)
\r
745 /* No data in ring buffer, save the request to UART handle. */
\r
746 handle->rxData = xfer->data + bytesCurrentReceived;
\r
747 handle->rxDataSize = bytesToReceive;
\r
748 handle->rxDataSizeAll = bytesToReceive;
\r
749 handle->rxState = (uint8_t)kUSART_RxBusy;
\r
751 /* Enable IRQ if previously enabled. */
\r
752 EnableGlobalIRQ(regPrimask);
\r
753 /* Call user callback since all data are received. */
\r
754 if (0U == bytesToReceive)
\r
756 if (handle->callback != NULL)
\r
758 handle->callback(base, handle, kStatus_USART_RxIdle, handle->userData);
\r
762 /* Ring buffer not used. */
\r
765 handle->rxData = xfer->data + bytesCurrentReceived;
\r
766 handle->rxDataSize = bytesToReceive;
\r
767 handle->rxDataSizeAll = bytesToReceive;
\r
768 handle->rxState = (uint8_t)kUSART_RxBusy;
\r
770 /* Enable RX interrupt. */
\r
771 base->FIFOINTENSET |= USART_FIFOINTENSET_RXLVL_MASK;
\r
773 /* Return the how many bytes have read. */
\r
774 if (receivedBytes != NULL)
\r
776 *receivedBytes = bytesCurrentReceived;
\r
779 return kStatus_Success;
\r
783 * brief Aborts the interrupt-driven data receiving.
\r
785 * This function aborts the interrupt-driven data receiving. The user can get the remainBytes to find out
\r
786 * how many bytes not received yet.
\r
788 * param base USART peripheral base address.
\r
789 * param handle USART handle pointer.
\r
791 void USART_TransferAbortReceive(USART_Type *base, usart_handle_t *handle)
\r
793 assert(NULL != handle);
\r
795 /* Only abort the receive to handle->rxData, the RX ring buffer is still working. */
\r
796 if (NULL == handle->rxRingBuffer)
\r
798 /* Disable interrupts */
\r
799 USART_DisableInterrupts(base, (uint32_t)kUSART_RxLevelInterruptEnable);
\r
801 base->FIFOCFG |= USART_FIFOCFG_EMPTYRX_MASK;
\r
804 handle->rxDataSize = 0U;
\r
805 handle->rxState = (uint8_t)kUSART_RxIdle;
\r
809 * brief Get the number of bytes that have been received.
\r
811 * This function gets the number of bytes that have been received.
\r
813 * param base USART peripheral base address.
\r
814 * param handle USART handle pointer.
\r
815 * param count Receive bytes count.
\r
816 * retval kStatus_NoTransferInProgress No receive in progress.
\r
817 * retval kStatus_InvalidArgument Parameter is invalid.
\r
818 * retval kStatus_Success Get successfully through the parameter \p count;
\r
820 status_t USART_TransferGetReceiveCount(USART_Type *base, usart_handle_t *handle, uint32_t *count)
\r
822 assert(NULL != handle);
\r
823 assert(NULL != count);
\r
825 if ((uint8_t)kUSART_RxIdle == handle->rxState)
\r
827 return kStatus_NoTransferInProgress;
\r
830 *count = handle->rxDataSizeAll - handle->rxDataSize;
\r
832 return kStatus_Success;
\r
836 * brief USART IRQ handle function.
\r
838 * This function handles the USART transmit and receive IRQ request.
\r
840 * param base USART peripheral base address.
\r
841 * param handle USART handle pointer.
\r
843 void USART_TransferHandleIRQ(USART_Type *base, usart_handle_t *handle)
\r
845 /* Check arguments */
\r
846 assert((NULL != base) && (NULL != handle));
\r
848 bool receiveEnabled = ((handle->rxDataSize != 0U) || (handle->rxRingBuffer != NULL));
\r
849 bool sendEnabled = (handle->txDataSize != 0U);
\r
853 /* If RX overrun. */
\r
854 if ((base->FIFOSTAT & USART_FIFOSTAT_RXERR_MASK) != 0U)
\r
856 /* Clear rx error state. */
\r
857 base->FIFOSTAT |= USART_FIFOSTAT_RXERR_MASK;
\r
859 base->FIFOCFG |= USART_FIFOCFG_EMPTYRX_MASK;
\r
860 /* Trigger callback. */
\r
861 if (handle->callback != NULL)
\r
863 handle->callback(base, handle, kStatus_USART_RxError, handle->userData);
\r
866 while ((receiveEnabled && ((base->FIFOSTAT & USART_FIFOSTAT_RXNOTEMPTY_MASK) != 0U)) ||
\r
867 (sendEnabled && ((base->FIFOSTAT & USART_FIFOSTAT_TXNOTFULL_MASK) != 0U)))
\r
870 if (receiveEnabled && ((base->FIFOSTAT & USART_FIFOSTAT_RXNOTEMPTY_MASK) != 0U))
\r
872 /* Receive to app bufffer if app buffer is present */
\r
873 if (handle->rxDataSize != 0U)
\r
875 rxdata = (uint8_t)base->FIFORD;
\r
876 *handle->rxData = rxdata;
\r
877 handle->rxDataSize--;
\r
879 receiveEnabled = ((handle->rxDataSize != 0U) || (handle->rxRingBuffer != NULL));
\r
880 if (0U == handle->rxDataSize)
\r
882 if (NULL == handle->rxRingBuffer)
\r
884 base->FIFOINTENCLR = USART_FIFOINTENCLR_RXLVL_MASK | USART_FIFOINTENSET_RXERR_MASK;
\r
886 handle->rxState = (uint8_t)kUSART_RxIdle;
\r
887 if (handle->callback != NULL)
\r
889 handle->callback(base, handle, kStatus_USART_RxIdle, handle->userData);
\r
893 /* Otherwise receive to ring buffer if ring buffer is present */
\r
896 if (handle->rxRingBuffer != NULL)
\r
898 /* If RX ring buffer is full, trigger callback to notify over run. */
\r
899 if (USART_TransferIsRxRingBufferFull(handle))
\r
901 if (handle->callback != NULL)
\r
903 handle->callback(base, handle, kStatus_USART_RxRingBufferOverrun, handle->userData);
\r
906 /* If ring buffer is still full after callback function, the oldest data is overridden. */
\r
907 if (USART_TransferIsRxRingBufferFull(handle))
\r
909 /* Increase handle->rxRingBufferTail to make room for new data. */
\r
910 if ((size_t)handle->rxRingBufferTail + 1U == handle->rxRingBufferSize)
\r
912 handle->rxRingBufferTail = 0U;
\r
916 handle->rxRingBufferTail++;
\r
920 rxdata = (uint8_t)base->FIFORD;
\r
921 handle->rxRingBuffer[handle->rxRingBufferHead] = rxdata;
\r
922 /* Increase handle->rxRingBufferHead. */
\r
923 if ((size_t)handle->rxRingBufferHead + 1U == handle->rxRingBufferSize)
\r
925 handle->rxRingBufferHead = 0U;
\r
929 handle->rxRingBufferHead++;
\r
935 if (sendEnabled && ((base->FIFOSTAT & USART_FIFOSTAT_TXNOTFULL_MASK) != 0U))
\r
937 base->FIFOWR = *handle->txData;
\r
938 handle->txDataSize--;
\r
940 sendEnabled = handle->txDataSize != 0U;
\r
943 base->FIFOINTENCLR = USART_FIFOINTENCLR_TXLVL_MASK;
\r
944 handle->txState = (uint8_t)kUSART_TxIdle;
\r
946 base->INTENSET |= USART_INTENSET_TXIDLEEN_MASK;
\r
951 /* Tx idle and the interrupt is enabled. */
\r
952 if ((0U != (base->INTENSET & USART_INTENSET_TXIDLEEN_MASK)) &&
\r
953 (0U != (base->INTSTAT & USART_INTSTAT_TXIDLE_MASK)) && (handle->txState == (uint8_t)kUSART_TxIdle))
\r
955 /* Disable tx idle interrupt */
\r
956 base->INTENCLR |= USART_INTENCLR_TXIDLECLR_MASK;
\r
957 /* Trigger callback. */
\r
958 if (handle->callback != NULL)
\r
960 handle->callback(base, handle, kStatus_USART_TxIdle, handle->userData);
\r
964 /* ring buffer is not used */
\r
965 if (NULL == handle->rxRingBuffer)
\r
967 tmpsize = handle->rxDataSize;
\r
969 /* restore if rx transfer ends and rxLevel is different from default value */
\r
970 if ((tmpsize == 0U) && (USART_FIFOTRIG_RXLVL_GET(base) != handle->rxWatermark))
\r
973 (base->FIFOTRIG & (~USART_FIFOTRIG_RXLVL_MASK)) | USART_FIFOTRIG_RXLVL(handle->rxWatermark);
\r
975 /* decrease level if rx transfer is bellow */
\r
976 if ((tmpsize != 0U) && (tmpsize < (USART_FIFOTRIG_RXLVL_GET(base) + 1U)))
\r
978 base->FIFOTRIG = (base->FIFOTRIG & (~USART_FIFOTRIG_RXLVL_MASK)) | (USART_FIFOTRIG_RXLVL(tmpsize - 1U));
\r