1 /*
2 * Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
3 * Copyright 2016-2017 NXP
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * o Redistributions of source code must retain the above copyright notice, this list
9 * of conditions and the following disclaimer.
10 *
11 * o Redistributions in binary form must reproduce the above copyright notice, this
12 * list of conditions and the following disclaimer in the documentation and/or
13 * other materials provided with the distribution.
14 *
15 * o Neither the name of the copyright holder nor the names of its
16 * contributors may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "fsl_lpsci.h"
32
33 /*******************************************************************************
34 * Definitions
35 ******************************************************************************/
36
37 /* LPSCI transfer state. */
38 enum _lpsci_tansfer_state
39 {
40 kLPSCI_TxIdle, /*!< TX idle. */
41 kLPSCI_TxBusy, /*!< TX busy. */
42 kLPSCI_RxIdle, /*!< RX idle. */
43 kLPSCI_RxBusy, /*!< RX busy. */
44 kLPSCI_RxFramingError, /* Rx framing error */
45 kLPSCI_RxParityError /* Rx parity error */
46 };
47
48 /* Typedef for interrupt handler. */
49 typedef void (*lpsci_isr_t)(UART0_Type *base, lpsci_handle_t *handle);
50
51 /*******************************************************************************
52 * Prototypes
53 ******************************************************************************/
54
55 /*!
56 * @brief Get the LPSCI instance from peripheral base address.
57 *
58 * @param base LPSCI peripheral base address.
59 * @return LPSCI instance.
60 */
61 uint32_t LPSCI_GetInstance(UART0_Type *base);
62
63 /*!
64 * @brief Get the length of received data in RX ring buffer.
65 *
66 * @userData handle LPSCI handle pointer.
67 * @return Length of received data in RX ring buffer.
68 */
69 static size_t LPSCI_TransferGetRxRingBufferLength(lpsci_handle_t *handle);
70
71 /*!
72 * @brief Check whether the RX ring buffer is full.
73 *
74 * @parram handle LPSCI handle pointer.
75 * @retval true RX ring buffer is full.
76 * @retval false RX ring buffer is not full.
77 */
78 static bool LPSCI_TransferIsRxRingBufferFull(lpsci_handle_t *handle);
79
80 /*!
81 * @brief Write to TX register using non-blocking method.
82 *
83 * This function writes data to the TX register directly, upper layer must make
84 * sure the TX register is empty before calling this function.
85 *
86 * @note This function does not check whether all the data has been sent out to bus,
87 * so before disable TX, check kLPSCI_TransmissionCompleteFlag to ensure the TX is
88 * finished.
89 *
90 * @param base LPSCI peripheral base address.
91 * @param data Start addresss of the data to write.
92 * @param length Size of the buffer to be sent.
93 */
94 static void LPSCI_WriteNonBlocking(UART0_Type *base, const uint8_t *data, size_t length);
95
96 /*!
97 * @brief Read RX data register using blocking method.
98 *
99 * This function polls the RX register, waits for the RX register full
100 * then read data from TX register.
101 *
102 * @param base LPSCI peripheral base address.
103 * @param data Start addresss of the buffer to store the received data.
104 * @param length Size of the buffer.
105 */
106 static void LPSCI_ReadNonBlocking(UART0_Type *base, uint8_t *data, size_t length);
107
108 /*******************************************************************************
109 * Variables
110 ******************************************************************************/
111 /* Array of LPSCI handle. */
112 static lpsci_handle_t *s_lpsciHandle[FSL_FEATURE_SOC_LPSCI_COUNT];
113
114 /* Array of LPSCI peripheral base address. */
115 static UART0_Type *const s_lpsciBases[] = UART0_BASE_PTRS;
116
117 /* Array of LPSCI IRQ number. */
118 static const IRQn_Type s_lpsciIRQ[] = UART0_RX_TX_IRQS;
119 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
120 /* Array of LPSCI clock name. */
121 static const clock_ip_name_t s_lpsciClock[] = UART0_CLOCKS;
122 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
123
124 /* LPSCI ISR for transactional APIs. */
125 static lpsci_isr_t s_lpsciIsr;
126
127 /*******************************************************************************
128 * Code
129 ******************************************************************************/
130
LPSCI_GetInstance(UART0_Type * base)131 uint32_t LPSCI_GetInstance(UART0_Type *base)
132 {
133 uint32_t instance;
134
135 /* Find the instance index from base address mappings. */
136 for (instance = 0; instance < ARRAY_SIZE(s_lpsciBases); instance++)
137 {
138 if (s_lpsciBases[instance] == base)
139 {
140 break;
141 }
142 }
143
144 assert(instance < ARRAY_SIZE(s_lpsciBases));
145
146 return instance;
147 }
148
LPSCI_TransferGetRxRingBufferLength(lpsci_handle_t * handle)149 static size_t LPSCI_TransferGetRxRingBufferLength(lpsci_handle_t *handle)
150 {
151 assert(handle);
152
153 size_t size;
154
155 if (handle->rxRingBufferTail > handle->rxRingBufferHead)
156 {
157 size = (size_t)(handle->rxRingBufferHead + handle->rxRingBufferSize - handle->rxRingBufferTail);
158 }
159 else
160 {
161 size = (size_t)(handle->rxRingBufferHead - handle->rxRingBufferTail);
162 }
163
164 return size;
165 }
166
LPSCI_TransferIsRxRingBufferFull(lpsci_handle_t * handle)167 static bool LPSCI_TransferIsRxRingBufferFull(lpsci_handle_t *handle)
168 {
169 assert(handle);
170
171 bool full;
172
173 if (LPSCI_TransferGetRxRingBufferLength(handle) == (handle->rxRingBufferSize - 1U))
174 {
175 full = true;
176 }
177 else
178 {
179 full = false;
180 }
181
182 return full;
183 }
184
LPSCI_ReadNonBlocking(UART0_Type * base,uint8_t * data,size_t length)185 static void LPSCI_ReadNonBlocking(UART0_Type *base, uint8_t *data, size_t length)
186 {
187 assert(data);
188
189 /* The Non Blocking read data API assume user have ensured there is enough space in
190 peripheral to write. */
191 size_t i;
192
193 for (i = 0; i < length; i++)
194 {
195 data[i] = base->D;
196 }
197 }
198
LPSCI_WriteNonBlocking(UART0_Type * base,const uint8_t * data,size_t length)199 static void LPSCI_WriteNonBlocking(UART0_Type *base, const uint8_t *data, size_t length)
200 {
201 assert(data);
202
203 /* The Non Blocking write data API assume user have ensured there is enough space in
204 peripheral to write. */
205 size_t i;
206
207 for (i = 0; i < length; i++)
208 {
209 base->D = data[i];
210 }
211 }
212
LPSCI_Init(UART0_Type * base,const lpsci_config_t * config,uint32_t srcClock_Hz)213 status_t LPSCI_Init(UART0_Type *base, const lpsci_config_t *config, uint32_t srcClock_Hz)
214 {
215 assert(config);
216 assert(config->baudRate_Bps);
217
218 uint8_t temp;
219 uint16_t sbr = 0;
220 uint16_t sbrTemp;
221 uint32_t osr = 0;
222 uint32_t osrTemp;
223 uint32_t tempDiff, calculatedBaud, baudDiff;
224
225 /* This LPSCI instantiation uses a slightly different baud rate calculation
226 * The idea is to use the best OSR (over-sampling rate) possible
227 * Note, OSR is typically hard-set to 16 in other LPSCI instantiations
228 * loop to find the best OSR value possible, one that generates minimum baudDiff
229 * iterate through the rest of the supported values of OSR */
230
231 baudDiff = config->baudRate_Bps;
232 for (osrTemp = 4; osrTemp <= 32; osrTemp++)
233 {
234 /* calculate the temporary sbr value */
235 sbrTemp = (srcClock_Hz / (config->baudRate_Bps * osrTemp));
236 /* set sbrTemp to 1 if the sourceClockInHz can not satisfy the desired baud rate */
237 if (sbrTemp == 0)
238 {
239 sbrTemp = 1;
240 }
241 /* Calculate the baud rate based on the temporary OSR and SBR values */
242 calculatedBaud = (srcClock_Hz / (osrTemp * sbrTemp));
243
244 tempDiff = calculatedBaud - config->baudRate_Bps;
245
246 /* Select the better value between srb and (sbr + 1) */
247 if (tempDiff > (config->baudRate_Bps - (srcClock_Hz / (osrTemp * (sbrTemp + 1)))))
248 {
249 tempDiff = config->baudRate_Bps - (srcClock_Hz / (osrTemp * (sbrTemp + 1)));
250 sbrTemp++;
251 }
252
253 if (tempDiff <= baudDiff)
254 {
255 baudDiff = tempDiff;
256 osr = osrTemp; /* update and store the best OSR value calculated*/
257 sbr = sbrTemp; /* update store the best SBR value calculated*/
258 }
259 }
260
261 /* next, check to see if actual baud rate is within 3% of desired baud rate
262 * based on the best calculate OSR value */
263 if (baudDiff > ((config->baudRate_Bps / 100) * 3))
264 {
265 /* Unacceptable baud rate difference of more than 3%*/
266 return kStatus_LPSCI_BaudrateNotSupport;
267 }
268
269 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
270 /* Enable LPSCI clock */
271 CLOCK_EnableClock(s_lpsciClock[LPSCI_GetInstance(base)]);
272 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
273
274 /* Disable TX RX before setting. */
275 base->C2 &= ~(UART0_C2_TE_MASK | UART0_C2_RE_MASK);
276
277 /* Acceptable baud rate */
278 /* Check if OSR is between 4x and 7x oversampling*/
279 /* If so, then "BOTHEDGE" sampling must be turned on*/
280 if ((osr > 3) && (osr < 8))
281 {
282 base->C5 |= UART0_C5_BOTHEDGE_MASK;
283 }
284
285 /* program the osr value (bit value is one less than actual value)*/
286 base->C4 = ((base->C4 & ~UART0_C4_OSR_MASK) | (osr - 1));
287
288 /* program the sbr (divider) value obtained above*/
289 base->BDH = ((base->C4 & ~UART0_BDH_SBR_MASK) | (uint8_t)(sbr >> 8));
290 base->BDL = (uint8_t)sbr;
291
292 /* set parity mode */
293 temp = base->C1 & ~(UART0_C1_PE_MASK | UART0_C1_PT_MASK | UART0_C1_M_MASK);
294
295 if (kLPSCI_ParityDisabled != config->parityMode)
296 {
297 temp |= (uint8_t)config->parityMode | UART0_C1_M_MASK;
298 }
299
300 base->C1 = temp;
301
302 #if defined(FSL_FEATURE_LPSCI_HAS_STOP_BIT_CONFIG_SUPPORT) && FSL_FEATURE_LPSCI_HAS_STOP_BIT_CONFIG_SUPPORT
303 /* set stop bit per char */
304 base->BDH &= ~UART0_BDH_SBNS_MASK;
305 base->BDH |= UART0_BDH_SBNS((uint8_t)config->stopBitCount);
306 #endif
307
308 /* Enable TX/RX base on configure structure. */
309 temp = base->C2;
310
311 if (config->enableTx)
312 {
313 temp |= UART0_C2_TE_MASK;
314 }
315
316 if (config->enableRx)
317 {
318 temp |= UART0_C2_RE_MASK;
319 }
320
321 base->C2 = temp;
322
323 return kStatus_Success;
324 }
325
LPSCI_Deinit(UART0_Type * base)326 void LPSCI_Deinit(UART0_Type *base)
327 {
328 /* Wait last char out */
329 while (0 == (base->S1 & UART0_S1_TC_MASK))
330 {
331 }
332
333 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
334 /* Disable LPSCI clock */
335 CLOCK_DisableClock(s_lpsciClock[LPSCI_GetInstance(base)]);
336 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
337 }
338
LPSCI_GetDefaultConfig(lpsci_config_t * config)339 void LPSCI_GetDefaultConfig(lpsci_config_t *config)
340 {
341 assert(config);
342
343 config->baudRate_Bps = 115200U;
344 config->parityMode = kLPSCI_ParityDisabled;
345 config->stopBitCount = kLPSCI_OneStopBit;
346 config->enableTx = false;
347 config->enableRx = false;
348 }
349
LPSCI_SetBaudRate(UART0_Type * base,uint32_t baudRate_Bps,uint32_t srcClock_Hz)350 status_t LPSCI_SetBaudRate(UART0_Type *base, uint32_t baudRate_Bps, uint32_t srcClock_Hz)
351 {
352 assert(baudRate_Bps);
353
354 uint16_t sbrTemp;
355 uint32_t osr = 0, sbr = 0;
356 uint8_t osrTemp;
357 uint32_t tempDiff, calculatedBaud, baudDiff;
358 uint8_t oldCtrl;
359
360 /* This LPSCI instantiation uses a slightly different baud rate calculation
361 * The idea is to use the best OSR (over-sampling rate) possible
362 * Note, OSR is typically hard-set to 16 in other LPSCI instantiations
363 * First calculate the baud rate using the minimum OSR possible (4). */
364 baudDiff = baudRate_Bps;
365 for (osrTemp = 4; osrTemp <= 32; osrTemp++)
366 {
367 /* calculate the temporary sbr value */
368 sbrTemp = (srcClock_Hz / (baudRate_Bps * osrTemp));
369 /* set sbrTemp to 1 if the sourceClockInHz can not satisfy the desired baud rate */
370 if (sbrTemp == 0)
371 {
372 sbrTemp = 1;
373 }
374 /* Calculate the baud rate based on the temporary OSR and SBR values */
375 calculatedBaud = (srcClock_Hz / (osrTemp * sbrTemp));
376
377 tempDiff = calculatedBaud - baudRate_Bps;
378
379 /* Select the better value between srb and (sbr + 1) */
380 if (tempDiff > (baudRate_Bps - (srcClock_Hz / (osrTemp * (sbrTemp + 1)))))
381 {
382 tempDiff = baudRate_Bps - (srcClock_Hz / (osrTemp * (sbrTemp + 1)));
383 sbrTemp++;
384 }
385
386 if (tempDiff <= baudDiff)
387 {
388 baudDiff = tempDiff;
389 osr = osrTemp; /* update and store the best OSR value calculated*/
390 sbr = sbrTemp; /* update store the best SBR value calculated*/
391 }
392 }
393
394 /* next, check to see if actual baud rate is within 3% of desired baud rate
395 * based on the best calculate OSR value */
396 if (baudDiff < ((baudRate_Bps / 100) * 3))
397 {
398 /* Store C2 before disable Tx and Rx */
399 oldCtrl = base->C2;
400
401 /* Disable LPSCI TX RX before setting. */
402 base->C2 &= ~(UART0_C2_TE_MASK | UART0_C2_RE_MASK);
403
404 /* Acceptable baud rate */
405 /* Check if OSR is between 4x and 7x oversampling*/
406 /* If so, then "BOTHEDGE" sampling must be turned on*/
407 if ((osr > 3) && (osr < 8))
408 {
409 base->C5 |= UART0_C5_BOTHEDGE_MASK;
410 }
411
412 /* program the osr value (bit value is one less than actual value)*/
413 base->C4 = ((base->C4 & ~UART0_C4_OSR_MASK) | (osr - 1));
414
415 /* program the sbr (divider) value obtained above*/
416 base->BDH = ((base->C4 & ~UART0_BDH_SBR_MASK) | (uint8_t)(sbr >> 8));
417 base->BDL = (uint8_t)sbr;
418
419 /* Restore C2. */
420 base->C2 = oldCtrl;
421
422 return kStatus_Success;
423 }
424 else
425 {
426 /* Unacceptable baud rate difference of more than 3%*/
427 return kStatus_LPSCI_BaudrateNotSupport;
428 }
429 }
430
LPSCI_EnableInterrupts(UART0_Type * base,uint32_t mask)431 void LPSCI_EnableInterrupts(UART0_Type *base, uint32_t mask)
432 {
433 mask &= kLPSCI_AllInterruptsEnable;
434
435 /* The interrupt mask is combined by control bits from several register: ((C3<<16) | (C2<<8) |(BDH))
436 */
437 base->BDH |= mask;
438 base->C2 |= (mask >> 8);
439 base->C3 |= (mask >> 16);
440 }
441
LPSCI_DisableInterrupts(UART0_Type * base,uint32_t mask)442 void LPSCI_DisableInterrupts(UART0_Type *base, uint32_t mask)
443 {
444 mask &= kLPSCI_AllInterruptsEnable;
445
446 /* The interrupt mask is combined by control bits from several register: ((C3<<16) | (C2<<8) |(BDH))
447 */
448 base->BDH &= ~mask;
449 base->C2 &= ~(mask >> 8);
450 base->C3 &= ~(mask >> 16);
451 }
452
LPSCI_GetEnabledInterrupts(UART0_Type * base)453 uint32_t LPSCI_GetEnabledInterrupts(UART0_Type *base)
454 {
455 uint32_t temp;
456 temp = base->BDH | ((uint32_t)(base->C2) << 8) | ((uint32_t)(base->C3) << 16);
457
458 return temp & kLPSCI_AllInterruptsEnable;
459 }
460
LPSCI_GetStatusFlags(UART0_Type * base)461 uint32_t LPSCI_GetStatusFlags(UART0_Type *base)
462 {
463 uint32_t status_flag;
464 status_flag = base->S1 | ((uint32_t)(base->S2) << 8);
465
466 #if defined(FSL_FEATURE_LPSCI_HAS_EXTENDED_DATA_REGISTER_FLAGS) && FSL_FEATURE_LPSCI_HAS_EXTENDED_DATA_REGISTER_FLAGS
467 status_flag |= ((uint32_t)(base->ED) << 16);
468 #endif
469
470 return status_flag;
471 }
472
LPSCI_ClearStatusFlags(UART0_Type * base,uint32_t mask)473 status_t LPSCI_ClearStatusFlags(UART0_Type *base, uint32_t mask)
474 {
475 volatile uint8_t dummy = 0;
476 status_t status;
477 dummy++; /* For unused variable warning */
478
479 #if defined(FSL_FEATURE_LPSCI_HAS_LIN_BREAK_DETECT) && FSL_FEATURE_LPSCI_HAS_LIN_BREAK_DETECT
480 if (mask & kLPSCI_LinBreakFlag)
481 {
482 base->S2 = UART0_S2_LBKDIF_MASK;
483 mask &= ~(uint32_t)kLPSCI_LinBreakFlag;
484 }
485 #endif
486
487 if (mask & kLPSCI_RxActiveEdgeFlag)
488 {
489 base->S2 = UART0_S2_RXEDGIF_MASK;
490 mask &= ~(uint32_t)kLPSCI_RxActiveEdgeFlag;
491 }
492
493 if ((mask & (kLPSCI_IdleLineFlag | kLPSCI_RxOverrunFlag | kLPSCI_NoiseErrorFlag | kLPSCI_FramingErrorFlag |
494 kLPSCI_ParityErrorFlag)))
495 {
496 base->S1 = (mask & (kLPSCI_IdleLineFlag | kLPSCI_RxOverrunFlag | kLPSCI_NoiseErrorFlag |
497 kLPSCI_FramingErrorFlag | kLPSCI_ParityErrorFlag));
498 mask &= ~(uint32_t)(kLPSCI_IdleLineFlag | kLPSCI_RxOverrunFlag | kLPSCI_NoiseErrorFlag |
499 kLPSCI_FramingErrorFlag | kLPSCI_ParityErrorFlag);
500 }
501
502 if (mask)
503 {
504 /* Some flags can only clear or set by the hardware itself, these flags are: kLPSCI_TxDataRegEmptyFlag,
505 kLPSCI_TransmissionCompleteFlag, kLPSCI_RxDataRegFullFlag, kLPSCI_RxActiveFlag,
506 kLPSCI_NoiseErrorInRxDataRegFlag,
507 kLPSCI_ParityErrorInRxDataRegFlag*/
508
509 status = kStatus_LPSCI_FlagCannotClearManually;
510 }
511 else
512 {
513 status = kStatus_Success;
514 }
515
516 return status;
517 }
518
LPSCI_WriteBlocking(UART0_Type * base,const uint8_t * data,size_t length)519 void LPSCI_WriteBlocking(UART0_Type *base, const uint8_t *data, size_t length)
520 {
521 assert(data);
522
523 /* This API can only ensure that the data is written into the data buffer but can't
524 ensure all data in the data buffer are sent into the transmit shift buffer. */
525 while (length--)
526 {
527 while (!(base->S1 & UART0_S1_TDRE_MASK))
528 {
529 }
530 base->D = *(data++);
531 }
532 }
533
LPSCI_ReadBlocking(UART0_Type * base,uint8_t * data,size_t length)534 status_t LPSCI_ReadBlocking(UART0_Type *base, uint8_t *data, size_t length)
535 {
536 assert(data);
537
538 uint32_t statusFlag;
539
540 while (length--)
541 {
542 while (!(base->S1 & UART0_S1_RDRF_MASK))
543 {
544 statusFlag = LPSCI_GetStatusFlags(base);
545
546 if (statusFlag & kLPSCI_RxOverrunFlag)
547 {
548 LPSCI_ClearStatusFlags(base, kLPSCI_RxOverrunFlag);
549 return kStatus_LPSCI_RxHardwareOverrun;
550 }
551
552 if (statusFlag & kLPSCI_NoiseErrorFlag)
553 {
554 LPSCI_ClearStatusFlags(base, kLPSCI_NoiseErrorFlag);
555 return kStatus_LPSCI_NoiseError;
556 }
557
558 if (statusFlag & kLPSCI_FramingErrorFlag)
559 {
560 LPSCI_ClearStatusFlags(base, kLPSCI_FramingErrorFlag);
561 return kStatus_LPSCI_FramingError;
562 }
563
564 if (statusFlag & kLPSCI_ParityErrorFlag)
565 {
566 LPSCI_ClearStatusFlags(base, kLPSCI_ParityErrorFlag);
567 return kStatus_LPSCI_ParityError;
568 }
569 }
570 *(data++) = base->D;
571 }
572
573 return kStatus_Success;
574 }
575
LPSCI_TransferCreateHandle(UART0_Type * base,lpsci_handle_t * handle,lpsci_transfer_callback_t callback,void * userData)576 void LPSCI_TransferCreateHandle(UART0_Type *base,
577 lpsci_handle_t *handle,
578 lpsci_transfer_callback_t callback,
579 void *userData)
580 {
581 assert(handle);
582
583 uint32_t instance;
584
585 /* Zero the handle. */
586 memset(handle, 0, sizeof(lpsci_handle_t));
587
588 /* Set the TX/RX state. */
589 handle->rxState = kLPSCI_RxIdle;
590 handle->txState = kLPSCI_TxIdle;
591
592 /* Set the callback and user data. */
593 handle->callback = callback;
594 handle->userData = userData;
595
596 /* Get instance from peripheral base address. */
597 instance = LPSCI_GetInstance(base);
598
599 /* Save the handle in global variables to support the double weak mechanism. */
600 s_lpsciHandle[instance] = handle;
601
602 s_lpsciIsr = LPSCI_TransferHandleIRQ;
603
604 /* Enable interrupt in NVIC. */
605 EnableIRQ(s_lpsciIRQ[instance]);
606 }
607
LPSCI_TransferStartRingBuffer(UART0_Type * base,lpsci_handle_t * handle,uint8_t * ringBuffer,size_t ringBufferSize)608 void LPSCI_TransferStartRingBuffer(UART0_Type *base, lpsci_handle_t *handle, uint8_t *ringBuffer, size_t ringBufferSize)
609 {
610 assert(handle);
611 assert(ringBuffer);
612
613 /* Setup the ringbuffer address */
614 handle->rxRingBuffer = ringBuffer;
615 handle->rxRingBufferSize = ringBufferSize;
616 handle->rxRingBufferHead = 0U;
617 handle->rxRingBufferTail = 0U;
618
619 /* Enable the interrupt to accept the data when user need the ring buffer. */
620 LPSCI_EnableInterrupts(base, kLPSCI_RxDataRegFullInterruptEnable | kLPSCI_RxOverrunInterruptEnable |
621 kLPSCI_FramingErrorInterruptEnable);
622 /* Enable parity error interrupt when parity mode is enable*/
623 if (UART0_C1_PE_MASK & base->C1)
624 {
625 LPSCI_EnableInterrupts(base, kLPSCI_ParityErrorInterruptEnable);
626 }
627 }
628
LPSCI_TransferStopRingBuffer(UART0_Type * base,lpsci_handle_t * handle)629 void LPSCI_TransferStopRingBuffer(UART0_Type *base, lpsci_handle_t *handle)
630 {
631 assert(handle);
632
633 if (handle->rxState == kLPSCI_RxIdle)
634 {
635 LPSCI_DisableInterrupts(base, kLPSCI_RxDataRegFullInterruptEnable | kLPSCI_RxOverrunInterruptEnable |
636 kLPSCI_FramingErrorInterruptEnable);
637
638 /* Disable parity error interrupt when parity mode is enable*/
639 if (UART0_C1_PE_MASK & base->C1)
640 {
641 LPSCI_DisableInterrupts(base, kLPSCI_ParityErrorInterruptEnable);
642 }
643 }
644
645 handle->rxRingBuffer = NULL;
646 handle->rxRingBufferSize = 0U;
647 handle->rxRingBufferHead = 0U;
648 handle->rxRingBufferTail = 0U;
649 }
650
LPSCI_TransferSendNonBlocking(UART0_Type * base,lpsci_handle_t * handle,lpsci_transfer_t * xfer)651 status_t LPSCI_TransferSendNonBlocking(UART0_Type *base, lpsci_handle_t *handle, lpsci_transfer_t *xfer)
652 {
653 assert(handle);
654 assert(xfer);
655 assert(xfer->dataSize);
656 assert(xfer->data);
657
658 status_t status;
659
660 /* Return error if current TX busy. */
661 if (kLPSCI_TxBusy == handle->txState)
662 {
663 status = kStatus_LPSCI_TxBusy;
664 }
665 else
666 {
667 handle->txData = xfer->data;
668 handle->txDataSize = xfer->dataSize;
669 handle->txDataSizeAll = xfer->dataSize;
670 handle->txState = kLPSCI_TxBusy;
671
672 /* Enable transmiter interrupt. */
673 LPSCI_EnableInterrupts(base, kLPSCI_TxDataRegEmptyInterruptEnable);
674
675 status = kStatus_Success;
676 }
677
678 return status;
679 }
680
LPSCI_TransferAbortSend(UART0_Type * base,lpsci_handle_t * handle)681 void LPSCI_TransferAbortSend(UART0_Type *base, lpsci_handle_t *handle)
682 {
683 assert(handle);
684
685 LPSCI_DisableInterrupts(base, kLPSCI_TxDataRegEmptyInterruptEnable | kLPSCI_TransmissionCompleteInterruptEnable);
686
687 handle->txDataSize = 0;
688 handle->txState = kLPSCI_TxIdle;
689 }
690
LPSCI_TransferGetSendCount(UART0_Type * base,lpsci_handle_t * handle,uint32_t * count)691 status_t LPSCI_TransferGetSendCount(UART0_Type *base, lpsci_handle_t *handle, uint32_t *count)
692 {
693 assert(handle);
694 assert(count);
695
696 if (kLPSCI_TxIdle == handle->txState)
697 {
698 return kStatus_NoTransferInProgress;
699 }
700
701 *count = handle->txDataSizeAll - handle->txDataSize;
702
703 return kStatus_Success;
704 }
705
LPSCI_TransferReceiveNonBlocking(UART0_Type * base,lpsci_handle_t * handle,lpsci_transfer_t * xfer,size_t * receivedBytes)706 status_t LPSCI_TransferReceiveNonBlocking(UART0_Type *base,
707 lpsci_handle_t *handle,
708 lpsci_transfer_t *xfer,
709 size_t *receivedBytes)
710 {
711 assert(handle);
712 assert(xfer);
713 assert(xfer->dataSize);
714 assert(xfer->data);
715
716 uint32_t i;
717 status_t status;
718 /* How many bytes to copy from ring buffer to user memory. */
719 size_t bytesToCopy = 0U;
720 /* How many bytes to receive. */
721 size_t bytesToReceive;
722 /* How many bytes currently have received. */
723 size_t bytesCurrentReceived;
724
725 /* How to get data:
726 1. If RX ring buffer is not enabled, then save xfer->data and xfer->dataSize
727 to lpsci handle, enable interrupt to store received data to xfer->data. When
728 all data received, trigger callback.
729 2. If RX ring buffer is enabled and not empty, get data from ring buffer first.
730 If there are enough data in ring buffer, copy them to xfer->data and return.
731 If there are not enough data in ring buffer, copy all of them to xfer->data,
732 save the xfer->data remained empty space to lpsci handle, receive data
733 to this empty space and trigger callback when finished. */
734
735 if (kLPSCI_RxBusy == handle->rxState)
736 {
737 status = kStatus_LPSCI_RxBusy;
738 }
739 else
740 {
741 bytesToReceive = xfer->dataSize;
742 bytesCurrentReceived = 0U;
743
744 /* If RX ring buffer is used. */
745 if (handle->rxRingBuffer)
746 {
747 /* Disable LPSCI RX IRQ, protect ring buffer. */
748 LPSCI_DisableInterrupts(base, kLPSCI_RxDataRegFullInterruptEnable);
749
750 /* How many bytes in RX ring buffer currently. */
751 bytesToCopy = LPSCI_TransferGetRxRingBufferLength(handle);
752
753 if (bytesToCopy)
754 {
755 bytesToCopy = MIN(bytesToReceive, bytesToCopy);
756
757 bytesToReceive -= bytesToCopy;
758
759 /* Copy data from ring buffer to user memory. */
760 for (i = 0U; i < bytesToCopy; i++)
761 {
762 xfer->data[bytesCurrentReceived++] = handle->rxRingBuffer[handle->rxRingBufferTail];
763
764 /* Wrap to 0. Not use modulo (%) because it might be large and slow. */
765 if (handle->rxRingBufferTail + 1U == handle->rxRingBufferSize)
766 {
767 handle->rxRingBufferTail = 0U;
768 }
769 else
770 {
771 handle->rxRingBufferTail++;
772 }
773 }
774 }
775
776 /* If ring buffer does not have enough data, still need to read more data. */
777 if (bytesToReceive)
778 {
779 /* No data in ring buffer, save the request to lpsci handle. */
780 handle->rxData = xfer->data + bytesCurrentReceived;
781 handle->rxDataSize = bytesToReceive;
782 handle->rxDataSizeAll = bytesToReceive;
783 handle->rxState = kLPSCI_RxBusy;
784 }
785
786 /* Enable LPSCI RX IRQ if previously enabled. */
787 LPSCI_EnableInterrupts(base, kLPSCI_RxDataRegFullInterruptEnable);
788
789 /* Call user callback since all data are received. */
790 if (0 == bytesToReceive)
791 {
792 if (handle->callback)
793 {
794 handle->callback(base, handle, kStatus_LPSCI_RxIdle, handle->userData);
795 }
796 }
797 }
798 /* Ring buffer not used. */
799 else
800 {
801 handle->rxData = xfer->data + bytesCurrentReceived;
802 handle->rxDataSize = bytesToReceive;
803 handle->rxDataSizeAll = bytesToReceive;
804 handle->rxState = kLPSCI_RxBusy;
805
806 /* Enable RX interrupt. */
807 LPSCI_EnableInterrupts(base, kLPSCI_RxDataRegFullInterruptEnable | kLPSCI_RxOverrunInterruptEnable |
808 kLPSCI_FramingErrorInterruptEnable);
809 /* Enable parity error interrupt when parity mode is enable*/
810 if (UART0_C1_PE_MASK & base->C1)
811 {
812 LPSCI_EnableInterrupts(base, kLPSCI_ParityErrorInterruptEnable);
813 }
814 }
815
816 /* Return the how many bytes have read. */
817 if (receivedBytes)
818 {
819 *receivedBytes = bytesCurrentReceived;
820 }
821
822 status = kStatus_Success;
823 }
824
825 return status;
826 }
827
LPSCI_TransferAbortReceive(UART0_Type * base,lpsci_handle_t * handle)828 void LPSCI_TransferAbortReceive(UART0_Type *base, lpsci_handle_t *handle)
829 {
830 assert(handle);
831
832 /* Only abort the receive to handle->rxData, the RX ring buffer is still working. */
833 if (!handle->rxRingBuffer)
834 {
835 /* Disable RX interrupt. */
836 LPSCI_DisableInterrupts(base, kLPSCI_RxDataRegFullInterruptEnable | kLPSCI_RxOverrunInterruptEnable |
837 kLPSCI_FramingErrorInterruptEnable);
838 /* Disable parity error interrupt when parity mode is enable*/
839 if (UART0_C1_PE_MASK & base->C1)
840 {
841 LPSCI_DisableInterrupts(base, kLPSCI_ParityErrorInterruptEnable);
842 }
843 }
844
845 handle->rxDataSize = 0U;
846 handle->rxState = kLPSCI_RxIdle;
847 }
848
LPSCI_TransferGetReceiveCount(UART0_Type * base,lpsci_handle_t * handle,uint32_t * count)849 status_t LPSCI_TransferGetReceiveCount(UART0_Type *base, lpsci_handle_t *handle, uint32_t *count)
850 {
851 assert(handle);
852 assert(count);
853
854 if (kLPSCI_RxIdle == handle->rxState)
855 {
856 return kStatus_NoTransferInProgress;
857 }
858
859 *count = handle->rxDataSizeAll - handle->rxDataSize;
860
861 return kStatus_Success;
862 }
863
LPSCI_TransferHandleIRQ(UART0_Type * base,lpsci_handle_t * handle)864 void LPSCI_TransferHandleIRQ(UART0_Type *base, lpsci_handle_t *handle)
865 {
866 assert(handle);
867
868 uint8_t count;
869 uint8_t tempCount;
870
871 /* If RX parity error */
872 if (UART0_S1_PF_MASK & base->S1)
873 {
874 handle->rxState = kLPSCI_RxParityError;
875
876 LPSCI_ClearStatusFlags(base, kLPSCI_ParityErrorFlag);
877 /* Trigger callback. */
878 if (handle->callback)
879 {
880 handle->callback(base, handle, kStatus_LPSCI_ParityError, handle->userData);
881 }
882 }
883
884 /* If RX framing error */
885 if (UART0_S1_FE_MASK & base->S1)
886 {
887 handle->rxState = kLPSCI_RxFramingError;
888
889 LPSCI_ClearStatusFlags(base, kLPSCI_FramingErrorFlag);
890 /* Trigger callback. */
891 if (handle->callback)
892 {
893 handle->callback(base, handle, kStatus_LPSCI_FramingError, handle->userData);
894 }
895 }
896 /* If RX overrun. */
897 if (UART0_S1_OR_MASK & base->S1)
898 {
899 while (UART0_S1_RDRF_MASK & base->S1)
900 {
901 (void)base->D;
902 }
903
904 LPSCI_ClearStatusFlags(base, kLPSCI_RxOverrunFlag);
905 /* Trigger callback. */
906 if (handle->callback)
907 {
908 handle->callback(base, handle, kStatus_LPSCI_RxHardwareOverrun, handle->userData);
909 }
910 }
911
912 /* Receive data register full */
913 if ((UART0_S1_RDRF_MASK & base->S1) && (UART0_C2_RIE_MASK & base->C2))
914 {
915 /* Get the size that can be stored into buffer for this interrupt. */
916 #if defined(FSL_FEATURE_LPSCI_HAS_FIFO) && FSL_FEATURE_LPSCI_HAS_FIFO
917 count = base->RCFIFO;
918 #else
919 count = 1;
920 #endif
921
922 /* If handle->rxDataSize is not 0, first save data to handle->rxData. */
923 while ((count) && (handle->rxDataSize))
924 {
925 #if defined(FSL_FEATURE_LPSCI_HAS_FIFO) && FSL_FEATURE_LPSCI_HAS_FIFO
926 tempCount = MIN(handle->rxDataSize, count);
927 #else
928 tempCount = 1;
929 #endif
930
931 /* Using non block API to read the data from the registers. */
932 LPSCI_ReadNonBlocking(base, handle->rxData, tempCount);
933 handle->rxData += tempCount;
934 handle->rxDataSize -= tempCount;
935 count -= tempCount;
936
937 /* If all the data required for upper layer is ready, trigger callback. */
938 if (!handle->rxDataSize)
939 {
940 handle->rxState = kLPSCI_RxIdle;
941
942 if (handle->callback)
943 {
944 handle->callback(base, handle, kStatus_LPSCI_RxIdle, handle->userData);
945 }
946 }
947 }
948
949 /* If use RX ring buffer, receive data to ring buffer. */
950 if (handle->rxRingBuffer)
951 {
952 while (count--)
953 {
954 /* If RX ring buffer is full, trigger callback to notify over run. */
955 if (LPSCI_TransferIsRxRingBufferFull(handle))
956 {
957 if (handle->callback)
958 {
959 handle->callback(base, handle, kStatus_LPSCI_RxRingBufferOverrun, handle->userData);
960 }
961 }
962
963 /* If ring buffer is still full after callback function, the oldest data is overrided. */
964 if (LPSCI_TransferIsRxRingBufferFull(handle))
965 {
966 /* Increase handle->rxRingBufferTail to make room for new data. */
967 if (handle->rxRingBufferTail + 1U == handle->rxRingBufferSize)
968 {
969 handle->rxRingBufferTail = 0U;
970 }
971 else
972 {
973 handle->rxRingBufferTail++;
974 }
975 }
976
977 /* Read data. */
978 handle->rxRingBuffer[handle->rxRingBufferHead] = base->D;
979
980 /* Increase handle->rxRingBufferHead. */
981 if (handle->rxRingBufferHead + 1U == handle->rxRingBufferSize)
982 {
983 handle->rxRingBufferHead = 0U;
984 }
985 else
986 {
987 handle->rxRingBufferHead++;
988 }
989 }
990 }
991 /* If no receive requst pending, stop RX interrupt. */
992 else if (!handle->rxDataSize)
993 {
994 LPSCI_DisableInterrupts(base, kLPSCI_RxDataRegFullInterruptEnable | kLPSCI_RxOverrunInterruptEnable |
995 kLPSCI_FramingErrorInterruptEnable);
996
997 /* Disable parity error interrupt when parity mode is enable*/
998 if (UART0_C1_PE_MASK & base->C1)
999 {
1000 LPSCI_DisableInterrupts(base, kLPSCI_ParityErrorInterruptEnable);
1001 }
1002 }
1003 else
1004 {
1005 }
1006 }
1007 /* If framing error or parity error happened, stop the RX interrupt when ues no ring buffer */
1008 if (((handle->rxState == kLPSCI_RxFramingError) || (handle->rxState == kLPSCI_RxParityError)) &&
1009 (!handle->rxRingBuffer))
1010 {
1011 LPSCI_DisableInterrupts(base, kLPSCI_RxDataRegFullInterruptEnable | kLPSCI_RxOverrunInterruptEnable |
1012 kLPSCI_FramingErrorInterruptEnable);
1013
1014 /* Disable parity error interrupt when parity mode is enable*/
1015 if (UART0_C1_PE_MASK & base->C1)
1016 {
1017 LPSCI_DisableInterrupts(base, kLPSCI_ParityErrorInterruptEnable);
1018 }
1019 }
1020
1021 /* Send data register empty and the interrupt is enabled. */
1022 if ((base->S1 & UART0_S1_TDRE_MASK) && (base->C2 & UART0_C2_TIE_MASK))
1023 {
1024 /* Get the bytes that available at this moment. */
1025 #if defined(FSL_FEATURE_LPSCI_HAS_FIFO) && FSL_FEATURE_LPSCI_HAS_FIFO
1026 count = FSL_FEATURE_LPSCI_FIFO_SIZEn(base) - base->TCFIFO;
1027 #else
1028 count = 1;
1029 #endif
1030
1031 while ((count) && (handle->txDataSize))
1032 {
1033 #if defined(FSL_FEATURE_LPSCI_HAS_FIFO) && FSL_FEATURE_LPSCI_HAS_FIFO
1034 tempCount = MIN(handle->txDataSize, count);
1035 #else
1036 tempCount = 1;
1037 #endif
1038
1039 /* Using non block API to write the data to the registers. */
1040 LPSCI_WriteNonBlocking(base, handle->txData, tempCount);
1041 handle->txData += tempCount;
1042 handle->txDataSize -= tempCount;
1043 count -= tempCount;
1044
1045 /* If all the data are written to data register, enable TX complete interrupt. */
1046 if (!handle->txDataSize)
1047 {
1048 handle->txState = kLPSCI_TxIdle;
1049
1050 /* Disable TX register empty interrupt. */
1051 base->C2 &= ~UART0_C2_TIE_MASK;
1052
1053 /* Trigger callback. */
1054 if (handle->callback)
1055 {
1056 handle->callback(base, handle, kStatus_LPSCI_TxIdle, handle->userData);
1057 }
1058 }
1059 }
1060 }
1061 }
1062
LPSCI_TransferHandleErrorIRQ(UART0_Type * base,lpsci_handle_t * handle)1063 void LPSCI_TransferHandleErrorIRQ(UART0_Type *base, lpsci_handle_t *handle)
1064 {
1065 /* To be implemented by User. */
1066 }
1067
1068 #if defined(UART0)
UART0_DriverIRQHandler(void)1069 void UART0_DriverIRQHandler(void)
1070 {
1071 s_lpsciIsr(UART0, s_lpsciHandle[0]);
1072 }
1073
1074 #endif
1075