1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016-2020 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_uart_dma.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.uart_dma"
18 #endif
19
20 /* Array of UART handle. */
21 #if (defined(UART5))
22 #define UART_HANDLE_ARRAY_SIZE 6
23 #else /* UART5 */
24 #if (defined(UART4))
25 #define UART_HANDLE_ARRAY_SIZE 5
26 #else /* UART4 */
27 #if (defined(UART3))
28 #define UART_HANDLE_ARRAY_SIZE 4
29 #else /* UART3 */
30 #if (defined(UART2))
31 #define UART_HANDLE_ARRAY_SIZE 3
32 #else /* UART2 */
33 #if (defined(UART1))
34 #define UART_HANDLE_ARRAY_SIZE 2
35 #else /* UART1 */
36 #if (defined(UART0))
37 #define UART_HANDLE_ARRAY_SIZE 1
38 #else /* UART0 */
39 #error No UART instance.
40 #endif /* UART 0 */
41 #endif /* UART 1 */
42 #endif /* UART 2 */
43 #endif /* UART 3 */
44 #endif /* UART 4 */
45 #endif /* UART 5 */
46
47 /*<! Structure definition for uart_dma_handle_t. The structure is private. */
48 typedef struct _uart_dma_private_handle
49 {
50 UART_Type *base;
51 uart_dma_handle_t *handle;
52 } uart_dma_private_handle_t;
53
54 /* UART DMA transfer handle. */
55 enum
56 {
57 kUART_TxIdle, /* TX idle. */
58 kUART_TxBusy, /* TX busy. */
59 kUART_RxIdle, /* RX idle. */
60 kUART_RxBusy /* RX busy. */
61 };
62
63 /*******************************************************************************
64 * Variables
65 ******************************************************************************/
66
67 /*<! Private handle only used for internally. */
68 static uart_dma_private_handle_t s_dmaPrivateHandle[UART_HANDLE_ARRAY_SIZE];
69
70 /*******************************************************************************
71 * Prototypes
72 ******************************************************************************/
73
74 /*!
75 * @brief UART DMA send finished callback function.
76 *
77 * This function is called when UART DMA send finished. It disables the UART
78 * TX DMA request and sends @ref kStatus_UART_TxIdle to UART callback.
79 *
80 * @param handle The DMA handle.
81 * @param param Callback function parameter.
82 */
83 static void UART_TransferSendDMACallback(dma_handle_t *handle, void *param);
84
85 /*!
86 * @brief UART DMA receive finished callback function.
87 *
88 * This function is called when UART DMA receive finished. It disables the UART
89 * RX DMA request and sends @ref kStatus_UART_RxIdle to UART callback.
90 *
91 * @param handle The DMA handle.
92 * @param param Callback function parameter.
93 */
94 static void UART_TransferReceiveDMACallback(dma_handle_t *handle, void *param);
95
96 /*******************************************************************************
97 * Code
98 ******************************************************************************/
99
UART_TransferSendDMACallback(dma_handle_t * handle,void * param)100 static void UART_TransferSendDMACallback(dma_handle_t *handle, void *param)
101 {
102 assert(handle != NULL);
103 assert(param != NULL);
104
105 uart_dma_private_handle_t *uartPrivateHandle = (uart_dma_private_handle_t *)param;
106
107 /* Disable UART TX DMA. */
108 UART_EnableTxDMA(uartPrivateHandle->base, false);
109
110 /* Disable interrupt. */
111 DMA_DisableInterrupts(handle->base, handle->channel);
112
113 /* Enable tx complete interrupt */
114 UART_EnableInterrupts(uartPrivateHandle->base, (uint32_t)kUART_TransmissionCompleteInterruptEnable);
115 }
116
UART_TransferReceiveDMACallback(dma_handle_t * handle,void * param)117 static void UART_TransferReceiveDMACallback(dma_handle_t *handle, void *param)
118 {
119 assert(handle != NULL);
120 assert(param != NULL);
121
122 uart_dma_private_handle_t *uartPrivateHandle = (uart_dma_private_handle_t *)param;
123
124 /* Disable UART RX DMA. */
125 UART_EnableRxDMA(uartPrivateHandle->base, false);
126
127 /* Disable interrupt. */
128 DMA_DisableInterrupts(handle->base, handle->channel);
129
130 uartPrivateHandle->handle->rxState = (uint8_t)kUART_RxIdle;
131
132 if (uartPrivateHandle->handle->callback != NULL)
133 {
134 uartPrivateHandle->handle->callback(uartPrivateHandle->base, uartPrivateHandle->handle, kStatus_UART_RxIdle,
135 uartPrivateHandle->handle->userData);
136 }
137 }
138
139 /*!
140 * brief Initializes the UART handle which is used in transactional functions and sets the callback.
141 *
142 * param base UART peripheral base address.
143 * param handle Pointer to the uart_dma_handle_t structure.
144 * param callback UART callback, NULL means no callback.
145 * param userData User callback function data.
146 * param rxDmaHandle User requested DMA handle for the RX DMA transfer.
147 * param txDmaHandle User requested DMA handle for the TX DMA transfer.
148 */
UART_TransferCreateHandleDMA(UART_Type * base,uart_dma_handle_t * handle,uart_dma_transfer_callback_t callback,void * userData,dma_handle_t * txDmaHandle,dma_handle_t * rxDmaHandle)149 void UART_TransferCreateHandleDMA(UART_Type *base,
150 uart_dma_handle_t *handle,
151 uart_dma_transfer_callback_t callback,
152 void *userData,
153 dma_handle_t *txDmaHandle,
154 dma_handle_t *rxDmaHandle)
155 {
156 assert(handle != NULL);
157
158 uint32_t instance = UART_GetInstance(base);
159
160 (void)memset(handle, 0, sizeof(*handle));
161
162 s_dmaPrivateHandle[instance].base = base;
163 s_dmaPrivateHandle[instance].handle = handle;
164
165 handle->rxState = (uint8_t)kUART_RxIdle;
166 handle->txState = (uint8_t)kUART_TxIdle;
167
168 handle->callback = callback;
169 handle->userData = userData;
170
171 #if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
172 /* Note:
173 Take care of the RX FIFO, DMA request only assert when received bytes
174 equal or more than RX water mark, there is potential issue if RX water
175 mark larger than 1.
176 For example, if RX FIFO water mark is 2, upper layer needs 5 bytes and
177 5 bytes are received. the last byte will be saved in FIFO but not trigger
178 DMA transfer because the water mark is 2.
179 */
180 if (rxDmaHandle != NULL)
181 {
182 base->RWFIFO = 1U;
183 }
184 #endif
185
186 handle->rxDmaHandle = rxDmaHandle;
187 handle->txDmaHandle = txDmaHandle;
188
189 /* Save the handle in global variables to support the double weak mechanism. */
190 s_uartHandle[instance] = handle;
191 /* Save IRQ handler into static ISR function pointer. */
192 s_uartIsr = UART_TransferDMAHandleIRQ;
193 /* Disable internal IRQs and enable global IRQ. */
194 UART_DisableInterrupts(base, (uint32_t)kUART_AllInterruptsEnable);
195 (void)EnableIRQ(s_uartIRQ[instance]);
196
197 /* Configure TX. */
198 if (txDmaHandle != NULL)
199 {
200 DMA_SetCallback(txDmaHandle, UART_TransferSendDMACallback, &s_dmaPrivateHandle[instance]);
201 }
202
203 /* Configure RX. */
204 if (rxDmaHandle != NULL)
205 {
206 DMA_SetCallback(rxDmaHandle, UART_TransferReceiveDMACallback, &s_dmaPrivateHandle[instance]);
207 }
208 }
209
210 /*!
211 * brief Sends data using DMA.
212 *
213 * This function sends data using DMA. This is non-blocking function, which returns
214 * right away. When all data is sent, the send callback function is called.
215 *
216 * param base UART peripheral base address.
217 * param handle UART handle pointer.
218 * param xfer UART DMA transfer structure. See #uart_transfer_t.
219 * retval kStatus_Success if succeeded; otherwise failed.
220 * retval kStatus_UART_TxBusy Previous transfer ongoing.
221 * retval kStatus_InvalidArgument Invalid argument.
222 */
UART_TransferSendDMA(UART_Type * base,uart_dma_handle_t * handle,uart_transfer_t * xfer)223 status_t UART_TransferSendDMA(UART_Type *base, uart_dma_handle_t *handle, uart_transfer_t *xfer)
224 {
225 assert(handle != NULL);
226 assert(handle->txDmaHandle != NULL);
227 assert(xfer != NULL);
228 assert(xfer->data != NULL);
229 assert(xfer->dataSize != 0U);
230
231 dma_transfer_config_t xferConfig;
232 status_t status;
233
234 /* If previous TX not finished. */
235 if ((uint8_t)kUART_TxBusy == handle->txState)
236 {
237 status = kStatus_UART_TxBusy;
238 }
239 else
240 {
241 handle->txState = (uint8_t)kUART_TxBusy;
242 handle->txDataSizeAll = xfer->dataSize;
243
244 /* Prepare transfer. */
245 DMA_PrepareTransfer(&xferConfig, xfer->data, sizeof(uint8_t), (uint32_t *)UART_GetDataRegisterAddress(base),
246 sizeof(uint8_t), xfer->dataSize, kDMA_MemoryToPeripheral);
247
248 /* Submit transfer. */
249 (void)DMA_SubmitTransfer(handle->txDmaHandle, &xferConfig, (uint32_t)kDMA_EnableInterrupt);
250 DMA_StartTransfer(handle->txDmaHandle);
251
252 /* Enable UART TX DMA. */
253 UART_EnableTxDMA(base, true);
254
255 status = kStatus_Success;
256 }
257
258 return status;
259 }
260
261 /*!
262 * brief Receives data using DMA.
263 *
264 * This function receives data using DMA. This is non-blocking function, which returns
265 * right away. When all data is received, the receive callback function is called.
266 *
267 * param base UART peripheral base address.
268 * param handle Pointer to the uart_dma_handle_t structure.
269 * param xfer UART DMA transfer structure. See #uart_transfer_t.
270 * retval kStatus_Success if succeeded; otherwise failed.
271 * retval kStatus_UART_RxBusy Previous transfer on going.
272 * retval kStatus_InvalidArgument Invalid argument.
273 */
UART_TransferReceiveDMA(UART_Type * base,uart_dma_handle_t * handle,uart_transfer_t * xfer)274 status_t UART_TransferReceiveDMA(UART_Type *base, uart_dma_handle_t *handle, uart_transfer_t *xfer)
275 {
276 assert(handle != NULL);
277 assert(handle->rxDmaHandle != NULL);
278 assert(xfer != NULL);
279 assert(xfer->data != NULL);
280 assert(xfer->dataSize != 0U);
281
282 dma_transfer_config_t xferConfig;
283 status_t status;
284
285 /* If previous RX not finished. */
286 if ((uint8_t)kUART_RxBusy == handle->rxState)
287 {
288 status = kStatus_UART_RxBusy;
289 }
290 else
291 {
292 handle->rxState = (uint8_t)kUART_RxBusy;
293 handle->rxDataSizeAll = xfer->dataSize;
294
295 /* Prepare transfer. */
296 DMA_PrepareTransfer(&xferConfig, (uint32_t *)UART_GetDataRegisterAddress(base), sizeof(uint8_t), xfer->data,
297 sizeof(uint8_t), xfer->dataSize, kDMA_PeripheralToMemory);
298
299 /* Submit transfer. */
300 (void)DMA_SubmitTransfer(handle->rxDmaHandle, &xferConfig, (uint32_t)kDMA_EnableInterrupt);
301 DMA_StartTransfer(handle->rxDmaHandle);
302
303 /* Enable UART RX DMA. */
304 UART_EnableRxDMA(base, true);
305
306 status = kStatus_Success;
307 }
308
309 return status;
310 }
311
312 /*!
313 * brief Aborts the send data using DMA.
314 *
315 * This function aborts the sent data using DMA.
316 *
317 * param base UART peripheral base address.
318 * param handle Pointer to uart_dma_handle_t structure.
319 */
UART_TransferAbortSendDMA(UART_Type * base,uart_dma_handle_t * handle)320 void UART_TransferAbortSendDMA(UART_Type *base, uart_dma_handle_t *handle)
321 {
322 assert(handle != NULL);
323 assert(handle->txDmaHandle != NULL);
324
325 /* Disable UART TX DMA. */
326 UART_EnableTxDMA(base, false);
327
328 /* Stop transfer. */
329 DMA_AbortTransfer(handle->txDmaHandle);
330
331 /* Write DMA->DSR[DONE] to abort transfer and clear status. */
332 DMA_ClearChannelStatusFlags(handle->txDmaHandle->base, handle->txDmaHandle->channel,
333 (uint32_t)kDMA_TransactionsDoneFlag);
334
335 handle->txState = (uint8_t)kUART_TxIdle;
336 }
337
338 /*!
339 * brief Aborts the received data using DMA.
340 *
341 * This function abort receive data which using DMA.
342 *
343 * param base UART peripheral base address.
344 * param handle Pointer to uart_dma_handle_t structure.
345 */
UART_TransferAbortReceiveDMA(UART_Type * base,uart_dma_handle_t * handle)346 void UART_TransferAbortReceiveDMA(UART_Type *base, uart_dma_handle_t *handle)
347 {
348 assert(handle != NULL);
349 assert(handle->rxDmaHandle != NULL);
350
351 /* Disable UART RX DMA. */
352 UART_EnableRxDMA(base, false);
353
354 /* Stop transfer. */
355 DMA_AbortTransfer(handle->rxDmaHandle);
356
357 /* Write DMA->DSR[DONE] to abort transfer and clear status. */
358 DMA_ClearChannelStatusFlags(handle->rxDmaHandle->base, handle->rxDmaHandle->channel,
359 (uint32_t)kDMA_TransactionsDoneFlag);
360
361 handle->rxState = (uint8_t)kUART_RxIdle;
362 }
363
364 /*!
365 * brief Gets the number of bytes written to UART TX register.
366 *
367 * This function gets the number of bytes written to UART TX
368 * register by DMA.
369 *
370 * param base UART peripheral base address.
371 * param handle UART handle pointer.
372 * param count Send bytes count.
373 * retval kStatus_NoTransferInProgress No send in progress.
374 * retval kStatus_InvalidArgument Parameter is invalid.
375 * retval kStatus_Success Get successfully through the parameter \p count;
376 */
UART_TransferGetSendCountDMA(UART_Type * base,uart_dma_handle_t * handle,uint32_t * count)377 status_t UART_TransferGetSendCountDMA(UART_Type *base, uart_dma_handle_t *handle, uint32_t *count)
378 {
379 assert(handle != NULL);
380 assert(handle->txDmaHandle != NULL);
381 assert(count != NULL);
382
383 if ((uint8_t)kUART_TxIdle == handle->txState)
384 {
385 return kStatus_NoTransferInProgress;
386 }
387
388 *count = handle->txDataSizeAll - DMA_GetRemainingBytes(handle->txDmaHandle->base, handle->txDmaHandle->channel);
389
390 return kStatus_Success;
391 }
392
393 /*!
394 * brief Gets the number of bytes that have been received.
395 *
396 * This function gets the number of bytes that have been received.
397 *
398 * param base UART peripheral base address.
399 * param handle UART handle pointer.
400 * param count Receive bytes count.
401 * retval kStatus_NoTransferInProgress No receive in progress.
402 * retval kStatus_InvalidArgument Parameter is invalid.
403 * retval kStatus_Success Get successfully through the parameter \p count;
404 */
UART_TransferGetReceiveCountDMA(UART_Type * base,uart_dma_handle_t * handle,uint32_t * count)405 status_t UART_TransferGetReceiveCountDMA(UART_Type *base, uart_dma_handle_t *handle, uint32_t *count)
406 {
407 assert(handle != NULL);
408 assert(handle->rxDmaHandle != NULL);
409 assert(count != NULL);
410
411 if ((uint8_t)kUART_RxIdle == handle->rxState)
412 {
413 return kStatus_NoTransferInProgress;
414 }
415
416 *count = handle->rxDataSizeAll - DMA_GetRemainingBytes(handle->rxDmaHandle->base, handle->rxDmaHandle->channel);
417
418 return kStatus_Success;
419 }
420
UART_TransferDMAHandleIRQ(UART_Type * base,void * uartDmaHandle)421 void UART_TransferDMAHandleIRQ(UART_Type *base, void *uartDmaHandle)
422 {
423 assert(uartDmaHandle != NULL);
424
425 uart_dma_handle_t *handle = (uart_dma_handle_t *)uartDmaHandle;
426
427 handle->txState = (uint8_t)kUART_TxIdle;
428
429 /* Disable tx complete interrupt */
430 UART_DisableInterrupts(base, (uint32_t)kUART_TransmissionCompleteInterruptEnable);
431
432 if (handle->callback != NULL)
433 {
434 handle->callback(base, handle, kStatus_UART_TxIdle, handle->userData);
435 }
436 }
437