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