1 /*
2  * Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
3  * Copyright 2016-2020 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_flexio_uart.h"
10 
11 /*******************************************************************************
12  * Definitions
13  ******************************************************************************/
14 
15 /* Component ID definition, used by tools. */
16 #ifndef FSL_COMPONENT_ID
17 #define FSL_COMPONENT_ID "platform.drivers.flexio_uart"
18 #endif
19 
20 /*<! @brief uart transfer state. */
21 enum _flexio_uart_transfer_states
22 {
23     kFLEXIO_UART_TxIdle, /* TX idle. */
24     kFLEXIO_UART_TxBusy, /* TX busy. */
25     kFLEXIO_UART_RxIdle, /* RX idle. */
26     kFLEXIO_UART_RxBusy  /* RX busy. */
27 };
28 
29 /*******************************************************************************
30  * Prototypes
31  ******************************************************************************/
32 
33 /*!
34  * @brief Get the length of received data in RX ring buffer.
35  *
36  * @param handle FLEXIO UART handle pointer.
37  * @return Length of received data in RX ring buffer.
38  */
39 static size_t FLEXIO_UART_TransferGetRxRingBufferLength(flexio_uart_handle_t *handle);
40 
41 /*!
42  * @brief Check whether the RX ring buffer is full.
43  *
44  * @param handle FLEXIO UART handle pointer.
45  * @retval true  RX ring buffer is full.
46  * @retval false RX ring buffer is not full.
47  */
48 static bool FLEXIO_UART_TransferIsRxRingBufferFull(flexio_uart_handle_t *handle);
49 
50 /*******************************************************************************
51  * Codes
52  ******************************************************************************/
53 
FLEXIO_UART_GetInstance(FLEXIO_UART_Type * base)54 static uint32_t FLEXIO_UART_GetInstance(FLEXIO_UART_Type *base)
55 {
56     return FLEXIO_GetInstance(base->flexioBase);
57 }
58 
FLEXIO_UART_TransferGetRxRingBufferLength(flexio_uart_handle_t * handle)59 static size_t FLEXIO_UART_TransferGetRxRingBufferLength(flexio_uart_handle_t *handle)
60 {
61     size_t size;
62     uint16_t rxRingBufferHead = handle->rxRingBufferHead;
63     uint16_t rxRingBufferTail = handle->rxRingBufferTail;
64 
65     if (rxRingBufferTail > rxRingBufferHead)
66     {
67         size = (size_t)rxRingBufferHead + handle->rxRingBufferSize - (size_t)rxRingBufferTail;
68     }
69     else
70     {
71         size = (size_t)rxRingBufferHead - (size_t)rxRingBufferTail;
72     }
73 
74     return size;
75 }
76 
FLEXIO_UART_TransferIsRxRingBufferFull(flexio_uart_handle_t * handle)77 static bool FLEXIO_UART_TransferIsRxRingBufferFull(flexio_uart_handle_t *handle)
78 {
79     bool full;
80 
81     if (FLEXIO_UART_TransferGetRxRingBufferLength(handle) == (handle->rxRingBufferSize - 1U))
82     {
83         full = true;
84     }
85     else
86     {
87         full = false;
88     }
89 
90     return full;
91 }
92 
93 /*!
94  * brief Ungates the FlexIO clock, resets the FlexIO module, configures FlexIO UART
95  * hardware, and configures the FlexIO UART with FlexIO UART configuration.
96  * The configuration structure can be filled by the user or be set with
97  * default values by FLEXIO_UART_GetDefaultConfig().
98  *
99  * Example
100    code
101    FLEXIO_UART_Type base = {
102    .flexioBase = FLEXIO,
103    .TxPinIndex = 0,
104    .RxPinIndex = 1,
105    .shifterIndex = {0,1},
106    .timerIndex = {0,1}
107    };
108    flexio_uart_config_t config = {
109    .enableInDoze = false,
110    .enableInDebug = true,
111    .enableFastAccess = false,
112    .baudRate_Bps = 115200U,
113    .bitCountPerChar = 8
114    };
115    FLEXIO_UART_Init(base, &config, srcClock_Hz);
116    endcode
117  *
118  * param base Pointer to the FLEXIO_UART_Type structure.
119  * param userConfig Pointer to the flexio_uart_config_t structure.
120  * param srcClock_Hz FlexIO source clock in Hz.
121  * retval kStatus_Success Configuration success
122  * retval kStatus_InvalidArgument Buadrate configuration out of range
123 */
FLEXIO_UART_Init(FLEXIO_UART_Type * base,const flexio_uart_config_t * userConfig,uint32_t srcClock_Hz)124 status_t FLEXIO_UART_Init(FLEXIO_UART_Type *base, const flexio_uart_config_t *userConfig, uint32_t srcClock_Hz)
125 {
126     assert((base != NULL) && (userConfig != NULL));
127 
128     flexio_shifter_config_t shifterConfig;
129     flexio_timer_config_t timerConfig;
130     uint32_t ctrlReg  = 0;
131     uint16_t timerDiv = 0;
132     uint16_t timerCmp = 0;
133     status_t result   = kStatus_Success;
134 
135     /* Clear the shifterConfig & timerConfig struct. */
136     (void)memset(&shifterConfig, 0, sizeof(shifterConfig));
137     (void)memset(&timerConfig, 0, sizeof(timerConfig));
138 
139 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
140     /* Ungate flexio clock. */
141     CLOCK_EnableClock(s_flexioClocks[FLEXIO_UART_GetInstance(base)]);
142 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
143 
144     /* Configure FLEXIO UART */
145     ctrlReg = base->flexioBase->CTRL;
146     ctrlReg &= ~(FLEXIO_CTRL_DOZEN_MASK | FLEXIO_CTRL_DBGE_MASK | FLEXIO_CTRL_FASTACC_MASK | FLEXIO_CTRL_FLEXEN_MASK);
147     ctrlReg |= (FLEXIO_CTRL_DBGE(userConfig->enableInDebug) | FLEXIO_CTRL_FASTACC(userConfig->enableFastAccess) |
148                 FLEXIO_CTRL_FLEXEN(userConfig->enableUart));
149     if (!userConfig->enableInDoze)
150     {
151         ctrlReg |= FLEXIO_CTRL_DOZEN_MASK;
152     }
153 
154     base->flexioBase->CTRL = ctrlReg;
155 
156     /* Do hardware configuration. */
157     /* 1. Configure the shifter 0 for tx. */
158     shifterConfig.timerSelect   = base->timerIndex[0];
159     shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnPositive;
160     shifterConfig.pinConfig     = kFLEXIO_PinConfigOutput;
161     shifterConfig.pinSelect     = base->TxPinIndex;
162     shifterConfig.pinPolarity   = kFLEXIO_PinActiveHigh;
163     shifterConfig.shifterMode   = kFLEXIO_ShifterModeTransmit;
164     shifterConfig.inputSource   = kFLEXIO_ShifterInputFromPin;
165     shifterConfig.shifterStop   = kFLEXIO_ShifterStopBitHigh;
166     shifterConfig.shifterStart  = kFLEXIO_ShifterStartBitLow;
167 
168     FLEXIO_SetShifterConfig(base->flexioBase, base->shifterIndex[0], &shifterConfig);
169 
170     /*2. Configure the timer 0 for tx. */
171     timerConfig.triggerSelect   = FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->shifterIndex[0]);
172     timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveLow;
173     timerConfig.triggerSource   = kFLEXIO_TimerTriggerSourceInternal;
174     timerConfig.pinConfig       = kFLEXIO_PinConfigOutputDisabled;
175     timerConfig.pinSelect       = base->TxPinIndex;
176     timerConfig.pinPolarity     = kFLEXIO_PinActiveHigh;
177     timerConfig.timerMode       = kFLEXIO_TimerModeDual8BitBaudBit;
178     timerConfig.timerOutput     = kFLEXIO_TimerOutputOneNotAffectedByReset;
179     timerConfig.timerDecrement  = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput;
180     timerConfig.timerReset      = kFLEXIO_TimerResetNever;
181     timerConfig.timerDisable    = kFLEXIO_TimerDisableOnTimerCompare;
182     timerConfig.timerEnable     = kFLEXIO_TimerEnableOnTriggerHigh;
183     timerConfig.timerStop       = kFLEXIO_TimerStopBitEnableOnTimerDisable;
184     timerConfig.timerStart      = kFLEXIO_TimerStartBitEnabled;
185 
186     timerDiv = (uint16_t)(srcClock_Hz / userConfig->baudRate_Bps);
187     timerDiv = timerDiv / 2U - 1U;
188 
189     if (timerDiv > 0xFFU)
190     {
191         result = kStatus_InvalidArgument;
192     }
193 
194     timerCmp = ((uint16_t)userConfig->bitCountPerChar * 2U - 1U) << 8U;
195     timerCmp |= timerDiv;
196 
197     timerConfig.timerCompare = timerCmp;
198 
199     FLEXIO_SetTimerConfig(base->flexioBase, base->timerIndex[0], &timerConfig);
200 
201     /* 3. Configure the shifter 1 for rx. */
202     shifterConfig.timerSelect   = base->timerIndex[1];
203     shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnNegitive;
204     shifterConfig.pinConfig     = kFLEXIO_PinConfigOutputDisabled;
205     shifterConfig.pinSelect     = base->RxPinIndex;
206     shifterConfig.pinPolarity   = kFLEXIO_PinActiveHigh;
207     shifterConfig.shifterMode   = kFLEXIO_ShifterModeReceive;
208     shifterConfig.inputSource   = kFLEXIO_ShifterInputFromPin;
209     shifterConfig.shifterStop   = kFLEXIO_ShifterStopBitHigh;
210     shifterConfig.shifterStart  = kFLEXIO_ShifterStartBitLow;
211 
212     FLEXIO_SetShifterConfig(base->flexioBase, base->shifterIndex[1], &shifterConfig);
213 
214     /* 4. Configure the timer 1 for rx. */
215     timerConfig.triggerSelect   = FLEXIO_TIMER_TRIGGER_SEL_PININPUT(base->RxPinIndex);
216     timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveHigh;
217     timerConfig.triggerSource   = kFLEXIO_TimerTriggerSourceExternal;
218     timerConfig.pinConfig       = kFLEXIO_PinConfigOutputDisabled;
219     timerConfig.pinSelect       = base->RxPinIndex;
220     timerConfig.pinPolarity     = kFLEXIO_PinActiveLow;
221     timerConfig.timerMode       = kFLEXIO_TimerModeDual8BitBaudBit;
222     timerConfig.timerOutput     = kFLEXIO_TimerOutputOneAffectedByReset;
223     timerConfig.timerDecrement  = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput;
224     timerConfig.timerReset      = kFLEXIO_TimerResetOnTimerPinRisingEdge;
225     timerConfig.timerDisable    = kFLEXIO_TimerDisableOnTimerCompare;
226     timerConfig.timerEnable     = kFLEXIO_TimerEnableOnPinRisingEdge;
227     timerConfig.timerStop       = kFLEXIO_TimerStopBitEnableOnTimerDisable;
228     timerConfig.timerStart      = kFLEXIO_TimerStartBitEnabled;
229 
230     timerConfig.timerCompare = timerCmp;
231 
232     FLEXIO_SetTimerConfig(base->flexioBase, base->timerIndex[1], &timerConfig);
233 
234     return result;
235 }
236 
237 /*!
238  * brief Resets the FlexIO UART shifter and timer config.
239  *
240  * note After calling this API, call the FLEXO_UART_Init to use the FlexIO UART module.
241  *
242  * param base Pointer to FLEXIO_UART_Type structure
243  */
FLEXIO_UART_Deinit(FLEXIO_UART_Type * base)244 void FLEXIO_UART_Deinit(FLEXIO_UART_Type *base)
245 {
246     base->flexioBase->SHIFTCFG[base->shifterIndex[0]] = 0;
247     base->flexioBase->SHIFTCTL[base->shifterIndex[0]] = 0;
248     base->flexioBase->SHIFTCFG[base->shifterIndex[1]] = 0;
249     base->flexioBase->SHIFTCTL[base->shifterIndex[1]] = 0;
250     base->flexioBase->TIMCFG[base->timerIndex[0]]     = 0;
251     base->flexioBase->TIMCMP[base->timerIndex[0]]     = 0;
252     base->flexioBase->TIMCTL[base->timerIndex[0]]     = 0;
253     base->flexioBase->TIMCFG[base->timerIndex[1]]     = 0;
254     base->flexioBase->TIMCMP[base->timerIndex[1]]     = 0;
255     base->flexioBase->TIMCTL[base->timerIndex[1]]     = 0;
256     /* Clear the shifter flag. */
257     base->flexioBase->SHIFTSTAT = (1UL << base->shifterIndex[0]);
258     base->flexioBase->SHIFTSTAT = (1UL << base->shifterIndex[1]);
259     /* Clear the timer flag. */
260     base->flexioBase->TIMSTAT = (1UL << base->timerIndex[0]);
261     base->flexioBase->TIMSTAT = (1UL << base->timerIndex[1]);
262 }
263 
264 /*!
265  * brief Gets the default configuration to configure the FlexIO UART. The configuration
266  * can be used directly for calling the FLEXIO_UART_Init().
267  * Example:
268    code
269    flexio_uart_config_t config;
270    FLEXIO_UART_GetDefaultConfig(&userConfig);
271    endcode
272  * param userConfig Pointer to the flexio_uart_config_t structure.
273 */
FLEXIO_UART_GetDefaultConfig(flexio_uart_config_t * userConfig)274 void FLEXIO_UART_GetDefaultConfig(flexio_uart_config_t *userConfig)
275 {
276     assert(userConfig != NULL);
277 
278     /* Initializes the configure structure to zero. */
279     (void)memset(userConfig, 0, sizeof(*userConfig));
280 
281     userConfig->enableUart       = true;
282     userConfig->enableInDoze     = false;
283     userConfig->enableInDebug    = true;
284     userConfig->enableFastAccess = false;
285     /* Default baud rate 115200. */
286     userConfig->baudRate_Bps = 115200U;
287     /* Default bit count at 8. */
288     userConfig->bitCountPerChar = kFLEXIO_UART_8BitsPerChar;
289 }
290 
291 /*!
292  * brief Enables the FlexIO UART interrupt.
293  *
294  * This function enables the FlexIO UART interrupt.
295  *
296  * param base Pointer to the FLEXIO_UART_Type structure.
297  * param mask Interrupt source.
298  */
FLEXIO_UART_EnableInterrupts(FLEXIO_UART_Type * base,uint32_t mask)299 void FLEXIO_UART_EnableInterrupts(FLEXIO_UART_Type *base, uint32_t mask)
300 {
301     if ((mask & (uint32_t)kFLEXIO_UART_TxDataRegEmptyInterruptEnable) != 0U)
302     {
303         FLEXIO_EnableShifterStatusInterrupts(base->flexioBase, 1UL << base->shifterIndex[0]);
304     }
305     if ((mask & (uint32_t)kFLEXIO_UART_RxDataRegFullInterruptEnable) != 0U)
306     {
307         FLEXIO_EnableShifterStatusInterrupts(base->flexioBase, 1UL << base->shifterIndex[1]);
308     }
309 }
310 
311 /*!
312  * brief Disables the FlexIO UART interrupt.
313  *
314  * This function disables the FlexIO UART interrupt.
315  *
316  * param base Pointer to the FLEXIO_UART_Type structure.
317  * param mask Interrupt source.
318  */
FLEXIO_UART_DisableInterrupts(FLEXIO_UART_Type * base,uint32_t mask)319 void FLEXIO_UART_DisableInterrupts(FLEXIO_UART_Type *base, uint32_t mask)
320 {
321     if ((mask & (uint32_t)kFLEXIO_UART_TxDataRegEmptyInterruptEnable) != 0U)
322     {
323         FLEXIO_DisableShifterStatusInterrupts(base->flexioBase, 1UL << base->shifterIndex[0]);
324     }
325     if ((mask & (uint32_t)kFLEXIO_UART_RxDataRegFullInterruptEnable) != 0U)
326     {
327         FLEXIO_DisableShifterStatusInterrupts(base->flexioBase, 1UL << base->shifterIndex[1]);
328     }
329 }
330 
331 /*!
332  * brief Gets the FlexIO UART status flags.
333  *
334  * param base Pointer to the FLEXIO_UART_Type structure.
335  * return FlexIO UART status flags.
336  */
337 
FLEXIO_UART_GetStatusFlags(FLEXIO_UART_Type * base)338 uint32_t FLEXIO_UART_GetStatusFlags(FLEXIO_UART_Type *base)
339 {
340     uint32_t status = 0U;
341     status =
342         ((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[0])) >> base->shifterIndex[0]);
343     status |=
344         (((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[1])) >> (base->shifterIndex[1]))
345          << 1U);
346     status |=
347         (((FLEXIO_GetShifterErrorFlags(base->flexioBase) & (1UL << base->shifterIndex[1])) >> (base->shifterIndex[1]))
348          << 2U);
349     return status;
350 }
351 
352 /*!
353  * brief Gets the FlexIO UART status flags.
354  *
355  * param base Pointer to the FLEXIO_UART_Type structure.
356  * param mask Status flag.
357  *      The parameter can be any combination of the following values:
358  *          arg kFLEXIO_UART_TxDataRegEmptyFlag
359  *          arg kFLEXIO_UART_RxEmptyFlag
360  *          arg kFLEXIO_UART_RxOverRunFlag
361  */
362 
FLEXIO_UART_ClearStatusFlags(FLEXIO_UART_Type * base,uint32_t mask)363 void FLEXIO_UART_ClearStatusFlags(FLEXIO_UART_Type *base, uint32_t mask)
364 {
365     if ((mask & (uint32_t)kFLEXIO_UART_TxDataRegEmptyFlag) != 0U)
366     {
367         FLEXIO_ClearShifterStatusFlags(base->flexioBase, 1UL << base->shifterIndex[0]);
368     }
369     if ((mask & (uint32_t)kFLEXIO_UART_RxDataRegFullFlag) != 0U)
370     {
371         FLEXIO_ClearShifterStatusFlags(base->flexioBase, 1UL << base->shifterIndex[1]);
372     }
373     if ((mask & (uint32_t)kFLEXIO_UART_RxOverRunFlag) != 0U)
374     {
375         FLEXIO_ClearShifterErrorFlags(base->flexioBase, 1UL << base->shifterIndex[1]);
376     }
377 }
378 
379 /*!
380  * brief Sends a buffer of data bytes.
381  *
382  * note This function blocks using the polling method until all bytes have been sent.
383  *
384  * param base Pointer to the FLEXIO_UART_Type structure.
385  * param txData The data bytes to send.
386  * param txSize The number of data bytes to send.
387  * retval kStatus_FLEXIO_UART_Timeout Transmission timed out and was aborted.
388  * retval kStatus_Success Successfully wrote all data.
389  */
FLEXIO_UART_WriteBlocking(FLEXIO_UART_Type * base,const uint8_t * txData,size_t txSize)390 status_t FLEXIO_UART_WriteBlocking(FLEXIO_UART_Type *base, const uint8_t *txData, size_t txSize)
391 {
392     assert(txData != NULL);
393     assert(txSize != 0U);
394 #if UART_RETRY_TIMES
395     uint32_t waitTimes;
396 #endif
397 
398     while (0U != txSize--)
399     {
400         /* Wait until data transfer complete. */
401 #if UART_RETRY_TIMES
402         waitTimes = UART_RETRY_TIMES;
403         while ((0U == (FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[0]))) &&
404                (0U != --waitTimes))
405 #else
406         while (0U == (FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[0])))
407 #endif
408         {
409         }
410 #if UART_RETRY_TIMES
411         if (0U == waitTimes)
412         {
413             return kStatus_FLEXIO_UART_Timeout;
414         }
415 #endif
416 
417         base->flexioBase->SHIFTBUF[base->shifterIndex[0]] = *txData++;
418     }
419     return kStatus_Success;
420 }
421 
422 /*!
423  * brief Receives a buffer of bytes.
424  *
425  * note This function blocks using the polling method until all bytes have been received.
426  *
427  * param base Pointer to the FLEXIO_UART_Type structure.
428  * param rxData The buffer to store the received bytes.
429  * param rxSize The number of data bytes to be received.
430  * retval kStatus_FLEXIO_UART_Timeout Transmission timed out and was aborted.
431  * retval kStatus_Success Successfully received all data.
432  */
FLEXIO_UART_ReadBlocking(FLEXIO_UART_Type * base,uint8_t * rxData,size_t rxSize)433 status_t FLEXIO_UART_ReadBlocking(FLEXIO_UART_Type *base, uint8_t *rxData, size_t rxSize)
434 {
435     assert(rxData != NULL);
436     assert(rxSize != 0U);
437 #if UART_RETRY_TIMES
438     uint32_t waitTimes;
439 #endif
440 
441     while (0U != rxSize--)
442     {
443         /* Wait until data transfer complete. */
444 #if UART_RETRY_TIMES
445         waitTimes = UART_RETRY_TIMES;
446         while ((0U == (FLEXIO_UART_GetStatusFlags(base) & (uint32_t)kFLEXIO_UART_RxDataRegFullFlag)) &&
447                (0U != --waitTimes))
448 #else
449         while (0U == (FLEXIO_UART_GetStatusFlags(base) & (uint32_t)kFLEXIO_UART_RxDataRegFullFlag))
450 #endif
451         {
452         }
453 #if UART_RETRY_TIMES
454         if (0U == waitTimes)
455         {
456             return kStatus_FLEXIO_UART_Timeout;
457         }
458 #endif
459 
460         *rxData++ = (uint8_t)(base->flexioBase->SHIFTBUFBYS[base->shifterIndex[1]]);
461     }
462     return kStatus_Success;
463 }
464 
465 /*!
466  * brief Initializes the UART handle.
467  *
468  * This function initializes the FlexIO UART handle, which can be used for other FlexIO
469  * UART transactional APIs. Call this API once to get the
470  * initialized handle.
471  *
472  * The UART driver supports the "background" receiving, which means that users can set up
473  * a RX ring buffer optionally. Data received is stored into the ring buffer even when
474  * the user doesn't call the FLEXIO_UART_TransferReceiveNonBlocking() API. If there is already data
475  * received in the ring buffer, users can get the received data from the ring buffer
476  * directly. The ring buffer is disabled if passing NULL as p ringBuffer.
477  *
478  * param base to FLEXIO_UART_Type structure.
479  * param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
480  * param callback The callback function.
481  * param userData The parameter of the callback function.
482  * retval kStatus_Success Successfully create the handle.
483  * retval kStatus_OutOfRange The FlexIO type/handle/ISR table out of range.
484  */
FLEXIO_UART_TransferCreateHandle(FLEXIO_UART_Type * base,flexio_uart_handle_t * handle,flexio_uart_transfer_callback_t callback,void * userData)485 status_t FLEXIO_UART_TransferCreateHandle(FLEXIO_UART_Type *base,
486                                           flexio_uart_handle_t *handle,
487                                           flexio_uart_transfer_callback_t callback,
488                                           void *userData)
489 {
490     assert(handle != NULL);
491 
492     IRQn_Type flexio_irqs[] = FLEXIO_IRQS;
493 
494     /* Zero the handle. */
495     (void)memset(handle, 0, sizeof(*handle));
496 
497     /* Set the TX/RX state. */
498     handle->rxState = (uint8_t)kFLEXIO_UART_RxIdle;
499     handle->txState = (uint8_t)kFLEXIO_UART_TxIdle;
500 
501     /* Set the callback and user data. */
502     handle->callback = callback;
503     handle->userData = userData;
504 
505     /* Enable interrupt in NVIC. */
506     (void)EnableIRQ(flexio_irqs[FLEXIO_UART_GetInstance(base)]);
507 
508     /* Save the context in global variables to support the double weak mechanism. */
509     return FLEXIO_RegisterHandleIRQ(base, handle, FLEXIO_UART_TransferHandleIRQ);
510 }
511 
512 /*!
513  * brief Sets up the RX ring buffer.
514  *
515  * This function sets up the RX ring buffer to a specific UART handle.
516  *
517  * When the RX ring buffer is used, data received is stored into the ring buffer even when
518  * the user doesn't call the UART_ReceiveNonBlocking() API. If there is already data received
519  * in the ring buffer, users can get the received data from the ring buffer directly.
520  *
521  * note When using the RX ring buffer, one byte is reserved for internal use. In other
522  * words, if p ringBufferSize is 32, only 31 bytes are used for saving data.
523  *
524  * param base Pointer to the FLEXIO_UART_Type structure.
525  * param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
526  * param ringBuffer Start address of ring buffer for background receiving. Pass NULL to disable the ring buffer.
527  * param ringBufferSize Size of the ring buffer.
528  */
FLEXIO_UART_TransferStartRingBuffer(FLEXIO_UART_Type * base,flexio_uart_handle_t * handle,uint8_t * ringBuffer,size_t ringBufferSize)529 void FLEXIO_UART_TransferStartRingBuffer(FLEXIO_UART_Type *base,
530                                          flexio_uart_handle_t *handle,
531                                          uint8_t *ringBuffer,
532                                          size_t ringBufferSize)
533 {
534     assert(handle != NULL);
535 
536     /* Setup the ringbuffer address */
537     if (ringBuffer != NULL)
538     {
539         handle->rxRingBuffer     = ringBuffer;
540         handle->rxRingBufferSize = ringBufferSize;
541         handle->rxRingBufferHead = 0U;
542         handle->rxRingBufferTail = 0U;
543 
544         /* Enable the interrupt to accept the data when user need the ring buffer. */
545         FLEXIO_UART_EnableInterrupts(base, (uint32_t)kFLEXIO_UART_RxDataRegFullInterruptEnable);
546     }
547 }
548 
549 /*!
550  * brief Aborts the background transfer and uninstalls the ring buffer.
551  *
552  * This function aborts the background transfer and uninstalls the ring buffer.
553  *
554  * param base Pointer to the FLEXIO_UART_Type structure.
555  * param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
556  */
FLEXIO_UART_TransferStopRingBuffer(FLEXIO_UART_Type * base,flexio_uart_handle_t * handle)557 void FLEXIO_UART_TransferStopRingBuffer(FLEXIO_UART_Type *base, flexio_uart_handle_t *handle)
558 {
559     assert(handle != NULL);
560 
561     if (handle->rxState == (uint8_t)kFLEXIO_UART_RxIdle)
562     {
563         FLEXIO_UART_DisableInterrupts(base, (uint32_t)kFLEXIO_UART_RxDataRegFullInterruptEnable);
564     }
565 
566     handle->rxRingBuffer     = NULL;
567     handle->rxRingBufferSize = 0U;
568     handle->rxRingBufferHead = 0U;
569     handle->rxRingBufferTail = 0U;
570 }
571 
572 /*!
573  * brief Transmits a buffer of data using the interrupt method.
574  *
575  * This function sends data using an interrupt method. This is a non-blocking function,
576  * which returns directly without waiting for all data to be written to the TX register. When
577  * all data is written to the TX register in ISR, the FlexIO UART driver calls the callback
578  * function and passes the ref kStatus_FLEXIO_UART_TxIdle as status parameter.
579  *
580  * note The kStatus_FLEXIO_UART_TxIdle is passed to the upper layer when all data is written
581  * to the TX register. However, it does not ensure that all data is sent out.
582  *
583  * param base Pointer to the FLEXIO_UART_Type structure.
584  * param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
585  * param xfer FlexIO UART transfer structure. See #flexio_uart_transfer_t.
586  * retval kStatus_Success Successfully starts the data transmission.
587  * retval kStatus_UART_TxBusy Previous transmission still not finished, data not written to the TX register.
588  */
FLEXIO_UART_TransferSendNonBlocking(FLEXIO_UART_Type * base,flexio_uart_handle_t * handle,flexio_uart_transfer_t * xfer)589 status_t FLEXIO_UART_TransferSendNonBlocking(FLEXIO_UART_Type *base,
590                                              flexio_uart_handle_t *handle,
591                                              flexio_uart_transfer_t *xfer)
592 {
593     status_t status;
594 
595     /* Return error if xfer invalid. */
596     if ((0U == xfer->dataSize) || (NULL == xfer->data))
597     {
598         return kStatus_InvalidArgument;
599     }
600 
601     /* Return error if current TX busy. */
602     if ((uint8_t)kFLEXIO_UART_TxBusy == handle->txState)
603     {
604         status = kStatus_FLEXIO_UART_TxBusy;
605     }
606     else
607     {
608         handle->txData        = xfer->data;
609         handle->txDataSize    = xfer->dataSize;
610         handle->txDataSizeAll = xfer->dataSize;
611         handle->txState       = (uint8_t)kFLEXIO_UART_TxBusy;
612 
613         /* Enable transmiter interrupt. */
614         FLEXIO_UART_EnableInterrupts(base, (uint32_t)kFLEXIO_UART_TxDataRegEmptyInterruptEnable);
615 
616         status = kStatus_Success;
617     }
618 
619     return status;
620 }
621 
622 /*!
623  * brief Aborts the interrupt-driven data transmit.
624  *
625  * This function aborts the interrupt-driven data sending. Get the remainBytes to find out
626  * how many bytes are still not sent out.
627  *
628  * param base Pointer to the FLEXIO_UART_Type structure.
629  * param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
630  */
FLEXIO_UART_TransferAbortSend(FLEXIO_UART_Type * base,flexio_uart_handle_t * handle)631 void FLEXIO_UART_TransferAbortSend(FLEXIO_UART_Type *base, flexio_uart_handle_t *handle)
632 {
633     /* Disable the transmitter and disable the interrupt. */
634     FLEXIO_UART_DisableInterrupts(base, (uint32_t)kFLEXIO_UART_TxDataRegEmptyInterruptEnable);
635 
636     handle->txDataSize = 0U;
637     handle->txState    = (uint8_t)kFLEXIO_UART_TxIdle;
638 }
639 
640 /*!
641  * brief Gets the number of bytes sent.
642  *
643  * This function gets the number of bytes sent driven by interrupt.
644  *
645  * param base Pointer to the FLEXIO_UART_Type structure.
646  * param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
647  * param count Number of bytes sent so far by the non-blocking transaction.
648  * retval kStatus_NoTransferInProgress transfer has finished or no transfer in progress.
649  * retval kStatus_Success Successfully return the count.
650  */
FLEXIO_UART_TransferGetSendCount(FLEXIO_UART_Type * base,flexio_uart_handle_t * handle,size_t * count)651 status_t FLEXIO_UART_TransferGetSendCount(FLEXIO_UART_Type *base, flexio_uart_handle_t *handle, size_t *count)
652 {
653     assert(handle != NULL);
654     assert(count != NULL);
655 
656     if ((uint8_t)kFLEXIO_UART_TxIdle == handle->txState)
657     {
658         return kStatus_NoTransferInProgress;
659     }
660 
661     *count = handle->txDataSizeAll - handle->txDataSize;
662 
663     return kStatus_Success;
664 }
665 
666 /*!
667  * brief Receives a buffer of data using the interrupt method.
668  *
669  * This function receives data using the interrupt method. This is a non-blocking function,
670  * which returns without waiting for all data to be received.
671  * If the RX ring buffer is used and not empty, the data in ring buffer is copied and
672  * the parameter p receivedBytes shows how many bytes are copied from the ring buffer.
673  * After copying, if the data in ring buffer is not enough to read, the receive
674  * request is saved by the UART driver. When new data arrives, the receive request
675  * is serviced first. When all data is received, the UART driver notifies the upper layer
676  * through a callback function and passes the status parameter ref kStatus_UART_RxIdle.
677  * For example, if the upper layer needs 10 bytes but there are only 5 bytes in the ring buffer,
678  * the 5 bytes are copied to xfer->data. This function returns with the
679  * parameter p receivedBytes set to 5. For the last 5 bytes, newly arrived data is
680  * saved from the xfer->data[5]. When 5 bytes are received, the UART driver notifies upper layer.
681  * If the RX ring buffer is not enabled, this function enables the RX and RX interrupt
682  * to receive data to xfer->data. When all data is received, the upper layer is notified.
683  *
684  * param base Pointer to the FLEXIO_UART_Type structure.
685  * param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
686  * param xfer UART transfer structure. See #flexio_uart_transfer_t.
687  * param receivedBytes Bytes received from the ring buffer directly.
688  * retval kStatus_Success Successfully queue the transfer into the transmit queue.
689  * retval kStatus_FLEXIO_UART_RxBusy Previous receive request is not finished.
690  */
FLEXIO_UART_TransferReceiveNonBlocking(FLEXIO_UART_Type * base,flexio_uart_handle_t * handle,flexio_uart_transfer_t * xfer,size_t * receivedBytes)691 status_t FLEXIO_UART_TransferReceiveNonBlocking(FLEXIO_UART_Type *base,
692                                                 flexio_uart_handle_t *handle,
693                                                 flexio_uart_transfer_t *xfer,
694                                                 size_t *receivedBytes)
695 {
696     uint32_t i;
697     status_t status;
698     /* How many bytes to copy from ring buffer to user memory. */
699     size_t bytesToCopy = 0U;
700     /* How many bytes to receive. */
701     size_t bytesToReceive;
702     /* How many bytes currently have received. */
703     size_t bytesCurrentReceived;
704 
705     /* Return error if xfer invalid. */
706     if ((0U == xfer->dataSize) || (NULL == xfer->data))
707     {
708         return kStatus_InvalidArgument;
709     }
710 
711     /* How to get data:
712        1. If RX ring buffer is not enabled, then save xfer->data and xfer->dataSize
713           to uart handle, enable interrupt to store received data to xfer->data. When
714           all data received, trigger callback.
715        2. If RX ring buffer is enabled and not empty, get data from ring buffer first.
716           If there are enough data in ring buffer, copy them to xfer->data and return.
717           If there are not enough data in ring buffer, copy all of them to xfer->data,
718           save the xfer->data remained empty space to uart handle, receive data
719           to this empty space and trigger callback when finished. */
720 
721     if ((uint8_t)kFLEXIO_UART_RxBusy == handle->rxState)
722     {
723         status = kStatus_FLEXIO_UART_RxBusy;
724     }
725     else
726     {
727         bytesToReceive       = xfer->dataSize;
728         bytesCurrentReceived = 0U;
729 
730         /* If RX ring buffer is used. */
731         if (handle->rxRingBuffer != NULL)
732         {
733             /* Disable FLEXIO_UART RX IRQ, protect ring buffer. */
734             FLEXIO_UART_DisableInterrupts(base, (uint32_t)kFLEXIO_UART_RxDataRegFullInterruptEnable);
735 
736             /* How many bytes in RX ring buffer currently. */
737             bytesToCopy = FLEXIO_UART_TransferGetRxRingBufferLength(handle);
738 
739             if (bytesToCopy != 0U)
740             {
741                 bytesToCopy = MIN(bytesToReceive, bytesToCopy);
742 
743                 bytesToReceive -= bytesToCopy;
744 
745                 /* Copy data from ring buffer to user memory. */
746                 for (i = 0U; i < bytesToCopy; i++)
747                 {
748                     xfer->data[bytesCurrentReceived++] = handle->rxRingBuffer[handle->rxRingBufferTail];
749 
750                     /* Wrap to 0. Not use modulo (%) because it might be large and slow. */
751                     if ((uint32_t)handle->rxRingBufferTail + 1U == handle->rxRingBufferSize)
752                     {
753                         handle->rxRingBufferTail = 0U;
754                     }
755                     else
756                     {
757                         handle->rxRingBufferTail++;
758                     }
759                 }
760             }
761 
762             /* If ring buffer does not have enough data, still need to read more data. */
763             if (bytesToReceive != 0U)
764             {
765                 /* No data in ring buffer, save the request to UART handle. */
766                 handle->rxData        = xfer->data + bytesCurrentReceived;
767                 handle->rxDataSize    = bytesToReceive;
768                 handle->rxDataSizeAll = bytesToReceive;
769                 handle->rxState       = (uint8_t)kFLEXIO_UART_RxBusy;
770             }
771 
772             /* Enable FLEXIO_UART RX IRQ if previously enabled. */
773             FLEXIO_UART_EnableInterrupts(base, (uint32_t)kFLEXIO_UART_RxDataRegFullInterruptEnable);
774 
775             /* Call user callback since all data are received. */
776             if (0U == bytesToReceive)
777             {
778                 if (handle->callback != NULL)
779                 {
780                     handle->callback(base, handle, kStatus_FLEXIO_UART_RxIdle, handle->userData);
781                 }
782             }
783         }
784         /* Ring buffer not used. */
785         else
786         {
787             handle->rxData        = xfer->data + bytesCurrentReceived;
788             handle->rxDataSize    = bytesToReceive;
789             handle->rxDataSizeAll = bytesToReceive;
790             handle->rxState       = (uint8_t)kFLEXIO_UART_RxBusy;
791 
792             /* Enable RX interrupt. */
793             FLEXIO_UART_EnableInterrupts(base, (uint32_t)kFLEXIO_UART_RxDataRegFullInterruptEnable);
794         }
795 
796         /* Return the how many bytes have read. */
797         if (receivedBytes != NULL)
798         {
799             *receivedBytes = bytesCurrentReceived;
800         }
801 
802         status = kStatus_Success;
803     }
804 
805     return status;
806 }
807 
808 /*!
809  * brief Aborts the receive data which was using IRQ.
810  *
811  * This function aborts the receive data which was using IRQ.
812  *
813  * param base Pointer to the FLEXIO_UART_Type structure.
814  * param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
815  */
FLEXIO_UART_TransferAbortReceive(FLEXIO_UART_Type * base,flexio_uart_handle_t * handle)816 void FLEXIO_UART_TransferAbortReceive(FLEXIO_UART_Type *base, flexio_uart_handle_t *handle)
817 {
818     /* Only abort the receive to handle->rxData, the RX ring buffer is still working. */
819     if (NULL == handle->rxRingBuffer)
820     {
821         /* Disable RX interrupt. */
822         FLEXIO_UART_DisableInterrupts(base, (uint32_t)kFLEXIO_UART_RxDataRegFullInterruptEnable);
823     }
824 
825     handle->rxDataSize = 0U;
826     handle->rxState    = (uint8_t)kFLEXIO_UART_RxIdle;
827 }
828 
829 /*!
830  * brief Gets the number of bytes received.
831  *
832  * This function gets the number of bytes received driven by interrupt.
833  *
834  * param base Pointer to the FLEXIO_UART_Type structure.
835  * param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
836  * param count Number of bytes received so far by the non-blocking transaction.
837  * retval kStatus_NoTransferInProgress transfer has finished or no transfer in progress.
838  * retval kStatus_Success Successfully return the count.
839  */
FLEXIO_UART_TransferGetReceiveCount(FLEXIO_UART_Type * base,flexio_uart_handle_t * handle,size_t * count)840 status_t FLEXIO_UART_TransferGetReceiveCount(FLEXIO_UART_Type *base, flexio_uart_handle_t *handle, size_t *count)
841 {
842     assert(handle != NULL);
843     assert(count != NULL);
844 
845     if ((uint8_t)kFLEXIO_UART_RxIdle == handle->rxState)
846     {
847         return kStatus_NoTransferInProgress;
848     }
849 
850     *count = handle->rxDataSizeAll - handle->rxDataSize;
851 
852     return kStatus_Success;
853 }
854 
855 /*!
856  * brief FlexIO UART IRQ handler function.
857  *
858  * This function processes the FlexIO UART transmit and receives the IRQ request.
859  *
860  * param uartType Pointer to the FLEXIO_UART_Type structure.
861  * param uartHandle Pointer to the flexio_uart_handle_t structure to store the transfer state.
862  */
FLEXIO_UART_TransferHandleIRQ(void * uartType,void * uartHandle)863 void FLEXIO_UART_TransferHandleIRQ(void *uartType, void *uartHandle)
864 {
865     uint8_t count                = 1;
866     FLEXIO_UART_Type *base       = (FLEXIO_UART_Type *)uartType;
867     flexio_uart_handle_t *handle = (flexio_uart_handle_t *)uartHandle;
868     uint16_t rxRingBufferHead;
869 
870     /* Read the status back. */
871     uint32_t status = FLEXIO_UART_GetStatusFlags(base);
872 
873     /* If RX overrun. */
874     if (((uint32_t)kFLEXIO_UART_RxOverRunFlag & status) != 0U)
875     {
876         /* Clear Overrun flag. */
877         FLEXIO_UART_ClearStatusFlags(base, (uint32_t)kFLEXIO_UART_RxOverRunFlag);
878 
879         /* Trigger callback. */
880         if (handle->callback != NULL)
881         {
882             handle->callback(base, handle, kStatus_FLEXIO_UART_RxHardwareOverrun, handle->userData);
883         }
884     }
885 
886     /* Receive data register full */
887     if ((((uint32_t)kFLEXIO_UART_RxDataRegFullFlag & status) != 0U) &&
888         ((base->flexioBase->SHIFTSIEN & (1UL << base->shifterIndex[1])) != 0U))
889     {
890         /* If handle->rxDataSize is not 0, first save data to handle->rxData. */
891         if (handle->rxDataSize != 0U)
892         {
893             /* Using non block API to read the data from the registers. */
894             FLEXIO_UART_ReadByte(base, handle->rxData);
895             handle->rxDataSize--;
896             handle->rxData++;
897             count--;
898 
899             /* If all the data required for upper layer is ready, trigger callback. */
900             if (0U == handle->rxDataSize)
901             {
902                 handle->rxState = (uint8_t)kFLEXIO_UART_RxIdle;
903 
904                 if (handle->callback != NULL)
905                 {
906                     handle->callback(base, handle, kStatus_FLEXIO_UART_RxIdle, handle->userData);
907                 }
908             }
909         }
910 
911         if (handle->rxRingBuffer != NULL)
912         {
913             if (count != 0U)
914             {
915                 /* If RX ring buffer is full, trigger callback to notify over run. */
916                 if (FLEXIO_UART_TransferIsRxRingBufferFull(handle))
917                 {
918                     if (handle->callback != NULL)
919                     {
920                         handle->callback(base, handle, kStatus_FLEXIO_UART_RxRingBufferOverrun, handle->userData);
921                     }
922                 }
923 
924                 /* If ring buffer is still full after callback function, the oldest data is overridden. */
925                 if (FLEXIO_UART_TransferIsRxRingBufferFull(handle))
926                 {
927                     /* Increase handle->rxRingBufferTail to make room for new data. */
928                     if ((uint32_t)handle->rxRingBufferTail + 1U == handle->rxRingBufferSize)
929                     {
930                         handle->rxRingBufferTail = 0U;
931                     }
932                     else
933                     {
934                         handle->rxRingBufferTail++;
935                     }
936                 }
937 
938                 /* Read data. */
939                 rxRingBufferHead = handle->rxRingBufferHead;
940                 handle->rxRingBuffer[rxRingBufferHead] =
941                     (uint8_t)(base->flexioBase->SHIFTBUFBYS[base->shifterIndex[1]]);
942 
943                 /* Increase handle->rxRingBufferHead. */
944                 if ((uint32_t)handle->rxRingBufferHead + 1U == handle->rxRingBufferSize)
945                 {
946                     handle->rxRingBufferHead = 0U;
947                 }
948                 else
949                 {
950                     handle->rxRingBufferHead++;
951                 }
952             }
953         }
954         /* If no receive requst pending, stop RX interrupt. */
955         else if (0U == handle->rxDataSize)
956         {
957             FLEXIO_UART_DisableInterrupts(base, (uint32_t)kFLEXIO_UART_RxDataRegFullInterruptEnable);
958         }
959         else
960         {
961         }
962     }
963 
964     /* Send data register empty and the interrupt is enabled. */
965     if ((((uint32_t)kFLEXIO_UART_TxDataRegEmptyFlag & status) != 0U) &&
966         ((base->flexioBase->SHIFTSIEN & (1UL << base->shifterIndex[0])) != 0U))
967     {
968         if (handle->txDataSize != 0U)
969         {
970             /* Using non block API to write the data to the registers. */
971             FLEXIO_UART_WriteByte(base, handle->txData);
972             handle->txData++;
973             handle->txDataSize--;
974 
975             /* If all the data are written to data register, TX finished. */
976             if (0U == handle->txDataSize)
977             {
978                 handle->txState = (uint8_t)kFLEXIO_UART_TxIdle;
979 
980                 /* Disable TX register empty interrupt. */
981                 FLEXIO_UART_DisableInterrupts(base, (uint32_t)kFLEXIO_UART_TxDataRegEmptyInterruptEnable);
982 
983                 /* Trigger callback. */
984                 if (handle->callback != NULL)
985                 {
986                     handle->callback(base, handle, kStatus_FLEXIO_UART_TxIdle, handle->userData);
987                 }
988             }
989         }
990     }
991 }
992