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