1 /*
2 * Copyright (c) 2016, Freescale Semiconductor, Inc.
3 * Copyright 2016-2020, 2022 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_i2c_dma.h"
10 #include "fsl_flexcomm.h"
11
12 /*******************************************************************************
13 * Definitions
14 ******************************************************************************/
15
16 /* Component ID definition, used by tools. */
17 #ifndef FSL_COMPONENT_ID
18 #define FSL_COMPONENT_ID "platform.drivers.flexcomm_i2c_dma"
19 #endif
20
21 /*<! @brief Structure definition for i2c_master_dma_handle_t. The structure is private. */
22 typedef struct _i2c_master_dma_private_handle
23 {
24 I2C_Type *base;
25 i2c_master_dma_handle_t *handle;
26 } i2c_master_dma_private_handle_t;
27
28 /*!
29 * @brief Used for conversion from `flexcomm_irq_handler_t` to `flexcomm_i2c_dma_master_irq_handler_t`
30 */
31 typedef union i2c_dma_to_flexcomm
32 {
33 flexcomm_i2c_dma_master_irq_handler_t i2c_dma_master_handler;
34 flexcomm_irq_handler_t flexcomm_handler;
35 } i2c_dma_to_flexcomm_t;
36
37 /*******************************************************************************
38 * Prototypes
39 ******************************************************************************/
40
41 /*!
42 * @brief DMA callback for I2C master DMA driver.
43 *
44 * @param handle DMA handler for I2C master DMA driver
45 * @param userData user param passed to the callback function
46 */
47 static void I2C_MasterTransferCallbackDMA(dma_handle_t *handle, void *userData, bool transferDone, uint32_t intmode);
48
49 /*!
50 * @brief Set up master transfer, send slave address and sub address(if any), wait until the
51 * wait until address sent status return.
52 *
53 * @param base I2C peripheral base address.
54 * @param handle pointer to i2c_master_dma_handle_t structure which stores the transfer state.
55 * @param xfer pointer to i2c_master_transfer_t structure.
56 */
57 static status_t I2C_InitTransferStateMachineDMA(I2C_Type *base,
58 i2c_master_dma_handle_t *handle,
59 i2c_master_transfer_t *xfer);
60
61 static void I2C_RunDMATransfer(I2C_Type *base, i2c_master_dma_handle_t *handle);
62
63 /*!
64 * @brief Execute states until the transfer is done.
65 * @param handle Master nonblocking driver handle.
66 * @param[out] isDone Set to true if the transfer has completed.
67 * @retval #kStatus_Success
68 * @retval #kStatus_I2C_ArbitrationLost
69 * @retval #kStatus_I2C_Nak
70 */
71 static status_t I2C_RunTransferStateMachineDMA(I2C_Type *base, i2c_master_dma_handle_t *handle, bool *isDone);
72 /*******************************************************************************
73 * Variables
74 ******************************************************************************/
75
76 /*! @brief IRQ name array */
77 static const IRQn_Type s_i2cIRQ[] = I2C_IRQS;
78
79 /*<! Private handle only used for internally. */
80 static i2c_master_dma_private_handle_t s_dmaPrivateHandle[ARRAY_SIZE(s_i2cIRQ)];
81
82 /*******************************************************************************
83 * Codes
84 ******************************************************************************/
I2C_InitTransferStateMachineDMA(I2C_Type * base,i2c_master_dma_handle_t * handle,i2c_master_transfer_t * xfer)85 static status_t I2C_InitTransferStateMachineDMA(I2C_Type *base,
86 i2c_master_dma_handle_t *handle,
87 i2c_master_transfer_t *xfer)
88 {
89 struct _i2c_master_transfer *transfer;
90
91 handle->transfer = *xfer;
92 transfer = &(handle->transfer);
93
94 handle->transferCount = 0U;
95 handle->remainingBytesDMA = 0U;
96 handle->buf = (uint8_t *)transfer->data;
97 handle->remainingSubaddr = 0U;
98
99 if ((transfer->flags & (uint32_t)kI2C_TransferNoStartFlag) != 0U)
100 {
101 handle->checkAddrNack = false;
102 /* Start condition shall not be ommited, switch directly to next phase */
103 if (transfer->dataSize == 0U)
104 {
105 handle->state = (uint8_t)kStopState;
106 }
107 else if (handle->transfer.direction == kI2C_Write)
108 {
109 handle->state = (uint8_t)kTransmitDataState;
110 }
111 else if (handle->transfer.direction == kI2C_Read)
112 {
113 handle->state = (xfer->dataSize == 1U) ? (uint8_t)kReceiveLastDataState : (uint8_t)kReceiveDataState;
114 }
115 else
116 {
117 return kStatus_I2C_InvalidParameter;
118 }
119 }
120 else
121 {
122 if (transfer->subaddressSize != 0U)
123 {
124 int i;
125 uint32_t subaddress;
126
127 if (transfer->subaddressSize > sizeof(handle->subaddrBuf))
128 {
129 return kStatus_I2C_InvalidParameter;
130 }
131
132 /* Prepare subaddress transmit buffer, most significant byte is stored at the lowest address */
133 subaddress = xfer->subaddress;
134 for (i = (int)xfer->subaddressSize - 1; i >= 0; i--)
135 {
136 handle->subaddrBuf[i] = (uint8_t)subaddress & 0xffU;
137 subaddress >>= 8;
138 }
139 handle->remainingSubaddr = transfer->subaddressSize;
140 }
141
142 handle->state = (uint8_t)kStartState;
143 handle->checkAddrNack = true;
144 }
145
146 return kStatus_Success;
147 }
148
I2C_RunDMATransfer(I2C_Type * base,i2c_master_dma_handle_t * handle)149 static void I2C_RunDMATransfer(I2C_Type *base, i2c_master_dma_handle_t *handle)
150 {
151 uint32_t transfer_size;
152 dma_transfer_config_t xferConfig;
153 uint32_t address;
154 address = (uint32_t)&base->MSTDAT;
155
156 /* Update transfer count */
157 int32_t count = handle->buf - (uint8_t *)handle->transfer.data;
158 assert(count >= 0);
159 handle->transferCount = (uint32_t)count;
160
161 /* Check if there is anything to be transferred at all */
162 if (handle->remainingBytesDMA == 0U)
163 {
164 /* No data to be transferrred, disable DMA */
165 base->MSTCTL = 0;
166 return;
167 }
168
169 /* Calculate transfer size */
170 transfer_size = handle->remainingBytesDMA;
171 if (transfer_size > (uint32_t)I2C_MAX_DMA_TRANSFER_COUNT)
172 {
173 transfer_size = (uint32_t)I2C_MAX_DMA_TRANSFER_COUNT;
174 }
175
176 switch (handle->transfer.direction)
177 {
178 case kI2C_Write:
179 DMA_PrepareTransfer(&xferConfig, handle->buf, (uint32_t *)address, sizeof(uint8_t), transfer_size,
180 kDMA_MemoryToPeripheral, NULL);
181 break;
182
183 case kI2C_Read:
184 DMA_PrepareTransfer(&xferConfig, (uint32_t *)address, handle->buf, sizeof(uint8_t), transfer_size,
185 kDMA_PeripheralToMemory, NULL);
186 break;
187
188 default:
189 /* This should never happen */
190 assert(0);
191 break;
192 }
193
194 (void)DMA_SubmitTransfer(handle->dmaHandle, &xferConfig);
195 DMA_StartTransfer(handle->dmaHandle);
196
197 handle->remainingBytesDMA -= transfer_size;
198 handle->buf += transfer_size;
199 handle->checkAddrNack = false;
200 }
201
I2C_RunTransferStateMachineDMA(I2C_Type * base,i2c_master_dma_handle_t * handle,bool * isDone)202 static status_t I2C_RunTransferStateMachineDMA(I2C_Type *base, i2c_master_dma_handle_t *handle, bool *isDone)
203 {
204 uint32_t status;
205 uint32_t master_state;
206 struct _i2c_master_transfer *transfer;
207 dma_transfer_config_t xferConfig;
208 status_t err;
209 uint32_t start_flag = 0U;
210 uint32_t address;
211 address = (uint32_t)&base->MSTDAT;
212
213 transfer = &(handle->transfer);
214
215 *isDone = false;
216
217 status = I2C_GetStatusFlags(base);
218
219 if ((status & (uint32_t)I2C_STAT_MSTARBLOSS_MASK) != 0U)
220 {
221 I2C_MasterClearStatusFlags(base, I2C_STAT_MSTARBLOSS_MASK);
222 DMA_AbortTransfer(handle->dmaHandle);
223 base->MSTCTL = 0;
224 return kStatus_I2C_ArbitrationLost;
225 }
226
227 if ((status & (uint32_t)I2C_STAT_MSTSTSTPERR_MASK) != 0U)
228 {
229 I2C_MasterClearStatusFlags(base, I2C_STAT_MSTSTSTPERR_MASK);
230 DMA_AbortTransfer(handle->dmaHandle);
231 base->MSTCTL = 0;
232 return kStatus_I2C_StartStopError;
233 }
234
235 /* Event timeout happens when the time since last bus event has been longer than the time specified by TIMEOUT
236 register. eg: Start signal fails to generate, no error status is set and transfer hangs if glitch on bus happens
237 before, the timeout status can be used to avoid the transfer hangs indefinitely. */
238 if ((status & (uint32_t)kI2C_EventTimeoutFlag) != 0U)
239 {
240 I2C_ClearStatusFlags(base, (uint32_t)kI2C_EventTimeoutFlag);
241 DMA_AbortTransfer(handle->dmaHandle);
242 base->MSTCTL = 0;
243 return kStatus_I2C_EventTimeout;
244 }
245
246 /* SCL timeout happens when the slave is holding the SCL line low and the time has been longer than the time
247 specified by TIMEOUT register. */
248 if ((status & (uint32_t)kI2C_SclTimeoutFlag) != 0U)
249 {
250 I2C_ClearStatusFlags(base, (uint32_t)kI2C_SclTimeoutFlag);
251 DMA_AbortTransfer(handle->dmaHandle);
252 base->MSTCTL = 0;
253 return kStatus_I2C_SclLowTimeout;
254 }
255
256 if ((status & (uint32_t)I2C_STAT_MSTPENDING_MASK) == 0U)
257 {
258 return kStatus_I2C_Busy;
259 }
260
261 /* Get the state of the I2C module */
262 master_state = (base->STAT & (uint32_t)I2C_STAT_MSTSTATE_MASK) >> I2C_STAT_MSTSTATE_SHIFT;
263
264 if ((master_state == (uint32_t)I2C_STAT_MSTCODE_NACKADR) || (master_state == (uint32_t)I2C_STAT_MSTCODE_NACKDAT))
265 {
266 /* Slave NACKed last byte, issue stop and return error */
267 DMA_AbortTransfer(handle->dmaHandle);
268 base->MSTCTL = I2C_MSTCTL_MSTSTOP_MASK;
269 handle->state = (uint8_t)kWaitForCompletionState;
270 if ((master_state == (uint32_t)I2C_STAT_MSTCODE_NACKADR) || (handle->checkAddrNack == true))
271 {
272 return kStatus_I2C_Addr_Nak;
273 }
274 else
275 {
276 return kStatus_I2C_Nak;
277 }
278 }
279
280 err = kStatus_Success;
281
282 if (handle->state == (uint8_t)kStartState)
283 {
284 /* set start flag for later use */
285 start_flag = I2C_MSTCTL_MSTSTART_MASK;
286
287 if (handle->remainingSubaddr != 0U)
288 {
289 base->MSTDAT = (uint32_t)transfer->slaveAddress << 1;
290 handle->state = (uint8_t)kTransmitSubaddrState;
291 }
292 else if (transfer->direction == kI2C_Write)
293 {
294 base->MSTDAT = (uint32_t)transfer->slaveAddress << 1;
295 if (transfer->dataSize == 0U)
296 {
297 /* No data to be transferred, initiate start and schedule stop */
298 base->MSTCTL = I2C_MSTCTL_MSTSTART_MASK;
299 handle->state = (uint8_t)kStopState;
300 return err;
301 }
302 handle->state = (uint8_t)kTransmitDataState;
303 }
304 else if ((transfer->direction == kI2C_Read) && (transfer->dataSize > 0U))
305 {
306 base->MSTDAT = ((uint32_t)transfer->slaveAddress << 1) | 1u;
307 if (transfer->dataSize == 1U)
308 {
309 /* The very last byte is always received by means of SW */
310 base->MSTCTL = I2C_MSTCTL_MSTSTART_MASK;
311 handle->state = (uint8_t)kReceiveLastDataState;
312 return err;
313 }
314 handle->state = (uint8_t)kReceiveDataState;
315 }
316 else
317 {
318 handle->state = (uint8_t)kIdleState;
319 err = kStatus_I2C_UnexpectedState;
320 return err;
321 }
322 }
323
324 switch (handle->state)
325 {
326 case (uint8_t)kTransmitSubaddrState:
327 if ((master_state != (uint32_t)I2C_STAT_MSTCODE_TXREADY) && (0U == start_flag))
328 {
329 return kStatus_I2C_UnexpectedState;
330 }
331
332 base->MSTCTL = start_flag | I2C_MSTCTL_MSTDMA_MASK;
333
334 /* Prepare and submit DMA transfer. */
335 DMA_PrepareTransfer(&xferConfig, handle->subaddrBuf, (uint32_t *)address, sizeof(uint8_t),
336 handle->remainingSubaddr, kDMA_MemoryToPeripheral, NULL);
337 (void)DMA_SubmitTransfer(handle->dmaHandle, &xferConfig);
338 DMA_StartTransfer(handle->dmaHandle);
339 handle->remainingSubaddr = 0;
340 if (transfer->dataSize != 0U)
341 {
342 /* There is data to be transferred, if there is write to read turnaround it is necessary to perform
343 * repeated start */
344 handle->state = (transfer->direction == kI2C_Read) ? (uint8_t)kStartState : (uint8_t)kTransmitDataState;
345 }
346 else
347 {
348 /* No more data, schedule stop condition */
349 handle->state = (uint8_t)kStopState;
350 }
351 break;
352
353 case (uint8_t)kTransmitDataState:
354 if ((master_state != (uint32_t)I2C_STAT_MSTCODE_TXREADY) && (0U == start_flag))
355 {
356 return kStatus_I2C_UnexpectedState;
357 }
358
359 base->MSTCTL = start_flag | I2C_MSTCTL_MSTDMA_MASK;
360 handle->remainingBytesDMA = handle->transfer.dataSize;
361
362 I2C_RunDMATransfer(base, handle);
363
364 /* Schedule stop condition */
365 handle->state = (uint8_t)kStopState;
366 handle->checkAddrNack = false;
367 break;
368
369 case (uint8_t)kReceiveDataState:
370 if ((master_state != (uint32_t)I2C_STAT_MSTCODE_RXREADY) && (0U == start_flag))
371 {
372 if (0U == (transfer->flags & (uint32_t)kI2C_TransferNoStartFlag))
373 {
374 return kStatus_I2C_UnexpectedState;
375 }
376 }
377
378 base->MSTCTL = start_flag | I2C_MSTCTL_MSTDMA_MASK;
379 handle->remainingBytesDMA = handle->transfer.dataSize - 1U;
380
381 if ((transfer->flags & (uint32_t)kI2C_TransferNoStartFlag) != 0U)
382 {
383 /* Read the master data register to avoid the data be read again */
384 (void)base->MSTDAT;
385 }
386 I2C_RunDMATransfer(base, handle);
387
388 /* Schedule reception of last data byte */
389 handle->state = (uint8_t)kReceiveLastDataState;
390 handle->checkAddrNack = false;
391 break;
392
393 case (uint8_t)kReceiveLastDataState:
394 if (master_state != (uint32_t)I2C_STAT_MSTCODE_RXREADY)
395 {
396 return kStatus_I2C_UnexpectedState;
397 }
398
399 ((uint8_t *)transfer->data)[transfer->dataSize - 1U] = (uint8_t)base->MSTDAT;
400 handle->transferCount++;
401
402 /* No more data expected, issue NACK and STOP right away */
403 if (0U == (transfer->flags & (uint32_t)kI2C_TransferNoStopFlag))
404 {
405 base->MSTCTL = I2C_MSTCTL_MSTSTOP_MASK;
406 }
407 handle->state = (uint8_t)kWaitForCompletionState;
408 break;
409
410 case (uint8_t)kStopState:
411 if ((transfer->flags & (uint32_t)kI2C_TransferNoStopFlag) != 0U)
412 {
413 /* Stop condition is omitted, we are done */
414 *isDone = true;
415 handle->state = (uint8_t)kIdleState;
416 break;
417 }
418 /* Send stop condition */
419 base->MSTCTL = I2C_MSTCTL_MSTSTOP_MASK;
420 handle->state = (uint8_t)kWaitForCompletionState;
421 break;
422
423 case (uint8_t)kWaitForCompletionState:
424 *isDone = true;
425 handle->state = (uint8_t)kIdleState;
426 break;
427
428 case (uint8_t)kStartState:
429 case (uint8_t)kIdleState:
430 default:
431 /* State machine shall not be invoked again once it enters the idle state */
432 err = kStatus_I2C_UnexpectedState;
433 break;
434 }
435
436 return err;
437 }
438
I2C_MasterTransferDMAHandleIRQ(I2C_Type * base,i2c_master_dma_handle_t * handle)439 static void I2C_MasterTransferDMAHandleIRQ(I2C_Type *base, i2c_master_dma_handle_t *handle)
440 {
441 bool isDone;
442 status_t result;
443
444 /* Don't do anything if we don't have a valid handle. */
445 if (NULL == handle)
446 {
447 return;
448 }
449
450 result = I2C_RunTransferStateMachineDMA(base, handle, &isDone);
451
452 if ((result != kStatus_Success) || isDone)
453 {
454 /* Restore handle to idle state. */
455 handle->state = (uint8_t)kIdleState;
456
457 /* Disable internal IRQ enables. */
458 I2C_DisableInterrupts(base, I2C_INTSTAT_MSTPENDING_MASK | I2C_INTSTAT_MSTARBLOSS_MASK |
459 I2C_INTSTAT_MSTSTSTPERR_MASK | I2C_INTSTAT_EVENTTIMEOUT_MASK);
460
461 /* Invoke callback. */
462 if (handle->completionCallback != NULL)
463 {
464 handle->completionCallback(base, handle, result, handle->userData);
465 }
466 }
467 }
468
I2C_MasterTransferCallbackDMA(dma_handle_t * handle,void * userData,bool transferDone,uint32_t intmode)469 static void I2C_MasterTransferCallbackDMA(dma_handle_t *handle, void *userData, bool transferDone, uint32_t intmode)
470 {
471 i2c_master_dma_private_handle_t *dmaPrivateHandle;
472
473 /* Don't do anything if we don't have a valid handle. */
474 if (NULL == handle)
475 {
476 return;
477 }
478
479 dmaPrivateHandle = (i2c_master_dma_private_handle_t *)userData;
480 I2C_RunDMATransfer(dmaPrivateHandle->base, dmaPrivateHandle->handle);
481 }
482
483 /*!
484 * brief Init the I2C handle which is used in transactional functions
485 *
486 * param base I2C peripheral base address
487 * param handle pointer to i2c_master_dma_handle_t structure
488 * param callback pointer to user callback function
489 * param userData user param passed to the callback function
490 * param dmaHandle DMA handle pointer
491 */
I2C_MasterTransferCreateHandleDMA(I2C_Type * base,i2c_master_dma_handle_t * handle,i2c_master_dma_transfer_callback_t callback,void * userData,dma_handle_t * dmaHandle)492 void I2C_MasterTransferCreateHandleDMA(I2C_Type *base,
493 i2c_master_dma_handle_t *handle,
494 i2c_master_dma_transfer_callback_t callback,
495 void *userData,
496 dma_handle_t *dmaHandle)
497 {
498 assert(handle != NULL);
499 assert(dmaHandle != NULL);
500
501 uint32_t instance;
502 i2c_dma_to_flexcomm_t handler;
503 handler.i2c_dma_master_handler = I2C_MasterTransferDMAHandleIRQ;
504
505 /* Zero handle. */
506 (void)memset(handle, 0, sizeof(*handle));
507
508 /* Look up instance number */
509 instance = I2C_GetInstance(base);
510
511 /* Set the user callback and userData. */
512 handle->completionCallback = callback;
513 handle->userData = userData;
514
515 FLEXCOMM_SetIRQHandler(base, handler.flexcomm_handler, handle);
516
517 /* Clear internal IRQ enables and enable NVIC IRQ. */
518 I2C_DisableInterrupts(base, I2C_INTSTAT_MSTPENDING_MASK | I2C_INTSTAT_MSTARBLOSS_MASK |
519 I2C_INTSTAT_MSTSTSTPERR_MASK | I2C_INTSTAT_EVENTTIMEOUT_MASK);
520 (void)EnableIRQ(s_i2cIRQ[instance]);
521
522 /* Set the handle for DMA. */
523 handle->dmaHandle = dmaHandle;
524
525 s_dmaPrivateHandle[instance].base = base;
526 s_dmaPrivateHandle[instance].handle = handle;
527
528 DMA_SetCallback(dmaHandle, I2C_MasterTransferCallbackDMA, &s_dmaPrivateHandle[instance]);
529 }
530
531 /*!
532 * brief Performs a master dma non-blocking transfer on the I2C bus
533 *
534 * param base I2C peripheral base address
535 * param handle pointer to i2c_master_dma_handle_t structure
536 * param xfer pointer to transfer structure of i2c_master_transfer_t
537 * retval kStatus_Success Sucessully complete the data transmission.
538 * retval kStatus_I2C_Busy Previous transmission still not finished.
539 * retval kStatus_I2C_Timeout Transfer error, wait signal timeout.
540 * retval kStatus_I2C_ArbitrationLost Transfer error, arbitration lost.
541 * retval kStataus_I2C_Nak Transfer error, receive Nak during transfer.
542 */
I2C_MasterTransferDMA(I2C_Type * base,i2c_master_dma_handle_t * handle,i2c_master_transfer_t * xfer)543 status_t I2C_MasterTransferDMA(I2C_Type *base, i2c_master_dma_handle_t *handle, i2c_master_transfer_t *xfer)
544 {
545 status_t result;
546
547 assert(handle != NULL);
548 assert(xfer != NULL);
549 assert(xfer->subaddressSize <= sizeof(xfer->subaddress));
550
551 /* Return busy if another transaction is in progress. */
552 if (handle->state != (uint8_t)kIdleState)
553 {
554 return kStatus_I2C_Busy;
555 }
556
557 /* Enable the master function and disable the slave function. */
558 I2C_MasterEnable(base, true);
559 I2C_SlaveEnable(base, false);
560
561 /* Prepare transfer state machine. */
562 result = I2C_InitTransferStateMachineDMA(base, handle, xfer);
563
564 /* Clear error flags. */
565 I2C_MasterClearStatusFlags(base, I2C_STAT_MSTARBLOSS_MASK | I2C_STAT_MSTSTSTPERR_MASK);
566
567 /* Enable I2C internal IRQ sources */
568 /* Enable arbitration lost interrupt, start/stop error interrupt and master pending interrupt.
569 The master pending flag is not set during dma transfer. */
570 I2C_EnableInterrupts(base, I2C_INTSTAT_MSTARBLOSS_MASK | I2C_INTSTAT_MSTSTSTPERR_MASK |
571 I2C_INTSTAT_MSTPENDING_MASK | I2C_INTSTAT_EVENTTIMEOUT_MASK);
572
573 return result;
574 }
575
576 /*!
577 * brief Get master transfer status during a dma non-blocking transfer
578 *
579 * param base I2C peripheral base address
580 * param handle pointer to i2c_master_dma_handle_t structure
581 * param count Number of bytes transferred so far by the non-blocking transaction.
582 */
I2C_MasterTransferGetCountDMA(I2C_Type * base,i2c_master_dma_handle_t * handle,size_t * count)583 status_t I2C_MasterTransferGetCountDMA(I2C_Type *base, i2c_master_dma_handle_t *handle, size_t *count)
584 {
585 assert(handle != NULL);
586
587 if (NULL == count)
588 {
589 return kStatus_InvalidArgument;
590 }
591
592 /* Catch when there is not an active transfer. */
593 if (handle->state == (uint8_t)kIdleState)
594 {
595 *count = 0;
596 return kStatus_NoTransferInProgress;
597 }
598
599 /* There is no necessity to disable interrupts as we read a single integer value */
600 *count = handle->transferCount;
601 return kStatus_Success;
602 }
603
604 /*!
605 * brief Abort a master dma non-blocking transfer in a early time
606 *
607 * param base I2C peripheral base address
608 * param handle pointer to i2c_master_dma_handle_t structure
609 */
I2C_MasterTransferAbortDMA(I2C_Type * base,i2c_master_dma_handle_t * handle)610 void I2C_MasterTransferAbortDMA(I2C_Type *base, i2c_master_dma_handle_t *handle)
611 {
612 uint32_t status;
613 uint32_t master_state;
614
615 if (handle->state != (uint8_t)kIdleState)
616 {
617 DMA_AbortTransfer(handle->dmaHandle);
618
619 /* Disable DMA */
620 base->MSTCTL = 0;
621
622 /* Disable internal IRQ enables. */
623 I2C_DisableInterrupts(base, I2C_INTSTAT_MSTPENDING_MASK | I2C_INTSTAT_MSTARBLOSS_MASK |
624 I2C_INTSTAT_MSTSTSTPERR_MASK | I2C_INTSTAT_EVENTTIMEOUT_MASK);
625
626 /* Wait until module is ready */
627 do
628 {
629 status = I2C_GetStatusFlags(base);
630 } while ((status & (uint8_t)I2C_STAT_MSTPENDING_MASK) == 0U);
631
632 /* Clear controller state. */
633 I2C_MasterClearStatusFlags(base, I2C_STAT_MSTARBLOSS_MASK | I2C_STAT_MSTSTSTPERR_MASK);
634
635 /* Get the state of the I2C module */
636 master_state = (base->STAT & I2C_STAT_MSTSTATE_MASK) >> I2C_STAT_MSTSTATE_SHIFT;
637
638 if (master_state != (uint32_t)I2C_STAT_MSTCODE_IDLE)
639 {
640 /* Send a stop command to finalize the transfer. */
641 base->MSTCTL = I2C_MSTCTL_MSTSTOP_MASK;
642
643 /* Wait until module is ready */
644 do
645 {
646 status = I2C_GetStatusFlags(base);
647 } while ((status & (uint32_t)I2C_STAT_MSTPENDING_MASK) == 0U);
648
649 /* Clear controller state. */
650 I2C_MasterClearStatusFlags(base, I2C_STAT_MSTARBLOSS_MASK | I2C_STAT_MSTSTSTPERR_MASK);
651 }
652
653 /* Reset the state to idle. */
654 handle->state = (uint8_t)kIdleState;
655 }
656 }
657