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 handle->instance = instance;
186 handle->dataBytesEveryTime = DMA_MAX_TRANSFER_COUNT;
187
188 /* Set SPI state to idle */
189 handle->state = (uint8_t)kSPI_Idle;
190
191 /* Set handle to global state */
192 s_dmaPrivateHandle[instance].base = base;
193 s_dmaPrivateHandle[instance].handle = handle;
194
195 /* Install callback for Tx dma channel */
196 DMA_SetCallback(handle->txHandle, SPI_TxDMACallback, &s_dmaPrivateHandle[instance]);
197 DMA_SetCallback(handle->rxHandle, SPI_RxDMACallback, &s_dmaPrivateHandle[instance]);
198
199 return kStatus_Success;
200 }
201
202 /*!
203 * brief Perform a non-blocking SPI transfer using DMA.
204 *
205 * note This interface returned immediately after transfer initiates, users should call
206 * SPI_GetTransferStatus to poll the transfer status to check whether SPI transfer finished.
207 *
208 * param base SPI peripheral base address.
209 * param handle SPI DMA handle pointer.
210 * param xfer Pointer to dma transfer structure.
211 * retval kStatus_Success Successfully start a transfer.
212 * retval kStatus_InvalidArgument Input argument is invalid.
213 * retval kStatus_SPI_Busy SPI is not idle, is running another transfer.
214 */
SPI_MasterTransferDMA(SPI_Type * base,spi_dma_handle_t * handle,spi_transfer_t * xfer)215 status_t SPI_MasterTransferDMA(SPI_Type *base, spi_dma_handle_t *handle, spi_transfer_t *xfer)
216 {
217 assert(!((NULL == handle) || (NULL == xfer)));
218
219 uint32_t instance;
220 status_t result = kStatus_Success;
221 spi_config_t *spi_config_p;
222 uint32_t address;
223 void *nextDesc = NULL;
224 uint32_t firstTimeSize = 0;
225 dma_transfer_config_t xferConfig = {0};
226 spi_config_p = (spi_config_t *)SPI_GetConfig(base);
227 bool firstTimeIntFlag = false;
228 bool lastTimeIntFlag = false;
229 uint8_t bytesPerFrame =
230 (uint8_t)((spi_config_p->dataWidth > kSPI_Data8Bits) ? (sizeof(uint16_t)) : (sizeof(uint8_t)));
231 handle->bytesPerFrame = bytesPerFrame;
232 uint8_t lastwordBytes = 0U;
233
234 if ((xfer->configFlags & (uint32_t)kSPI_FrameAssert) != 0U)
235 {
236 handle->lastwordBytes = bytesPerFrame;
237 lastwordBytes = bytesPerFrame;
238 }
239 else
240 {
241 handle->lastwordBytes = 0U;
242 lastwordBytes = 0U;
243 }
244
245 if ((NULL == handle) || (NULL == xfer))
246 {
247 return kStatus_InvalidArgument;
248 }
249
250 /* Byte size is zero. */
251 if (xfer->dataSize == 0U)
252 {
253 return kStatus_InvalidArgument;
254 }
255 /* cannot get instance from base address */
256 instance = SPI_GetInstance(base);
257
258 /* Check if the device is busy */
259 if (handle->state == (uint8_t)kSPI_Busy)
260 {
261 return kStatus_SPI_Busy;
262 }
263 else
264 {
265 /* Set the dma unit by dataSize */
266 if (xfer->dataSize <= bytesPerFrame)
267 {
268 nextDesc = NULL;
269 firstTimeSize = xfer->dataSize;
270 firstTimeIntFlag = false;
271 lastTimeIntFlag = true;
272 }
273 else if (xfer->dataSize - lastwordBytes <= handle->dataBytesEveryTime)
274 {
275 firstTimeSize = xfer->dataSize - lastwordBytes;
276 if (lastwordBytes != 0U)
277 {
278 firstTimeIntFlag = false;
279 lastTimeIntFlag = false;
280 nextDesc = &s_spi_descriptor_table[instance];
281 }
282 else
283 {
284 nextDesc = NULL;
285 firstTimeIntFlag = true;
286 }
287 }
288 else
289 {
290 firstTimeSize = handle->dataBytesEveryTime;
291 nextDesc = NULL;
292 firstTimeIntFlag = true;
293 lastTimeIntFlag = false;
294 }
295
296 /* Clear FIFOs before transfer. */
297 base->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
298 base->FIFOSTAT |= SPI_FIFOSTAT_TXERR_MASK | SPI_FIFOSTAT_RXERR_MASK;
299
300 handle->state = (uint8_t)kSPI_Busy;
301 handle->transferSize = xfer->dataSize;
302
303 /* receive */
304 SPI_EnableRxDMA(base, true);
305 address = (uint32_t)&base->FIFORD;
306 if (xfer->rxData != NULL)
307 {
308 handle->rxEndData = xfer->rxData + xfer->dataSize;
309 DMA_PrepareTransfer(&xferConfig, (uint32_t *)address, xfer->rxData, bytesPerFrame, firstTimeSize,
310 kDMA_PeripheralToMemory, NULL);
311 handle->rxNextData = xfer->rxData + firstTimeSize;
312 }
313 else
314 {
315 DMA_PrepareTransfer(&xferConfig, (uint32_t *)address, &s_rxDummy,
316 ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (sizeof(uint16_t)) : (sizeof(uint8_t))),
317 xfer->dataSize, kDMA_StaticToStatic, NULL);
318 }
319 (void)DMA_SubmitTransfer(handle->rxHandle, &xferConfig);
320 handle->rxInProgress = true;
321 DMA_StartTransfer(handle->rxHandle);
322
323 /* transmit */
324 SPI_EnableTxDMA(base, true);
325 address = (uint32_t)&base->FIFOWR;
326 if (xfer->txData != NULL)
327 {
328 handle->txEndData = xfer->txData + xfer->dataSize;
329 handle->txNextData = xfer->txData + firstTimeSize;
330 if ((xfer->configFlags & (uint32_t)kSPI_FrameAssert) != 0U)
331 {
332 PrepareTxLastWord(xfer, &s_txLastWord[instance], spi_config_p);
333 }
334 /* If end of tranfer function is enabled and data transfer frame is bigger then 1, use dma
335 * descriptor to send the last data.
336 */
337 if (((xfer->configFlags & (uint32_t)kSPI_FrameAssert) != 0U) &&
338 ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (xfer->dataSize > 2U) : (xfer->dataSize > 1U)))
339 {
340 dma_xfercfg_t tmp_xfercfg;
341 tmp_xfercfg.valid = true;
342 tmp_xfercfg.swtrig = true;
343 tmp_xfercfg.intA = false;
344 tmp_xfercfg.byteWidth = 4U;
345 tmp_xfercfg.srcInc = 0;
346 tmp_xfercfg.dstInc = 0;
347 tmp_xfercfg.transferCount = 1U;
348 tmp_xfercfg.reload = false;
349 tmp_xfercfg.clrtrig = false;
350 tmp_xfercfg.intB = true;
351 /* Create chained descriptor to transmit last word */
352 DMA_CreateDescriptor(&s_spi_descriptor_table[instance], &tmp_xfercfg, &s_txLastWord[instance],
353 (uint32_t *)address, NULL);
354 }
355 DMA_PrepareTransfer(&xferConfig, (void *)xfer->txData, (uint32_t *)address, bytesPerFrame, firstTimeSize,
356 kDMA_MemoryToPeripheral, nextDesc);
357
358 /* Disable interrupts for first descriptor to avoid calling callback twice. */
359 xferConfig.xfercfg.intA = firstTimeIntFlag;
360 xferConfig.xfercfg.intB = lastTimeIntFlag;
361 result = DMA_SubmitTransfer(handle->txHandle, &xferConfig);
362 if (result != kStatus_Success)
363 {
364 return result;
365 }
366 }
367 else
368 {
369 /* Setup tx dummy data. */
370 SPI_SetupDummy(base, &s_txDummy[instance], xfer, spi_config_p);
371 if (((xfer->configFlags & (uint32_t)kSPI_FrameAssert) != 0U) &&
372 ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (xfer->dataSize > 2U) : (xfer->dataSize > 1U)))
373 {
374 dma_xfercfg_t tmp_xfercfg;
375 tmp_xfercfg.valid = true;
376 tmp_xfercfg.swtrig = true;
377 tmp_xfercfg.intA = true;
378 tmp_xfercfg.byteWidth = (uint8_t)sizeof(uint32_t);
379 tmp_xfercfg.srcInc = 0;
380 tmp_xfercfg.dstInc = 0;
381 tmp_xfercfg.transferCount = 1;
382 tmp_xfercfg.reload = false;
383 tmp_xfercfg.clrtrig = false;
384 tmp_xfercfg.intB = false;
385 /* Create chained descriptor to transmit last word */
386 DMA_CreateDescriptor(&s_spi_descriptor_table[instance], &tmp_xfercfg, &s_txDummy[instance].lastWord,
387 (uint32_t *)address, NULL);
388 /* Use common API to setup first descriptor */
389 DMA_PrepareTransfer(
390 &xferConfig, &s_txDummy[instance].word, (uint32_t *)address,
391 ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (sizeof(uint16_t)) : (sizeof(uint8_t))),
392 ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (xfer->dataSize - 2U) : (xfer->dataSize - 1U)),
393 kDMA_StaticToStatic, &s_spi_descriptor_table[instance]);
394 /* Disable interrupts for first descriptor to avoid calling callback twice */
395 xferConfig.xfercfg.intA = false;
396 xferConfig.xfercfg.intB = false;
397 result = DMA_SubmitTransfer(handle->txHandle, &xferConfig);
398 if (result != kStatus_Success)
399 {
400 return result;
401 }
402 }
403 else
404 {
405 DMA_PrepareTransfer(
406 &xferConfig, &s_txDummy[instance].word, (uint32_t *)address,
407 ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (sizeof(uint16_t)) : (sizeof(uint8_t))),
408 xfer->dataSize, kDMA_StaticToStatic, NULL);
409 result = DMA_SubmitTransfer(handle->txHandle, &xferConfig);
410 if (result != kStatus_Success)
411 {
412 return result;
413 }
414 }
415 }
416
417 handle->txInProgress = true;
418 uint32_t tmpData = 0U;
419 uint32_t writeAddress = (uint32_t) & (base->FIFOWR) + 2UL;
420 XferToFifoWR(xfer, &tmpData);
421 SpiConfigToFifoWR(spi_config_p, &tmpData);
422
423 /* Setup the control info.
424 * Halfword writes to just the control bits (offset 0xE22) doesn't push anything into the FIFO.
425 * And the data access type of control bits must be uint16_t, byte writes or halfword writes to FIFOWR
426 * will push the data and the current control bits into the FIFO.
427 */
428 if (((xfer->configFlags & (uint32_t)kSPI_FrameAssert) != 0U) &&
429 ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (xfer->dataSize == 2U) : (xfer->dataSize == 1U)))
430 {
431 *(uint16_t *)writeAddress = (uint16_t)(tmpData >> 16U);
432 }
433 else
434 {
435 /* Clear the SPI_FIFOWR_EOT_MASK bit when data is not the last. */
436 tmpData &= (~(uint32_t)kSPI_FrameAssert);
437 *(uint16_t *)writeAddress = (uint16_t)(tmpData >> 16U);
438 }
439
440 DMA_StartTransfer(handle->txHandle);
441 }
442
443 return result;
444 }
445
446 /*!
447 * brief Transfers a block of data using a DMA method.
448 *
449 * This function using polling way to do the first half transimission and using DMA way to
450 * do the srcond half transimission, the transfer mechanism is half-duplex.
451 * When do the second half transimission, code will return right away. When all data is transferred,
452 * the callback function is called.
453 *
454 * param base SPI base pointer
455 * param handle A pointer to the spi_master_dma_handle_t structure which stores the transfer state.
456 * param transfer A pointer to the spi_half_duplex_transfer_t structure.
457 * return status of status_t.
458 */
SPI_MasterHalfDuplexTransferDMA(SPI_Type * base,spi_dma_handle_t * handle,spi_half_duplex_transfer_t * xfer)459 status_t SPI_MasterHalfDuplexTransferDMA(SPI_Type *base, spi_dma_handle_t *handle, spi_half_duplex_transfer_t *xfer)
460 {
461 assert((xfer != NULL) && (handle != NULL));
462 spi_transfer_t tempXfer = {0};
463 status_t status;
464
465 if (xfer->isTransmitFirst)
466 {
467 tempXfer.txData = xfer->txData;
468 tempXfer.rxData = NULL;
469 tempXfer.dataSize = xfer->txDataSize;
470 }
471 else
472 {
473 tempXfer.txData = NULL;
474 tempXfer.rxData = xfer->rxData;
475 tempXfer.dataSize = xfer->rxDataSize;
476 }
477 /* If the pcs pin keep assert between transmit and receive. */
478 if (xfer->isPcsAssertInTransfer)
479 {
480 tempXfer.configFlags = (xfer->configFlags) & (~(uint32_t)kSPI_FrameAssert);
481 }
482 else
483 {
484 tempXfer.configFlags = (xfer->configFlags) | (uint32_t)kSPI_FrameAssert;
485 }
486
487 status = SPI_MasterTransferBlocking(base, &tempXfer);
488 if (status != kStatus_Success)
489 {
490 return status;
491 }
492
493 if (xfer->isTransmitFirst)
494 {
495 tempXfer.txData = NULL;
496 tempXfer.rxData = xfer->rxData;
497 tempXfer.dataSize = xfer->rxDataSize;
498 }
499 else
500 {
501 tempXfer.txData = xfer->txData;
502 tempXfer.rxData = NULL;
503 tempXfer.dataSize = xfer->txDataSize;
504 }
505 tempXfer.configFlags = xfer->configFlags;
506
507 status = SPI_MasterTransferDMA(base, handle, &tempXfer);
508
509 return status;
510 }
511
SPI_RxDMACallback(dma_handle_t * handle,void * userData,bool transferDone,uint32_t intmode)512 static void SPI_RxDMACallback(dma_handle_t *handle, void *userData, bool transferDone, uint32_t intmode)
513 {
514 spi_dma_private_handle_t *privHandle = (spi_dma_private_handle_t *)userData;
515 spi_dma_handle_t *spiHandle = privHandle->handle;
516 SPI_Type *base = privHandle->base;
517 status_t result = kStatus_Success;
518 uint8_t bytesPerFrame = spiHandle->bytesPerFrame;
519 uint32_t nextDataSize = 0;
520 uint32_t address = (uint32_t)&base->FIFORD;
521
522 if (spiHandle->rxNextData >= spiHandle->rxEndData)
523 {
524 /* change the state */
525 spiHandle->rxInProgress = false;
526 /* All finished, call the callback */
527 if ((spiHandle->txInProgress == false) && (spiHandle->rxInProgress == false))
528 {
529 spiHandle->state = (uint8_t)kSPI_Idle;
530 if (spiHandle->callback != NULL)
531 {
532 (spiHandle->callback)(base, spiHandle, kStatus_Success, spiHandle->userData);
533 }
534 }
535 }
536 else
537 {
538 /* need transmit by DMA again */
539 if (spiHandle->rxEndData <= (spiHandle->dataBytesEveryTime + spiHandle->rxNextData))
540 {
541 nextDataSize = (uint32_t)((uint32_t)spiHandle->rxEndData - (uint32_t)spiHandle->rxNextData);
542 }
543 else if (spiHandle->rxEndData > (spiHandle->dataBytesEveryTime + spiHandle->rxNextData))
544 {
545 nextDataSize = spiHandle->dataBytesEveryTime;
546 }
547 else
548 {
549 /* MISRA 15.7*/
550 }
551 dma_transfer_config_t xferConfig = {0};
552 DMA_PrepareTransfer(&xferConfig, (uint32_t *)(address), (uint8_t *)spiHandle->rxNextData, bytesPerFrame,
553 nextDataSize, kDMA_PeripheralToMemory, NULL);
554 spiHandle->rxNextData = (uint8_t *)(spiHandle->rxNextData + nextDataSize);
555 result = DMA_SubmitTransfer(spiHandle->rxHandle, &xferConfig);
556 if (result != kStatus_Success)
557 {
558 return;
559 }
560 DMA_StartTransfer(spiHandle->rxHandle);
561 }
562 }
563
SPI_TxDMACallback(dma_handle_t * handle,void * userData,bool transferDone,uint32_t intmode)564 static void SPI_TxDMACallback(dma_handle_t *handle, void *userData, bool transferDone, uint32_t intmode)
565 {
566 spi_dma_private_handle_t *privHandle = (spi_dma_private_handle_t *)userData;
567 spi_dma_handle_t *spiHandle = privHandle->handle;
568 SPI_Type *base = privHandle->base;
569 status_t result = kStatus_Success;
570 uint32_t instance = spiHandle->instance;
571 bool thisTimeIntFlag = false;
572 uint8_t bytesPerFrame = spiHandle->bytesPerFrame;
573 void *nextDesc = NULL;
574 uint32_t nextDataSize = 0U;
575 uint8_t lastwordBytes = spiHandle->lastwordBytes;
576 uint32_t writeAddress = (uint32_t) & (base->FIFOWR);
577 if (spiHandle->txNextData + lastwordBytes >= spiHandle->txEndData)
578 {
579 spiHandle->txInProgress = false;
580 if ((spiHandle->txInProgress == false) && (spiHandle->rxInProgress == false))
581 {
582 spiHandle->state = (uint8_t)kSPI_Idle;
583 if (spiHandle->callback != NULL)
584 {
585 (spiHandle->callback)(base, spiHandle, kStatus_Success, spiHandle->userData);
586 }
587 }
588 }
589 else
590 {
591 if ((uint32_t)((uint32_t)(spiHandle->txEndData)) <=
592 (spiHandle->dataBytesEveryTime + lastwordBytes + (uint32_t)spiHandle->txNextData))
593 {
594 if (lastwordBytes != 0U)
595 {
596 nextDesc = &s_spi_descriptor_table[instance];
597 thisTimeIntFlag = false;
598 }
599 else
600 {
601 thisTimeIntFlag = true;
602 }
603 nextDataSize = (uint32_t)((uint32_t)spiHandle->txEndData - (uint32_t)spiHandle->txNextData - lastwordBytes);
604 }
605 else if ((uint32_t)(spiHandle->txEndData) >
606 (spiHandle->dataBytesEveryTime + lastwordBytes + (uint32_t)spiHandle->txNextData))
607 {
608 nextDesc = NULL;
609 nextDataSize = spiHandle->dataBytesEveryTime;
610 thisTimeIntFlag = true;
611 }
612 else
613 {
614 /* MISRA 15.7*/
615 }
616 dma_transfer_config_t xferConfig = {0};
617 DMA_PrepareTransfer(&xferConfig, (uint8_t *)spiHandle->txNextData, (uint32_t *)(writeAddress), bytesPerFrame,
618 nextDataSize, kDMA_MemoryToPeripheral, nextDesc);
619 spiHandle->txNextData = (uint8_t *)(spiHandle->txNextData + nextDataSize);
620 xferConfig.xfercfg.intA = thisTimeIntFlag;
621 xferConfig.xfercfg.intB = false;
622 result = DMA_SubmitTransfer(spiHandle->txHandle, &xferConfig);
623 if (result != kStatus_Success)
624 {
625 return;
626 }
627 DMA_StartTransfer(spiHandle->txHandle);
628 }
629 }
630
631 /*!
632 * brief Abort a SPI transfer using DMA.
633 *
634 * param base SPI peripheral base address.
635 * param handle SPI DMA handle pointer.
636 */
SPI_MasterTransferAbortDMA(SPI_Type * base,spi_dma_handle_t * handle)637 void SPI_MasterTransferAbortDMA(SPI_Type *base, spi_dma_handle_t *handle)
638 {
639 assert(NULL != handle);
640
641 /* Stop tx transfer first */
642 DMA_AbortTransfer(handle->txHandle);
643 /* Then rx transfer */
644 DMA_AbortTransfer(handle->rxHandle);
645
646 /* Set the handle state */
647 handle->txInProgress = false;
648 handle->rxInProgress = false;
649 handle->state = (uint8_t)kSPI_Idle;
650 }
651
652 /*!
653 * brief Gets the master DMA transfer remaining bytes.
654 *
655 * This function gets the master DMA transfer remaining bytes.
656 *
657 * param base SPI peripheral base address.
658 * param handle A pointer to the spi_dma_handle_t structure which stores the transfer state.
659 * param count A number of bytes transferred by the non-blocking transaction.
660 * return status of status_t.
661 */
SPI_MasterTransferGetCountDMA(SPI_Type * base,spi_dma_handle_t * handle,size_t * count)662 status_t SPI_MasterTransferGetCountDMA(SPI_Type *base, spi_dma_handle_t *handle, size_t *count)
663 {
664 assert(handle != NULL);
665
666 if (NULL == count)
667 {
668 return kStatus_InvalidArgument;
669 }
670
671 /* Catch when there is not an active transfer. */
672 if (handle->state != (uint8_t)kSPI_Busy)
673 {
674 *count = 0;
675 return kStatus_NoTransferInProgress;
676 }
677
678 size_t bytes;
679
680 bytes = DMA_GetRemainingBytes(handle->rxHandle->base, handle->rxHandle->channel);
681
682 *count = handle->transferSize - bytes;
683
684 return kStatus_Success;
685 }
686