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 | |
54 | static uint32_t FLEXIO_UART_GetInstance(FLEXIO_UART_Type *base) |
55 | { |
56 | return FLEXIO_GetInstance(base->flexioBase); |
57 | } |
58 | |
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 | |
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 | */ |
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 | */ |
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 | */ |
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 | */ |
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 | */ |
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 | |
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 | |
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 | */ |
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 | */ |
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 | */ |
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 | */ |
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 | */ |
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 | */ |
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 | */ |
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 | */ |
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 | */ |
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 | */ |
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 | */ |
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 | */ |
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 | |