1 /*
2 * Copyright (c) 2016, Freescale Semiconductor, Inc.
3 * Copyright 2016-2022 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_dma.h"
10 #include "fsl_i2s_dma.h"
11 #include "fsl_flexcomm.h"
12 #include <string.h>
13
14 /*******************************************************************************
15 * Definitions
16 ******************************************************************************/
17
18 /* Component ID definition, used by tools. */
19 #ifndef FSL_COMPONENT_ID
20 #define FSL_COMPONENT_ID "platform.drivers.flexcomm_i2s_dma"
21 #endif
22
23 #define DMA_MAX_TRANSFER_BYTES (DMA_MAX_TRANSFER_COUNT * sizeof(uint32_t))
24 #define DMA_DESCRIPTORS (2U)
25
26 /*<! @brief Structure for statically allocated private data. */
27 typedef struct _i2s_dma_private_handle
28 {
29 I2S_Type *base; /*!< I2S base address */
30 i2s_dma_handle_t *handle; /*!< I2S handle */
31
32 volatile uint16_t enqueuedBytes[DMA_DESCRIPTORS]; /*!< Number of bytes being transferred by DMA descriptors */
33 volatile uint8_t enqueuedBytesStart; /*!< First item in enqueuedBytes (for reading) */
34 volatile uint8_t enqueuedBytesEnd; /*!< Last item in enqueuedBytes (for adding) */
35
36 volatile uint8_t
37 dmaDescriptorsUsed; /*!< Number of DMA descriptors with valid data (in queue, excluding initial descriptor) */
38 volatile uint8_t descriptor; /*!< Index of next DMA descriptor in s_DmaDescriptors to be configured with data (does
39 not include I2S instance offset) */
40
41 volatile uint8_t queueDescriptor; /*!< Queue index of buffer to be actually consumed by DMA
42 * (queueUser - advanced when user adds a buffer,
43 * queueDescriptor - advanced when user buffer queued to DMA,
44 * queueDriver - advanced when DMA queued buffer sent out to I2S) */
45 volatile i2s_transfer_t descriptorQueue[I2S_NUM_BUFFERS]; /*!< Transfer data to be queued to DMA */
46
47 volatile bool intA; /*!< If next scheduled DMA transfer will cause interrupt A or B */
48 } i2s_dma_private_handle_t;
49
50 /*! @brief I2S DMA transfer private state. */
51 enum _i2s_dma_state
52 {
53 kI2S_DmaStateIdle = 0x0U, /*!< I2S is in idle state */
54 kI2S_DmaStateTx, /*!< I2S is busy transmitting data */
55 kI2S_DmaStateRx, /*!< I2S is busy receiving data */
56 kI2S_DmaStateBusyLoopTransfer, /*!< I2S is busy loop transfer */
57 };
58
59 /*******************************************************************************
60 * Prototypes
61 ******************************************************************************/
62
63 static status_t I2S_EnqueueUserBuffer(I2S_Type *base, i2s_dma_handle_t *handle, i2s_transfer_t transfer);
64 static uint32_t I2S_GetInstance(I2S_Type *base);
65 static inline void I2S_DisableDMAInterrupts(i2s_dma_handle_t *handle);
66 static inline void I2S_EnableDMAInterrupts(i2s_dma_handle_t *handle);
67 static void I2S_TxEnableDMA(I2S_Type *base, bool enable);
68 static void I2S_RxEnableDMA(I2S_Type *base, bool enable);
69 static uint16_t I2S_GetTransferBytes(volatile i2s_transfer_t *transfer);
70 static status_t I2S_StartTransferDMA(I2S_Type *base, i2s_dma_handle_t *handle);
71 static void I2S_AddTransferDMA(I2S_Type *base, i2s_dma_handle_t *handle);
72
73 /*******************************************************************************
74 * Variables
75 ******************************************************************************/
76 /*<! @brief Allocate DMA transfer descriptors. */
77 #if (defined(CPU_MIMXRT685SEVKA_dsp) || defined(CPU_MIMXRT685SFVKB_dsp))
78 AT_NONCACHEABLE_SECTION_ALIGN(static dma_descriptor_t s_DmaDescriptors[DMA_DESCRIPTORS * FSL_FEATURE_SOC_I2S_COUNT],
79 FSL_FEATURE_DMA_LINK_DESCRIPTOR_ALIGN_SIZE);
80 #else
81 SDK_ALIGN(static dma_descriptor_t s_DmaDescriptors[DMA_DESCRIPTORS * FSL_FEATURE_SOC_I2S_COUNT],
82 FSL_FEATURE_DMA_LINK_DESCRIPTOR_ALIGN_SIZE);
83 #endif
84
85 /*<! @brief Buffer with dummy TX data. */
86 SDK_ALIGN(static uint32_t s_DummyBufferTx, 4U);
87
88 /*<! @brief Buffer to fill with RX data to discard. */
89 SDK_ALIGN(static uint32_t s_DummyBufferRx, 4U);
90
91 /*<! @brief Private array of data associated with available I2S peripherals. */
92 static i2s_dma_private_handle_t s_DmaPrivateHandle[FSL_FEATURE_SOC_I2S_COUNT];
93
94 /*<! @brief Base addresses of available I2S peripherals. */
95 static const uint32_t s_I2sBaseAddrs[FSL_FEATURE_SOC_I2S_COUNT] = I2S_BASE_ADDRS;
96
97 /*******************************************************************************
98 * Code
99 ******************************************************************************/
100
I2S_EnqueueUserBuffer(I2S_Type * base,i2s_dma_handle_t * handle,i2s_transfer_t transfer)101 static status_t I2S_EnqueueUserBuffer(I2S_Type *base, i2s_dma_handle_t *handle, i2s_transfer_t transfer)
102 {
103 uint32_t instance = I2S_GetInstance(base);
104 i2s_dma_private_handle_t *privateHandle = &(s_DmaPrivateHandle[instance]);
105
106 /* Validate input data and transfer buffer */
107
108 assert(handle != NULL);
109 if (handle == NULL)
110 {
111 return kStatus_InvalidArgument;
112 }
113
114 assert((((uint32_t)transfer.data) % 4U) == 0U);
115 if ((((uint32_t)transfer.data) % 4U) != 0U)
116 {
117 /* Data not 4-bytes aligned */
118 return kStatus_InvalidArgument;
119 }
120
121 assert(transfer.dataSize != 0U);
122 if (transfer.dataSize == 0U)
123 {
124 /* No data to send or receive */
125 return kStatus_InvalidArgument;
126 }
127
128 assert((transfer.dataSize % 4U) == 0U);
129 if ((transfer.dataSize % 4U) != 0U)
130 {
131 /* Data length not multiply of 4 bytes */
132 return kStatus_InvalidArgument;
133 }
134
135 if (handle->i2sQueue[handle->queueUser].dataSize != 0UL)
136 {
137 /* Previously prepared buffers not processed yet, reject request */
138 return kStatus_I2S_Busy;
139 }
140
141 /* Enqueue data */
142 privateHandle->descriptorQueue[handle->queueUser].data = transfer.data;
143 privateHandle->descriptorQueue[handle->queueUser].dataSize = transfer.dataSize;
144 handle->i2sQueue[handle->queueUser].data = transfer.data;
145 handle->i2sQueue[handle->queueUser].dataSize = transfer.dataSize;
146 handle->queueUser = (handle->queueUser + 1U) % I2S_NUM_BUFFERS;
147
148 return kStatus_Success;
149 }
150
I2S_GetInstance(I2S_Type * base)151 static uint32_t I2S_GetInstance(I2S_Type *base)
152 {
153 uint32_t i;
154
155 for (i = 0U; i < ARRAY_SIZE(s_I2sBaseAddrs); i++)
156 {
157 if ((uint32_t)base == s_I2sBaseAddrs[i])
158 {
159 return i;
160 }
161 }
162
163 assert(false);
164 return 0U;
165 }
166
I2S_DisableDMAInterrupts(i2s_dma_handle_t * handle)167 static inline void I2S_DisableDMAInterrupts(i2s_dma_handle_t *handle)
168 {
169 DMA_DisableChannelInterrupts(handle->dmaHandle->base, handle->dmaHandle->channel);
170 }
171
I2S_EnableDMAInterrupts(i2s_dma_handle_t * handle)172 static inline void I2S_EnableDMAInterrupts(i2s_dma_handle_t *handle)
173 {
174 if (handle->state != (uint32_t)kI2S_DmaStateIdle)
175 {
176 DMA_EnableChannelInterrupts(handle->dmaHandle->base, handle->dmaHandle->channel);
177 }
178 }
179
180 /*!
181 * brief Initializes handle for transfer of audio data.
182 *
183 * param base I2S base pointer.
184 * param handle pointer to handle structure.
185 * param dmaHandle pointer to dma handle structure.
186 * param callback function to be called back when transfer is done or fails.
187 * param userData pointer to data passed to callback.
188 */
I2S_TxTransferCreateHandleDMA(I2S_Type * base,i2s_dma_handle_t * handle,dma_handle_t * dmaHandle,i2s_dma_transfer_callback_t callback,void * userData)189 void I2S_TxTransferCreateHandleDMA(I2S_Type *base,
190 i2s_dma_handle_t *handle,
191 dma_handle_t *dmaHandle,
192 i2s_dma_transfer_callback_t callback,
193 void *userData)
194 {
195 assert(handle != NULL);
196 assert(dmaHandle != NULL);
197
198 uint32_t instance = I2S_GetInstance(base);
199 i2s_dma_private_handle_t *privateHandle = &(s_DmaPrivateHandle[instance]);
200
201 (void)memset(handle, 0, sizeof(*handle));
202 handle->state = (uint32_t)kI2S_DmaStateIdle;
203 handle->dmaHandle = dmaHandle;
204 handle->completionCallback = callback;
205 handle->userData = userData;
206
207 handle->bytesPerFrame = (uint8_t)((((base->CFG1 & I2S_CFG1_DATALEN_MASK) >> I2S_CFG1_DATALEN_SHIFT) + 1U) / 8U);
208 /* if one channel is disabled, bytesPerFrame should be 4U, user should pay attention that when data length is
209 * shorter than 16, the data format: left data put in 0-15 bit and right data should put in 16-31
210 */
211 if (((base->CFG1 & I2S_CFG1_ONECHANNEL_MASK) == 0U))
212 {
213 handle->bytesPerFrame = 4U;
214 }
215 /* since DMA do not support 24bit transfer width, use 32bit instead */
216 if (handle->bytesPerFrame == 3U)
217 {
218 handle->bytesPerFrame = 4U;
219 }
220
221 (void)memset(privateHandle, 0, sizeof(*privateHandle));
222 privateHandle->base = base;
223 privateHandle->handle = handle;
224
225 DMA_SetCallback(dmaHandle, I2S_DMACallback, privateHandle);
226 }
227
228 /*!
229 * brief Begins or queue sending of the given data.
230 *
231 * param base I2S base pointer.
232 * param handle pointer to handle structure.
233 * param transfer data buffer.
234 *
235 * retval kStatus_Success
236 * retval kStatus_I2S_Busy if all queue slots are occupied with unsent buffers.
237 */
I2S_TxTransferSendDMA(I2S_Type * base,i2s_dma_handle_t * handle,i2s_transfer_t transfer)238 status_t I2S_TxTransferSendDMA(I2S_Type *base, i2s_dma_handle_t *handle, i2s_transfer_t transfer)
239 {
240 status_t status;
241
242 I2S_DisableDMAInterrupts(handle);
243
244 /* Enqueue transfer buffer */
245 status = I2S_EnqueueUserBuffer(base, handle, transfer);
246 if (status != kStatus_Success)
247 {
248 I2S_EnableDMAInterrupts(handle);
249 return status;
250 }
251
252 /* Initialize DMA transfer */
253 if (handle->state == (uint32_t)kI2S_DmaStateIdle)
254 {
255 handle->state = (uint32_t)kI2S_DmaStateTx;
256 status = I2S_StartTransferDMA(base, handle);
257 if (status != kStatus_Success)
258 {
259 I2S_EnableDMAInterrupts(handle);
260 return status;
261 }
262 }
263
264 I2S_AddTransferDMA(base, handle);
265 I2S_EnableDMAInterrupts(handle);
266
267 return kStatus_Success;
268 }
269
270 /*!
271 * brief Aborts transfer of data.
272 *
273 * param base I2S base pointer.
274 * param handle pointer to handle structure.
275 */
I2S_TransferAbortDMA(I2S_Type * base,i2s_dma_handle_t * handle)276 void I2S_TransferAbortDMA(I2S_Type *base, i2s_dma_handle_t *handle)
277 {
278 assert(handle != NULL);
279 assert(handle->dmaHandle != NULL);
280
281 uint32_t instance = I2S_GetInstance(base);
282 i2s_dma_private_handle_t *privateHandle = &(s_DmaPrivateHandle[instance]);
283
284 I2S_DisableDMAInterrupts(handle);
285
286 /* Abort operation */
287 DMA_AbortTransfer(handle->dmaHandle);
288
289 if (handle->state == (uint32_t)kI2S_DmaStateTx)
290 {
291 /* Disable TX */
292 I2S_TxEnableDMA(base, false);
293 }
294 else
295 {
296 /* Disable RX */
297 I2S_RxEnableDMA(base, false);
298 }
299
300 I2S_Disable(base);
301
302 /* Reset state */
303 handle->state = (uint32_t)kI2S_DmaStateIdle;
304
305 /* Clear transfer queue */
306 (void)memset((void *)&(handle->i2sQueue), 0, sizeof(handle->i2sQueue));
307 handle->queueDriver = 0U;
308 handle->queueUser = 0U;
309
310 /* Clear internal state */
311 (void)memset((void *)&(privateHandle->descriptorQueue), 0, sizeof(privateHandle->descriptorQueue));
312 (void)memset((void *)&(privateHandle->enqueuedBytes), 0, sizeof(privateHandle->enqueuedBytes));
313 privateHandle->enqueuedBytesStart = 0U;
314 privateHandle->enqueuedBytesEnd = 0U;
315 privateHandle->dmaDescriptorsUsed = 0U;
316 privateHandle->descriptor = 0U;
317 privateHandle->queueDescriptor = 0U;
318 privateHandle->intA = false;
319 }
320
321 /*!
322 * brief Initializes handle for reception of audio data.
323 *
324 * param base I2S base pointer.
325 * param handle pointer to handle structure.
326 * param dmaHandle pointer to dma handle structure.
327 * param callback function to be called back when transfer is done or fails.
328 * param userData pointer to data passed to callback.
329 */
I2S_RxTransferCreateHandleDMA(I2S_Type * base,i2s_dma_handle_t * handle,dma_handle_t * dmaHandle,i2s_dma_transfer_callback_t callback,void * userData)330 void I2S_RxTransferCreateHandleDMA(I2S_Type *base,
331 i2s_dma_handle_t *handle,
332 dma_handle_t *dmaHandle,
333 i2s_dma_transfer_callback_t callback,
334 void *userData)
335 {
336 I2S_TxTransferCreateHandleDMA(base, handle, dmaHandle, callback, userData);
337 }
338
339 /*!
340 * brief Begins or queue reception of data into given buffer.
341 *
342 * param base I2S base pointer.
343 * param handle pointer to handle structure.
344 * param transfer data buffer.
345 *
346 * retval kStatus_Success
347 * retval kStatus_I2S_Busy if all queue slots are occupied with buffers
348 * which are not full.
349 */
I2S_RxTransferReceiveDMA(I2S_Type * base,i2s_dma_handle_t * handle,i2s_transfer_t transfer)350 status_t I2S_RxTransferReceiveDMA(I2S_Type *base, i2s_dma_handle_t *handle, i2s_transfer_t transfer)
351 {
352 status_t status;
353
354 I2S_DisableDMAInterrupts(handle);
355
356 /* Enqueue transfer buffer */
357 status = I2S_EnqueueUserBuffer(base, handle, transfer);
358 if (status != kStatus_Success)
359 {
360 I2S_EnableDMAInterrupts(handle);
361 return status;
362 }
363
364 /* Initialize DMA transfer */
365 if (handle->state == (uint32_t)kI2S_DmaStateIdle)
366 {
367 handle->state = (uint32_t)kI2S_DmaStateRx;
368 status = I2S_StartTransferDMA(base, handle);
369 if (status != kStatus_Success)
370 {
371 I2S_EnableDMAInterrupts(handle);
372 return status;
373 }
374 }
375
376 I2S_AddTransferDMA(base, handle);
377 I2S_EnableDMAInterrupts(handle);
378
379 return kStatus_Success;
380 }
381
I2S_TxEnableDMA(I2S_Type * base,bool enable)382 static void I2S_TxEnableDMA(I2S_Type *base, bool enable)
383 {
384 if (enable)
385 {
386 base->FIFOCFG |= I2S_FIFOCFG_DMATX_MASK;
387 }
388 else
389 {
390 base->FIFOCFG &= (~I2S_FIFOCFG_DMATX_MASK);
391 base->FIFOCFG |= I2S_FIFOCFG_EMPTYTX_MASK;
392 }
393 }
394
I2S_RxEnableDMA(I2S_Type * base,bool enable)395 static void I2S_RxEnableDMA(I2S_Type *base, bool enable)
396 {
397 if (enable)
398 {
399 base->FIFOCFG |= I2S_FIFOCFG_DMARX_MASK;
400 }
401 else
402 {
403 base->FIFOCFG &= (~I2S_FIFOCFG_DMARX_MASK);
404 base->FIFOCFG |= I2S_FIFOCFG_EMPTYRX_MASK;
405 }
406 }
407
I2S_GetTransferBytes(volatile i2s_transfer_t * transfer)408 static uint16_t I2S_GetTransferBytes(volatile i2s_transfer_t *transfer)
409 {
410 assert(transfer != NULL);
411
412 uint16_t transferBytes;
413
414 if (transfer->dataSize >= (2UL * DMA_MAX_TRANSFER_BYTES))
415 {
416 transferBytes = DMA_MAX_TRANSFER_BYTES;
417 }
418 else if (transfer->dataSize > DMA_MAX_TRANSFER_BYTES)
419 {
420 transferBytes = (uint16_t)(transfer->dataSize / 2U);
421 if ((transferBytes % 4U) != 0U)
422 {
423 transferBytes -= (transferBytes % 4U);
424 }
425 }
426 else
427 {
428 transferBytes = (uint16_t)transfer->dataSize;
429 }
430
431 return transferBytes;
432 }
433
434 /*!
435 * brief Install DMA descriptor memory for loop transfer only.
436 *
437 * This function used to register DMA descriptor memory for the i2s loop dma transfer.
438 *
439 * It must be callbed before I2S_TransferSendLoopDMA/I2S_TransferReceiveLoopDMA and after
440 * I2S_RxTransferCreateHandleDMA/I2S_TxTransferCreateHandleDMA.
441 *
442 * User should be take care about the address of DMA descriptor pool which required align with 16BYTE at least.
443 *
444 * param handle Pointer to i2s DMA transfer handle.
445 * param dmaDescriptorAddr DMA descriptor start address.
446 * param dmaDescriptorNum DMA descriptor number.
447 */
I2S_TransferInstallLoopDMADescriptorMemory(i2s_dma_handle_t * handle,void * dmaDescriptorAddr,size_t dmaDescriptorNum)448 void I2S_TransferInstallLoopDMADescriptorMemory(i2s_dma_handle_t *handle,
449 void *dmaDescriptorAddr,
450 size_t dmaDescriptorNum)
451 {
452 assert(handle != NULL);
453 assert((((uint32_t)(uint32_t *)dmaDescriptorAddr) & ((uint32_t)FSL_FEATURE_DMA_LINK_DESCRIPTOR_ALIGN_SIZE - 1UL)) ==
454 0UL);
455
456 handle->i2sLoopDMADescriptor = (dma_descriptor_t *)dmaDescriptorAddr;
457 handle->i2sLoopDMADescriptorNum = dmaDescriptorNum;
458 }
459
I2S_TransferLoopDMA(I2S_Type * base,i2s_dma_handle_t * handle,i2s_transfer_t * xfer,uint32_t loopTransferCount)460 static status_t I2S_TransferLoopDMA(I2S_Type *base,
461 i2s_dma_handle_t *handle,
462 i2s_transfer_t *xfer,
463 uint32_t loopTransferCount)
464 {
465 assert(handle != NULL);
466 assert(handle->dmaHandle != NULL);
467 assert(xfer != NULL);
468
469 uint32_t *srcAddr = NULL, *destAddr = NULL, srcInc = 4UL, destInc = 4UL;
470 i2s_transfer_t *currentTransfer = xfer;
471 bool intA = true;
472
473 if (handle->i2sLoopDMADescriptor == NULL)
474 {
475 return kStatus_InvalidArgument;
476 }
477
478 if (handle->state == (uint32_t)kI2S_DmaStateBusyLoopTransfer)
479 {
480 return kStatus_I2S_Busy;
481 }
482
483 for (uint32_t i = 0U; i < loopTransferCount; i++)
484 {
485 currentTransfer = &xfer[i];
486
487 if ((currentTransfer->data == NULL) || (currentTransfer->dataSize == 0U) ||
488 (i >= handle->i2sLoopDMADescriptorNum) ||
489 (currentTransfer->dataSize / handle->bytesPerFrame > DMA_MAX_TRANSFER_COUNT))
490 {
491 return kStatus_InvalidArgument;
492 }
493
494 if (handle->state == (uint32_t)kI2S_DmaStateTx)
495 {
496 srcAddr = (uint32_t *)(uint32_t)currentTransfer->data;
497 destAddr = (uint32_t *)(uint32_t)(&(base->FIFOWR));
498 srcInc = 1U;
499 destInc = 0UL;
500 }
501 else
502 {
503 srcAddr = (uint32_t *)(uint32_t)(&(base->FIFORD));
504 destAddr = (uint32_t *)(uint32_t)currentTransfer->data;
505 srcInc = 0U;
506 destInc = 1UL;
507 }
508
509 intA = intA == true ? false : true;
510
511 if (i == (loopTransferCount - 1U))
512 {
513 /* set up linked descriptor */
514 DMA_SetupDescriptor(&handle->i2sLoopDMADescriptor[i],
515 DMA_CHANNEL_XFER(true, false, intA, !intA, handle->bytesPerFrame, (uint8_t)srcInc,
516 (uint8_t)destInc, currentTransfer->dataSize),
517 srcAddr, destAddr, &handle->i2sLoopDMADescriptor[0U]);
518 }
519 else
520 {
521 /* set up linked descriptor */
522 DMA_SetupDescriptor(&handle->i2sLoopDMADescriptor[i],
523 DMA_CHANNEL_XFER(true, false, intA, !intA, handle->bytesPerFrame, (uint8_t)srcInc,
524 (uint8_t)destInc, currentTransfer->dataSize),
525 srcAddr, destAddr, &handle->i2sLoopDMADescriptor[i + 1U]);
526 }
527 }
528
529 /* transferSize make sense to non link transfer only */
530 if (handle->state == (uint32_t)kI2S_DmaStateTx)
531 {
532 srcAddr = (uint32_t *)(uint32_t)xfer->data;
533 destAddr = (uint32_t *)(uint32_t)(&(base->FIFOWR));
534 srcInc = 1U;
535 destInc = 0UL;
536 }
537 else
538 {
539 srcAddr = (uint32_t *)(uint32_t)(&(base->FIFORD));
540 destAddr = (uint32_t *)(uint32_t)xfer->data;
541 srcInc = 0U;
542 destInc = 1UL;
543 }
544
545 DMA_SubmitChannelTransferParameter(handle->dmaHandle,
546 DMA_CHANNEL_XFER(true, false, false, true, handle->bytesPerFrame,
547 (uint8_t)srcInc, (uint8_t)destInc, (uint32_t)xfer->dataSize),
548 srcAddr, destAddr, (void *)&handle->i2sLoopDMADescriptor[1U]);
549
550 /* Submit and start initial DMA transfer */
551 if (handle->state == (uint32_t)kI2S_DmaStateTx)
552 {
553 I2S_TxEnableDMA(base, true);
554 }
555 else
556 {
557 I2S_RxEnableDMA(base, true);
558 }
559 DMA_EnableChannelPeriphRq(handle->dmaHandle->base, handle->dmaHandle->channel);
560 /* start transfer */
561 DMA_StartTransfer(handle->dmaHandle);
562 I2S_Enable(base);
563
564 handle->state = (uint32_t)kI2S_DmaStateBusyLoopTransfer;
565
566 return kStatus_Success;
567 }
568
569 /*!
570 * brief Send loop transfer data using DMA.
571 *
572 * This function receives data using DMA. This is a non-blocking function, which returns
573 * right away. When all data is received, the receive callback function is called.
574 *
575 * This function support loop transfer, such as A->B->...->A, the loop transfer chain
576 * will be converted into a chain of descriptor and submit to dma.
577 * Application must be aware of that the more counts of the loop transfer, then more DMA descriptor memory required,
578 * user can use function I2S_InstallDMADescriptorMemory to register the dma descriptor memory.
579 *
580 * As the DMA support maximum 1024 transfer count, so application must be aware of that this transfer function support
581 * maximum 1024 samples in each transfer, otherwise assert error or error status will be returned. Once the loop
582 * transfer start, application can use function I2S_TransferAbortDMA to stop the loop transfer.
583 *
584 * param base I2S peripheral base address.
585 * param handle Pointer to usart_dma_handle_t structure.
586 * param xfer I2S DMA transfer structure. See #i2s_transfer_t.
587 * param i2s_channel I2S start channel number
588 * retval kStatus_Success
589 */
I2S_TransferSendLoopDMA(I2S_Type * base,i2s_dma_handle_t * handle,i2s_transfer_t * xfer,uint32_t loopTransferCount)590 status_t I2S_TransferSendLoopDMA(I2S_Type *base,
591 i2s_dma_handle_t *handle,
592 i2s_transfer_t *xfer,
593 uint32_t loopTransferCount)
594 {
595 assert(handle != NULL);
596 assert(handle->i2sLoopDMADescriptor != NULL);
597
598 handle->state = (uint32_t)kI2S_DmaStateTx;
599
600 return I2S_TransferLoopDMA(base, handle, xfer, loopTransferCount);
601 }
602
603 /*!
604 * brief Receive loop transfer data using DMA.
605 *
606 * This function receives data using DMA. This is a non-blocking function, which returns
607 * right away. When all data is received, the receive callback function is called.
608 *
609 * This function support loop transfer, such as A->B->...->A, the loop transfer chain
610 * will be converted into a chain of descriptor and submit to dma.
611 * Application must be aware of that the more counts of the loop transfer, then more DMA descriptor memory required,
612 * user can use function I2S_InstallDMADescriptorMemory to register the dma descriptor memory.
613 *
614 * As the DMA support maximum 1024 transfer count, so application must be aware of that this transfer function support
615 * maximum 1024 samples in each transfer, otherwise assert error or error status will be returned. Once the loop
616 * transfer start, application can use function I2S_TransferAbortDMA to stop the loop transfer.
617 *
618 * param base I2S peripheral base address.
619 * param handle Pointer to usart_dma_handle_t structure.
620 * param xfer I2S DMA transfer structure. See #i2s_transfer_t.
621 * param i2s_channel I2S start channel number
622 * retval kStatus_Success
623 */
I2S_TransferReceiveLoopDMA(I2S_Type * base,i2s_dma_handle_t * handle,i2s_transfer_t * xfer,uint32_t loopTransferCount)624 status_t I2S_TransferReceiveLoopDMA(I2S_Type *base,
625 i2s_dma_handle_t *handle,
626 i2s_transfer_t *xfer,
627 uint32_t loopTransferCount)
628 {
629 assert(handle != NULL);
630 assert(handle->i2sLoopDMADescriptor != NULL);
631
632 handle->state = (uint32_t)kI2S_DmaStateRx;
633
634 return I2S_TransferLoopDMA(base, handle, xfer, loopTransferCount);
635 }
636
I2S_StartTransferDMA(I2S_Type * base,i2s_dma_handle_t * handle)637 static status_t I2S_StartTransferDMA(I2S_Type *base, i2s_dma_handle_t *handle)
638 {
639 uint32_t instance = I2S_GetInstance(base);
640 i2s_dma_private_handle_t *privateHandle = &(s_DmaPrivateHandle[instance]);
641 volatile i2s_transfer_t *transfer = &(privateHandle->descriptorQueue[privateHandle->queueDescriptor]);
642 uint16_t transferBytes = I2S_GetTransferBytes(transfer);
643 uint32_t i = 0U;
644 uint32_t xferConfig = 0U;
645 uint32_t *srcAddr = NULL, *destAddr = NULL, srcInc = 4UL, destInc = 4UL;
646
647 if (handle->state == (uint32_t)kI2S_DmaStateTx)
648 {
649 srcAddr = (uint32_t *)(uint32_t)transfer->data;
650 destAddr = (uint32_t *)(uint32_t)(&(base->FIFOWR));
651 srcInc = 1U;
652 destInc = 0UL;
653 }
654 else
655 {
656 srcAddr = (uint32_t *)(uint32_t)(&(base->FIFORD));
657 destAddr = (uint32_t *)(uint32_t)transfer->data;
658 srcInc = 0U;
659 destInc = 1UL;
660 }
661 /* Initial descriptor is stored in another place in memory, but treat it as another descriptor for simplicity */
662 privateHandle->dmaDescriptorsUsed = 1U;
663 privateHandle->intA = false;
664
665 /* submit transfer parameter directly */
666 xferConfig = DMA_CHANNEL_XFER(true, false, false, true, handle->bytesPerFrame, (uint8_t)srcInc, (uint8_t)destInc,
667 (uint32_t)transferBytes);
668
669 DMA_SubmitChannelTransferParameter(handle->dmaHandle, xferConfig, srcAddr, destAddr,
670 (void *)&(s_DmaDescriptors[(instance * DMA_DESCRIPTORS) + 0U]));
671
672 privateHandle->enqueuedBytes[privateHandle->enqueuedBytesEnd] = transferBytes;
673 privateHandle->enqueuedBytesEnd = (privateHandle->enqueuedBytesEnd + 1U) % DMA_DESCRIPTORS;
674
675 transfer->dataSize -= transferBytes;
676 transfer->data = (uint8_t *)((uint32_t)transfer->data + transferBytes);
677
678 if (transfer->dataSize == 0U)
679 {
680 transfer->data = NULL;
681 privateHandle->queueDescriptor = (privateHandle->queueDescriptor + 1U) % I2S_NUM_BUFFERS;
682 }
683
684 /* Link the DMA descriptors for the case when no additional transfer is queued before the initial one finishes
685 * The configuration for the DMA dummy descriptor make no sense to tx or rx transfer, since it will be overwritten
686 * when another transfer request comes before the previous finished.
687 * To make sure the audio data transfer continuously, application must request another transfer by call
688 * I2S_RxTransferReceiveDMA or I2S_TxTransferSendDMA before previous transfer finished.
689 */
690 for (i = 0; i < DMA_DESCRIPTORS; i++)
691 {
692 /* DMA_CHANNEL_XFER(1UL, 0UL, 0UL, 0UL, sizeof(uint32_t), 0U, 0U, 8U) = 0x10203UL */
693 DMA_SetupDescriptor(
694 &(s_DmaDescriptors[(instance * DMA_DESCRIPTORS) + i]), 0x10203UL,
695 ((handle->state == (uint32_t)kI2S_DmaStateTx) ? &s_DummyBufferTx : (uint32_t *)(uint32_t)(&(base->FIFORD))),
696 ((handle->state == (uint32_t)kI2S_DmaStateTx) ? (uint32_t *)(uint32_t)(&(base->FIFOWR)) : &s_DummyBufferRx),
697 &(s_DmaDescriptors[(instance * DMA_DESCRIPTORS) + ((i + 1U) % DMA_DESCRIPTORS)]));
698 }
699
700 /* Submit and start initial DMA transfer */
701 if (handle->state == (uint32_t)kI2S_DmaStateTx)
702 {
703 I2S_TxEnableDMA(base, true);
704 }
705 else
706 {
707 I2S_RxEnableDMA(base, true);
708 }
709 /* enable I2S peripheral request and put the channel into triggered status */
710 DMA_EnableChannelPeriphRq(handle->dmaHandle->base, handle->dmaHandle->channel);
711 DMA_StartTransfer(handle->dmaHandle);
712
713 I2S_Enable(base);
714
715 return kStatus_Success;
716 }
717
I2S_AddTransferDMA(I2S_Type * base,i2s_dma_handle_t * handle)718 static void I2S_AddTransferDMA(I2S_Type *base, i2s_dma_handle_t *handle)
719 {
720 volatile i2s_transfer_t *transfer;
721 uint16_t transferBytes;
722 uint32_t instance;
723 i2s_dma_private_handle_t *privateHandle;
724 dma_descriptor_t *descriptor;
725 dma_descriptor_t *nextDescriptor;
726 uint32_t xferConfig = 0U;
727 bool intA = false;
728 uint32_t *srcAddr = NULL, *destAddr = NULL, srcInc = 4UL, destInc = 4UL;
729
730 instance = I2S_GetInstance(base);
731 privateHandle = &(s_DmaPrivateHandle[instance]);
732
733 while (privateHandle->dmaDescriptorsUsed < DMA_DESCRIPTORS)
734 {
735 transfer = &(privateHandle->descriptorQueue[privateHandle->queueDescriptor]);
736 intA = privateHandle->intA;
737 if (transfer->dataSize == 0U)
738 {
739 /* Nothing to be added */
740 return;
741 }
742
743 if (handle->state == (uint32_t)kI2S_DmaStateTx)
744 {
745 srcAddr = (uint32_t *)(uint32_t)transfer->data;
746 destAddr = (uint32_t *)(uint32_t)(&(base->FIFOWR));
747 srcInc = 1U;
748 destInc = 0UL;
749 }
750 else
751 {
752 srcAddr = (uint32_t *)(uint32_t)(&(base->FIFORD));
753 destAddr = (uint32_t *)(uint32_t)transfer->data;
754 srcInc = 0U;
755 destInc = 1UL;
756 }
757
758 /* Determine currently configured descriptor and the other which it will link to */
759 descriptor = &(s_DmaDescriptors[(instance * DMA_DESCRIPTORS) + privateHandle->descriptor]);
760 privateHandle->descriptor = (privateHandle->descriptor + 1U) % DMA_DESCRIPTORS;
761 nextDescriptor = &(s_DmaDescriptors[(instance * DMA_DESCRIPTORS) + privateHandle->descriptor]);
762
763 transferBytes = I2S_GetTransferBytes(transfer);
764 privateHandle->enqueuedBytes[privateHandle->enqueuedBytesEnd] = transferBytes;
765 privateHandle->enqueuedBytesEnd = (privateHandle->enqueuedBytesEnd + 1U) % DMA_DESCRIPTORS;
766
767 xferConfig = DMA_CHANNEL_XFER(true, false, !intA, intA, handle->bytesPerFrame, (uint8_t)srcInc,
768 (uint8_t)destInc, (uint32_t)transferBytes);
769
770 DMA_SetupDescriptor(descriptor, xferConfig, srcAddr, destAddr, nextDescriptor);
771
772 /* Advance internal state */
773 privateHandle->dmaDescriptorsUsed++;
774 privateHandle->intA = !privateHandle->intA;
775
776 transfer->dataSize -= transferBytes;
777 transfer->data += transferBytes;
778 if (transfer->dataSize == 0U)
779 {
780 transfer->data = NULL;
781 privateHandle->queueDescriptor = (privateHandle->queueDescriptor + 1U) % I2S_NUM_BUFFERS;
782 }
783 }
784 }
785
786 /*!
787 * brief Invoked from DMA interrupt handler.
788 *
789 * param handle pointer to DMA handle structure.
790 * param userData argument for user callback.
791 * param transferDone if transfer was done.
792 * param tcds
793 */
I2S_DMACallback(dma_handle_t * handle,void * userData,bool transferDone,uint32_t tcds)794 void I2S_DMACallback(dma_handle_t *handle, void *userData, bool transferDone, uint32_t tcds)
795 {
796 i2s_dma_private_handle_t *privateHandle = (i2s_dma_private_handle_t *)userData;
797 i2s_dma_handle_t *i2sHandle = privateHandle->handle;
798 I2S_Type *base = privateHandle->base;
799 uint8_t queueDriverIndex = i2sHandle->queueDriver;
800 uint32_t enqueueBytes = privateHandle->enqueuedBytes[privateHandle->enqueuedBytesStart];
801 uint32_t queueDataAddr = (uint32_t)i2sHandle->i2sQueue[queueDriverIndex].data;
802
803 if ((!transferDone) || (i2sHandle->state == (uint32_t)kI2S_DmaStateIdle))
804 {
805 return;
806 }
807
808 if (privateHandle->dmaDescriptorsUsed > 0U)
809 {
810 /* Finished descriptor, decrease amount of data to be processed */
811
812 i2sHandle->i2sQueue[queueDriverIndex].dataSize -= enqueueBytes;
813 i2sHandle->i2sQueue[queueDriverIndex].data = (uint8_t *)(queueDataAddr + enqueueBytes);
814 privateHandle->enqueuedBytes[privateHandle->enqueuedBytesStart] = 0U;
815 privateHandle->enqueuedBytesStart = (privateHandle->enqueuedBytesStart + 1U) % DMA_DESCRIPTORS;
816 privateHandle->dmaDescriptorsUsed--;
817 }
818
819 if (i2sHandle->i2sQueue[queueDriverIndex].dataSize == 0U)
820 {
821 /* Entire user buffer sent or received - advance to next one */
822 i2sHandle->i2sQueue[queueDriverIndex].data = NULL;
823 i2sHandle->queueDriver = (queueDriverIndex + 1U) % I2S_NUM_BUFFERS;
824 /* Notify user about buffer completion */
825 if (i2sHandle->completionCallback != NULL)
826 {
827 (i2sHandle->completionCallback)(base, i2sHandle, kStatus_I2S_BufferComplete, i2sHandle->userData);
828 }
829 }
830
831 if (i2sHandle->state != (uint32_t)kI2S_DmaStateBusyLoopTransfer)
832 {
833 /* check next buffer queue is avaliable or not */
834 if (i2sHandle->i2sQueue[i2sHandle->queueDriver].dataSize == 0U)
835 {
836 if (i2sHandle->state == (uint32_t)kI2S_DmaStateTx)
837 {
838 (void)I2S_EmptyTxFifo(base);
839 }
840 /* All user buffers processed */
841 I2S_TransferAbortDMA(base, i2sHandle);
842 }
843 else
844 {
845 /* Enqueue another user buffer to DMA if it could not be done when in I2S_Rx/TxTransferSendDMA */
846 I2S_AddTransferDMA(base, i2sHandle);
847 }
848 }
849 }
850