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_lpspi_edma.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.lpspi_edma" |
18 | #endif |
19 | |
20 | /*! |
21 | * @brief Structure definition for dspi_master_edma_private_handle_t. The structure is private. |
22 | */ |
23 | typedef struct _lpspi_master_edma_private_handle |
24 | { |
25 | LPSPI_Type *base; /*!< LPSPI peripheral base address. */ |
26 | lpspi_master_edma_handle_t *handle; /*!< lpspi_master_edma_handle_t handle */ |
27 | } lpspi_master_edma_private_handle_t; |
28 | |
29 | /*! |
30 | * @brief Structure definition for dspi_slave_edma_private_handle_t. The structure is private. |
31 | */ |
32 | typedef struct _lpspi_slave_edma_private_handle |
33 | { |
34 | LPSPI_Type *base; /*!< LPSPI peripheral base address. */ |
35 | lpspi_slave_edma_handle_t *handle; /*!< lpspi_slave_edma_handle_t handle */ |
36 | } lpspi_slave_edma_private_handle_t; |
37 | |
38 | /*********************************************************************************************************************** |
39 | * Prototypes |
40 | ***********************************************************************************************************************/ |
41 | |
42 | /*! |
43 | * @brief EDMA_LpspiMasterCallback after the LPSPI master transfer completed by using EDMA. |
44 | * This is not a public API. |
45 | */ |
46 | static void EDMA_LpspiMasterCallback(edma_handle_t *edmaHandle, |
47 | void *g_lpspiEdmaPrivateHandle, |
48 | bool transferDone, |
49 | uint32_t tcds); |
50 | |
51 | /*! |
52 | * @brief EDMA_LpspiSlaveCallback after the LPSPI slave transfer completed by using EDMA. |
53 | * This is not a public API. |
54 | */ |
55 | static void EDMA_LpspiSlaveCallback(edma_handle_t *edmaHandle, |
56 | void *g_lpspiEdmaPrivateHandle, |
57 | bool transferDone, |
58 | uint32_t tcds); |
59 | |
60 | static void LPSPI_SeparateEdmaReadData(uint8_t *rxData, uint32_t readData, uint32_t bytesEachRead, bool isByteSwap); |
61 | |
62 | /*********************************************************************************************************************** |
63 | * Variables |
64 | ***********************************************************************************************************************/ |
65 | /*! @brief Pointers to lpspi bases for each instance. */ |
66 | static LPSPI_Type *const s_lpspiBases[] = LPSPI_BASE_PTRS; |
67 | |
68 | /*! @brief Pointers to lpspi edma handles for each instance. */ |
69 | static lpspi_master_edma_private_handle_t s_lpspiMasterEdmaPrivateHandle[ARRAY_SIZE(s_lpspiBases)]; |
70 | static lpspi_slave_edma_private_handle_t s_lpspiSlaveEdmaPrivateHandle[ARRAY_SIZE(s_lpspiBases)]; |
71 | |
72 | /*********************************************************************************************************************** |
73 | * Code |
74 | ***********************************************************************************************************************/ |
75 | static void LPSPI_SeparateEdmaReadData(uint8_t *rxData, uint32_t readData, uint32_t bytesEachRead, bool isByteSwap) |
76 | { |
77 | assert(rxData != NULL); |
78 | |
79 | switch (bytesEachRead) |
80 | { |
81 | case 1: |
82 | if (!isByteSwap) |
83 | { |
84 | *rxData = (uint8_t)readData; |
85 | ++rxData; |
86 | } |
87 | else |
88 | { |
89 | *rxData = (uint8_t)(readData >> 24); |
90 | ++rxData; |
91 | } |
92 | break; |
93 | |
94 | case 2: |
95 | if (!isByteSwap) |
96 | { |
97 | *rxData = (uint8_t)readData; |
98 | ++rxData; |
99 | *rxData = (uint8_t)(readData >> 8); |
100 | ++rxData; |
101 | } |
102 | else |
103 | { |
104 | *rxData = (uint8_t)(readData >> 16); |
105 | ++rxData; |
106 | *rxData = (uint8_t)(readData >> 24); |
107 | ++rxData; |
108 | } |
109 | break; |
110 | |
111 | case 4: |
112 | |
113 | *rxData = (uint8_t)readData; |
114 | ++rxData; |
115 | *rxData = (uint8_t)(readData >> 8); |
116 | ++rxData; |
117 | *rxData = (uint8_t)(readData >> 16); |
118 | ++rxData; |
119 | *rxData = (uint8_t)(readData >> 24); |
120 | ++rxData; |
121 | |
122 | break; |
123 | |
124 | default: |
125 | assert(false); |
126 | break; |
127 | } |
128 | } |
129 | |
130 | /*! |
131 | * brief Initializes the LPSPI master eDMA handle. |
132 | * |
133 | * This function initializes the LPSPI eDMA handle which can be used for other LPSPI transactional APIs. Usually, for a |
134 | * specified LPSPI instance, call this API once to get the initialized handle. |
135 | * |
136 | * Note that the LPSPI eDMA has a separated (Rx and Rx as two sources) or shared (Rx and Tx are the same source) DMA |
137 | * request source. |
138 | * (1) For a separated DMA request source, enable and set the Rx DMAMUX source for edmaRxRegToRxDataHandle and |
139 | * Tx DMAMUX source for edmaIntermediaryToTxRegHandle. |
140 | * (2) For a shared DMA request source, enable and set the Rx/Rx DMAMUX source for edmaRxRegToRxDataHandle. |
141 | * |
142 | * param base LPSPI peripheral base address. |
143 | * param handle LPSPI handle pointer to lpspi_master_edma_handle_t. |
144 | * param callback LPSPI callback. |
145 | * param userData callback function parameter. |
146 | * param edmaRxRegToRxDataHandle edmaRxRegToRxDataHandle pointer to edma_handle_t. |
147 | * param edmaTxDataToTxRegHandle edmaTxDataToTxRegHandle pointer to edma_handle_t. |
148 | */ |
149 | void LPSPI_MasterTransferCreateHandleEDMA(LPSPI_Type *base, |
150 | lpspi_master_edma_handle_t *handle, |
151 | lpspi_master_edma_transfer_callback_t callback, |
152 | void *userData, |
153 | edma_handle_t *edmaRxRegToRxDataHandle, |
154 | edma_handle_t *edmaTxDataToTxRegHandle) |
155 | { |
156 | assert(handle != NULL); |
157 | assert(edmaRxRegToRxDataHandle != NULL); |
158 | assert(edmaTxDataToTxRegHandle != NULL); |
159 | |
160 | /* Zero the handle. */ |
161 | (void)memset(handle, 0, sizeof(*handle)); |
162 | |
163 | uint32_t instance = LPSPI_GetInstance(base); |
164 | |
165 | s_lpspiMasterEdmaPrivateHandle[instance].base = base; |
166 | s_lpspiMasterEdmaPrivateHandle[instance].handle = handle; |
167 | |
168 | handle->callback = callback; |
169 | handle->userData = userData; |
170 | |
171 | handle->edmaRxRegToRxDataHandle = edmaRxRegToRxDataHandle; |
172 | handle->edmaTxDataToTxRegHandle = edmaTxDataToTxRegHandle; |
173 | } |
174 | |
175 | static void LPSPI_PrepareTransferEDMA(LPSPI_Type *base) |
176 | { |
177 | /* Flush FIFO, clear status, disable all the inerrupts and DMA requests. */ |
178 | LPSPI_FlushFifo(base, true, true); |
179 | LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_AllStatusFlag); |
180 | LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable); |
181 | LPSPI_DisableDMA(base, (uint32_t)kLPSPI_RxDmaEnable | (uint32_t)kLPSPI_TxDmaEnable); |
182 | } |
183 | |
184 | /*! |
185 | * brief LPSPI master transfer data using eDMA. |
186 | * |
187 | * This function transfers data using eDMA. This is a non-blocking function, which returns right away. When all data |
188 | * is transferred, the callback function is called. |
189 | * |
190 | * Note: |
191 | * The transfer data size should be an integer multiple of bytesPerFrame if bytesPerFrame is less than or equal to 4. |
192 | * For bytesPerFrame greater than 4: |
193 | * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not an integer multiple of 4. |
194 | * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame. |
195 | * |
196 | * param base LPSPI peripheral base address. |
197 | * param handle pointer to lpspi_master_edma_handle_t structure which stores the transfer state. |
198 | * param transfer pointer to lpspi_transfer_t structure. |
199 | * return status of status_t. |
200 | */ |
201 | status_t LPSPI_MasterTransferEDMA(LPSPI_Type *base, lpspi_master_edma_handle_t *handle, lpspi_transfer_t *transfer) |
202 | { |
203 | assert(handle != NULL); |
204 | assert(transfer != NULL); |
205 | |
206 | /* Check that we're not busy.*/ |
207 | if (handle->state == (uint8_t)kLPSPI_Busy) |
208 | { |
209 | return kStatus_LPSPI_Busy; |
210 | } |
211 | |
212 | /* Disable module before configuration */ |
213 | LPSPI_Enable(base, false); |
214 | /* Check arguements */ |
215 | if (!LPSPI_CheckTransferArgument(base, transfer, true)) |
216 | { |
217 | return kStatus_InvalidArgument; |
218 | } |
219 | |
220 | LPSPI_PrepareTransferEDMA(base); |
221 | |
222 | /* Variables */ |
223 | bool isThereExtraTxBytes = false; |
224 | bool isByteSwap = ((transfer->configFlags & (uint32_t)kLPSPI_MasterByteSwap) != 0U); |
225 | bool isPcsContinuous = ((transfer->configFlags & (uint32_t)kLPSPI_MasterPcsContinuous) != 0U); |
226 | uint32_t instance = LPSPI_GetInstance(base); |
227 | uint8_t dummyData = g_lpspiDummyData[instance]; |
228 | uint8_t bytesLastWrite = 0; |
229 | /*Used for byte swap*/ |
230 | uint32_t addrOffset = 0; |
231 | uint32_t rxAddr = LPSPI_GetRxRegisterAddress(base); |
232 | uint32_t txAddr = LPSPI_GetTxRegisterAddress(base); |
233 | uint32_t whichPcs = (transfer->configFlags & LPSPI_MASTER_PCS_MASK) >> LPSPI_MASTER_PCS_SHIFT; |
234 | uint32_t bytesPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) / 8U + 1U; |
235 | edma_transfer_config_t transferConfigRx; |
236 | edma_transfer_config_t transferConfigTx; |
237 | edma_tcd_t *softwareTCD_pcsContinuous = (edma_tcd_t *)((uint32_t)(&handle->lpspiSoftwareTCD[2]) & (~0x1FU)); |
238 | edma_tcd_t *softwareTCD_extraBytes = (edma_tcd_t *)((uint32_t)(&handle->lpspiSoftwareTCD[1]) & (~0x1FU)); |
239 | |
240 | handle->state = (uint8_t)kLPSPI_Busy; |
241 | handle->txData = transfer->txData; |
242 | handle->rxData = transfer->rxData; |
243 | handle->txRemainingByteCount = transfer->dataSize; |
244 | handle->rxRemainingByteCount = transfer->dataSize; |
245 | handle->totalByteCount = transfer->dataSize; |
246 | handle->writeRegRemainingTimes = (transfer->dataSize / bytesPerFrame) * ((bytesPerFrame + 3U) / 4U); |
247 | handle->readRegRemainingTimes = handle->writeRegRemainingTimes; |
248 | handle->txBuffIfNull = |
249 | ((uint32_t)dummyData) | ((uint32_t)dummyData << 8) | ((uint32_t)dummyData << 16) | ((uint32_t)dummyData << 24); |
250 | /*The TX and RX FIFO sizes are always the same*/ |
251 | handle->fifoSize = LPSPI_GetRxFifoSize(base); |
252 | handle->isPcsContinuous = isPcsContinuous; |
253 | handle->isByteSwap = isByteSwap; |
254 | handle->isThereExtraRxBytes = false; |
255 | |
256 | /*Because DMA is fast enough , so set the RX and TX watermarks to 0 .*/ |
257 | LPSPI_SetFifoWatermarks(base, 0U, 0U); |
258 | |
259 | /* Transfers will stall when transmit FIFO is empty or receive FIFO is full. */ |
260 | base->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK); |
261 | |
262 | /* Enable module for following configuration of TCR to take effect. */ |
263 | LPSPI_Enable(base, true); |
264 | |
265 | /* For DMA transfer , we'd better not masked the transmit data and receive data in TCR since the transfer flow is |
266 | * hard to controlled by software. */ |
267 | base->TCR = (base->TCR & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_BYSW_MASK | LPSPI_TCR_PCS_MASK)) | |
268 | LPSPI_TCR_CONT(isPcsContinuous) | LPSPI_TCR_BYSW(isByteSwap) | LPSPI_TCR_PCS(whichPcs); |
269 | |
270 | /*Calculate the bytes for write/read the TX/RX register each time*/ |
271 | if (bytesPerFrame <= 4U) |
272 | { |
273 | handle->bytesEachWrite = (uint8_t)bytesPerFrame; |
274 | handle->bytesEachRead = (uint8_t)bytesPerFrame; |
275 | |
276 | handle->bytesLastRead = (uint8_t)bytesPerFrame; |
277 | } |
278 | else |
279 | { |
280 | handle->bytesEachWrite = 4U; |
281 | handle->bytesEachRead = 4U; |
282 | |
283 | handle->bytesLastRead = 4U; |
284 | |
285 | if ((transfer->dataSize % 4U) != 0U) |
286 | { |
287 | bytesLastWrite = (uint8_t)(transfer->dataSize % 4U); |
288 | handle->bytesLastRead = bytesLastWrite; |
289 | |
290 | isThereExtraTxBytes = true; |
291 | |
292 | --handle->writeRegRemainingTimes; |
293 | |
294 | --handle->readRegRemainingTimes; |
295 | handle->isThereExtraRxBytes = true; |
296 | } |
297 | } |
298 | |
299 | EDMA_SetCallback(handle->edmaRxRegToRxDataHandle, EDMA_LpspiMasterCallback, |
300 | &s_lpspiMasterEdmaPrivateHandle[instance]); |
301 | |
302 | /* Configure rx EDMA transfer */ |
303 | EDMA_ResetChannel(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel); |
304 | |
305 | if (handle->rxData != NULL) |
306 | { |
307 | transferConfigRx.destAddr = (uint32_t) & (handle->rxData[0]); |
308 | transferConfigRx.destOffset = 1; |
309 | } |
310 | else |
311 | { |
312 | transferConfigRx.destAddr = (uint32_t) & (handle->rxBuffIfNull); |
313 | transferConfigRx.destOffset = 0; |
314 | } |
315 | transferConfigRx.destTransferSize = kEDMA_TransferSize1Bytes; |
316 | |
317 | addrOffset = 0; |
318 | switch (handle->bytesEachRead) |
319 | { |
320 | case (1U): |
321 | transferConfigRx.srcTransferSize = kEDMA_TransferSize1Bytes; |
322 | transferConfigRx.minorLoopBytes = 1; |
323 | if (handle->isByteSwap) |
324 | { |
325 | addrOffset = 3; |
326 | } |
327 | break; |
328 | |
329 | case (2U): |
330 | transferConfigRx.srcTransferSize = kEDMA_TransferSize2Bytes; |
331 | transferConfigRx.minorLoopBytes = 2; |
332 | if (handle->isByteSwap) |
333 | { |
334 | addrOffset = 2; |
335 | } |
336 | break; |
337 | |
338 | case (4U): |
339 | transferConfigRx.srcTransferSize = kEDMA_TransferSize4Bytes; |
340 | transferConfigRx.minorLoopBytes = 4; |
341 | break; |
342 | |
343 | default: |
344 | transferConfigRx.srcTransferSize = kEDMA_TransferSize1Bytes; |
345 | transferConfigRx.minorLoopBytes = 1; |
346 | assert(false); |
347 | break; |
348 | } |
349 | |
350 | transferConfigRx.srcAddr = (uint32_t)rxAddr + addrOffset; |
351 | transferConfigRx.srcOffset = 0; |
352 | |
353 | transferConfigRx.majorLoopCounts = handle->readRegRemainingTimes; |
354 | |
355 | /* Store the initially configured eDMA minor byte transfer count into the LPSPI handle */ |
356 | handle->nbytes = (uint8_t)transferConfigRx.minorLoopBytes; |
357 | |
358 | EDMA_SetTransferConfig(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel, |
359 | &transferConfigRx, NULL); |
360 | EDMA_EnableChannelInterrupts(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel, |
361 | (uint32_t)kEDMA_MajorInterruptEnable); |
362 | |
363 | /* Configure tx EDMA transfer */ |
364 | EDMA_ResetChannel(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel); |
365 | |
366 | if (isThereExtraTxBytes) |
367 | { |
368 | if (handle->txData != NULL) |
369 | { |
370 | transferConfigTx.srcAddr = (uint32_t) & (transfer->txData[transfer->dataSize - bytesLastWrite]); |
371 | transferConfigTx.srcOffset = 1; |
372 | } |
373 | else |
374 | { |
375 | transferConfigTx.srcAddr = (uint32_t)(&handle->txBuffIfNull); |
376 | transferConfigTx.srcOffset = 0; |
377 | } |
378 | |
379 | transferConfigTx.destOffset = 0; |
380 | |
381 | transferConfigTx.srcTransferSize = kEDMA_TransferSize1Bytes; |
382 | |
383 | addrOffset = 0; |
384 | switch (bytesLastWrite) |
385 | { |
386 | case (1U): |
387 | transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes; |
388 | transferConfigTx.minorLoopBytes = 1; |
389 | if (handle->isByteSwap) |
390 | { |
391 | addrOffset = 3; |
392 | } |
393 | break; |
394 | |
395 | case (2U): |
396 | transferConfigTx.destTransferSize = kEDMA_TransferSize2Bytes; |
397 | transferConfigTx.minorLoopBytes = 2; |
398 | if (handle->isByteSwap) |
399 | { |
400 | addrOffset = 2; |
401 | } |
402 | break; |
403 | |
404 | default: |
405 | transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes; |
406 | transferConfigTx.minorLoopBytes = 1; |
407 | assert(false); |
408 | break; |
409 | } |
410 | |
411 | transferConfigTx.destAddr = (uint32_t)txAddr + addrOffset; |
412 | transferConfigTx.majorLoopCounts = 1; |
413 | |
414 | EDMA_TcdReset(softwareTCD_extraBytes); |
415 | |
416 | if (handle->isPcsContinuous) |
417 | { |
418 | EDMA_TcdSetTransferConfig(softwareTCD_extraBytes, &transferConfigTx, softwareTCD_pcsContinuous); |
419 | } |
420 | else |
421 | { |
422 | EDMA_TcdSetTransferConfig(softwareTCD_extraBytes, &transferConfigTx, NULL); |
423 | } |
424 | } |
425 | |
426 | if (handle->isPcsContinuous) |
427 | { |
428 | handle->transmitCommand = base->TCR & ~(LPSPI_TCR_CONTC_MASK | LPSPI_TCR_CONT_MASK); |
429 | |
430 | transferConfigTx.srcAddr = (uint32_t) & (handle->transmitCommand); |
431 | transferConfigTx.srcOffset = 0; |
432 | |
433 | transferConfigTx.destAddr = (uint32_t) & (base->TCR); |
434 | transferConfigTx.destOffset = 0; |
435 | |
436 | transferConfigTx.srcTransferSize = kEDMA_TransferSize4Bytes; |
437 | transferConfigTx.destTransferSize = kEDMA_TransferSize4Bytes; |
438 | transferConfigTx.minorLoopBytes = 4; |
439 | transferConfigTx.majorLoopCounts = 1; |
440 | |
441 | EDMA_TcdReset(softwareTCD_pcsContinuous); |
442 | EDMA_TcdSetTransferConfig(softwareTCD_pcsContinuous, &transferConfigTx, NULL); |
443 | } |
444 | |
445 | if (handle->txData != NULL) |
446 | { |
447 | transferConfigTx.srcAddr = (uint32_t)(handle->txData); |
448 | transferConfigTx.srcOffset = 1; |
449 | } |
450 | else |
451 | { |
452 | transferConfigTx.srcAddr = (uint32_t)(&handle->txBuffIfNull); |
453 | transferConfigTx.srcOffset = 0; |
454 | } |
455 | |
456 | transferConfigTx.destOffset = 0; |
457 | |
458 | transferConfigTx.srcTransferSize = kEDMA_TransferSize1Bytes; |
459 | |
460 | addrOffset = 0U; |
461 | switch (handle->bytesEachRead) |
462 | { |
463 | case (1U): |
464 | transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes; |
465 | transferConfigTx.minorLoopBytes = 1; |
466 | if (handle->isByteSwap) |
467 | { |
468 | addrOffset = 3; |
469 | } |
470 | break; |
471 | |
472 | case (2U): |
473 | transferConfigTx.destTransferSize = kEDMA_TransferSize2Bytes; |
474 | transferConfigTx.minorLoopBytes = 2; |
475 | |
476 | if (handle->isByteSwap) |
477 | { |
478 | addrOffset = 2; |
479 | } |
480 | break; |
481 | |
482 | case (4U): |
483 | transferConfigTx.destTransferSize = kEDMA_TransferSize4Bytes; |
484 | transferConfigTx.minorLoopBytes = 4; |
485 | break; |
486 | |
487 | default: |
488 | transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes; |
489 | transferConfigTx.minorLoopBytes = 1; |
490 | assert(false); |
491 | break; |
492 | } |
493 | |
494 | transferConfigTx.destAddr = (uint32_t)txAddr + addrOffset; |
495 | |
496 | transferConfigTx.majorLoopCounts = handle->writeRegRemainingTimes; |
497 | |
498 | if (isThereExtraTxBytes) |
499 | { |
500 | EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel, |
501 | &transferConfigTx, softwareTCD_extraBytes); |
502 | } |
503 | else if (handle->isPcsContinuous) |
504 | { |
505 | EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel, |
506 | &transferConfigTx, softwareTCD_pcsContinuous); |
507 | } |
508 | else |
509 | { |
510 | EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel, |
511 | &transferConfigTx, NULL); |
512 | } |
513 | |
514 | EDMA_StartTransfer(handle->edmaTxDataToTxRegHandle); |
515 | EDMA_StartTransfer(handle->edmaRxRegToRxDataHandle); |
516 | LPSPI_EnableDMA(base, (uint32_t)kLPSPI_RxDmaEnable | (uint32_t)kLPSPI_TxDmaEnable); |
517 | |
518 | return kStatus_Success; |
519 | } |
520 | |
521 | static void EDMA_LpspiMasterCallback(edma_handle_t *edmaHandle, |
522 | void *g_lpspiEdmaPrivateHandle, |
523 | bool transferDone, |
524 | uint32_t tcds) |
525 | { |
526 | assert(edmaHandle != NULL); |
527 | assert(g_lpspiEdmaPrivateHandle != NULL); |
528 | |
529 | uint32_t readData; |
530 | |
531 | lpspi_master_edma_private_handle_t *lpspiEdmaPrivateHandle; |
532 | |
533 | lpspiEdmaPrivateHandle = (lpspi_master_edma_private_handle_t *)g_lpspiEdmaPrivateHandle; |
534 | |
535 | size_t rxRemainingByteCount = lpspiEdmaPrivateHandle->handle->rxRemainingByteCount; |
536 | uint8_t bytesLastRead = lpspiEdmaPrivateHandle->handle->bytesLastRead; |
537 | bool isByteSwap = lpspiEdmaPrivateHandle->handle->isByteSwap; |
538 | |
539 | LPSPI_DisableDMA(lpspiEdmaPrivateHandle->base, (uint32_t)kLPSPI_TxDmaEnable | (uint32_t)kLPSPI_RxDmaEnable); |
540 | |
541 | if (lpspiEdmaPrivateHandle->handle->isThereExtraRxBytes) |
542 | { |
543 | while (LPSPI_GetRxFifoCount(lpspiEdmaPrivateHandle->base) == 0U) |
544 | { |
545 | } |
546 | readData = LPSPI_ReadData(lpspiEdmaPrivateHandle->base); |
547 | |
548 | if (lpspiEdmaPrivateHandle->handle->rxData != NULL) |
549 | { |
550 | LPSPI_SeparateEdmaReadData(&(lpspiEdmaPrivateHandle->handle->rxData[rxRemainingByteCount - bytesLastRead]), |
551 | readData, bytesLastRead, isByteSwap); |
552 | } |
553 | } |
554 | |
555 | lpspiEdmaPrivateHandle->handle->state = (uint8_t)kLPSPI_Idle; |
556 | |
557 | if (lpspiEdmaPrivateHandle->handle->callback != NULL) |
558 | { |
559 | lpspiEdmaPrivateHandle->handle->callback(lpspiEdmaPrivateHandle->base, lpspiEdmaPrivateHandle->handle, |
560 | kStatus_Success, lpspiEdmaPrivateHandle->handle->userData); |
561 | } |
562 | } |
563 | |
564 | /*! |
565 | * brief LPSPI master aborts a transfer which is using eDMA. |
566 | * |
567 | * This function aborts a transfer which is using eDMA. |
568 | * |
569 | * param base LPSPI peripheral base address. |
570 | * param handle pointer to lpspi_master_edma_handle_t structure which stores the transfer state. |
571 | */ |
572 | void LPSPI_MasterTransferAbortEDMA(LPSPI_Type *base, lpspi_master_edma_handle_t *handle) |
573 | { |
574 | assert(handle != NULL); |
575 | |
576 | LPSPI_DisableDMA(base, (uint32_t)kLPSPI_RxDmaEnable | (uint32_t)kLPSPI_TxDmaEnable); |
577 | |
578 | EDMA_AbortTransfer(handle->edmaRxRegToRxDataHandle); |
579 | EDMA_AbortTransfer(handle->edmaTxDataToTxRegHandle); |
580 | |
581 | handle->state = (uint8_t)kLPSPI_Idle; |
582 | } |
583 | |
584 | /*! |
585 | * brief Gets the master eDMA transfer remaining bytes. |
586 | * |
587 | * This function gets the master eDMA transfer remaining bytes. |
588 | * |
589 | * param base LPSPI peripheral base address. |
590 | * param handle pointer to lpspi_master_edma_handle_t structure which stores the transfer state. |
591 | * param count Number of bytes transferred so far by the EDMA transaction. |
592 | * return status of status_t. |
593 | */ |
594 | status_t LPSPI_MasterTransferGetCountEDMA(LPSPI_Type *base, lpspi_master_edma_handle_t *handle, size_t *count) |
595 | { |
596 | assert(handle != NULL); |
597 | |
598 | if (NULL == count) |
599 | { |
600 | return kStatus_InvalidArgument; |
601 | } |
602 | |
603 | /* Catch when there is not an active transfer. */ |
604 | if (handle->state != (uint8_t)kLPSPI_Busy) |
605 | { |
606 | *count = 0; |
607 | return kStatus_NoTransferInProgress; |
608 | } |
609 | |
610 | size_t remainingByte; |
611 | |
612 | remainingByte = |
613 | (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->edmaRxRegToRxDataHandle->base, |
614 | handle->edmaRxRegToRxDataHandle->channel); |
615 | |
616 | *count = handle->totalByteCount - remainingByte; |
617 | |
618 | return kStatus_Success; |
619 | } |
620 | |
621 | /*! |
622 | * brief Initializes the LPSPI slave eDMA handle. |
623 | * |
624 | * This function initializes the LPSPI eDMA handle which can be used for other LPSPI transactional APIs. Usually, for a |
625 | * specified LPSPI instance, call this API once to get the initialized handle. |
626 | * |
627 | * Note that LPSPI eDMA has a separated (Rx and Tx as two sources) or shared (Rx and Tx as the same source) DMA request |
628 | * source. |
629 | * |
630 | * (1) For a separated DMA request source, enable and set the Rx DMAMUX source for edmaRxRegToRxDataHandle and |
631 | * Tx DMAMUX source for edmaTxDataToTxRegHandle. |
632 | * (2) For a shared DMA request source, enable and set the Rx/Rx DMAMUX source for edmaRxRegToRxDataHandle . |
633 | * |
634 | * param base LPSPI peripheral base address. |
635 | * param handle LPSPI handle pointer to lpspi_slave_edma_handle_t. |
636 | * param callback LPSPI callback. |
637 | * param userData callback function parameter. |
638 | * param edmaRxRegToRxDataHandle edmaRxRegToRxDataHandle pointer to edma_handle_t. |
639 | * param edmaTxDataToTxRegHandle edmaTxDataToTxRegHandle pointer to edma_handle_t. |
640 | */ |
641 | void LPSPI_SlaveTransferCreateHandleEDMA(LPSPI_Type *base, |
642 | lpspi_slave_edma_handle_t *handle, |
643 | lpspi_slave_edma_transfer_callback_t callback, |
644 | void *userData, |
645 | edma_handle_t *edmaRxRegToRxDataHandle, |
646 | edma_handle_t *edmaTxDataToTxRegHandle) |
647 | { |
648 | assert(handle != NULL); |
649 | assert(edmaRxRegToRxDataHandle != NULL); |
650 | assert(edmaTxDataToTxRegHandle != NULL); |
651 | |
652 | /* Zero the handle. */ |
653 | (void)memset(handle, 0, sizeof(*handle)); |
654 | |
655 | uint32_t instance = LPSPI_GetInstance(base); |
656 | |
657 | s_lpspiSlaveEdmaPrivateHandle[instance].base = base; |
658 | s_lpspiSlaveEdmaPrivateHandle[instance].handle = handle; |
659 | |
660 | handle->callback = callback; |
661 | handle->userData = userData; |
662 | |
663 | handle->edmaRxRegToRxDataHandle = edmaRxRegToRxDataHandle; |
664 | handle->edmaTxDataToTxRegHandle = edmaTxDataToTxRegHandle; |
665 | } |
666 | |
667 | /*! |
668 | * brief LPSPI slave transfers data using eDMA. |
669 | * |
670 | * This function transfers data using eDMA. This is a non-blocking function, which return right away. When all data |
671 | * is transferred, the callback function is called. |
672 | * |
673 | * Note: |
674 | * The transfer data size should be an integer multiple of bytesPerFrame if bytesPerFrame is less than or equal to 4. |
675 | * For bytesPerFrame greater than 4: |
676 | * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not an integer multiple of 4. |
677 | * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame. |
678 | * |
679 | * param base LPSPI peripheral base address. |
680 | * param handle pointer to lpspi_slave_edma_handle_t structure which stores the transfer state. |
681 | * param transfer pointer to lpspi_transfer_t structure. |
682 | * return status of status_t. |
683 | */ |
684 | status_t LPSPI_SlaveTransferEDMA(LPSPI_Type *base, lpspi_slave_edma_handle_t *handle, lpspi_transfer_t *transfer) |
685 | { |
686 | assert(handle != NULL); |
687 | assert(transfer != NULL); |
688 | |
689 | /* Check that we're not busy.*/ |
690 | if (handle->state == (uint8_t)kLPSPI_Busy) |
691 | { |
692 | return kStatus_LPSPI_Busy; |
693 | } |
694 | /* Disable module before configuration. */ |
695 | LPSPI_Enable(base, false); |
696 | /* Check arguements, also dma transfer can not support 3 bytes */ |
697 | if (!LPSPI_CheckTransferArgument(base, transfer, true)) |
698 | { |
699 | return kStatus_InvalidArgument; |
700 | } |
701 | |
702 | LPSPI_PrepareTransferEDMA(base); |
703 | |
704 | /* Variables */ |
705 | bool isThereExtraTxBytes = false; |
706 | bool isByteSwap = ((transfer->configFlags & (uint32_t)kLPSPI_MasterByteSwap) != 0U); |
707 | uint8_t bytesLastWrite = 0; |
708 | uint8_t dummyData = g_lpspiDummyData[LPSPI_GetInstance(base)]; |
709 | uint32_t mask = (uint32_t)kLPSPI_RxDmaEnable; |
710 | |
711 | /* Used for byte swap */ |
712 | uint32_t addrOffset = 0; |
713 | uint32_t instance = LPSPI_GetInstance(base); |
714 | uint32_t rxAddr = LPSPI_GetRxRegisterAddress(base); |
715 | uint32_t txAddr = LPSPI_GetTxRegisterAddress(base); |
716 | uint32_t whichPcs = (transfer->configFlags & LPSPI_MASTER_PCS_MASK) >> LPSPI_MASTER_PCS_SHIFT; |
717 | uint32_t bytesPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) / 8U + 1U; |
718 | edma_transfer_config_t transferConfigRx; |
719 | edma_transfer_config_t transferConfigTx; |
720 | edma_tcd_t *softwareTCD_extraBytes = (edma_tcd_t *)((uint32_t)(&handle->lpspiSoftwareTCD[1]) & (~0x1FU)); |
721 | |
722 | /* Assign the original value for members of transfer handle. */ |
723 | handle->state = (uint8_t)kLPSPI_Busy; |
724 | handle->txData = transfer->txData; |
725 | handle->rxData = transfer->rxData; |
726 | handle->txRemainingByteCount = transfer->dataSize; |
727 | handle->rxRemainingByteCount = transfer->dataSize; |
728 | handle->totalByteCount = transfer->dataSize; |
729 | handle->writeRegRemainingTimes = (transfer->dataSize / bytesPerFrame) * ((bytesPerFrame + 3U) / 4U); |
730 | handle->readRegRemainingTimes = handle->writeRegRemainingTimes; |
731 | handle->txBuffIfNull = |
732 | ((uint32_t)dummyData) | ((uint32_t)dummyData << 8) | ((uint32_t)dummyData << 16) | ((uint32_t)dummyData << 24); |
733 | /*The TX and RX FIFO sizes are always the same*/ |
734 | handle->fifoSize = LPSPI_GetRxFifoSize(base); |
735 | handle->isByteSwap = isByteSwap; |
736 | handle->isThereExtraRxBytes = false; |
737 | |
738 | /* Because DMA is fast enough, set the RX and TX watermarks to 0. */ |
739 | LPSPI_SetFifoWatermarks(base, 0U, 0U); |
740 | |
741 | /* Transfers will stall when transmit FIFO is empty or receive FIFO is full. */ |
742 | base->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK); |
743 | |
744 | /* Enable module for following configuration of TCR to take effect. */ |
745 | LPSPI_Enable(base, true); |
746 | |
747 | /* For DMA transfer, mask the transmit data if the tx data is null, for rx the receive data should not be masked at |
748 | any time since we use rx dma transfer finish cllback to indicate transfer finish. */ |
749 | base->TCR = |
750 | (base->TCR & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_BYSW_MASK | LPSPI_TCR_TXMSK_MASK)) | |
751 | LPSPI_TCR_TXMSK(transfer->txData == NULL) | LPSPI_TCR_BYSW(isByteSwap) | LPSPI_TCR_PCS(whichPcs); |
752 | |
753 | /*Calculate the bytes for write/read the TX/RX register each time*/ |
754 | if (bytesPerFrame <= 4U) |
755 | { |
756 | handle->bytesEachWrite = (uint8_t)bytesPerFrame; |
757 | handle->bytesEachRead = (uint8_t)bytesPerFrame; |
758 | |
759 | handle->bytesLastRead = (uint8_t)bytesPerFrame; |
760 | } |
761 | else |
762 | { |
763 | handle->bytesEachWrite = 4U; |
764 | handle->bytesEachRead = 4U; |
765 | |
766 | handle->bytesLastRead = 4U; |
767 | |
768 | if ((transfer->dataSize % 4U) != 0U) |
769 | { |
770 | bytesLastWrite = (uint8_t)(transfer->dataSize % 4U); |
771 | handle->bytesLastRead = bytesLastWrite; |
772 | |
773 | isThereExtraTxBytes = true; |
774 | --handle->writeRegRemainingTimes; |
775 | |
776 | handle->isThereExtraRxBytes = true; |
777 | --handle->readRegRemainingTimes; |
778 | } |
779 | } |
780 | |
781 | EDMA_SetCallback(handle->edmaRxRegToRxDataHandle, EDMA_LpspiSlaveCallback, |
782 | &s_lpspiSlaveEdmaPrivateHandle[instance]); |
783 | |
784 | /*Rx*/ |
785 | if (handle->readRegRemainingTimes > 0U) |
786 | { |
787 | EDMA_ResetChannel(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel); |
788 | |
789 | if (handle->rxData != NULL) |
790 | { |
791 | transferConfigRx.destAddr = (uint32_t) & (handle->rxData[0]); |
792 | transferConfigRx.destOffset = 1; |
793 | } |
794 | else |
795 | { |
796 | transferConfigRx.destAddr = (uint32_t) & (handle->rxBuffIfNull); |
797 | transferConfigRx.destOffset = 0; |
798 | } |
799 | transferConfigRx.destTransferSize = kEDMA_TransferSize1Bytes; |
800 | |
801 | addrOffset = 0; |
802 | switch (handle->bytesEachRead) |
803 | { |
804 | case (1U): |
805 | transferConfigRx.srcTransferSize = kEDMA_TransferSize1Bytes; |
806 | transferConfigRx.minorLoopBytes = 1; |
807 | if (handle->isByteSwap) |
808 | { |
809 | addrOffset = 3; |
810 | } |
811 | break; |
812 | |
813 | case (2U): |
814 | transferConfigRx.srcTransferSize = kEDMA_TransferSize2Bytes; |
815 | transferConfigRx.minorLoopBytes = 2; |
816 | if (handle->isByteSwap) |
817 | { |
818 | addrOffset = 2; |
819 | } |
820 | break; |
821 | |
822 | case (4U): |
823 | transferConfigRx.srcTransferSize = kEDMA_TransferSize4Bytes; |
824 | transferConfigRx.minorLoopBytes = 4; |
825 | break; |
826 | |
827 | default: |
828 | transferConfigRx.srcTransferSize = kEDMA_TransferSize1Bytes; |
829 | transferConfigRx.minorLoopBytes = 1; |
830 | assert(false); |
831 | break; |
832 | } |
833 | |
834 | transferConfigRx.srcAddr = (uint32_t)rxAddr + addrOffset; |
835 | transferConfigRx.srcOffset = 0; |
836 | |
837 | transferConfigRx.majorLoopCounts = handle->readRegRemainingTimes; |
838 | |
839 | /* Store the initially configured eDMA minor byte transfer count into the DSPI handle */ |
840 | handle->nbytes = (uint8_t)transferConfigRx.minorLoopBytes; |
841 | |
842 | EDMA_SetTransferConfig(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel, |
843 | &transferConfigRx, NULL); |
844 | EDMA_EnableChannelInterrupts(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel, |
845 | (uint32_t)kEDMA_MajorInterruptEnable); |
846 | EDMA_StartTransfer(handle->edmaRxRegToRxDataHandle); |
847 | } |
848 | |
849 | /*Tx*/ |
850 | if (handle->txData != NULL) |
851 | { |
852 | EDMA_ResetChannel(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel); |
853 | if (isThereExtraTxBytes) |
854 | { |
855 | transferConfigTx.srcAddr = (uint32_t) & (transfer->txData[transfer->dataSize - bytesLastWrite]); |
856 | transferConfigTx.srcOffset = 1; |
857 | transferConfigTx.destOffset = 0; |
858 | transferConfigTx.srcTransferSize = kEDMA_TransferSize1Bytes; |
859 | addrOffset = 0; |
860 | switch (bytesLastWrite) |
861 | { |
862 | case (1U): |
863 | transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes; |
864 | transferConfigTx.minorLoopBytes = 1; |
865 | if (handle->isByteSwap) |
866 | { |
867 | addrOffset = 3; |
868 | } |
869 | break; |
870 | |
871 | case (2U): |
872 | transferConfigTx.destTransferSize = kEDMA_TransferSize2Bytes; |
873 | transferConfigTx.minorLoopBytes = 2; |
874 | if (handle->isByteSwap) |
875 | { |
876 | addrOffset = 2; |
877 | } |
878 | break; |
879 | |
880 | default: |
881 | transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes; |
882 | transferConfigTx.minorLoopBytes = 1; |
883 | assert(false); |
884 | break; |
885 | } |
886 | |
887 | transferConfigTx.destAddr = (uint32_t)txAddr + addrOffset; |
888 | transferConfigTx.majorLoopCounts = 1; |
889 | |
890 | EDMA_TcdReset(softwareTCD_extraBytes); |
891 | EDMA_TcdSetTransferConfig(softwareTCD_extraBytes, &transferConfigTx, NULL); |
892 | } |
893 | |
894 | transferConfigTx.srcAddr = (uint32_t)(handle->txData); |
895 | transferConfigTx.srcOffset = 1; |
896 | transferConfigTx.destOffset = 0; |
897 | transferConfigTx.srcTransferSize = kEDMA_TransferSize1Bytes; |
898 | addrOffset = 0; |
899 | switch (handle->bytesEachRead) |
900 | { |
901 | case (1U): |
902 | transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes; |
903 | transferConfigTx.minorLoopBytes = 1; |
904 | if (handle->isByteSwap) |
905 | { |
906 | addrOffset = 3; |
907 | } |
908 | break; |
909 | |
910 | case (2U): |
911 | transferConfigTx.destTransferSize = kEDMA_TransferSize2Bytes; |
912 | transferConfigTx.minorLoopBytes = 2; |
913 | |
914 | if (handle->isByteSwap) |
915 | { |
916 | addrOffset = 2; |
917 | } |
918 | break; |
919 | |
920 | case (4U): |
921 | transferConfigTx.destTransferSize = kEDMA_TransferSize4Bytes; |
922 | transferConfigTx.minorLoopBytes = 4; |
923 | break; |
924 | |
925 | default: |
926 | transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes; |
927 | transferConfigTx.minorLoopBytes = 1; |
928 | assert(false); |
929 | break; |
930 | } |
931 | |
932 | transferConfigTx.destAddr = (uint32_t)txAddr + addrOffset; |
933 | transferConfigTx.majorLoopCounts = handle->writeRegRemainingTimes; |
934 | |
935 | if (isThereExtraTxBytes) |
936 | { |
937 | EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel, |
938 | &transferConfigTx, softwareTCD_extraBytes); |
939 | } |
940 | else |
941 | { |
942 | EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel, |
943 | &transferConfigTx, NULL); |
944 | } |
945 | EDMA_StartTransfer(handle->edmaTxDataToTxRegHandle); |
946 | mask |= (uint32_t)kLPSPI_TxDmaEnable; |
947 | } |
948 | |
949 | LPSPI_EnableDMA(base, mask); |
950 | |
951 | return kStatus_Success; |
952 | } |
953 | |
954 | static void EDMA_LpspiSlaveCallback(edma_handle_t *edmaHandle, |
955 | void *g_lpspiEdmaPrivateHandle, |
956 | bool transferDone, |
957 | uint32_t tcds) |
958 | { |
959 | assert(edmaHandle != NULL); |
960 | assert(g_lpspiEdmaPrivateHandle != NULL); |
961 | |
962 | uint32_t readData; |
963 | |
964 | lpspi_slave_edma_private_handle_t *lpspiEdmaPrivateHandle; |
965 | |
966 | lpspiEdmaPrivateHandle = (lpspi_slave_edma_private_handle_t *)g_lpspiEdmaPrivateHandle; |
967 | |
968 | size_t rxRemainingByteCount = lpspiEdmaPrivateHandle->handle->rxRemainingByteCount; |
969 | uint8_t bytesLastRead = lpspiEdmaPrivateHandle->handle->bytesLastRead; |
970 | bool isByteSwap = lpspiEdmaPrivateHandle->handle->isByteSwap; |
971 | |
972 | LPSPI_DisableDMA(lpspiEdmaPrivateHandle->base, (uint32_t)kLPSPI_TxDmaEnable | (uint32_t)kLPSPI_RxDmaEnable); |
973 | |
974 | if (lpspiEdmaPrivateHandle->handle->isThereExtraRxBytes) |
975 | { |
976 | while (LPSPI_GetRxFifoCount(lpspiEdmaPrivateHandle->base) == 0U) |
977 | { |
978 | } |
979 | readData = LPSPI_ReadData(lpspiEdmaPrivateHandle->base); |
980 | |
981 | if (lpspiEdmaPrivateHandle->handle->rxData != NULL) |
982 | { |
983 | LPSPI_SeparateEdmaReadData(&(lpspiEdmaPrivateHandle->handle->rxData[rxRemainingByteCount - bytesLastRead]), |
984 | readData, bytesLastRead, isByteSwap); |
985 | } |
986 | } |
987 | |
988 | lpspiEdmaPrivateHandle->handle->state = (uint8_t)kLPSPI_Idle; |
989 | |
990 | if (lpspiEdmaPrivateHandle->handle->callback != NULL) |
991 | { |
992 | lpspiEdmaPrivateHandle->handle->callback(lpspiEdmaPrivateHandle->base, lpspiEdmaPrivateHandle->handle, |
993 | kStatus_Success, lpspiEdmaPrivateHandle->handle->userData); |
994 | } |
995 | } |
996 | |
997 | /*! |
998 | * brief LPSPI slave aborts a transfer which is using eDMA. |
999 | * |
1000 | * This function aborts a transfer which is using eDMA. |
1001 | * |
1002 | * param base LPSPI peripheral base address. |
1003 | * param handle pointer to lpspi_slave_edma_handle_t structure which stores the transfer state. |
1004 | */ |
1005 | void LPSPI_SlaveTransferAbortEDMA(LPSPI_Type *base, lpspi_slave_edma_handle_t *handle) |
1006 | { |
1007 | assert(handle != NULL); |
1008 | |
1009 | LPSPI_DisableDMA(base, (uint32_t)kLPSPI_RxDmaEnable | (uint32_t)kLPSPI_TxDmaEnable); |
1010 | |
1011 | EDMA_AbortTransfer(handle->edmaRxRegToRxDataHandle); |
1012 | EDMA_AbortTransfer(handle->edmaTxDataToTxRegHandle); |
1013 | |
1014 | handle->state = (uint8_t)kLPSPI_Idle; |
1015 | } |
1016 | |
1017 | /*! |
1018 | * brief Gets the slave eDMA transfer remaining bytes. |
1019 | * |
1020 | * This function gets the slave eDMA transfer remaining bytes. |
1021 | * |
1022 | * param base LPSPI peripheral base address. |
1023 | * param handle pointer to lpspi_slave_edma_handle_t structure which stores the transfer state. |
1024 | * param count Number of bytes transferred so far by the eDMA transaction. |
1025 | * return status of status_t. |
1026 | */ |
1027 | status_t LPSPI_SlaveTransferGetCountEDMA(LPSPI_Type *base, lpspi_slave_edma_handle_t *handle, size_t *count) |
1028 | { |
1029 | assert(handle != NULL); |
1030 | |
1031 | if (NULL == count) |
1032 | { |
1033 | return kStatus_InvalidArgument; |
1034 | } |
1035 | |
1036 | /* Catch when there is not an active transfer. */ |
1037 | if (handle->state != (uint8_t)kLPSPI_Busy) |
1038 | { |
1039 | *count = 0; |
1040 | return kStatus_NoTransferInProgress; |
1041 | } |
1042 | |
1043 | size_t remainingByte; |
1044 | |
1045 | remainingByte = |
1046 | (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->edmaRxRegToRxDataHandle->base, |
1047 | handle->edmaRxRegToRxDataHandle->channel); |
1048 | |
1049 | *count = handle->totalByteCount - remainingByte; |
1050 | |
1051 | return kStatus_Success; |
1052 | } |
1053 | |