This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

RTOS/AM5728: I2C receive with DMA not working

Part Number: AM5728

Tool/software: TI-RTOS

Hi,

As I2C with dma support is not present in the existing I2C driver, I have tried to build the DMA support by looking at the UART and SPI driver TI RTOS pdk v 4.0.0.4

Using the eeprom example to test the i2c driver with dma support. I am able to transmit the data from dsp to eeprom. It is said that we can read this data back by sending the 2 byte slave address and then triggering the data recieve from eeprom. 

When i try to receive the data I am getting all 0s instead of the data that I have written. But when i tried to transmit data with DMA/ receive the data without DMA I am able to receive the data that I have written

My code follows the UART tx and rx params for DMA and most of the logic is from SPI driver.

Any idea can be shared so that i can work on the receive part also.

Thanks in advance

With regards

Manjula

  • The RTOS team have been notified. They will respond here.
  • Hi,

    Can you use the latest Processor SDK RTOS 4.2 release, then try the pdk_am57xx_1_0_9\packages\ti\drv\i2c\test\master_slave example with DMA support?

    Regards, Eric
  • Hi

    I downloaded the latest Processor SDK RTOS 4.2 release and saw the pdk_am57xx_1_0_9\packages\ti\drv\i2c\test\master_slave example for DMA support. Though it mentions that DMA initializations to be done here and dmamode flag but the driver does not have EDMA support and the application also does not mention of data transfer using EDMA.

    If any example with EDMA parameter configuration performing i2c transfer with edma would be of great help.

    Regards

    Manjula 

  • Hi,

    Sorry I overlooked this! The dma_mode in the code is a place holder for future implementation but not planned yet. In your code for I2C read from EEPROM with DMA, I assume that you send a read command following the I2C protocol, this command is still by CPU, correct? Then the data returned from EEPROM to the I2C controller via the bus. When the I2C FIFO reached to certain level, it triggered a DMA transfer automatically, the transfer completion triggered an interrupt. Is this the way you implemented? In the application side, you have an callback function? Then you read the DMA destination buffer, it is all zero?

    Regards, Eric
  • In my code for I2C read from EEPROM with DMA, I am sending the sending 2 bytes using DMA only followed by DMA read from EEPROM to I2C controller. DMA transfer is triggered automatically when the FIFO is reached and I have received transfer completion interrupt too.

    For reference I am attaching the code snippet. Actually I am working in blocking mode. I2C returns once transfer is complete and depending on the status I compare the data.

    /* Clear all interrupts */
    I2CMasterIntClearEx(hwAttrs->baseAddr, I2C_INT_ALL);

    /* Configure TX DMA parameters */

    /* transmit parameter set */
    EDMA3_DRV_getPaRAM((EDMA3_DRV_Handle)hwAttrs->edmaHandle,
    hwAttrs->txDmaEventNumber,
    &txParamSet);

    /* Update param sets based on the transaction parameters */
    I2C_DMA_localEdmaUpdateParams_v1(handle,
    transaction,
    &rxParamSet,
    &txParamSet);

    /* Dummy paramSet Configuration */
    EDMA3_DRV_getPaRAM(hwAttrs->edmaHandle,
    EDMA3_DRV_LINK_CHANNEL,
    &dummyParamSet);

    dummyParamSet.aCnt = I2C_EDMA3CC_PARAM_ACNT;
    dummyParamSet.linkAddr = I2C_EDMA3CC_PARAM_LINK_ADDRESS;
    dummyParamSet.opt &= ~((uint32_t)0x01U << I2C_EDMA3CC_OPT_STATIC_SHIFT);

    /* Now, write the PaRAM Set. */
    EDMA3_DRV_setPaRAM(hwAttrs->edmaHandle,
    EDMA3_DRV_LINK_CHANNEL,
    &dummyParamSet);

    /* Write Tx param set */
    EDMA3_DRV_setPaRAM((EDMA3_DRV_Handle)(hwAttrs->edmaHandle),
    hwAttrs->txDmaEventNumber,
    &txParamSet);

    /* Link the Dummy paramset */
    EDMA3_DRV_linkChannel(hwAttrs->edmaHandle,
    hwAttrs->txDmaEventNumber,
    EDMA3_DRV_LINK_CHANNEL);

    /* Set I2C device in Master, TX mode */
    /* Enable 7BIT SLAVE ADDR */
    /* TODO: check for 10bit slave addr */
    I2CMasterControl(hwAttrs->baseAddr, I2C_CFG_MST_TX | I2C_CFG_7BIT_SLAVE_ADDR | I2C_CFG_STOP);

    /* Enable Interrupts */
    I2CMasterIntEnableEx(hwAttrs->baseAddr, I2C_INT_TRANSMIT_READY | I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST);

    /* Program the TX side */
    // TODO: check for return value
    result = EDMA3_DRV_enableTransfer(hwAttrs->edmaHandle,
    hwAttrs->txDmaEventNumber,
    EDMA3_DRV_TRIG_MODE_EVENT);

    /* Enable DMA TX Event */
    I2CDMATxEventEnable(hwAttrs->baseAddr);

    /* In master mode, set the I2C slave address */
    I2CMasterSlaveAddrSet(hwAttrs->baseAddr,
    object->currentTransaction->slaveAddress);

    /* Set number of bytes to be transmitting */
    I2CSetDataCount(hwAttrs->baseAddr, object->writeCountIdx);

    printf("\n I2C:(0x%x) Writing w/ START \n", hwAttrs->baseAddr);

    /* Enable Start bit to start transfer */
    I2CMasterStart(hwAttrs->baseAddr);

    /* Wait for TX tobe completed and Bus to be free */
    /* TODO: Convert to a sem wait, not an ideal solution to be polling */
    while(I2CMasterBusBusy(hwAttrs->baseAddr) == 0);

    /* Done with TX, start RX */

    /* Configure RX DMA parameters */

    /* receive parameter set */
    EDMA3_DRV_getPaRAM((EDMA3_DRV_Handle)hwAttrs->edmaHandle,
    hwAttrs->rxDmaEventNumber,
    &rxParamSet);

    /* Update param sets based on the transaction parameters */
    I2C_DMA_localEdmaUpdateParams_v1(handle,
    transaction,
    &rxParamSet,
    &txParamSet);

    /* Write Rx param set */
    EDMA3_DRV_setPaRAM((EDMA3_DRV_Handle)(hwAttrs->edmaHandle),
    hwAttrs->rxDmaEventNumber,
    &rxParamSet);

    /* Set I2C device in Master, RX mode */
    /* Enable Stop Bit */
    /* Enable 7BIT SLAVE ADDR */

    I2CMasterControl(hwAttrs->baseAddr, I2C_CFG_MST_RX | I2C_CFG_7BIT_SLAVE_ADDR | I2C_CFG_STOP);

    /* Program the RX side */
    // TODO: check for return value
    result = EDMA3_DRV_enableTransfer(hwAttrs->edmaHandle,
    hwAttrs->rxDmaEventNumber,
    EDMA3_DRV_TRIG_MODE_EVENT);

    /* Enable DMA RX Event */
    I2CDMARxEventEnable(hwAttrs->baseAddr);

    // TODO: Check if this is really needed, has already been programmed while doing TX
    /* In master mode, set the I2C slave address */
    I2CMasterSlaveAddrSet(hwAttrs->baseAddr,
    object->currentTransaction->slaveAddress);

    /* Set number of bytes to be receiving */

    I2CSetDataCount(hwAttrs->baseAddr, object->readCountIdx);

    I2CMasterStart(hwAttrs->baseAddr);

    I am using AB sync DMA rx and tx params

    rxParamSet->srcAddr = hwAttrs->baseAddr + 0X9C;

    rxParamSet->destAddr = (uint32_t) object->readBufIdx;

    rxParamSet->aCnt = 1;

    rxParamSet->bCnt = object->currentTransaction->readCount;

    rxParamSet->cCnt = 1; 

    rxParamSet->srcBIdx = 0; 

    rxParamSet->destBIdx = rxParamSet->aCnt;

    rxPararxParamSet->destCIdx = rxParamSet->bCnt;

    rxParamSet->linkAddr = 0xFFFF;

    rxParamSet->bCntReload = rxParamSet->bCnt;

    rxParamSet->opt &= I2C_EDMA3CC_OPT_DAM_INCR_MODE;

    rxParamSet->opt |= I2C_EDMA3CC_OPT_SAM_CONST_MODE;

    rxParamSet->opt &= I2C_EDMA3CC_OPT_FIFO_WIDTH;

    rxParamSet->opt &= I2C_EDMA3CC_OPT_SYNC_MASK_VALUE;

    rxParamSet->opt |= I2C_EDMA3CC_OPT_SYNC_AB;

    /* EDMA3_DRV_OPT_FIELD_TCINTEN */
    rxParamSet->opt |= 1U << I2C_OPT_TCINTEN_SHIFT;

    /* update the transfer completion code */
    rxParamSet->opt &= (~I2C_OPT_TCC_MASK);
    rxParamSet->opt |= ((hwAttrs->rxDmaEventNumber) <<
    I2C_OPT_TCC_SHIFT);

    tx params as below

    /* Transmit param set configuration */

    txParamSet->srcAddr = (uint32_t) object->writeBufIdx;

    txParamSet->destAddr = (uint32_t) hwAttrs->baseAddr + 0x9C;

    txParamSet->aCnt = 1;

    txParamSet->bCnt = object->currentTransaction->writeCount;

    txParamSet->cCnt = 1;

    txParamSet->srcBIdx = txParamSet->aCnt;
    txParamSet->destBIdx = 0;

    txParamSet->srcCIdx = txParamSet->bCnt;
    txParamSet->destCIdx = 0;

    txParamSet->linkAddr = I2C_EDMA3CC_PARAM_LINK_ADDRESS;
    txParamSet->bCntReload = txParamSet->bCnt;

    txParamSet->opt &= I2C_EDMA3CC_OPT_SAM_INCR_MODE;
    txParamSet->opt |= I2C_EDMA3CC_OPT_DAM_CONST_MODE;

    txParamSet->opt &= I2C_EDMA3CC_OPT_FIFO_WIDTH;

    txParamSet->opt &= I2C_EDMA3CC_OPT_SYNC_MASK_VALUE;
    txParamSet->opt |= I2C_EDMA3CC_OPT_SYNC_AB;

    txParamSet->opt |= (1U << I2C_OPT_TCINTEN_SHIFT);

    txParamSet->opt &= (~I2C_OPT_TCC_MASK);
    txParamSet->opt |= ((hwAttrs->txDmaEventNumber) <<
    I2C_OPT_TCC_SHIFT);

    Please let me know I am missing anything. I required send me the code snippet that i can try for receive to work with DMA

    Thanks & Regards

    Manjula

  • reminder...

    any insight into this issue really helps a lot. Thanks in advance.