1 /*
2 * Copyright (c) 2016, 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_spi_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.flexcomm_spi_dma"
18 #endif
19
20 /*<! Structure definition for spi_dma_private_handle_t. The structure is private. */
21 typedef struct _spi_dma_private_handle
22 {
23 SPI_Type *base;
24 spi_dma_handle_t *handle;
25 } spi_dma_private_handle_t;
26
27 /*! @brief SPI transfer state, which is used for SPI transactiaonl APIs' internal state. */
28 enum _spi_dma_states_t
29 {
30 kSPI_Idle = 0x0, /*!< SPI is idle state */
31 kSPI_Busy /*!< SPI is busy tranferring data. */
32 };
33
34 typedef struct _spi_dma_txdummy
35 {
36 uint32_t lastWord;
37 uint32_t word;
38 } spi_dma_txdummy_t;
39
40 static spi_dma_private_handle_t s_dmaPrivateHandle[FSL_FEATURE_SOC_SPI_COUNT];
41 /*******************************************************************************
42 * Prototypes
43 ******************************************************************************/
44
45 /*!
46 * @brief DMA callback function for SPI send transfer.
47 *
48 * @param handle DMA handle pointer.
49 * @param userData User data for DMA callback function.
50 */
51 static void SPI_TxDMACallback(dma_handle_t *handle, void *userData, bool transferDone, uint32_t intmode);
52
53 /*!
54 * @brief DMA callback function for SPI receive transfer.
55 *
56 * @param handle DMA handle pointer.
57 * @param userData User data for DMA callback function.
58 */
59 static void SPI_RxDMACallback(dma_handle_t *handle, void *userData, bool transferDone, uint32_t intmode);
60
61 /*******************************************************************************
62 * Variables
63 ******************************************************************************/
64 #if defined(__ICCARM__)
65 #pragma data_alignment = 4
66 static spi_dma_txdummy_t s_txDummy[FSL_FEATURE_SOC_SPI_COUNT] = {0};
67 #elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
68 __attribute__((aligned(4))) static spi_dma_txdummy_t s_txDummy[FSL_FEATURE_SOC_SPI_COUNT] = {0};
69 #elif defined(__GNUC__)
70 __attribute__((aligned(4))) static spi_dma_txdummy_t s_txDummy[FSL_FEATURE_SOC_SPI_COUNT] = {0};
71 #endif
72
73 #if defined(__ICCARM__)
74 #pragma data_alignment = 4
75 static uint16_t s_rxDummy;
76 static uint32_t s_txLastWord[FSL_FEATURE_SOC_SPI_COUNT];
77 #elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
78 __attribute__((aligned(4))) static uint16_t s_rxDummy;
79 __attribute__((aligned(4))) static uint32_t s_txLastWord[FSL_FEATURE_SOC_SPI_COUNT];
80 #elif defined(__GNUC__)
81 __attribute__((aligned(4))) static uint16_t s_rxDummy;
82 __attribute__((aligned(4))) static uint32_t s_txLastWord[FSL_FEATURE_SOC_SPI_COUNT];
83 #endif
84
85 #if defined(__ICCARM__)
86 #pragma data_alignment = 16
87 static dma_descriptor_t s_spi_descriptor_table[FSL_FEATURE_SOC_SPI_COUNT] = {0};
88 #elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
89 __attribute__((aligned(16))) static dma_descriptor_t s_spi_descriptor_table[FSL_FEATURE_SOC_SPI_COUNT] = {0};
90 #elif defined(__GNUC__)
91 __attribute__((aligned(16))) static dma_descriptor_t s_spi_descriptor_table[FSL_FEATURE_SOC_SPI_COUNT] = {0};
92 #endif
93
94 /*******************************************************************************
95 * Code
96 ******************************************************************************/
97
XferToFifoWR(spi_transfer_t * xfer,uint32_t * fifowr)98 static void XferToFifoWR(spi_transfer_t *xfer, uint32_t *fifowr)
99 {
100 *fifowr |= ((xfer->configFlags & (uint32_t)kSPI_FrameDelay) != 0U) ? (uint32_t)kSPI_FrameDelay : 0U;
101 *fifowr |= ((xfer->configFlags & (uint32_t)kSPI_FrameAssert) != 0U) ? (uint32_t)kSPI_FrameAssert : 0U;
102 }
103
SpiConfigToFifoWR(spi_config_t * config,uint32_t * fifowr)104 static void SpiConfigToFifoWR(spi_config_t *config, uint32_t *fifowr)
105 {
106 *fifowr |= ((uint32_t)SPI_DEASSERT_ALL & (~(uint32_t)SPI_DEASSERTNUM_SSEL((uint32_t)config->sselNum)));
107 /* set width of data - range asserted at entry */
108 *fifowr |= SPI_FIFOWR_LEN(config->dataWidth);
109 }
110
PrepareTxLastWord(spi_transfer_t * xfer,uint32_t * txLastWord,spi_config_t * config)111 static void PrepareTxLastWord(spi_transfer_t *xfer, uint32_t *txLastWord, spi_config_t *config)
112 {
113 if (config->dataWidth > kSPI_Data8Bits)
114 {
115 *txLastWord = (((uint32_t)xfer->txData[xfer->dataSize - 1U] << 8U) | (xfer->txData[xfer->dataSize - 2U]));
116 }
117 else
118 {
119 *txLastWord = xfer->txData[xfer->dataSize - 1U];
120 }
121 XferToFifoWR(xfer, txLastWord);
122 SpiConfigToFifoWR(config, txLastWord);
123 }
124
SPI_SetupDummy(SPI_Type * base,spi_dma_txdummy_t * dummy,spi_transfer_t * xfer,spi_config_t * spi_config_p)125 static void SPI_SetupDummy(SPI_Type *base, spi_dma_txdummy_t *dummy, spi_transfer_t *xfer, spi_config_t *spi_config_p)
126 {
127 uint32_t instance = SPI_GetInstance(base);
128 uint32_t dummydata = (uint32_t)s_dummyData[instance];
129 dummydata |= (uint32_t)s_dummyData[instance] << 8U;
130
131 dummy->word = dummydata;
132 dummy->lastWord = dummydata;
133
134 XferToFifoWR(xfer, &dummy->word);
135 XferToFifoWR(xfer, &dummy->lastWord);
136 SpiConfigToFifoWR(spi_config_p, &dummy->word);
137 SpiConfigToFifoWR(spi_config_p, &dummy->lastWord);
138 /* Clear the end of transfer bit for continue word transfer. */
139 dummy->word &= (~(uint32_t)kSPI_FrameAssert);
140 }
141
142 /*!
143 * brief Initialize the SPI master DMA handle.
144 *
145 * This function initializes the SPI master DMA handle which can be used for other SPI master transactional APIs.
146 * Usually, for a specified SPI instance, user need only call this API once to get the initialized handle.
147 *
148 * param base SPI peripheral base address.
149 * param handle SPI handle pointer.
150 * param callback User callback function called at the end of a transfer.
151 * param userData User data for callback.
152 * param txHandle DMA handle pointer for SPI Tx, the handle shall be static allocated by users.
153 * param rxHandle DMA handle pointer for SPI Rx, the handle shall be static allocated by users.
154 */
SPI_MasterTransferCreateHandleDMA(SPI_Type * base,spi_dma_handle_t * handle,spi_dma_callback_t callback,void * userData,dma_handle_t * txHandle,dma_handle_t * rxHandle)155 status_t SPI_MasterTransferCreateHandleDMA(SPI_Type *base,
156 spi_dma_handle_t *handle,
157 spi_dma_callback_t callback,
158 void *userData,
159 dma_handle_t *txHandle,
160 dma_handle_t *rxHandle)
161 {
162 uint32_t instance;
163
164 /* check 'base' */
165 assert(!(NULL == base));
166 if (NULL == base)
167 {
168 return kStatus_InvalidArgument;
169 }
170 /* check 'handle' */
171 assert(!(NULL == handle));
172 if (NULL == handle)
173 {
174 return kStatus_InvalidArgument;
175 }
176
177 instance = SPI_GetInstance(base);
178
179 (void)memset(handle, 0, sizeof(*handle));
180 /* Set spi base to handle */
181 handle->txHandle = txHandle;
182 handle->rxHandle = rxHandle;
183 handle->callback = callback;
184 handle->userData = userData;
185
186 /* Set SPI state to idle */
187 handle->state = (uint8_t)kSPI_Idle;
188
189 /* Set handle to global state */
190 s_dmaPrivateHandle[instance].base = base;
191 s_dmaPrivateHandle[instance].handle = handle;
192
193 /* Install callback for Tx dma channel */
194 DMA_SetCallback(handle->txHandle, SPI_TxDMACallback, &s_dmaPrivateHandle[instance]);
195 DMA_SetCallback(handle->rxHandle, SPI_RxDMACallback, &s_dmaPrivateHandle[instance]);
196
197 return kStatus_Success;
198 }
199
200 /*!
201 * brief Perform a non-blocking SPI transfer using DMA.
202 *
203 * note This interface returned immediately after transfer initiates, users should call
204 * SPI_GetTransferStatus to poll the transfer status to check whether SPI transfer finished.
205 *
206 * param base SPI peripheral base address.
207 * param handle SPI DMA handle pointer.
208 * param xfer Pointer to dma transfer structure.
209 * retval kStatus_Success Successfully start a transfer.
210 * retval kStatus_InvalidArgument Input argument is invalid.
211 * retval kStatus_SPI_Busy SPI is not idle, is running another transfer.
212 */
SPI_MasterTransferDMA(SPI_Type * base,spi_dma_handle_t * handle,spi_transfer_t * xfer)213 status_t SPI_MasterTransferDMA(SPI_Type *base, spi_dma_handle_t *handle, spi_transfer_t *xfer)
214 {
215 assert(!((NULL == handle) || (NULL == xfer)));
216
217 uint32_t instance;
218 status_t result = kStatus_Success;
219 spi_config_t *spi_config_p;
220 uint32_t address;
221
222 if ((NULL == handle) || (NULL == xfer))
223 {
224 return kStatus_InvalidArgument;
225 }
226
227 /* Byte size is zero. */
228 if (xfer->dataSize == 0U)
229 {
230 return kStatus_InvalidArgument;
231 }
232 /* cannot get instance from base address */
233 instance = SPI_GetInstance(base);
234
235 /* Check if the device is busy */
236 if (handle->state == (uint8_t)kSPI_Busy)
237 {
238 return kStatus_SPI_Busy;
239 }
240 else
241 {
242 /* Clear FIFOs before transfer. */
243 base->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
244 base->FIFOSTAT |= SPI_FIFOSTAT_TXERR_MASK | SPI_FIFOSTAT_RXERR_MASK;
245
246 dma_transfer_config_t xferConfig = {0};
247 spi_config_p = (spi_config_t *)SPI_GetConfig(base);
248
249 handle->state = (uint8_t)kSPI_Busy;
250 handle->transferSize = xfer->dataSize;
251
252 /* receive */
253 SPI_EnableRxDMA(base, true);
254 address = (uint32_t)&base->FIFORD;
255 if (xfer->rxData != NULL)
256 {
257 DMA_PrepareTransfer(&xferConfig, (uint32_t *)address, xfer->rxData,
258 ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (sizeof(uint16_t)) : (sizeof(uint8_t))),
259 xfer->dataSize, kDMA_PeripheralToMemory, NULL);
260 }
261 else
262 {
263 DMA_PrepareTransfer(&xferConfig, (uint32_t *)address, &s_rxDummy,
264 ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (sizeof(uint16_t)) : (sizeof(uint8_t))),
265 xfer->dataSize, kDMA_StaticToStatic, NULL);
266 }
267 (void)DMA_SubmitTransfer(handle->rxHandle, &xferConfig);
268 handle->rxInProgress = true;
269 DMA_StartTransfer(handle->rxHandle);
270
271 /* transmit */
272 SPI_EnableTxDMA(base, true);
273 address = (uint32_t)&base->FIFOWR;
274 if (xfer->txData != NULL)
275 {
276 if ((xfer->configFlags & (uint32_t)kSPI_FrameAssert) != 0U)
277 {
278 PrepareTxLastWord(xfer, &s_txLastWord[instance], spi_config_p);
279 }
280 /* If end of tranfer function is enabled and data transfer frame is bigger then 1, use dma
281 * descriptor to send the last data.
282 */
283 if (((xfer->configFlags & (uint32_t)kSPI_FrameAssert) != 0U) &&
284 ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (xfer->dataSize > 2U) : (xfer->dataSize > 1U)))
285 {
286 dma_xfercfg_t tmp_xfercfg;
287 tmp_xfercfg.valid = true;
288 tmp_xfercfg.swtrig = true;
289 tmp_xfercfg.intA = true;
290 tmp_xfercfg.byteWidth = 4U;
291 tmp_xfercfg.srcInc = 0;
292 tmp_xfercfg.dstInc = 0;
293 tmp_xfercfg.transferCount = 1;
294 tmp_xfercfg.reload = false;
295 tmp_xfercfg.clrtrig = false;
296 tmp_xfercfg.intB = false;
297 /* Create chained descriptor to transmit last word */
298 DMA_CreateDescriptor(&s_spi_descriptor_table[instance], &tmp_xfercfg, &s_txLastWord[instance],
299 (uint32_t *)address, NULL);
300
301 DMA_PrepareTransfer(
302 &xferConfig, xfer->txData, (uint32_t *)address,
303 ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (sizeof(uint16_t)) : (sizeof(uint8_t))),
304 ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (xfer->dataSize - 2U) : (xfer->dataSize - 1U)),
305 kDMA_MemoryToPeripheral, &s_spi_descriptor_table[instance]);
306 /* Disable interrupts for first descriptor to avoid calling callback twice. */
307 xferConfig.xfercfg.intA = false;
308 xferConfig.xfercfg.intB = false;
309 result = DMA_SubmitTransfer(handle->txHandle, &xferConfig);
310 if (result != kStatus_Success)
311 {
312 return result;
313 }
314 }
315 else
316 {
317 DMA_PrepareTransfer(
318 &xferConfig, xfer->txData, (uint32_t *)address,
319 ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (sizeof(uint16_t)) : (sizeof(uint8_t))),
320 xfer->dataSize, kDMA_MemoryToPeripheral, NULL);
321 (void)DMA_SubmitTransfer(handle->txHandle, &xferConfig);
322 }
323 }
324 else
325 {
326 /* Setup tx dummy data. */
327 SPI_SetupDummy(base, &s_txDummy[instance], xfer, spi_config_p);
328 if (((xfer->configFlags & (uint32_t)kSPI_FrameAssert) != 0U) &&
329 ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (xfer->dataSize > 2U) : (xfer->dataSize > 1U)))
330 {
331 dma_xfercfg_t tmp_xfercfg;
332 tmp_xfercfg.valid = true;
333 tmp_xfercfg.swtrig = true;
334 tmp_xfercfg.intA = true;
335 tmp_xfercfg.byteWidth = (uint8_t)sizeof(uint32_t);
336 tmp_xfercfg.srcInc = 0;
337 tmp_xfercfg.dstInc = 0;
338 tmp_xfercfg.transferCount = 1;
339 tmp_xfercfg.reload = false;
340 tmp_xfercfg.clrtrig = false;
341 tmp_xfercfg.intB = false;
342 /* Create chained descriptor to transmit last word */
343 DMA_CreateDescriptor(&s_spi_descriptor_table[instance], &tmp_xfercfg, &s_txDummy[instance].lastWord,
344 (uint32_t *)address, NULL);
345 /* Use common API to setup first descriptor */
346 DMA_PrepareTransfer(
347 &xferConfig, &s_txDummy[instance].word, (uint32_t *)address,
348 ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (sizeof(uint16_t)) : (sizeof(uint8_t))),
349 ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (xfer->dataSize - 2U) : (xfer->dataSize - 1U)),
350 kDMA_StaticToStatic, &s_spi_descriptor_table[instance]);
351 /* Disable interrupts for first descriptor to avoid calling callback twice */
352 xferConfig.xfercfg.intA = false;
353 xferConfig.xfercfg.intB = false;
354 result = DMA_SubmitTransfer(handle->txHandle, &xferConfig);
355 if (result != kStatus_Success)
356 {
357 return result;
358 }
359 }
360 else
361 {
362 DMA_PrepareTransfer(
363 &xferConfig, &s_txDummy[instance].word, (uint32_t *)address,
364 ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (sizeof(uint16_t)) : (sizeof(uint8_t))),
365 xfer->dataSize, kDMA_StaticToStatic, NULL);
366 result = DMA_SubmitTransfer(handle->txHandle, &xferConfig);
367 if (result != kStatus_Success)
368 {
369 return result;
370 }
371 }
372 }
373
374 handle->txInProgress = true;
375 uint32_t tmpData = 0U;
376 uint32_t writeAddress = (uint32_t) & (base->FIFOWR) + 2UL;
377 XferToFifoWR(xfer, &tmpData);
378 SpiConfigToFifoWR(spi_config_p, &tmpData);
379
380 /* Setup the control info.
381 * Halfword writes to just the control bits (offset 0xE22) doesn't push anything into the FIFO.
382 * And the data access type of control bits must be uint16_t, byte writes or halfword writes to FIFOWR
383 * will push the data and the current control bits into the FIFO.
384 */
385 if (((xfer->configFlags & (uint32_t)kSPI_FrameAssert) != 0U) &&
386 ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (xfer->dataSize == 2U) : (xfer->dataSize == 1U)))
387 {
388 *(uint16_t *)writeAddress = (uint16_t)(tmpData >> 16U);
389 }
390 else
391 {
392 /* Clear the SPI_FIFOWR_EOT_MASK bit when data is not the last. */
393 tmpData &= (~(uint32_t)kSPI_FrameAssert);
394 *(uint16_t *)writeAddress = (uint16_t)(tmpData >> 16U);
395 }
396
397 DMA_StartTransfer(handle->txHandle);
398 }
399
400 return result;
401 }
402
403 /*!
404 * brief Transfers a block of data using a DMA method.
405 *
406 * This function using polling way to do the first half transimission and using DMA way to
407 * do the srcond half transimission, the transfer mechanism is half-duplex.
408 * When do the second half transimission, code will return right away. When all data is transferred,
409 * the callback function is called.
410 *
411 * param base SPI base pointer
412 * param handle A pointer to the spi_master_dma_handle_t structure which stores the transfer state.
413 * param transfer A pointer to the spi_half_duplex_transfer_t structure.
414 * return status of status_t.
415 */
SPI_MasterHalfDuplexTransferDMA(SPI_Type * base,spi_dma_handle_t * handle,spi_half_duplex_transfer_t * xfer)416 status_t SPI_MasterHalfDuplexTransferDMA(SPI_Type *base, spi_dma_handle_t *handle, spi_half_duplex_transfer_t *xfer)
417 {
418 assert((xfer != NULL) && (handle != NULL));
419 spi_transfer_t tempXfer = {0};
420 status_t status;
421
422 if (xfer->isTransmitFirst)
423 {
424 tempXfer.txData = xfer->txData;
425 tempXfer.rxData = NULL;
426 tempXfer.dataSize = xfer->txDataSize;
427 }
428 else
429 {
430 tempXfer.txData = NULL;
431 tempXfer.rxData = xfer->rxData;
432 tempXfer.dataSize = xfer->rxDataSize;
433 }
434 /* If the pcs pin keep assert between transmit and receive. */
435 if (xfer->isPcsAssertInTransfer)
436 {
437 tempXfer.configFlags = (xfer->configFlags) & (~(uint32_t)kSPI_FrameAssert);
438 }
439 else
440 {
441 tempXfer.configFlags = (xfer->configFlags) | (uint32_t)kSPI_FrameAssert;
442 }
443
444 status = SPI_MasterTransferBlocking(base, &tempXfer);
445 if (status != kStatus_Success)
446 {
447 return status;
448 }
449
450 if (xfer->isTransmitFirst)
451 {
452 tempXfer.txData = NULL;
453 tempXfer.rxData = xfer->rxData;
454 tempXfer.dataSize = xfer->rxDataSize;
455 }
456 else
457 {
458 tempXfer.txData = xfer->txData;
459 tempXfer.rxData = NULL;
460 tempXfer.dataSize = xfer->txDataSize;
461 }
462 tempXfer.configFlags = xfer->configFlags;
463
464 status = SPI_MasterTransferDMA(base, handle, &tempXfer);
465
466 return status;
467 }
468
SPI_RxDMACallback(dma_handle_t * handle,void * userData,bool transferDone,uint32_t intmode)469 static void SPI_RxDMACallback(dma_handle_t *handle, void *userData, bool transferDone, uint32_t intmode)
470 {
471 spi_dma_private_handle_t *privHandle = (spi_dma_private_handle_t *)userData;
472 spi_dma_handle_t *spiHandle = privHandle->handle;
473 SPI_Type *base = privHandle->base;
474
475 /* change the state */
476 spiHandle->rxInProgress = false;
477
478 /* All finished, call the callback */
479 if ((spiHandle->txInProgress == false) && (spiHandle->rxInProgress == false))
480 {
481 spiHandle->state = (uint8_t)kSPI_Idle;
482 if (spiHandle->callback != NULL)
483 {
484 (spiHandle->callback)(base, spiHandle, kStatus_Success, spiHandle->userData);
485 }
486 }
487 }
488
SPI_TxDMACallback(dma_handle_t * handle,void * userData,bool transferDone,uint32_t intmode)489 static void SPI_TxDMACallback(dma_handle_t *handle, void *userData, bool transferDone, uint32_t intmode)
490 {
491 spi_dma_private_handle_t *privHandle = (spi_dma_private_handle_t *)userData;
492 spi_dma_handle_t *spiHandle = privHandle->handle;
493 SPI_Type *base = privHandle->base;
494
495 /* change the state */
496 spiHandle->txInProgress = false;
497
498 /* All finished, call the callback */
499 if ((spiHandle->txInProgress == false) && (spiHandle->rxInProgress == false))
500 {
501 spiHandle->state = (uint8_t)kSPI_Idle;
502 if (spiHandle->callback != NULL)
503 {
504 (spiHandle->callback)(base, spiHandle, kStatus_Success, spiHandle->userData);
505 }
506 }
507 }
508
509 /*!
510 * brief Abort a SPI transfer using DMA.
511 *
512 * param base SPI peripheral base address.
513 * param handle SPI DMA handle pointer.
514 */
SPI_MasterTransferAbortDMA(SPI_Type * base,spi_dma_handle_t * handle)515 void SPI_MasterTransferAbortDMA(SPI_Type *base, spi_dma_handle_t *handle)
516 {
517 assert(NULL != handle);
518
519 /* Stop tx transfer first */
520 DMA_AbortTransfer(handle->txHandle);
521 /* Then rx transfer */
522 DMA_AbortTransfer(handle->rxHandle);
523
524 /* Set the handle state */
525 handle->txInProgress = false;
526 handle->rxInProgress = false;
527 handle->state = (uint8_t)kSPI_Idle;
528 }
529
530 /*!
531 * brief Gets the master DMA transfer remaining bytes.
532 *
533 * This function gets the master DMA transfer remaining bytes.
534 *
535 * param base SPI peripheral base address.
536 * param handle A pointer to the spi_dma_handle_t structure which stores the transfer state.
537 * param count A number of bytes transferred by the non-blocking transaction.
538 * return status of status_t.
539 */
SPI_MasterTransferGetCountDMA(SPI_Type * base,spi_dma_handle_t * handle,size_t * count)540 status_t SPI_MasterTransferGetCountDMA(SPI_Type *base, spi_dma_handle_t *handle, size_t *count)
541 {
542 assert(handle != NULL);
543
544 if (NULL == count)
545 {
546 return kStatus_InvalidArgument;
547 }
548
549 /* Catch when there is not an active transfer. */
550 if (handle->state != (uint8_t)kSPI_Busy)
551 {
552 *count = 0;
553 return kStatus_NoTransferInProgress;
554 }
555
556 size_t bytes;
557
558 bytes = DMA_GetRemainingBytes(handle->rxHandle->base, handle->rxHandle->channel);
559
560 *count = handle->transferSize - bytes;
561
562 return kStatus_Success;
563 }
564