AnsweredAssumed Answered

How to enable interrupts for a I2C eDMA transaction

Question asked by Chris Detka on Mar 23, 2019
Latest reply on Mar 27, 2019 by Chris Detka



I'm using an MKL28Z512XXX7 processor.

I have SDK 2.2.

I'm trying to use DMA to send messages out LpI2C2 (transmit only).

With a logic analyzer connected to SCK and SDA, I see that the I2C message is sent.

My problem is that I do not get the callback for my transaction.

Through investigation, I've found that no interrupt fires after the completion of the DMA transfer (at least I can find no signs of an interrupt)


I followed the example in lpi2c_edma_transfer.c


Importantly, after transmission occurs (seen on the logic analyzer), I stop the processor and inspect the DMA0_INT register, I see a value of 1 which, to me, indicates that the DMA transfer is complete. I would expect an interrupt to occur since my DMAx_TCDn_CSR register has a value of 0x8a which indicates that the transfer is done and since INTMAJOR is set, I would expect an interrupt. 


If I call LPI2C_MasterTransferEDMA twice, the second call returns the "BUSY" error code. This is further evidence that I never get the transmit complete interrupt.


Can you offer any advice on how to debug this? Why do I not see interrupts? Which interrupt handler might you expect to be called? LPI2C2_DriverIRQHandler? DMA0_xx_DriverIRQHandler? INTMUX0_x_DriverIRQHandler?


I've been at this for a while so my code includes a lot to "ideas", but none seem helpful. That said, here's the initialization code, feel free to point out where I've gone wrong:


ledI2cConfig.baudRate_Hz = WSNINIT_LED_I2C_BAUD_RATE;
/* Initialize the LPI2C master peripheral */
LPI2C_MasterInit(((LPI2C_Type *)LPI2C2_BASE), &ledI2cConfig, CLOCK_GetIpFreq(kCLOCK_Lpi2c2));
// LPI2C_MasterInit(((LPI2C_Type *)LPI2C2_BASE), &ledI2cConfig, CLOCK_GetFreq(kCLOCK_BusClk));
// CLOCK_EnableClock(kCLOCK_Dma0);
// CLOCK_EnableClock(kCLOCK_Intmux0);
// NVIC_SetPriority(DMA0_04_IRQn, 2);
// INTMUX_SetChannelMode(INTMUX0, 0, kINTMUX_ChannelLogicOR);
// INTMUX_SetChannelMode(INTMUX0, 1, kINTMUX_ChannelLogicOR);
// INTMUX_SetChannelMode(INTMUX0, 2, kINTMUX_ChannelLogicOR);
// INTMUX_SetChannelMode(INTMUX0, 3, kINTMUX_ChannelLogicOR);
// INTMUX_EnableInterrupt(INTMUX0, 1, DMA0_26_IRQn);
// INTMUX_EnableInterrupt(INTMUX0, 1, DMA0_37_IRQn);
INTMUX_EnableInterrupt(INTMUX0, 0, LPI2C2_IRQn);
// INTMUX_EnableInterrupt(INTMUX0, 1, LPI2C2_IRQn);
// INTMUX_EnableInterrupt(INTMUX0, 2, LPI2C2_IRQn);
// INTMUX_EnableInterrupt(INTMUX0, 3, LPI2C2_IRQn);
for (uint8_t ich = 0; ich < 4; ich++) {
  for (uint8_t intr = 32; intr < 64; intr++) {
    INTMUX_EnableInterrupt(INTMUX0, ich, intr);
// /* DMAMux init and EDMA init */
DMAMUX_SetSource(DMAMUX0, 0U, (uint8_t)kDmaRequestMux0LPI2C2Tx);
DMAMUX_EnableChannel(DMAMUX0, 0);
DMAMUX_SetSource(DMAMUX0, 1U, (uint8_t)kDmaRequestMux0LPI2C2Tx);
DMAMUX_SetSource(DMAMUX0, 2U, (uint8_t)kDmaRequestMux0LPI2C2Tx);
DMAMUX_SetSource(DMAMUX0, 3U, (uint8_t)kDmaRequestMux0LPI2C2Tx);
DMAMUX_SetSource(DMAMUX0, 4U, (uint8_t)kDmaRequestMux0LPI2C2Tx);
DMAMUX_SetSource(DMAMUX0, 5U, (uint8_t)kDmaRequestMux0LPI2C2Tx);
DMAMUX_SetSource(DMAMUX0, 6U, (uint8_t)kDmaRequestMux0LPI2C2Tx);
DMAMUX_SetSource(DMAMUX0, 7U, (uint8_t)kDmaRequestMux0LPI2C2Tx);
DMAMUX_EnableChannel(DMAMUX0, 1);
DMAMUX_EnableChannel(DMAMUX0, 2);
DMAMUX_EnableChannel(DMAMUX0, 3);
DMAMUX_EnableChannel(DMAMUX0, 4);
DMAMUX_EnableChannel(DMAMUX0, 5);
DMAMUX_EnableChannel(DMAMUX0, 6);
DMAMUX_EnableChannel(DMAMUX0, 7);
EDMA_Init(DMA0, &ledEdmaConfig);
/* Create the EDMA channel handles */
EDMA_CreateHandle(&ledEdmaRxHandle, DMA0, 7);
EDMA_CreateHandle(&ledEdmaTxHandle, DMA0, 0);
CLOCK_SetIpSrc(kCLOCK_Lpi2c2, kCLOCK_IpSrcSircAsync); /
* Create the LPI2C master DMA driver handle */
LPI2C_MasterCreateEDMAHandle(((LPI2C_Type *)LPI2C2_BASE), &ledEdmaMasterHandle, &ledEdmaRxHandle, &ledEdmaTxHandle, &UiTaskFactory_LedCallback, NULL);
// LPI2C_MasterCreateEDMAHandle(((LPI2C_Type *)LPI2C2_BASE), &ledEdmaMasterHandle, NULL, &ledEdmaTxHandle, &UiTaskFactory_LedCallback, NULL);
// LPI2C_MasterEnableInterrupts(((LPI2C_Type *)LPI2C2_BASE), 0x1U);


Then I have this code to send a message:

ledTransfer.slaveAddress = ISSIDRIVER_I2C_SLAVE_ADDRESS; 
ledTransfer.direction = kLPI2C_Write;
ledTransfer.subaddress = 0;
ledTransfer.subaddressSize = 0; = message;
ledTransfer.dataSize = length;
ledTransfer.flags = kLPI2C_TransferDefaultFlag;
/* Send master non-blocking data to slave */
status_t reVal = LPI2C_MasterTransferEDMA((LPI2C_Type *)LPI2C2_BASE, &ledEdmaMasterHandle, &ledTransfer);
if (reVal != kStatus_Success) { while (1); }