1 /*
2  * Copyright (c) 2016, Freescale Semiconductor, Inc.
3  * Copyright 2016-2021 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_usart.h"
10 #include "fsl_device_registers.h"
11 #include "fsl_flexcomm.h"
12 
13 /*******************************************************************************
14  * Definitions
15  ******************************************************************************/
16 
17 /* Component ID definition, used by tools. */
18 #ifndef FSL_COMPONENT_ID
19 #define FSL_COMPONENT_ID "platform.drivers.flexcomm_usart"
20 #endif
21 
22 /*!
23  * @brief Used for conversion from `flexcomm_usart_irq_handler_t` to `flexcomm_irq_handler_t`
24  */
25 typedef union usart_to_flexcomm
26 {
27     flexcomm_usart_irq_handler_t usart_master_handler;
28     flexcomm_irq_handler_t flexcomm_handler;
29 } usart_to_flexcomm_t;
30 
31 enum
32 {
33     kUSART_TxIdle, /* TX idle. */
34     kUSART_TxBusy, /* TX busy. */
35     kUSART_RxIdle, /* RX idle. */
36     kUSART_RxBusy  /* RX busy. */
37 };
38 
39 /*******************************************************************************
40  * Variables
41  ******************************************************************************/
42 
43 /*! @brief IRQ name array */
44 static const IRQn_Type s_usartIRQ[] = USART_IRQS;
45 
46 /*! @brief Array to map USART instance number to base address. */
47 static const uint32_t s_usartBaseAddrs[FSL_FEATURE_SOC_USART_COUNT] = USART_BASE_ADDRS;
48 
49 /*******************************************************************************
50  * Code
51  ******************************************************************************/
52 
53 /* Get the index corresponding to the USART */
54 /*! brief Returns instance number for USART peripheral base address. */
USART_GetInstance(USART_Type * base)55 uint32_t USART_GetInstance(USART_Type *base)
56 {
57     uint32_t i;
58 
59     for (i = 0; i < (uint32_t)FSL_FEATURE_SOC_USART_COUNT; i++)
60     {
61         if ((uint32_t)base == s_usartBaseAddrs[i])
62         {
63             break;
64         }
65     }
66 
67     assert(i < (uint32_t)FSL_FEATURE_SOC_USART_COUNT);
68     return i;
69 }
70 
71 /*!
72  * brief Get the length of received data in RX ring buffer.
73  *
74  * param handle USART handle pointer.
75  * return Length of received data in RX ring buffer.
76  */
USART_TransferGetRxRingBufferLength(usart_handle_t * handle)77 size_t USART_TransferGetRxRingBufferLength(usart_handle_t *handle)
78 {
79     size_t size;
80 
81     /* Check arguments */
82     assert(NULL != handle);
83     uint16_t rxRingBufferHead = handle->rxRingBufferHead;
84     uint16_t rxRingBufferTail = handle->rxRingBufferTail;
85 
86     if (rxRingBufferTail > rxRingBufferHead)
87     {
88         size = (size_t)rxRingBufferHead + handle->rxRingBufferSize - (size_t)rxRingBufferTail;
89     }
90     else
91     {
92         size = (size_t)rxRingBufferHead - (size_t)rxRingBufferTail;
93     }
94     return size;
95 }
96 
USART_TransferIsRxRingBufferFull(usart_handle_t * handle)97 static bool USART_TransferIsRxRingBufferFull(usart_handle_t *handle)
98 {
99     bool full;
100 
101     /* Check arguments */
102     assert(NULL != handle);
103 
104     if (USART_TransferGetRxRingBufferLength(handle) == (handle->rxRingBufferSize - 1U))
105     {
106         full = true;
107     }
108     else
109     {
110         full = false;
111     }
112     return full;
113 }
114 
115 /*!
116  * brief Sets up the RX ring buffer.
117  *
118  * This function sets up the RX ring buffer to a specific USART handle.
119  *
120  * When the RX ring buffer is used, data received are stored into the ring buffer even when the
121  * user doesn't call the USART_TransferReceiveNonBlocking() API. If there is already data received
122  * in the ring buffer, the user can get the received data from the ring buffer directly.
123  *
124  * note When using the RX ring buffer, one byte is reserved for internal use. In other
125  * words, if p ringBufferSize is 32, then only 31 bytes are used for saving data.
126  *
127  * param base USART peripheral base address.
128  * param handle USART handle pointer.
129  * param ringBuffer Start address of the ring buffer for background receiving. Pass NULL to disable the ring buffer.
130  * param ringBufferSize size of the ring buffer.
131  */
USART_TransferStartRingBuffer(USART_Type * base,usart_handle_t * handle,uint8_t * ringBuffer,size_t ringBufferSize)132 void USART_TransferStartRingBuffer(USART_Type *base, usart_handle_t *handle, uint8_t *ringBuffer, size_t ringBufferSize)
133 {
134     /* Check arguments */
135     assert(NULL != base);
136     assert(NULL != handle);
137     assert(NULL != ringBuffer);
138 
139     /* Setup the ringbuffer address */
140     handle->rxRingBuffer     = ringBuffer;
141     handle->rxRingBufferSize = ringBufferSize;
142     handle->rxRingBufferHead = 0U;
143     handle->rxRingBufferTail = 0U;
144     /* ring buffer is ready we can start receiving data */
145     base->FIFOINTENSET = USART_FIFOINTENSET_RXLVL_MASK | USART_FIFOINTENSET_RXERR_MASK;
146 }
147 
148 /*!
149  * brief Aborts the background transfer and uninstalls the ring buffer.
150  *
151  * This function aborts the background transfer and uninstalls the ring buffer.
152  *
153  * param base USART peripheral base address.
154  * param handle USART handle pointer.
155  */
USART_TransferStopRingBuffer(USART_Type * base,usart_handle_t * handle)156 void USART_TransferStopRingBuffer(USART_Type *base, usart_handle_t *handle)
157 {
158     /* Check arguments */
159     assert(NULL != base);
160     assert(NULL != handle);
161 
162     if (handle->rxState == (uint8_t)kUSART_RxIdle)
163     {
164         base->FIFOINTENCLR = USART_FIFOINTENCLR_RXLVL_MASK | USART_FIFOINTENCLR_RXERR_MASK;
165     }
166     handle->rxRingBuffer     = NULL;
167     handle->rxRingBufferSize = 0U;
168     handle->rxRingBufferHead = 0U;
169     handle->rxRingBufferTail = 0U;
170 }
171 
172 /*!
173  * brief Initializes a USART instance with user configuration structure and peripheral clock.
174  *
175  * This function configures the USART module with the user-defined settings. The user can configure the configuration
176  * structure and also get the default configuration by using the USART_GetDefaultConfig() function.
177  * Example below shows how to use this API to configure USART.
178  * code
179  *  usart_config_t usartConfig;
180  *  usartConfig.baudRate_Bps = 115200U;
181  *  usartConfig.parityMode = kUSART_ParityDisabled;
182  *  usartConfig.stopBitCount = kUSART_OneStopBit;
183  *  USART_Init(USART1, &usartConfig, 20000000U);
184  * endcode
185  *
186  * param base USART peripheral base address.
187  * param config Pointer to user-defined configuration structure.
188  * param srcClock_Hz USART clock source frequency in HZ.
189  * retval kStatus_USART_BaudrateNotSupport Baudrate is not support in current clock source.
190  * retval kStatus_InvalidArgument USART base address is not valid
191  * retval kStatus_Success Status USART initialize succeed
192  */
USART_Init(USART_Type * base,const usart_config_t * config,uint32_t srcClock_Hz)193 status_t USART_Init(USART_Type *base, const usart_config_t *config, uint32_t srcClock_Hz)
194 {
195     int result;
196 
197     /* check arguments */
198     assert(!((NULL == base) || (NULL == config) || (0U == srcClock_Hz)));
199     if ((NULL == base) || (NULL == config) || (0U == srcClock_Hz))
200     {
201         return kStatus_InvalidArgument;
202     }
203 
204     /* initialize flexcomm to USART mode */
205     result = FLEXCOMM_Init(base, FLEXCOMM_PERIPH_USART);
206     if (kStatus_Success != result)
207     {
208         return result;
209     }
210 
211     if (config->enableTx)
212     {
213         /* empty and enable txFIFO */
214         base->FIFOCFG |= USART_FIFOCFG_EMPTYTX_MASK | USART_FIFOCFG_ENABLETX_MASK;
215         /* setup trigger level */
216         base->FIFOTRIG &= ~(USART_FIFOTRIG_TXLVL_MASK);
217         base->FIFOTRIG |= USART_FIFOTRIG_TXLVL(config->txWatermark);
218         /* enable trigger interrupt */
219         base->FIFOTRIG |= USART_FIFOTRIG_TXLVLENA_MASK;
220     }
221 
222     /* empty and enable rxFIFO */
223     if (config->enableRx)
224     {
225         base->FIFOCFG |= USART_FIFOCFG_EMPTYRX_MASK | USART_FIFOCFG_ENABLERX_MASK;
226         /* setup trigger level */
227         base->FIFOTRIG &= ~(USART_FIFOTRIG_RXLVL_MASK);
228         base->FIFOTRIG |= USART_FIFOTRIG_RXLVL(config->rxWatermark);
229         /* enable trigger interrupt */
230         base->FIFOTRIG |= USART_FIFOTRIG_RXLVLENA_MASK;
231     }
232     /* setup configuration and enable USART */
233     base->CFG = USART_CFG_PARITYSEL(config->parityMode) | USART_CFG_STOPLEN(config->stopBitCount) |
234                 USART_CFG_DATALEN(config->bitCountPerChar) | USART_CFG_LOOP(config->loopback) |
235                 USART_CFG_SYNCEN((uint32_t)config->syncMode >> 1) | USART_CFG_SYNCMST((uint8_t)config->syncMode) |
236                 USART_CFG_CLKPOL(config->clockPolarity) | USART_CFG_MODE32K(config->enableMode32k) |
237                 USART_CFG_CTSEN(config->enableHardwareFlowControl) | USART_CFG_ENABLE_MASK;
238 
239     /* Setup baudrate */
240     if (config->enableMode32k)
241     {
242         if ((9600U % config->baudRate_Bps) == 0U)
243         {
244             base->BRG = 9600U / config->baudRate_Bps;
245         }
246         else
247         {
248             return kStatus_USART_BaudrateNotSupport;
249         }
250     }
251     else
252     {
253         result = USART_SetBaudRate(base, config->baudRate_Bps, srcClock_Hz);
254         if (kStatus_Success != result)
255         {
256             return result;
257         }
258     }
259     /* Setting continuous Clock configuration. used for synchronous mode. */
260     USART_EnableContinuousSCLK(base, config->enableContinuousSCLK);
261 
262     return kStatus_Success;
263 }
264 
265 /*!
266  * brief Deinitializes a USART instance.
267  *
268  * This function waits for TX complete, disables TX and RX, and disables the USART clock.
269  *
270  * param base USART peripheral base address.
271  */
USART_Deinit(USART_Type * base)272 void USART_Deinit(USART_Type *base)
273 {
274     /* Check arguments */
275     assert(NULL != base);
276     while (0U == (base->STAT & USART_STAT_TXIDLE_MASK))
277     {
278     }
279     /* Disable interrupts, disable dma requests, disable peripheral */
280     base->FIFOINTENCLR = USART_FIFOINTENCLR_TXERR_MASK | USART_FIFOINTENCLR_RXERR_MASK | USART_FIFOINTENCLR_TXLVL_MASK |
281                          USART_FIFOINTENCLR_RXLVL_MASK;
282     base->FIFOCFG &= ~(USART_FIFOCFG_DMATX_MASK | USART_FIFOCFG_DMARX_MASK);
283     base->CFG &= ~(USART_CFG_ENABLE_MASK);
284 }
285 
286 /*!
287  * brief Gets the default configuration structure.
288  *
289  * This function initializes the USART configuration structure to a default value. The default
290  * values are:
291  *   usartConfig->baudRate_Bps = 115200U;
292  *   usartConfig->parityMode = kUSART_ParityDisabled;
293  *   usartConfig->stopBitCount = kUSART_OneStopBit;
294  *   usartConfig->bitCountPerChar = kUSART_8BitsPerChar;
295  *   usartConfig->loopback = false;
296  *   usartConfig->enableTx = false;
297  *   usartConfig->enableRx = false;
298  *
299  * param config Pointer to configuration structure.
300  */
USART_GetDefaultConfig(usart_config_t * config)301 void USART_GetDefaultConfig(usart_config_t *config)
302 {
303     /* Check arguments */
304     assert(NULL != config);
305 
306     /* Initializes the configure structure to zero. */
307     (void)memset(config, 0, sizeof(*config));
308 
309     /* Set always all members ! */
310     config->baudRate_Bps              = 115200U;
311     config->parityMode                = kUSART_ParityDisabled;
312     config->stopBitCount              = kUSART_OneStopBit;
313     config->bitCountPerChar           = kUSART_8BitsPerChar;
314     config->loopback                  = false;
315     config->enableRx                  = false;
316     config->enableTx                  = false;
317     config->enableMode32k             = false;
318     config->txWatermark               = kUSART_TxFifo0;
319     config->rxWatermark               = kUSART_RxFifo1;
320     config->syncMode                  = kUSART_SyncModeDisabled;
321     config->enableContinuousSCLK      = false;
322     config->clockPolarity             = kUSART_RxSampleOnFallingEdge;
323     config->enableHardwareFlowControl = false;
324 }
325 
326 /*!
327  * brief Sets the USART instance baud rate.
328  *
329  * This function configures the USART module baud rate. This function is used to update
330  * the USART module baud rate after the USART module is initialized by the USART_Init.
331  * code
332  *  USART_SetBaudRate(USART1, 115200U, 20000000U);
333  * endcode
334  *
335  * param base USART peripheral base address.
336  * param baudrate_Bps USART baudrate to be set.
337  * param srcClock_Hz USART clock source frequency in HZ.
338  * retval kStatus_USART_BaudrateNotSupport Baudrate is not support in current clock source.
339  * retval kStatus_Success Set baudrate succeed.
340  * retval kStatus_InvalidArgument One or more arguments are invalid.
341  */
USART_SetBaudRate(USART_Type * base,uint32_t baudrate_Bps,uint32_t srcClock_Hz)342 status_t USART_SetBaudRate(USART_Type *base, uint32_t baudrate_Bps, uint32_t srcClock_Hz)
343 {
344     uint32_t best_diff = (uint32_t)-1, best_osrval = 0xf, best_brgval = (uint32_t)-1;
345     uint32_t osrval, brgval, diff, baudrate;
346 
347     /* check arguments */
348     assert(!((NULL == base) || (0U == baudrate_Bps) || (0U == srcClock_Hz)));
349     if ((NULL == base) || (0U == baudrate_Bps) || (0U == srcClock_Hz))
350     {
351         return kStatus_InvalidArgument;
352     }
353 
354     /* If synchronous master mode is enabled, only configure the BRG value. */
355     if ((base->CFG & USART_CFG_SYNCEN_MASK) != 0U)
356     {
357         if ((base->CFG & USART_CFG_SYNCMST_MASK) != 0U)
358         {
359             brgval    = srcClock_Hz / baudrate_Bps;
360             base->BRG = brgval - 1U;
361         }
362     }
363     else
364     {
365         /*
366          * Smaller values of OSR can make the sampling position within a data bit less accurate and may
367          * potentially cause more noise errors or incorrect data.
368          */
369         for (osrval = best_osrval; osrval >= 8U; osrval--)
370         {
371             brgval = (((srcClock_Hz * 10U) / ((osrval + 1U) * baudrate_Bps)) - 5U) / 10U;
372             if (brgval > 0xFFFFU)
373             {
374                 continue;
375             }
376             baudrate = srcClock_Hz / ((osrval + 1U) * (brgval + 1U));
377             diff     = (baudrate_Bps < baudrate) ? (baudrate - baudrate_Bps) : (baudrate_Bps - baudrate);
378             if (diff < best_diff)
379             {
380                 best_diff   = diff;
381                 best_osrval = osrval;
382                 best_brgval = brgval;
383             }
384         }
385 
386         /* Check to see if actual baud rate is within 3% of desired baud rate
387          * based on the best calculated OSR and BRG value */
388         baudrate = srcClock_Hz / ((best_osrval + 1U) * (best_brgval + 1U));
389         diff     = (baudrate_Bps < baudrate) ? (baudrate - baudrate_Bps) : (baudrate_Bps - baudrate);
390         if (diff > ((baudrate_Bps / 100U) * 3U))
391         {
392             return kStatus_USART_BaudrateNotSupport;
393         }
394 
395         /* value over range */
396         if (best_brgval > 0xFFFFU)
397         {
398             return kStatus_USART_BaudrateNotSupport;
399         }
400 
401         base->OSR = best_osrval;
402         base->BRG = best_brgval;
403     }
404 
405     return kStatus_Success;
406 }
407 
408 /*!
409  * brief Enable 32 kHz mode which USART uses clock from the RTC oscillator as the clock source.
410  *
411  * Please note that in order to use a 32 kHz clock to operate USART properly, the RTC oscillator
412  * and its 32 kHz output must be manully enabled by user, by calling RTC_Init and setting
413  * SYSCON_RTCOSCCTRL_EN bit to 1.
414  * And in 32kHz clocking mode the USART can only work at 9600 baudrate or at the baudrate that
415  * 9600 can evenly divide, eg: 4800, 3200.
416  *
417  * param base USART peripheral base address.
418  * param baudRate_Bps USART baudrate to be set..
419  * param enableMode32k true is 32k mode, false is normal mode.
420  * param srcClock_Hz USART clock source frequency in HZ.
421  * retval kStatus_USART_BaudrateNotSupport Baudrate is not support in current clock source.
422  * retval kStatus_Success Set baudrate succeed.
423  * retval kStatus_InvalidArgument One or more arguments are invalid.
424  */
USART_Enable32kMode(USART_Type * base,uint32_t baudRate_Bps,bool enableMode32k,uint32_t srcClock_Hz)425 status_t USART_Enable32kMode(USART_Type *base, uint32_t baudRate_Bps, bool enableMode32k, uint32_t srcClock_Hz)
426 {
427     status_t result = kStatus_Success;
428     base->CFG &= ~(USART_CFG_ENABLE_MASK);
429     if (enableMode32k)
430     {
431         base->CFG |= USART_CFG_MODE32K_MASK;
432         if ((9600U % baudRate_Bps) == 0U)
433         {
434             base->BRG = 9600U / baudRate_Bps - 1U;
435         }
436         else
437         {
438             return kStatus_USART_BaudrateNotSupport;
439         }
440     }
441     else
442     {
443         base->CFG &= ~(USART_CFG_MODE32K_MASK);
444         result = USART_SetBaudRate(base, baudRate_Bps, srcClock_Hz);
445         if (kStatus_Success != result)
446         {
447             return result;
448         }
449     }
450     base->CFG |= USART_CFG_ENABLE_MASK;
451     return result;
452 }
453 
454 /*!
455  * brief Enable 9-bit data mode for USART.
456  *
457  * This function set the 9-bit mode for USART module. The 9th bit is not used for parity thus can be modified by user.
458  *
459  * param base USART peripheral base address.
460  * param enable true to enable, false to disable.
461  */
USART_Enable9bitMode(USART_Type * base,bool enable)462 void USART_Enable9bitMode(USART_Type *base, bool enable)
463 {
464     assert(base != NULL);
465 
466     uint32_t temp = 0U;
467 
468     if (enable)
469     {
470         /* Set USART 9-bit mode, disable parity. */
471         temp = base->CFG & ~((uint32_t)USART_CFG_DATALEN_MASK | (uint32_t)USART_CFG_PARITYSEL_MASK);
472         temp |= (uint32_t)USART_CFG_DATALEN(0x2U);
473         base->CFG = temp;
474     }
475     else
476     {
477         /* Set USART to 8-bit mode. */
478         base->CFG &= ~((uint32_t)USART_CFG_DATALEN_MASK);
479         base->CFG |= (uint32_t)USART_CFG_DATALEN(0x1U);
480     }
481 }
482 
483 /*!
484  * brief Transmit an address frame in 9-bit data mode.
485  *
486  * param base USART peripheral base address.
487  * param address USART slave address.
488  */
USART_SendAddress(USART_Type * base,uint8_t address)489 void USART_SendAddress(USART_Type *base, uint8_t address)
490 {
491     assert(base != NULL);
492     base->FIFOWR = ((uint32_t)address | 0x100UL);
493 }
494 
495 /*!
496  * brief Writes to the TX register using a blocking method.
497  *
498  * This function polls the TX register, waits for the TX register to be empty or for the TX FIFO
499  * to have room and writes data to the TX buffer.
500  *
501  * param base USART peripheral base address.
502  * param data Start address of the data to write.
503  * param length Size of the data to write.
504  * retval kStatus_USART_Timeout Transmission timed out and was aborted.
505  * retval kStatus_InvalidArgument Invalid argument.
506  * retval kStatus_Success Successfully wrote all data.
507  */
USART_WriteBlocking(USART_Type * base,const uint8_t * data,size_t length)508 status_t USART_WriteBlocking(USART_Type *base, const uint8_t *data, size_t length)
509 {
510     /* Check arguments */
511     assert(!((NULL == base) || (NULL == data)));
512 #if UART_RETRY_TIMES
513     uint32_t waitTimes;
514 #endif
515     if ((NULL == base) || (NULL == data))
516     {
517         return kStatus_InvalidArgument;
518     }
519     /* Check whether txFIFO is enabled */
520     if (0U == (base->FIFOCFG & USART_FIFOCFG_ENABLETX_MASK))
521     {
522         return kStatus_InvalidArgument;
523     }
524     for (; length > 0U; length--)
525     {
526         /* Loop until txFIFO get some space for new data */
527 #if UART_RETRY_TIMES
528         waitTimes = UART_RETRY_TIMES;
529         while ((0U == (base->FIFOSTAT & USART_FIFOSTAT_TXNOTFULL_MASK)) && (--waitTimes != 0U))
530 #else
531         while (0U == (base->FIFOSTAT & USART_FIFOSTAT_TXNOTFULL_MASK))
532 #endif
533         {
534         }
535 #if UART_RETRY_TIMES
536         if (0U == waitTimes)
537         {
538             return kStatus_USART_Timeout;
539         }
540 #endif
541         base->FIFOWR = *data;
542         data++;
543     }
544     /* Wait to finish transfer */
545 #if UART_RETRY_TIMES
546     waitTimes = UART_RETRY_TIMES;
547     while ((0U == (base->STAT & USART_STAT_TXIDLE_MASK)) && (--waitTimes != 0U))
548 #else
549     while (0U == (base->STAT & USART_STAT_TXIDLE_MASK))
550 #endif
551     {
552     }
553 #if UART_RETRY_TIMES
554     if (0U == waitTimes)
555     {
556         return kStatus_USART_Timeout;
557     }
558 #endif
559     return kStatus_Success;
560 }
561 
562 /*!
563  * brief Read RX data register using a blocking method.
564  *
565  * This function polls the RX register, waits for the RX register to be full or for RX FIFO to
566  * have data and read data from the TX register.
567  *
568  * param base USART peripheral base address.
569  * param data Start address of the buffer to store the received data.
570  * param length Size of the buffer.
571  * retval kStatus_USART_FramingError Receiver overrun happened while receiving data.
572  * retval kStatus_USART_ParityError Noise error happened while receiving data.
573  * retval kStatus_USART_NoiseError Framing error happened while receiving data.
574  * retval kStatus_USART_RxError Overflow or underflow rxFIFO happened.
575  * retval kStatus_USART_Timeout Transmission timed out and was aborted.
576  * retval kStatus_Success Successfully received all data.
577  */
USART_ReadBlocking(USART_Type * base,uint8_t * data,size_t length)578 status_t USART_ReadBlocking(USART_Type *base, uint8_t *data, size_t length)
579 {
580     uint32_t statusFlag;
581     status_t status = kStatus_Success;
582 #if UART_RETRY_TIMES
583     uint32_t waitTimes;
584 #endif
585 
586     /* check arguments */
587     assert(!((NULL == base) || (NULL == data)));
588     if ((NULL == base) || (NULL == data))
589     {
590         return kStatus_InvalidArgument;
591     }
592 
593     /* Check whether rxFIFO is enabled */
594     if ((base->FIFOCFG & USART_FIFOCFG_ENABLERX_MASK) == 0U)
595     {
596         return kStatus_Fail;
597     }
598     for (; length > 0U; length--)
599     {
600         /* loop until rxFIFO have some data to read */
601 #if UART_RETRY_TIMES
602         waitTimes = UART_RETRY_TIMES;
603         while (((base->FIFOSTAT & USART_FIFOSTAT_RXNOTEMPTY_MASK) == 0U) && (--waitTimes != 0U))
604 #else
605         while ((base->FIFOSTAT & USART_FIFOSTAT_RXNOTEMPTY_MASK) == 0U)
606 #endif
607         {
608         }
609 #if UART_RETRY_TIMES
610         if (waitTimes == 0U)
611         {
612             status = kStatus_USART_Timeout;
613             break;
614         }
615 #endif
616         /* check rxFIFO statusFlag */
617         if ((base->FIFOSTAT & USART_FIFOSTAT_RXERR_MASK) != 0U)
618         {
619             base->FIFOCFG |= USART_FIFOCFG_EMPTYRX_MASK;
620             base->FIFOSTAT |= USART_FIFOSTAT_RXERR_MASK;
621             status = kStatus_USART_RxError;
622             break;
623         }
624         /* check receive statusFlag */
625         statusFlag = base->STAT;
626         /* Clear all status flags */
627         base->STAT |= statusFlag;
628         if ((statusFlag & USART_STAT_PARITYERRINT_MASK) != 0U)
629         {
630             status = kStatus_USART_ParityError;
631         }
632         if ((statusFlag & USART_STAT_FRAMERRINT_MASK) != 0U)
633         {
634             status = kStatus_USART_FramingError;
635         }
636         if ((statusFlag & USART_STAT_RXNOISEINT_MASK) != 0U)
637         {
638             status = kStatus_USART_NoiseError;
639         }
640 
641         if (kStatus_Success == status)
642         {
643             *data = (uint8_t)base->FIFORD;
644             data++;
645         }
646         else
647         {
648             break;
649         }
650     }
651     return status;
652 }
653 
654 /*!
655  * brief Initializes the USART handle.
656  *
657  * This function initializes the USART handle which can be used for other USART
658  * transactional APIs. Usually, for a specified USART instance,
659  * call this API once to get the initialized handle.
660  *
661  * param base USART peripheral base address.
662  * param handle USART handle pointer.
663  * param callback The callback function.
664  * param userData The parameter of the callback function.
665  */
USART_TransferCreateHandle(USART_Type * base,usart_handle_t * handle,usart_transfer_callback_t callback,void * userData)666 status_t USART_TransferCreateHandle(USART_Type *base,
667                                     usart_handle_t *handle,
668                                     usart_transfer_callback_t callback,
669                                     void *userData)
670 {
671     /* Check 'base' */
672     assert(!((NULL == base) || (NULL == handle)));
673 
674     uint32_t instance = 0;
675     usart_to_flexcomm_t handler;
676     handler.usart_master_handler = USART_TransferHandleIRQ;
677 
678     if ((NULL == base) || (NULL == handle))
679     {
680         return kStatus_InvalidArgument;
681     }
682 
683     instance = USART_GetInstance(base);
684 
685     (void)memset(handle, 0, sizeof(*handle));
686     /* Set the TX/RX state. */
687     handle->rxState = (uint8_t)kUSART_RxIdle;
688     handle->txState = (uint8_t)kUSART_TxIdle;
689     /* Set the callback and user data. */
690     handle->callback    = callback;
691     handle->userData    = userData;
692     handle->rxWatermark = (uint8_t)USART_FIFOTRIG_RXLVL_GET(base);
693     handle->txWatermark = (uint8_t)USART_FIFOTRIG_TXLVL_GET(base);
694 
695     FLEXCOMM_SetIRQHandler(base, handler.flexcomm_handler, handle);
696 
697     /* Enable interrupt in NVIC. */
698     (void)EnableIRQ(s_usartIRQ[instance]);
699 
700     return kStatus_Success;
701 }
702 
703 /*!
704  * brief Transmits a buffer of data using the interrupt method.
705  *
706  * This function sends data using an interrupt method. This is a non-blocking function, which
707  * returns directly without waiting for all data to be written to the TX register. When
708  * all data is written to the TX register in the IRQ handler, the USART driver calls the callback
709  * function and passes the ref kStatus_USART_TxIdle as status parameter.
710  *
711  * note The kStatus_USART_TxIdle is passed to the upper layer when all data is written
712  * to the TX register. However it does not ensure that all data are sent out. Before disabling the TX,
713  * check the kUSART_TransmissionCompleteFlag to ensure that the TX is finished.
714  *
715  * param base USART peripheral base address.
716  * param handle USART handle pointer.
717  * param xfer USART transfer structure. See  #usart_transfer_t.
718  * retval kStatus_Success Successfully start the data transmission.
719  * retval kStatus_USART_TxBusy Previous transmission still not finished, data not all written to TX register yet.
720  * retval kStatus_InvalidArgument Invalid argument.
721  */
USART_TransferSendNonBlocking(USART_Type * base,usart_handle_t * handle,usart_transfer_t * xfer)722 status_t USART_TransferSendNonBlocking(USART_Type *base, usart_handle_t *handle, usart_transfer_t *xfer)
723 {
724     /* Check arguments */
725     assert(!((NULL == base) || (NULL == handle) || (NULL == xfer)));
726     if ((NULL == base) || (NULL == handle) || (NULL == xfer))
727     {
728         return kStatus_InvalidArgument;
729     }
730     /* Check xfer members */
731     assert(!((0U == xfer->dataSize) || (NULL == xfer->txData)));
732     if ((0U == xfer->dataSize) || (NULL == xfer->txData))
733     {
734         return kStatus_InvalidArgument;
735     }
736 
737     /* Return error if current TX busy. */
738     if ((uint8_t)kUSART_TxBusy == handle->txState)
739     {
740         return kStatus_USART_TxBusy;
741     }
742     else
743     {
744         /* Disable IRQ when configuring transfer handle, in case interrupt occurs during the process and messes up the
745          * handle value. */
746         uint32_t interruptMask = USART_GetEnabledInterrupts(base);
747         USART_DisableInterrupts(base, interruptMask);
748         handle->txData        = xfer->txData;
749         handle->txDataSize    = xfer->dataSize;
750         handle->txDataSizeAll = xfer->dataSize;
751         handle->txState       = (uint8_t)kUSART_TxBusy;
752         /* Enable transmiter interrupt and the previously disabled interrupt. */
753         USART_EnableInterrupts(base, interruptMask | (uint32_t)kUSART_TxLevelInterruptEnable);
754     }
755     return kStatus_Success;
756 }
757 
758 /*!
759  * brief Aborts the interrupt-driven data transmit.
760  *
761  * This function aborts the interrupt driven data sending. The user can get the remainBtyes to find out
762  * how many bytes are still not sent out.
763  *
764  * param base USART peripheral base address.
765  * param handle USART handle pointer.
766  */
USART_TransferAbortSend(USART_Type * base,usart_handle_t * handle)767 void USART_TransferAbortSend(USART_Type *base, usart_handle_t *handle)
768 {
769     assert(NULL != handle);
770 
771     /* Disable interrupts */
772     USART_DisableInterrupts(base, (uint32_t)kUSART_TxLevelInterruptEnable);
773     /* Empty txFIFO */
774     base->FIFOCFG |= USART_FIFOCFG_EMPTYTX_MASK;
775 
776     handle->txDataSize = 0U;
777     handle->txState    = (uint8_t)kUSART_TxIdle;
778 }
779 
780 /*!
781  * brief Get the number of bytes that have been sent out to bus.
782  *
783  * This function gets the number of bytes that have been sent out to bus by interrupt method.
784  *
785  * param base USART peripheral base address.
786  * param handle USART handle pointer.
787  * param count Send bytes count.
788  * retval kStatus_NoTransferInProgress No send in progress.
789  * retval kStatus_InvalidArgument Parameter is invalid.
790  * retval kStatus_Success Get successfully through the parameter \p count;
791  */
USART_TransferGetSendCount(USART_Type * base,usart_handle_t * handle,uint32_t * count)792 status_t USART_TransferGetSendCount(USART_Type *base, usart_handle_t *handle, uint32_t *count)
793 {
794     assert(NULL != handle);
795     assert(NULL != count);
796 
797     if ((uint8_t)kUSART_TxIdle == handle->txState)
798     {
799         return kStatus_NoTransferInProgress;
800     }
801 
802     *count = handle->txDataSizeAll - handle->txDataSize -
803              ((base->FIFOSTAT & USART_FIFOSTAT_TXLVL_MASK) >> USART_FIFOSTAT_TXLVL_SHIFT);
804 
805     return kStatus_Success;
806 }
807 
808 /*!
809  * brief Receives a buffer of data using an interrupt method.
810  *
811  * This function receives data using an interrupt method. This is a non-blocking function, which
812  *  returns without waiting for all data to be received.
813  * If the RX ring buffer is used and not empty, the data in the ring buffer is copied and
814  * the parameter p receivedBytes shows how many bytes are copied from the ring buffer.
815  * After copying, if the data in the ring buffer is not enough to read, the receive
816  * request is saved by the USART driver. When the new data arrives, the receive request
817  * is serviced first. When all data is received, the USART driver notifies the upper layer
818  * through a callback function and passes the status parameter ref kStatus_USART_RxIdle.
819  * For example, the upper layer needs 10 bytes but there are only 5 bytes in the ring buffer.
820  * The 5 bytes are copied to the xfer->data and this function returns with the
821  * parameter p receivedBytes set to 5. For the left 5 bytes, newly arrived data is
822  * saved from the xfer->data[5]. When 5 bytes are received, the USART driver notifies the upper layer.
823  * If the RX ring buffer is not enabled, this function enables the RX and RX interrupt
824  * to receive data to the xfer->data. When all data is received, the upper layer is notified.
825  *
826  * param base USART peripheral base address.
827  * param handle USART handle pointer.
828  * param xfer USART transfer structure, see #usart_transfer_t.
829  * param receivedBytes Bytes received from the ring buffer directly.
830  * retval kStatus_Success Successfully queue the transfer into transmit queue.
831  * retval kStatus_USART_RxBusy Previous receive request is not finished.
832  * retval kStatus_InvalidArgument Invalid argument.
833  */
USART_TransferReceiveNonBlocking(USART_Type * base,usart_handle_t * handle,usart_transfer_t * xfer,size_t * receivedBytes)834 status_t USART_TransferReceiveNonBlocking(USART_Type *base,
835                                           usart_handle_t *handle,
836                                           usart_transfer_t *xfer,
837                                           size_t *receivedBytes)
838 {
839     uint32_t i;
840     /* How many bytes to copy from ring buffer to user memory. */
841     size_t bytesToCopy = 0U;
842     /* How many bytes to receive. */
843     size_t bytesToReceive;
844     /* How many bytes currently have received. */
845     size_t bytesCurrentReceived;
846     uint32_t interruptMask = 0U;
847 
848     /* Check arguments */
849     assert(!((NULL == base) || (NULL == handle) || (NULL == xfer)));
850     if ((NULL == base) || (NULL == handle) || (NULL == xfer))
851     {
852         return kStatus_InvalidArgument;
853     }
854     /* Check xfer members */
855     assert(!((0U == xfer->dataSize) || (NULL == xfer->rxData)));
856     if ((0U == xfer->dataSize) || (NULL == xfer->rxData))
857     {
858         return kStatus_InvalidArgument;
859     }
860 
861     /* Enable address detect when address match is enabled. */
862     if ((base->CFG & (uint32_t)USART_CFG_AUTOADDR_MASK) != 0U)
863     {
864         base->CTL |= (uint32_t)USART_CTL_ADDRDET_MASK;
865     }
866 
867     /* How to get data:
868        1. If RX ring buffer is not enabled, then save xfer->data and xfer->dataSize
869           to uart handle, enable interrupt to store received data to xfer->data. When
870           all data received, trigger callback.
871        2. If RX ring buffer is enabled and not empty, get data from ring buffer first.
872           If there are enough data in ring buffer, copy them to xfer->data and return.
873           If there are not enough data in ring buffer, copy all of them to xfer->data,
874           save the xfer->data remained empty space to uart handle, receive data
875           to this empty space and trigger callback when finished. */
876     if ((uint8_t)kUSART_RxBusy == handle->rxState)
877     {
878         return kStatus_USART_RxBusy;
879     }
880     else
881     {
882         bytesToReceive       = xfer->dataSize;
883         bytesCurrentReceived = 0U;
884         /* If RX ring buffer is used. */
885         if (handle->rxRingBuffer != NULL)
886         {
887             /* Disable IRQ, protect ring buffer. */
888             interruptMask = USART_GetEnabledInterrupts(base);
889             USART_DisableInterrupts(base, interruptMask);
890 
891             /* How many bytes in RX ring buffer currently. */
892             bytesToCopy = USART_TransferGetRxRingBufferLength(handle);
893             if (bytesToCopy != 0U)
894             {
895                 bytesToCopy = MIN(bytesToReceive, bytesToCopy);
896                 bytesToReceive -= bytesToCopy;
897                 /* Copy data from ring buffer to user memory. */
898                 for (i = 0U; i < bytesToCopy; i++)
899                 {
900                     xfer->rxData[bytesCurrentReceived++] = handle->rxRingBuffer[handle->rxRingBufferTail];
901                     /* Wrap to 0. Not use modulo (%) because it might be large and slow. */
902                     if ((size_t)handle->rxRingBufferTail + 1U == handle->rxRingBufferSize)
903                     {
904                         handle->rxRingBufferTail = 0U;
905                     }
906                     else
907                     {
908                         handle->rxRingBufferTail++;
909                     }
910                 }
911             }
912             /* If ring buffer does not have enough data, still need to read more data. */
913             if (bytesToReceive != 0U)
914             {
915                 /* No data in ring buffer, save the request to UART handle. */
916                 handle->rxData        = xfer->rxData + bytesCurrentReceived;
917                 handle->rxDataSize    = bytesToReceive;
918                 handle->rxDataSizeAll = xfer->dataSize;
919                 handle->rxState       = (uint8_t)kUSART_RxBusy;
920             }
921             /* Re-enable IRQ. */
922             USART_EnableInterrupts(base, interruptMask);
923             /* Call user callback since all data are received. */
924             if (0U == bytesToReceive)
925             {
926                 if (handle->callback != NULL)
927                 {
928                     handle->callback(base, handle, kStatus_USART_RxIdle, handle->userData);
929                 }
930             }
931         }
932         /* Ring buffer not used. */
933         else
934         {
935             /* Disable IRQ when configuring transfer handle, in case interrupt occurs during the process and messes up
936              * the handle value. */
937             interruptMask = USART_GetEnabledInterrupts(base);
938             USART_DisableInterrupts(base, interruptMask);
939             handle->rxData        = xfer->rxData + bytesCurrentReceived;
940             handle->rxDataSize    = bytesToReceive;
941             handle->rxDataSizeAll = bytesToReceive;
942             handle->rxState       = (uint8_t)kUSART_RxBusy;
943 
944             /* Enable RX interrupt. */
945             base->FIFOINTENSET = USART_FIFOINTENSET_RXLVL_MASK;
946             /* Re-enable IRQ. */
947             USART_EnableInterrupts(base, interruptMask);
948         }
949         /* Return the how many bytes have read. */
950         if (receivedBytes != NULL)
951         {
952             *receivedBytes = bytesCurrentReceived;
953         }
954     }
955     return kStatus_Success;
956 }
957 
958 /*!
959  * brief Aborts the interrupt-driven data receiving.
960  *
961  * This function aborts the interrupt-driven data receiving. The user can get the remainBytes to find out
962  * how many bytes not received yet.
963  *
964  * param base USART peripheral base address.
965  * param handle USART handle pointer.
966  */
USART_TransferAbortReceive(USART_Type * base,usart_handle_t * handle)967 void USART_TransferAbortReceive(USART_Type *base, usart_handle_t *handle)
968 {
969     assert(NULL != handle);
970 
971     /* Only abort the receive to handle->rxData, the RX ring buffer is still working. */
972     if (NULL == handle->rxRingBuffer)
973     {
974         /* Disable interrupts */
975         USART_DisableInterrupts(base, (uint32_t)kUSART_RxLevelInterruptEnable);
976         /* Empty rxFIFO */
977         base->FIFOCFG |= USART_FIFOCFG_EMPTYRX_MASK;
978     }
979 
980     handle->rxDataSize = 0U;
981     handle->rxState    = (uint8_t)kUSART_RxIdle;
982 }
983 
984 /*!
985  * brief Get the number of bytes that have been received.
986  *
987  * This function gets the number of bytes that have been received.
988  *
989  * param base USART peripheral base address.
990  * param handle USART handle pointer.
991  * param count Receive bytes count.
992  * retval kStatus_NoTransferInProgress No receive in progress.
993  * retval kStatus_InvalidArgument Parameter is invalid.
994  * retval kStatus_Success Get successfully through the parameter \p count;
995  */
USART_TransferGetReceiveCount(USART_Type * base,usart_handle_t * handle,uint32_t * count)996 status_t USART_TransferGetReceiveCount(USART_Type *base, usart_handle_t *handle, uint32_t *count)
997 {
998     assert(NULL != handle);
999     assert(NULL != count);
1000 
1001     if ((uint8_t)kUSART_RxIdle == handle->rxState)
1002     {
1003         return kStatus_NoTransferInProgress;
1004     }
1005 
1006     *count = handle->rxDataSizeAll - handle->rxDataSize;
1007 
1008     return kStatus_Success;
1009 }
1010 
1011 /*!
1012  * brief USART IRQ handle function.
1013  *
1014  * This function handles the USART transmit and receive IRQ request.
1015  *
1016  * param base USART peripheral base address.
1017  * param handle USART handle pointer.
1018  */
USART_TransferHandleIRQ(USART_Type * base,usart_handle_t * handle)1019 void USART_TransferHandleIRQ(USART_Type *base, usart_handle_t *handle)
1020 {
1021     /* Check arguments */
1022     assert((NULL != base) && (NULL != handle));
1023 
1024     bool receiveEnabled = ((handle->rxDataSize != 0U) || (handle->rxRingBuffer != NULL));
1025     bool sendEnabled    = (handle->txDataSize != 0U);
1026     uint8_t rxdata;
1027     size_t tmpsize;
1028 
1029     /* If RX overrun. */
1030     if ((base->FIFOSTAT & USART_FIFOSTAT_RXERR_MASK) != 0U)
1031     {
1032         /* Clear rx error state. */
1033         base->FIFOSTAT |= USART_FIFOSTAT_RXERR_MASK;
1034         /* clear rxFIFO */
1035         base->FIFOCFG |= USART_FIFOCFG_EMPTYRX_MASK;
1036         /* Trigger callback. */
1037         if (handle->callback != NULL)
1038         {
1039             handle->callback(base, handle, kStatus_USART_RxError, handle->userData);
1040         }
1041     }
1042     while ((receiveEnabled && ((base->FIFOSTAT & USART_FIFOSTAT_RXNOTEMPTY_MASK) != 0U)) ||
1043            (sendEnabled && ((base->FIFOSTAT & USART_FIFOSTAT_TXNOTFULL_MASK) != 0U)))
1044     {
1045         /* Receive data */
1046         if (receiveEnabled && ((base->FIFOSTAT & USART_FIFOSTAT_RXNOTEMPTY_MASK) != 0U))
1047         {
1048             /* Clear address detect when RXFIFO has data. */
1049             base->CTL &= ~(uint32_t)USART_CTL_ADDRDET_MASK;
1050             /* Receive to app bufffer if app buffer is present */
1051             if (handle->rxDataSize != 0U)
1052             {
1053                 rxdata          = (uint8_t)base->FIFORD;
1054                 *handle->rxData = rxdata;
1055                 handle->rxDataSize--;
1056                 handle->rxData++;
1057                 receiveEnabled = ((handle->rxDataSize != 0U) || (handle->rxRingBuffer != NULL));
1058                 if (0U == handle->rxDataSize)
1059                 {
1060                     if (NULL == handle->rxRingBuffer)
1061                     {
1062                         base->FIFOINTENCLR = USART_FIFOINTENCLR_RXLVL_MASK | USART_FIFOINTENSET_RXERR_MASK;
1063                     }
1064                     handle->rxState = (uint8_t)kUSART_RxIdle;
1065                     if (handle->callback != NULL)
1066                     {
1067                         handle->callback(base, handle, kStatus_USART_RxIdle, handle->userData);
1068                     }
1069                 }
1070             }
1071             /* Otherwise receive to ring buffer if ring buffer is present */
1072             else
1073             {
1074                 if (handle->rxRingBuffer != NULL)
1075                 {
1076                     /* If RX ring buffer is full, trigger callback to notify over run. */
1077                     if (USART_TransferIsRxRingBufferFull(handle))
1078                     {
1079                         if (handle->callback != NULL)
1080                         {
1081                             handle->callback(base, handle, kStatus_USART_RxRingBufferOverrun, handle->userData);
1082                         }
1083                     }
1084                     /* If ring buffer is still full after callback function, the oldest data is overridden. */
1085                     if (USART_TransferIsRxRingBufferFull(handle))
1086                     {
1087                         /* Increase handle->rxRingBufferTail to make room for new data. */
1088                         if ((size_t)handle->rxRingBufferTail + 1U == handle->rxRingBufferSize)
1089                         {
1090                             handle->rxRingBufferTail = 0U;
1091                         }
1092                         else
1093                         {
1094                             handle->rxRingBufferTail++;
1095                         }
1096                     }
1097                     /* Read data. */
1098                     rxdata                                         = (uint8_t)base->FIFORD;
1099                     handle->rxRingBuffer[handle->rxRingBufferHead] = rxdata;
1100                     /* Increase handle->rxRingBufferHead. */
1101                     if ((size_t)handle->rxRingBufferHead + 1U == handle->rxRingBufferSize)
1102                     {
1103                         handle->rxRingBufferHead = 0U;
1104                     }
1105                     else
1106                     {
1107                         handle->rxRingBufferHead++;
1108                     }
1109                 }
1110             }
1111         }
1112         /* Send data */
1113         if (sendEnabled && ((base->FIFOSTAT & USART_FIFOSTAT_TXNOTFULL_MASK) != 0U))
1114         {
1115             base->FIFOWR = *handle->txData;
1116             handle->txDataSize--;
1117             handle->txData++;
1118             sendEnabled = handle->txDataSize != 0U;
1119             if (!sendEnabled)
1120             {
1121                 base->FIFOINTENCLR = USART_FIFOINTENCLR_TXLVL_MASK;
1122 
1123                 base->INTENSET = USART_INTENSET_TXIDLEEN_MASK;
1124             }
1125         }
1126     }
1127 
1128     /* Tx idle and the interrupt is enabled. */
1129     if ((0U != (base->INTENSET & USART_INTENSET_TXIDLEEN_MASK)) && (0U != (base->INTSTAT & USART_INTSTAT_TXIDLE_MASK)))
1130     {
1131         /* Set txState to idle only when all data has been sent out to bus. */
1132         handle->txState = (uint8_t)kUSART_TxIdle;
1133         /* Disable tx idle interrupt */
1134         base->INTENCLR = USART_INTENCLR_TXIDLECLR_MASK;
1135 
1136         /* Trigger callback. */
1137         if (handle->callback != NULL)
1138         {
1139             handle->callback(base, handle, kStatus_USART_TxIdle, handle->userData);
1140         }
1141     }
1142 
1143     /* ring buffer is not used */
1144     if (NULL == handle->rxRingBuffer)
1145     {
1146         tmpsize = handle->rxDataSize;
1147 
1148         /* restore if rx transfer ends and rxLevel is different from default value */
1149         if ((tmpsize == 0U) && (USART_FIFOTRIG_RXLVL_GET(base) != handle->rxWatermark))
1150         {
1151             base->FIFOTRIG =
1152                 (base->FIFOTRIG & (~USART_FIFOTRIG_RXLVL_MASK)) | USART_FIFOTRIG_RXLVL(handle->rxWatermark);
1153         }
1154         /* decrease level if rx transfer is bellow */
1155         if ((tmpsize != 0U) && (tmpsize < (USART_FIFOTRIG_RXLVL_GET(base) + 1U)))
1156         {
1157             base->FIFOTRIG = (base->FIFOTRIG & (~USART_FIFOTRIG_RXLVL_MASK)) | (USART_FIFOTRIG_RXLVL(tmpsize - 1U));
1158         }
1159     }
1160 }
1161