1 /*
2 * Copyright (c) 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_usart.h"
10 #include "fsl_device_registers.h"
11 #include "fsl_flexcomm.h"
12
13 /*******************************************************************************
14 * Definitions
15 ******************************************************************************/
16
17 /* Component ID definition, used by tools. */
18 #ifndef FSL_COMPONENT_ID
19 #define FSL_COMPONENT_ID "platform.drivers.flexcomm_usart"
20 #endif
21
22 /*!
23 * @brief Used for conversion from `flexcomm_usart_irq_handler_t` to `flexcomm_irq_handler_t`
24 */
25 typedef union usart_to_flexcomm
26 {
27 flexcomm_usart_irq_handler_t usart_master_handler;
28 flexcomm_irq_handler_t flexcomm_handler;
29 } usart_to_flexcomm_t;
30
31 enum
32 {
33 kUSART_TxIdle, /* TX idle. */
34 kUSART_TxBusy, /* TX busy. */
35 kUSART_RxIdle, /* RX idle. */
36 kUSART_RxBusy /* RX busy. */
37 };
38
39 /*******************************************************************************
40 * Variables
41 ******************************************************************************/
42
43 /*! @brief IRQ name array */
44 static const IRQn_Type s_usartIRQ[] = USART_IRQS;
45
46 /*! @brief Array to map USART instance number to base address. */
47 static const uint32_t s_usartBaseAddrs[FSL_FEATURE_SOC_USART_COUNT] = USART_BASE_ADDRS;
48
49 /*******************************************************************************
50 * Code
51 ******************************************************************************/
52
53 /* Get the index corresponding to the USART */
54 /*! brief Returns instance number for USART peripheral base address. */
USART_GetInstance(USART_Type * base)55 uint32_t USART_GetInstance(USART_Type *base)
56 {
57 uint32_t i;
58
59 for (i = 0; i < (uint32_t)FSL_FEATURE_SOC_USART_COUNT; i++)
60 {
61 if ((uint32_t)base == s_usartBaseAddrs[i])
62 {
63 break;
64 }
65 }
66
67 assert(i < (uint32_t)FSL_FEATURE_SOC_USART_COUNT);
68 return i;
69 }
70
71 /*!
72 * brief Get the length of received data in RX ring buffer.
73 *
74 * param handle USART handle pointer.
75 * return Length of received data in RX ring buffer.
76 */
USART_TransferGetRxRingBufferLength(usart_handle_t * handle)77 size_t USART_TransferGetRxRingBufferLength(usart_handle_t *handle)
78 {
79 size_t size;
80
81 /* Check arguments */
82 assert(NULL != handle);
83 uint16_t rxRingBufferHead = handle->rxRingBufferHead;
84 uint16_t rxRingBufferTail = handle->rxRingBufferTail;
85
86 if (rxRingBufferTail > rxRingBufferHead)
87 {
88 size = (size_t)rxRingBufferHead + handle->rxRingBufferSize - (size_t)rxRingBufferTail;
89 }
90 else
91 {
92 size = (size_t)rxRingBufferHead - (size_t)rxRingBufferTail;
93 }
94 return size;
95 }
96
USART_TransferIsRxRingBufferFull(usart_handle_t * handle)97 static bool USART_TransferIsRxRingBufferFull(usart_handle_t *handle)
98 {
99 bool full;
100
101 /* Check arguments */
102 assert(NULL != handle);
103
104 if (USART_TransferGetRxRingBufferLength(handle) == (handle->rxRingBufferSize - 1U))
105 {
106 full = true;
107 }
108 else
109 {
110 full = false;
111 }
112 return full;
113 }
114
115 /*!
116 * brief Sets up the RX ring buffer.
117 *
118 * This function sets up the RX ring buffer to a specific USART handle.
119 *
120 * When the RX ring buffer is used, data received are stored into the ring buffer even when the
121 * user doesn't call the USART_TransferReceiveNonBlocking() API. If there is already data received
122 * in the ring buffer, the user can get the received data from the ring buffer directly.
123 *
124 * note When using the RX ring buffer, one byte is reserved for internal use. In other
125 * words, if p ringBufferSize is 32, then only 31 bytes are used for saving data.
126 *
127 * param base USART peripheral base address.
128 * param handle USART handle pointer.
129 * param ringBuffer Start address of the ring buffer for background receiving. Pass NULL to disable the ring buffer.
130 * param ringBufferSize size of the ring buffer.
131 */
USART_TransferStartRingBuffer(USART_Type * base,usart_handle_t * handle,uint8_t * ringBuffer,size_t ringBufferSize)132 void USART_TransferStartRingBuffer(USART_Type *base, usart_handle_t *handle, uint8_t *ringBuffer, size_t ringBufferSize)
133 {
134 /* Check arguments */
135 assert(NULL != base);
136 assert(NULL != handle);
137 assert(NULL != ringBuffer);
138
139 /* Setup the ringbuffer address */
140 handle->rxRingBuffer = ringBuffer;
141 handle->rxRingBufferSize = ringBufferSize;
142 handle->rxRingBufferHead = 0U;
143 handle->rxRingBufferTail = 0U;
144 /* ring buffer is ready we can start receiving data */
145 base->FIFOINTENSET = USART_FIFOINTENSET_RXLVL_MASK | USART_FIFOINTENSET_RXERR_MASK;
146 }
147
148 /*!
149 * brief Aborts the background transfer and uninstalls the ring buffer.
150 *
151 * This function aborts the background transfer and uninstalls the ring buffer.
152 *
153 * param base USART peripheral base address.
154 * param handle USART handle pointer.
155 */
USART_TransferStopRingBuffer(USART_Type * base,usart_handle_t * handle)156 void USART_TransferStopRingBuffer(USART_Type *base, usart_handle_t *handle)
157 {
158 /* Check arguments */
159 assert(NULL != base);
160 assert(NULL != handle);
161
162 if (handle->rxState == (uint8_t)kUSART_RxIdle)
163 {
164 base->FIFOINTENCLR = USART_FIFOINTENCLR_RXLVL_MASK | USART_FIFOINTENCLR_RXERR_MASK;
165 }
166 handle->rxRingBuffer = NULL;
167 handle->rxRingBufferSize = 0U;
168 handle->rxRingBufferHead = 0U;
169 handle->rxRingBufferTail = 0U;
170 }
171
172 /*!
173 * brief Initializes a USART instance with user configuration structure and peripheral clock.
174 *
175 * This function configures the USART module with the user-defined settings. The user can configure the configuration
176 * structure and also get the default configuration by using the USART_GetDefaultConfig() function.
177 * Example below shows how to use this API to configure USART.
178 * code
179 * usart_config_t usartConfig;
180 * usartConfig.baudRate_Bps = 115200U;
181 * usartConfig.parityMode = kUSART_ParityDisabled;
182 * usartConfig.stopBitCount = kUSART_OneStopBit;
183 * USART_Init(USART1, &usartConfig, 20000000U);
184 * endcode
185 *
186 * param base USART peripheral base address.
187 * param config Pointer to user-defined configuration structure.
188 * param srcClock_Hz USART clock source frequency in HZ.
189 * retval kStatus_USART_BaudrateNotSupport Baudrate is not support in current clock source.
190 * retval kStatus_InvalidArgument USART base address is not valid
191 * retval kStatus_Success Status USART initialize succeed
192 */
USART_Init(USART_Type * base,const usart_config_t * config,uint32_t srcClock_Hz)193 status_t USART_Init(USART_Type *base, const usart_config_t *config, uint32_t srcClock_Hz)
194 {
195 int result;
196
197 /* check arguments */
198 assert(!((NULL == base) || (NULL == config) || (0U == srcClock_Hz)));
199 if ((NULL == base) || (NULL == config) || (0U == srcClock_Hz))
200 {
201 return kStatus_InvalidArgument;
202 }
203
204 /* initialize flexcomm to USART mode */
205 result = FLEXCOMM_Init(base, FLEXCOMM_PERIPH_USART);
206 if (kStatus_Success != result)
207 {
208 return result;
209 }
210
211 if (config->enableTx)
212 {
213 /* empty and enable txFIFO */
214 base->FIFOCFG |= USART_FIFOCFG_EMPTYTX_MASK | USART_FIFOCFG_ENABLETX_MASK;
215 /* setup trigger level */
216 base->FIFOTRIG &= ~(USART_FIFOTRIG_TXLVL_MASK);
217 base->FIFOTRIG |= USART_FIFOTRIG_TXLVL(config->txWatermark);
218 /* enable trigger interrupt */
219 base->FIFOTRIG |= USART_FIFOTRIG_TXLVLENA_MASK;
220 }
221
222 /* empty and enable rxFIFO */
223 if (config->enableRx)
224 {
225 base->FIFOCFG |= USART_FIFOCFG_EMPTYRX_MASK | USART_FIFOCFG_ENABLERX_MASK;
226 /* setup trigger level */
227 base->FIFOTRIG &= ~(USART_FIFOTRIG_RXLVL_MASK);
228 base->FIFOTRIG |= USART_FIFOTRIG_RXLVL(config->rxWatermark);
229 /* enable trigger interrupt */
230 base->FIFOTRIG |= USART_FIFOTRIG_RXLVLENA_MASK;
231 }
232 /* setup configuration and enable USART */
233 base->CFG = USART_CFG_PARITYSEL(config->parityMode) | USART_CFG_STOPLEN(config->stopBitCount) |
234 USART_CFG_DATALEN(config->bitCountPerChar) | USART_CFG_LOOP(config->loopback) |
235 USART_CFG_SYNCEN((uint32_t)config->syncMode >> 1) | USART_CFG_SYNCMST((uint8_t)config->syncMode) |
236 USART_CFG_CLKPOL(config->clockPolarity) | USART_CFG_MODE32K(config->enableMode32k) |
237 USART_CFG_CTSEN(config->enableHardwareFlowControl) | USART_CFG_ENABLE_MASK;
238
239 /* Setup baudrate */
240 if (config->enableMode32k)
241 {
242 if ((9600U % config->baudRate_Bps) == 0U)
243 {
244 base->BRG = 9600U / config->baudRate_Bps;
245 }
246 else
247 {
248 return kStatus_USART_BaudrateNotSupport;
249 }
250 }
251 else
252 {
253 result = USART_SetBaudRate(base, config->baudRate_Bps, srcClock_Hz);
254 if (kStatus_Success != result)
255 {
256 return result;
257 }
258 }
259 /* Setting continuous Clock configuration. used for synchronous mode. */
260 USART_EnableContinuousSCLK(base, config->enableContinuousSCLK);
261
262 return kStatus_Success;
263 }
264
265 /*!
266 * brief Deinitializes a USART instance.
267 *
268 * This function waits for TX complete, disables TX and RX, and disables the USART clock.
269 *
270 * param base USART peripheral base address.
271 */
USART_Deinit(USART_Type * base)272 void USART_Deinit(USART_Type *base)
273 {
274 /* Check arguments */
275 assert(NULL != base);
276 while (0U == (base->STAT & USART_STAT_TXIDLE_MASK))
277 {
278 }
279 /* Disable interrupts, disable dma requests, disable peripheral */
280 base->FIFOINTENCLR = USART_FIFOINTENCLR_TXERR_MASK | USART_FIFOINTENCLR_RXERR_MASK | USART_FIFOINTENCLR_TXLVL_MASK |
281 USART_FIFOINTENCLR_RXLVL_MASK;
282 base->FIFOCFG &= ~(USART_FIFOCFG_DMATX_MASK | USART_FIFOCFG_DMARX_MASK);
283 base->CFG &= ~(USART_CFG_ENABLE_MASK);
284 }
285
286 /*!
287 * brief Gets the default configuration structure.
288 *
289 * This function initializes the USART configuration structure to a default value. The default
290 * values are:
291 * usartConfig->baudRate_Bps = 115200U;
292 * usartConfig->parityMode = kUSART_ParityDisabled;
293 * usartConfig->stopBitCount = kUSART_OneStopBit;
294 * usartConfig->bitCountPerChar = kUSART_8BitsPerChar;
295 * usartConfig->loopback = false;
296 * usartConfig->enableTx = false;
297 * usartConfig->enableRx = false;
298 *
299 * param config Pointer to configuration structure.
300 */
USART_GetDefaultConfig(usart_config_t * config)301 void USART_GetDefaultConfig(usart_config_t *config)
302 {
303 /* Check arguments */
304 assert(NULL != config);
305
306 /* Initializes the configure structure to zero. */
307 (void)memset(config, 0, sizeof(*config));
308
309 /* Set always all members ! */
310 config->baudRate_Bps = 115200U;
311 config->parityMode = kUSART_ParityDisabled;
312 config->stopBitCount = kUSART_OneStopBit;
313 config->bitCountPerChar = kUSART_8BitsPerChar;
314 config->loopback = false;
315 config->enableRx = false;
316 config->enableTx = false;
317 config->enableMode32k = false;
318 config->txWatermark = kUSART_TxFifo0;
319 config->rxWatermark = kUSART_RxFifo1;
320 config->syncMode = kUSART_SyncModeDisabled;
321 config->enableContinuousSCLK = false;
322 config->clockPolarity = kUSART_RxSampleOnFallingEdge;
323 config->enableHardwareFlowControl = false;
324 }
325
326 /*!
327 * brief Sets the USART instance baud rate.
328 *
329 * This function configures the USART module baud rate. This function is used to update
330 * the USART module baud rate after the USART module is initialized by the USART_Init.
331 * code
332 * USART_SetBaudRate(USART1, 115200U, 20000000U);
333 * endcode
334 *
335 * param base USART peripheral base address.
336 * param baudrate_Bps USART baudrate to be set.
337 * param srcClock_Hz USART clock source frequency in HZ.
338 * retval kStatus_USART_BaudrateNotSupport Baudrate is not support in current clock source.
339 * retval kStatus_Success Set baudrate succeed.
340 * retval kStatus_InvalidArgument One or more arguments are invalid.
341 */
USART_SetBaudRate(USART_Type * base,uint32_t baudrate_Bps,uint32_t srcClock_Hz)342 status_t USART_SetBaudRate(USART_Type *base, uint32_t baudrate_Bps, uint32_t srcClock_Hz)
343 {
344 uint32_t best_diff = (uint32_t)-1, best_osrval = 0xf, best_brgval = (uint32_t)-1;
345 uint32_t osrval, brgval, diff, baudrate;
346
347 /* check arguments */
348 assert(!((NULL == base) || (0U == baudrate_Bps) || (0U == srcClock_Hz)));
349 if ((NULL == base) || (0U == baudrate_Bps) || (0U == srcClock_Hz))
350 {
351 return kStatus_InvalidArgument;
352 }
353
354 /* If synchronous master mode is enabled, only configure the BRG value. */
355 if ((base->CFG & USART_CFG_SYNCEN_MASK) != 0U)
356 {
357 if ((base->CFG & USART_CFG_SYNCMST_MASK) != 0U)
358 {
359 brgval = srcClock_Hz / baudrate_Bps;
360 base->BRG = brgval - 1U;
361 }
362 }
363 else
364 {
365 /*
366 * Smaller values of OSR can make the sampling position within a data bit less accurate and may
367 * potentially cause more noise errors or incorrect data.
368 */
369 for (osrval = best_osrval; osrval >= 8U; osrval--)
370 {
371 brgval = (((srcClock_Hz * 10U) / ((osrval + 1U) * baudrate_Bps)) - 5U) / 10U;
372 if (brgval > 0xFFFFU)
373 {
374 continue;
375 }
376 baudrate = srcClock_Hz / ((osrval + 1U) * (brgval + 1U));
377 diff = (baudrate_Bps < baudrate) ? (baudrate - baudrate_Bps) : (baudrate_Bps - baudrate);
378 if (diff < best_diff)
379 {
380 best_diff = diff;
381 best_osrval = osrval;
382 best_brgval = brgval;
383 }
384 }
385
386 /* Check to see if actual baud rate is within 3% of desired baud rate
387 * based on the best calculated OSR and BRG value */
388 baudrate = srcClock_Hz / ((best_osrval + 1U) * (best_brgval + 1U));
389 diff = (baudrate_Bps < baudrate) ? (baudrate - baudrate_Bps) : (baudrate_Bps - baudrate);
390 if (diff > ((baudrate_Bps / 100U) * 3U))
391 {
392 return kStatus_USART_BaudrateNotSupport;
393 }
394
395 /* value over range */
396 if (best_brgval > 0xFFFFU)
397 {
398 return kStatus_USART_BaudrateNotSupport;
399 }
400
401 base->OSR = best_osrval;
402 base->BRG = best_brgval;
403 }
404
405 return kStatus_Success;
406 }
407
408 /*!
409 * brief Enable 32 kHz mode which USART uses clock from the RTC oscillator as the clock source.
410 *
411 * Please note that in order to use a 32 kHz clock to operate USART properly, the RTC oscillator
412 * and its 32 kHz output must be manully enabled by user, by calling RTC_Init and setting
413 * SYSCON_RTCOSCCTRL_EN bit to 1.
414 * And in 32kHz clocking mode the USART can only work at 9600 baudrate or at the baudrate that
415 * 9600 can evenly divide, eg: 4800, 3200.
416 *
417 * param base USART peripheral base address.
418 * param baudRate_Bps USART baudrate to be set..
419 * param enableMode32k true is 32k mode, false is normal mode.
420 * param srcClock_Hz USART clock source frequency in HZ.
421 * retval kStatus_USART_BaudrateNotSupport Baudrate is not support in current clock source.
422 * retval kStatus_Success Set baudrate succeed.
423 * retval kStatus_InvalidArgument One or more arguments are invalid.
424 */
USART_Enable32kMode(USART_Type * base,uint32_t baudRate_Bps,bool enableMode32k,uint32_t srcClock_Hz)425 status_t USART_Enable32kMode(USART_Type *base, uint32_t baudRate_Bps, bool enableMode32k, uint32_t srcClock_Hz)
426 {
427 status_t result = kStatus_Success;
428 base->CFG &= ~(USART_CFG_ENABLE_MASK);
429 if (enableMode32k)
430 {
431 base->CFG |= USART_CFG_MODE32K_MASK;
432 if ((9600U % baudRate_Bps) == 0U)
433 {
434 base->BRG = 9600U / baudRate_Bps - 1U;
435 }
436 else
437 {
438 return kStatus_USART_BaudrateNotSupport;
439 }
440 }
441 else
442 {
443 base->CFG &= ~(USART_CFG_MODE32K_MASK);
444 result = USART_SetBaudRate(base, baudRate_Bps, srcClock_Hz);
445 if (kStatus_Success != result)
446 {
447 return result;
448 }
449 }
450 base->CFG |= USART_CFG_ENABLE_MASK;
451 return result;
452 }
453
454 /*!
455 * brief Enable 9-bit data mode for USART.
456 *
457 * This function set the 9-bit mode for USART module. The 9th bit is not used for parity thus can be modified by user.
458 *
459 * param base USART peripheral base address.
460 * param enable true to enable, false to disable.
461 */
USART_Enable9bitMode(USART_Type * base,bool enable)462 void USART_Enable9bitMode(USART_Type *base, bool enable)
463 {
464 assert(base != NULL);
465
466 uint32_t temp = 0U;
467
468 if (enable)
469 {
470 /* Set USART 9-bit mode, disable parity. */
471 temp = base->CFG & ~((uint32_t)USART_CFG_DATALEN_MASK | (uint32_t)USART_CFG_PARITYSEL_MASK);
472 temp |= (uint32_t)USART_CFG_DATALEN(0x2U);
473 base->CFG = temp;
474 }
475 else
476 {
477 /* Set USART to 8-bit mode. */
478 base->CFG &= ~((uint32_t)USART_CFG_DATALEN_MASK);
479 base->CFG |= (uint32_t)USART_CFG_DATALEN(0x1U);
480 }
481 }
482
483 /*!
484 * brief Transmit an address frame in 9-bit data mode.
485 *
486 * param base USART peripheral base address.
487 * param address USART slave address.
488 */
USART_SendAddress(USART_Type * base,uint8_t address)489 void USART_SendAddress(USART_Type *base, uint8_t address)
490 {
491 assert(base != NULL);
492 base->FIFOWR = ((uint32_t)address | 0x100UL);
493 }
494
495 /*!
496 * brief Writes to the TX register using a blocking method.
497 *
498 * This function polls the TX register, waits for the TX register to be empty or for the TX FIFO
499 * to have room and writes data to the TX buffer.
500 *
501 * param base USART peripheral base address.
502 * param data Start address of the data to write.
503 * param length Size of the data to write.
504 * retval kStatus_USART_Timeout Transmission timed out and was aborted.
505 * retval kStatus_InvalidArgument Invalid argument.
506 * retval kStatus_Success Successfully wrote all data.
507 */
USART_WriteBlocking(USART_Type * base,const uint8_t * data,size_t length)508 status_t USART_WriteBlocking(USART_Type *base, const uint8_t *data, size_t length)
509 {
510 /* Check arguments */
511 assert(!((NULL == base) || (NULL == data)));
512 #if UART_RETRY_TIMES
513 uint32_t waitTimes;
514 #endif
515 if ((NULL == base) || (NULL == data))
516 {
517 return kStatus_InvalidArgument;
518 }
519 /* Check whether txFIFO is enabled */
520 if (0U == (base->FIFOCFG & USART_FIFOCFG_ENABLETX_MASK))
521 {
522 return kStatus_InvalidArgument;
523 }
524 for (; length > 0U; length--)
525 {
526 /* Loop until txFIFO get some space for new data */
527 #if UART_RETRY_TIMES
528 waitTimes = UART_RETRY_TIMES;
529 while ((0U == (base->FIFOSTAT & USART_FIFOSTAT_TXNOTFULL_MASK)) && (--waitTimes != 0U))
530 #else
531 while (0U == (base->FIFOSTAT & USART_FIFOSTAT_TXNOTFULL_MASK))
532 #endif
533 {
534 }
535 #if UART_RETRY_TIMES
536 if (0U == waitTimes)
537 {
538 return kStatus_USART_Timeout;
539 }
540 #endif
541 base->FIFOWR = *data;
542 data++;
543 }
544 /* Wait to finish transfer */
545 #if UART_RETRY_TIMES
546 waitTimes = UART_RETRY_TIMES;
547 while ((0U == (base->STAT & USART_STAT_TXIDLE_MASK)) && (--waitTimes != 0U))
548 #else
549 while (0U == (base->STAT & USART_STAT_TXIDLE_MASK))
550 #endif
551 {
552 }
553 #if UART_RETRY_TIMES
554 if (0U == waitTimes)
555 {
556 return kStatus_USART_Timeout;
557 }
558 #endif
559 return kStatus_Success;
560 }
561
562 /*!
563 * brief Read RX data register using a blocking method.
564 *
565 * This function polls the RX register, waits for the RX register to be full or for RX FIFO to
566 * have data and read data from the TX register.
567 *
568 * param base USART peripheral base address.
569 * param data Start address of the buffer to store the received data.
570 * param length Size of the buffer.
571 * retval kStatus_USART_FramingError Receiver overrun happened while receiving data.
572 * retval kStatus_USART_ParityError Noise error happened while receiving data.
573 * retval kStatus_USART_NoiseError Framing error happened while receiving data.
574 * retval kStatus_USART_RxError Overflow or underflow rxFIFO happened.
575 * retval kStatus_USART_Timeout Transmission timed out and was aborted.
576 * retval kStatus_Success Successfully received all data.
577 */
USART_ReadBlocking(USART_Type * base,uint8_t * data,size_t length)578 status_t USART_ReadBlocking(USART_Type *base, uint8_t *data, size_t length)
579 {
580 uint32_t statusFlag;
581 status_t status = kStatus_Success;
582 #if UART_RETRY_TIMES
583 uint32_t waitTimes;
584 #endif
585
586 /* check arguments */
587 assert(!((NULL == base) || (NULL == data)));
588 if ((NULL == base) || (NULL == data))
589 {
590 return kStatus_InvalidArgument;
591 }
592
593 /* Check whether rxFIFO is enabled */
594 if ((base->FIFOCFG & USART_FIFOCFG_ENABLERX_MASK) == 0U)
595 {
596 return kStatus_Fail;
597 }
598 for (; length > 0U; length--)
599 {
600 /* loop until rxFIFO have some data to read */
601 #if UART_RETRY_TIMES
602 waitTimes = UART_RETRY_TIMES;
603 while (((base->FIFOSTAT & USART_FIFOSTAT_RXNOTEMPTY_MASK) == 0U) && (--waitTimes != 0U))
604 #else
605 while ((base->FIFOSTAT & USART_FIFOSTAT_RXNOTEMPTY_MASK) == 0U)
606 #endif
607 {
608 }
609 #if UART_RETRY_TIMES
610 if (waitTimes == 0U)
611 {
612 status = kStatus_USART_Timeout;
613 break;
614 }
615 #endif
616 /* check rxFIFO statusFlag */
617 if ((base->FIFOSTAT & USART_FIFOSTAT_RXERR_MASK) != 0U)
618 {
619 base->FIFOCFG |= USART_FIFOCFG_EMPTYRX_MASK;
620 base->FIFOSTAT |= USART_FIFOSTAT_RXERR_MASK;
621 status = kStatus_USART_RxError;
622 break;
623 }
624 /* check receive statusFlag */
625 statusFlag = base->STAT;
626 /* Clear all status flags */
627 base->STAT |= statusFlag;
628 if ((statusFlag & USART_STAT_PARITYERRINT_MASK) != 0U)
629 {
630 status = kStatus_USART_ParityError;
631 }
632 if ((statusFlag & USART_STAT_FRAMERRINT_MASK) != 0U)
633 {
634 status = kStatus_USART_FramingError;
635 }
636 if ((statusFlag & USART_STAT_RXNOISEINT_MASK) != 0U)
637 {
638 status = kStatus_USART_NoiseError;
639 }
640
641 if (kStatus_Success == status)
642 {
643 *data = (uint8_t)base->FIFORD;
644 data++;
645 }
646 else
647 {
648 break;
649 }
650 }
651 return status;
652 }
653
654 /*!
655 * brief Initializes the USART handle.
656 *
657 * This function initializes the USART handle which can be used for other USART
658 * transactional APIs. Usually, for a specified USART instance,
659 * call this API once to get the initialized handle.
660 *
661 * param base USART peripheral base address.
662 * param handle USART handle pointer.
663 * param callback The callback function.
664 * param userData The parameter of the callback function.
665 */
USART_TransferCreateHandle(USART_Type * base,usart_handle_t * handle,usart_transfer_callback_t callback,void * userData)666 status_t USART_TransferCreateHandle(USART_Type *base,
667 usart_handle_t *handle,
668 usart_transfer_callback_t callback,
669 void *userData)
670 {
671 /* Check 'base' */
672 assert(!((NULL == base) || (NULL == handle)));
673
674 uint32_t instance = 0;
675 usart_to_flexcomm_t handler;
676 handler.usart_master_handler = USART_TransferHandleIRQ;
677
678 if ((NULL == base) || (NULL == handle))
679 {
680 return kStatus_InvalidArgument;
681 }
682
683 instance = USART_GetInstance(base);
684
685 (void)memset(handle, 0, sizeof(*handle));
686 /* Set the TX/RX state. */
687 handle->rxState = (uint8_t)kUSART_RxIdle;
688 handle->txState = (uint8_t)kUSART_TxIdle;
689 /* Set the callback and user data. */
690 handle->callback = callback;
691 handle->userData = userData;
692 handle->rxWatermark = (uint8_t)USART_FIFOTRIG_RXLVL_GET(base);
693 handle->txWatermark = (uint8_t)USART_FIFOTRIG_TXLVL_GET(base);
694
695 FLEXCOMM_SetIRQHandler(base, handler.flexcomm_handler, handle);
696
697 /* Enable interrupt in NVIC. */
698 (void)EnableIRQ(s_usartIRQ[instance]);
699
700 return kStatus_Success;
701 }
702
703 /*!
704 * brief Transmits a buffer of data using the interrupt method.
705 *
706 * This function sends data using an interrupt method. This is a non-blocking function, which
707 * returns directly without waiting for all data to be written to the TX register. When
708 * all data is written to the TX register in the IRQ handler, the USART driver calls the callback
709 * function and passes the ref kStatus_USART_TxIdle as status parameter.
710 *
711 * note The kStatus_USART_TxIdle is passed to the upper layer when all data is written
712 * to the TX register. However it does not ensure that all data are sent out. Before disabling the TX,
713 * check the kUSART_TransmissionCompleteFlag to ensure that the TX is finished.
714 *
715 * param base USART peripheral base address.
716 * param handle USART handle pointer.
717 * param xfer USART transfer structure. See #usart_transfer_t.
718 * retval kStatus_Success Successfully start the data transmission.
719 * retval kStatus_USART_TxBusy Previous transmission still not finished, data not all written to TX register yet.
720 * retval kStatus_InvalidArgument Invalid argument.
721 */
USART_TransferSendNonBlocking(USART_Type * base,usart_handle_t * handle,usart_transfer_t * xfer)722 status_t USART_TransferSendNonBlocking(USART_Type *base, usart_handle_t *handle, usart_transfer_t *xfer)
723 {
724 /* Check arguments */
725 assert(!((NULL == base) || (NULL == handle) || (NULL == xfer)));
726 if ((NULL == base) || (NULL == handle) || (NULL == xfer))
727 {
728 return kStatus_InvalidArgument;
729 }
730 /* Check xfer members */
731 assert(!((0U == xfer->dataSize) || (NULL == xfer->txData)));
732 if ((0U == xfer->dataSize) || (NULL == xfer->txData))
733 {
734 return kStatus_InvalidArgument;
735 }
736
737 /* Return error if current TX busy. */
738 if ((uint8_t)kUSART_TxBusy == handle->txState)
739 {
740 return kStatus_USART_TxBusy;
741 }
742 else
743 {
744 /* Disable IRQ when configuring transfer handle, in case interrupt occurs during the process and messes up the
745 * handle value. */
746 uint32_t interruptMask = USART_GetEnabledInterrupts(base);
747 USART_DisableInterrupts(base, interruptMask);
748 handle->txData = xfer->txData;
749 handle->txDataSize = xfer->dataSize;
750 handle->txDataSizeAll = xfer->dataSize;
751 handle->txState = (uint8_t)kUSART_TxBusy;
752 /* Enable transmiter interrupt and the previously disabled interrupt. */
753 USART_EnableInterrupts(base, interruptMask | (uint32_t)kUSART_TxLevelInterruptEnable);
754 }
755 return kStatus_Success;
756 }
757
758 /*!
759 * brief Aborts the interrupt-driven data transmit.
760 *
761 * This function aborts the interrupt driven data sending. The user can get the remainBtyes to find out
762 * how many bytes are still not sent out.
763 *
764 * param base USART peripheral base address.
765 * param handle USART handle pointer.
766 */
USART_TransferAbortSend(USART_Type * base,usart_handle_t * handle)767 void USART_TransferAbortSend(USART_Type *base, usart_handle_t *handle)
768 {
769 assert(NULL != handle);
770
771 /* Disable interrupts */
772 USART_DisableInterrupts(base, (uint32_t)kUSART_TxLevelInterruptEnable);
773 /* Empty txFIFO */
774 base->FIFOCFG |= USART_FIFOCFG_EMPTYTX_MASK;
775
776 handle->txDataSize = 0U;
777 handle->txState = (uint8_t)kUSART_TxIdle;
778 }
779
780 /*!
781 * brief Get the number of bytes that have been sent out to bus.
782 *
783 * This function gets the number of bytes that have been sent out to bus by interrupt method.
784 *
785 * param base USART peripheral base address.
786 * param handle USART handle pointer.
787 * param count Send bytes count.
788 * retval kStatus_NoTransferInProgress No send in progress.
789 * retval kStatus_InvalidArgument Parameter is invalid.
790 * retval kStatus_Success Get successfully through the parameter \p count;
791 */
USART_TransferGetSendCount(USART_Type * base,usart_handle_t * handle,uint32_t * count)792 status_t USART_TransferGetSendCount(USART_Type *base, usart_handle_t *handle, uint32_t *count)
793 {
794 assert(NULL != handle);
795 assert(NULL != count);
796
797 if ((uint8_t)kUSART_TxIdle == handle->txState)
798 {
799 return kStatus_NoTransferInProgress;
800 }
801
802 *count = handle->txDataSizeAll - handle->txDataSize -
803 ((base->FIFOSTAT & USART_FIFOSTAT_TXLVL_MASK) >> USART_FIFOSTAT_TXLVL_SHIFT);
804
805 return kStatus_Success;
806 }
807
808 /*!
809 * brief Receives a buffer of data using an interrupt method.
810 *
811 * This function receives data using an interrupt method. This is a non-blocking function, which
812 * returns without waiting for all data to be received.
813 * If the RX ring buffer is used and not empty, the data in the ring buffer is copied and
814 * the parameter p receivedBytes shows how many bytes are copied from the ring buffer.
815 * After copying, if the data in the ring buffer is not enough to read, the receive
816 * request is saved by the USART driver. When the new data arrives, the receive request
817 * is serviced first. When all data is received, the USART driver notifies the upper layer
818 * through a callback function and passes the status parameter ref kStatus_USART_RxIdle.
819 * For example, the upper layer needs 10 bytes but there are only 5 bytes in the ring buffer.
820 * The 5 bytes are copied to the xfer->data and this function returns with the
821 * parameter p receivedBytes set to 5. For the left 5 bytes, newly arrived data is
822 * saved from the xfer->data[5]. When 5 bytes are received, the USART driver notifies the upper layer.
823 * If the RX ring buffer is not enabled, this function enables the RX and RX interrupt
824 * to receive data to the xfer->data. When all data is received, the upper layer is notified.
825 *
826 * param base USART peripheral base address.
827 * param handle USART handle pointer.
828 * param xfer USART transfer structure, see #usart_transfer_t.
829 * param receivedBytes Bytes received from the ring buffer directly.
830 * retval kStatus_Success Successfully queue the transfer into transmit queue.
831 * retval kStatus_USART_RxBusy Previous receive request is not finished.
832 * retval kStatus_InvalidArgument Invalid argument.
833 */
USART_TransferReceiveNonBlocking(USART_Type * base,usart_handle_t * handle,usart_transfer_t * xfer,size_t * receivedBytes)834 status_t USART_TransferReceiveNonBlocking(USART_Type *base,
835 usart_handle_t *handle,
836 usart_transfer_t *xfer,
837 size_t *receivedBytes)
838 {
839 uint32_t i;
840 /* How many bytes to copy from ring buffer to user memory. */
841 size_t bytesToCopy = 0U;
842 /* How many bytes to receive. */
843 size_t bytesToReceive;
844 /* How many bytes currently have received. */
845 size_t bytesCurrentReceived;
846 uint32_t interruptMask = 0U;
847
848 /* Check arguments */
849 assert(!((NULL == base) || (NULL == handle) || (NULL == xfer)));
850 if ((NULL == base) || (NULL == handle) || (NULL == xfer))
851 {
852 return kStatus_InvalidArgument;
853 }
854 /* Check xfer members */
855 assert(!((0U == xfer->dataSize) || (NULL == xfer->rxData)));
856 if ((0U == xfer->dataSize) || (NULL == xfer->rxData))
857 {
858 return kStatus_InvalidArgument;
859 }
860
861 /* Enable address detect when address match is enabled. */
862 if ((base->CFG & (uint32_t)USART_CFG_AUTOADDR_MASK) != 0U)
863 {
864 base->CTL |= (uint32_t)USART_CTL_ADDRDET_MASK;
865 }
866
867 /* How to get data:
868 1. If RX ring buffer is not enabled, then save xfer->data and xfer->dataSize
869 to uart handle, enable interrupt to store received data to xfer->data. When
870 all data received, trigger callback.
871 2. If RX ring buffer is enabled and not empty, get data from ring buffer first.
872 If there are enough data in ring buffer, copy them to xfer->data and return.
873 If there are not enough data in ring buffer, copy all of them to xfer->data,
874 save the xfer->data remained empty space to uart handle, receive data
875 to this empty space and trigger callback when finished. */
876 if ((uint8_t)kUSART_RxBusy == handle->rxState)
877 {
878 return kStatus_USART_RxBusy;
879 }
880 else
881 {
882 bytesToReceive = xfer->dataSize;
883 bytesCurrentReceived = 0U;
884 /* If RX ring buffer is used. */
885 if (handle->rxRingBuffer != NULL)
886 {
887 /* Disable IRQ, protect ring buffer. */
888 interruptMask = USART_GetEnabledInterrupts(base);
889 USART_DisableInterrupts(base, interruptMask);
890
891 /* How many bytes in RX ring buffer currently. */
892 bytesToCopy = USART_TransferGetRxRingBufferLength(handle);
893 if (bytesToCopy != 0U)
894 {
895 bytesToCopy = MIN(bytesToReceive, bytesToCopy);
896 bytesToReceive -= bytesToCopy;
897 /* Copy data from ring buffer to user memory. */
898 for (i = 0U; i < bytesToCopy; i++)
899 {
900 xfer->rxData[bytesCurrentReceived++] = handle->rxRingBuffer[handle->rxRingBufferTail];
901 /* Wrap to 0. Not use modulo (%) because it might be large and slow. */
902 if ((size_t)handle->rxRingBufferTail + 1U == handle->rxRingBufferSize)
903 {
904 handle->rxRingBufferTail = 0U;
905 }
906 else
907 {
908 handle->rxRingBufferTail++;
909 }
910 }
911 }
912 /* If ring buffer does not have enough data, still need to read more data. */
913 if (bytesToReceive != 0U)
914 {
915 /* No data in ring buffer, save the request to UART handle. */
916 handle->rxData = xfer->rxData + bytesCurrentReceived;
917 handle->rxDataSize = bytesToReceive;
918 handle->rxDataSizeAll = xfer->dataSize;
919 handle->rxState = (uint8_t)kUSART_RxBusy;
920 }
921 /* Re-enable IRQ. */
922 USART_EnableInterrupts(base, interruptMask);
923 /* Call user callback since all data are received. */
924 if (0U == bytesToReceive)
925 {
926 if (handle->callback != NULL)
927 {
928 handle->callback(base, handle, kStatus_USART_RxIdle, handle->userData);
929 }
930 }
931 }
932 /* Ring buffer not used. */
933 else
934 {
935 /* Disable IRQ when configuring transfer handle, in case interrupt occurs during the process and messes up
936 * the handle value. */
937 interruptMask = USART_GetEnabledInterrupts(base);
938 USART_DisableInterrupts(base, interruptMask);
939 handle->rxData = xfer->rxData + bytesCurrentReceived;
940 handle->rxDataSize = bytesToReceive;
941 handle->rxDataSizeAll = bytesToReceive;
942 handle->rxState = (uint8_t)kUSART_RxBusy;
943
944 /* Enable RX interrupt. */
945 base->FIFOINTENSET = USART_FIFOINTENSET_RXLVL_MASK;
946 /* Re-enable IRQ. */
947 USART_EnableInterrupts(base, interruptMask);
948 }
949 /* Return the how many bytes have read. */
950 if (receivedBytes != NULL)
951 {
952 *receivedBytes = bytesCurrentReceived;
953 }
954 }
955 return kStatus_Success;
956 }
957
958 /*!
959 * brief Aborts the interrupt-driven data receiving.
960 *
961 * This function aborts the interrupt-driven data receiving. The user can get the remainBytes to find out
962 * how many bytes not received yet.
963 *
964 * param base USART peripheral base address.
965 * param handle USART handle pointer.
966 */
USART_TransferAbortReceive(USART_Type * base,usart_handle_t * handle)967 void USART_TransferAbortReceive(USART_Type *base, usart_handle_t *handle)
968 {
969 assert(NULL != handle);
970
971 /* Only abort the receive to handle->rxData, the RX ring buffer is still working. */
972 if (NULL == handle->rxRingBuffer)
973 {
974 /* Disable interrupts */
975 USART_DisableInterrupts(base, (uint32_t)kUSART_RxLevelInterruptEnable);
976 /* Empty rxFIFO */
977 base->FIFOCFG |= USART_FIFOCFG_EMPTYRX_MASK;
978 }
979
980 handle->rxDataSize = 0U;
981 handle->rxState = (uint8_t)kUSART_RxIdle;
982 }
983
984 /*!
985 * brief Get the number of bytes that have been received.
986 *
987 * This function gets the number of bytes that have been received.
988 *
989 * param base USART peripheral base address.
990 * param handle USART handle pointer.
991 * param count Receive bytes count.
992 * retval kStatus_NoTransferInProgress No receive in progress.
993 * retval kStatus_InvalidArgument Parameter is invalid.
994 * retval kStatus_Success Get successfully through the parameter \p count;
995 */
USART_TransferGetReceiveCount(USART_Type * base,usart_handle_t * handle,uint32_t * count)996 status_t USART_TransferGetReceiveCount(USART_Type *base, usart_handle_t *handle, uint32_t *count)
997 {
998 assert(NULL != handle);
999 assert(NULL != count);
1000
1001 if ((uint8_t)kUSART_RxIdle == handle->rxState)
1002 {
1003 return kStatus_NoTransferInProgress;
1004 }
1005
1006 *count = handle->rxDataSizeAll - handle->rxDataSize;
1007
1008 return kStatus_Success;
1009 }
1010
1011 /*!
1012 * brief USART IRQ handle function.
1013 *
1014 * This function handles the USART transmit and receive IRQ request.
1015 *
1016 * param base USART peripheral base address.
1017 * param handle USART handle pointer.
1018 */
USART_TransferHandleIRQ(USART_Type * base,usart_handle_t * handle)1019 void USART_TransferHandleIRQ(USART_Type *base, usart_handle_t *handle)
1020 {
1021 /* Check arguments */
1022 assert((NULL != base) && (NULL != handle));
1023
1024 bool receiveEnabled = ((handle->rxDataSize != 0U) || (handle->rxRingBuffer != NULL));
1025 bool sendEnabled = (handle->txDataSize != 0U);
1026 uint8_t rxdata;
1027 size_t tmpsize;
1028
1029 /* If RX overrun. */
1030 if ((base->FIFOSTAT & USART_FIFOSTAT_RXERR_MASK) != 0U)
1031 {
1032 /* Clear rx error state. */
1033 base->FIFOSTAT |= USART_FIFOSTAT_RXERR_MASK;
1034 /* clear rxFIFO */
1035 base->FIFOCFG |= USART_FIFOCFG_EMPTYRX_MASK;
1036 /* Trigger callback. */
1037 if (handle->callback != NULL)
1038 {
1039 handle->callback(base, handle, kStatus_USART_RxError, handle->userData);
1040 }
1041 }
1042 while ((receiveEnabled && ((base->FIFOSTAT & USART_FIFOSTAT_RXNOTEMPTY_MASK) != 0U)) ||
1043 (sendEnabled && ((base->FIFOSTAT & USART_FIFOSTAT_TXNOTFULL_MASK) != 0U)))
1044 {
1045 /* Receive data */
1046 if (receiveEnabled && ((base->FIFOSTAT & USART_FIFOSTAT_RXNOTEMPTY_MASK) != 0U))
1047 {
1048 /* Clear address detect when RXFIFO has data. */
1049 base->CTL &= ~(uint32_t)USART_CTL_ADDRDET_MASK;
1050 /* Receive to app bufffer if app buffer is present */
1051 if (handle->rxDataSize != 0U)
1052 {
1053 rxdata = (uint8_t)base->FIFORD;
1054 *handle->rxData = rxdata;
1055 handle->rxDataSize--;
1056 handle->rxData++;
1057 receiveEnabled = ((handle->rxDataSize != 0U) || (handle->rxRingBuffer != NULL));
1058 if (0U == handle->rxDataSize)
1059 {
1060 if (NULL == handle->rxRingBuffer)
1061 {
1062 base->FIFOINTENCLR = USART_FIFOINTENCLR_RXLVL_MASK | USART_FIFOINTENSET_RXERR_MASK;
1063 }
1064 handle->rxState = (uint8_t)kUSART_RxIdle;
1065 if (handle->callback != NULL)
1066 {
1067 handle->callback(base, handle, kStatus_USART_RxIdle, handle->userData);
1068 }
1069 }
1070 }
1071 /* Otherwise receive to ring buffer if ring buffer is present */
1072 else
1073 {
1074 if (handle->rxRingBuffer != NULL)
1075 {
1076 /* If RX ring buffer is full, trigger callback to notify over run. */
1077 if (USART_TransferIsRxRingBufferFull(handle))
1078 {
1079 if (handle->callback != NULL)
1080 {
1081 handle->callback(base, handle, kStatus_USART_RxRingBufferOverrun, handle->userData);
1082 }
1083 }
1084 /* If ring buffer is still full after callback function, the oldest data is overridden. */
1085 if (USART_TransferIsRxRingBufferFull(handle))
1086 {
1087 /* Increase handle->rxRingBufferTail to make room for new data. */
1088 if ((size_t)handle->rxRingBufferTail + 1U == handle->rxRingBufferSize)
1089 {
1090 handle->rxRingBufferTail = 0U;
1091 }
1092 else
1093 {
1094 handle->rxRingBufferTail++;
1095 }
1096 }
1097 /* Read data. */
1098 rxdata = (uint8_t)base->FIFORD;
1099 handle->rxRingBuffer[handle->rxRingBufferHead] = rxdata;
1100 /* Increase handle->rxRingBufferHead. */
1101 if ((size_t)handle->rxRingBufferHead + 1U == handle->rxRingBufferSize)
1102 {
1103 handle->rxRingBufferHead = 0U;
1104 }
1105 else
1106 {
1107 handle->rxRingBufferHead++;
1108 }
1109 }
1110 }
1111 }
1112 /* Send data */
1113 if (sendEnabled && ((base->FIFOSTAT & USART_FIFOSTAT_TXNOTFULL_MASK) != 0U))
1114 {
1115 base->FIFOWR = *handle->txData;
1116 handle->txDataSize--;
1117 handle->txData++;
1118 sendEnabled = handle->txDataSize != 0U;
1119 if (!sendEnabled)
1120 {
1121 base->FIFOINTENCLR = USART_FIFOINTENCLR_TXLVL_MASK;
1122
1123 base->INTENSET = USART_INTENSET_TXIDLEEN_MASK;
1124 }
1125 }
1126 }
1127
1128 /* Tx idle and the interrupt is enabled. */
1129 if ((0U != (base->INTENSET & USART_INTENSET_TXIDLEEN_MASK)) && (0U != (base->INTSTAT & USART_INTSTAT_TXIDLE_MASK)))
1130 {
1131 /* Set txState to idle only when all data has been sent out to bus. */
1132 handle->txState = (uint8_t)kUSART_TxIdle;
1133 /* Disable tx idle interrupt */
1134 base->INTENCLR = USART_INTENCLR_TXIDLECLR_MASK;
1135
1136 /* Trigger callback. */
1137 if (handle->callback != NULL)
1138 {
1139 handle->callback(base, handle, kStatus_USART_TxIdle, handle->userData);
1140 }
1141 }
1142
1143 /* ring buffer is not used */
1144 if (NULL == handle->rxRingBuffer)
1145 {
1146 tmpsize = handle->rxDataSize;
1147
1148 /* restore if rx transfer ends and rxLevel is different from default value */
1149 if ((tmpsize == 0U) && (USART_FIFOTRIG_RXLVL_GET(base) != handle->rxWatermark))
1150 {
1151 base->FIFOTRIG =
1152 (base->FIFOTRIG & (~USART_FIFOTRIG_RXLVL_MASK)) | USART_FIFOTRIG_RXLVL(handle->rxWatermark);
1153 }
1154 /* decrease level if rx transfer is bellow */
1155 if ((tmpsize != 0U) && (tmpsize < (USART_FIFOTRIG_RXLVL_GET(base) + 1U)))
1156 {
1157 base->FIFOTRIG = (base->FIFOTRIG & (~USART_FIFOTRIG_RXLVL_MASK)) | (USART_FIFOTRIG_RXLVL(tmpsize - 1U));
1158 }
1159 }
1160 }
1161