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