AnsweredAssumed Answered

KL17 I²C slave receiver with DMA - last byte read twice

Question asked by Serge Gadeyne on Dec 22, 2016
Latest reply on Jan 27, 2017 by Serge Gadeyne

Hello,

 

I'm working on a Kinetis KL17 microcontroller with KDS 3.2.0 and Kinetis SDK 2.0.

I would like to offload reception of I²C data to DMA for improved performance.

The initialization code looks as follows:

DMAMUX_Init(DMAMUX0);
DMAMUX_SetSource(DMAMUX0, 0, (uint8_t)kDmaRequestMux0I2C0);
DMAMUX_EnableChannel(DMAMUX0, 0);

DMA_Init(DMA0);
DMA_CreateHandle(dma_handle, DMA0, 0);
DMA_SetCallback(dma_handle, dma_cb, ctx);

I2C_SlaveGetDefaultConfig(&slave_config);
slave_config.slaveAddress = BOARD_I2C_SLAVE_ADDR;
I2C_SlaveInit(I2C0, &slave_config);

DMA_CreateHandle(dma_handle, DMA0, 0);
DMA_SetCallback(dma_handle, dma_cb, ctx);

I2C_SlaveTransferCreateHandle(I2C0, i2c_handle, i2c_slave_cb, ctx);
I2C_SlaveTransferNonBlocking(I2C0, i2c_handle, kI2C_SlaveAllEvents);

The DMA is configured in the registered I²C callback function (called by I2C_SlaveTransferHandleIRQ() from interrupt context - when the received address matches the slave address).

The length of the received data is unknown beforehand, so a large enough buffer is allocated (32 bytes in this example).

The DMA transfer is aborted when the stop condition is detected.

static void i2c_slave_cb(I2C_Type *base, i2c_slave_transfer_t *xfer, void *data)
{
   ...
   switch (xfer->event) {
   ...
   case kI2C_SlaveAddressMatchEvent:
      DMA_PrepareTransfer(&transfer_config,
                          &I2C0->D, sizeof(I2C0->D),
                           ctx->buf, sizeof(*ctx->buf),
                           ctx->len, kDMA_PeripheralToMemory);
      DMA_SubmitTransfer(&ctx->dma_handle, &transfer_config,
                          kDMA_EnableInterrupt);
      DMA_StartTransfer(&ctx->dma_handle);
      I2C_EnableDMA(I2C0, true);
      break;
   ...
   case kI2C_SlaveCompletionEvent:
      I2C_EnableDMA(I2C0, false);
      DMA_AbortTransfer(&ctx->dma_handle);
      break;
   ...
}

As is visible in the first attachment, the length of the received data is 5 bytes in this example.

When the data is printed on LPUART0 in the application the last byte seems to be duplicated (second attachment).

Investigation of the DMA BCR register shows that the initial value of 0x20 (32 bytes) is decremented to 0x1a (26 bytes).

This seems to indicate that the DMA got 6 requests to transfer a byte to the destination memory.

 

It's unclear to me how this behaviour is triggered. Did I misconfigure the DMA/I²C modules? Something else?

 

Kind regards,

Serge

Outcomes