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.

MSPM0G3507-Q1: I2C driver not handling patched writes correctly?

Part Number: MSPM0G3507-Q1

I am running into an issue where I am trying to use the MSPM0G3507-Q1 with TI-Drivers and FreeRTOS. Specifically, I am trying to pass in a 16K buffer to the I2C_transfer function to do a continuous Write ... data ... STOP transaction.

The problem is that in the middle of the transaction, the MSPM0+ seems to be giving a repeated start at the bounds of the burst lengths (255).... which my peripheral device doesn't like:

image.png

Looking into the implemntation code (specifically I2CMSPM0.c), I think the issue is in the I2CMSPM0_primeWriteBurst function:

static void I2CMSPM0_primeWriteBurst(
    I2CMSPM0_Object *object, I2CMSPM0_HWAttrs const *hwAttrs)
{
    /* Wait until bus is available */
    I2C_waitTillBusAvailable(hwAttrs);
    /* Disable the burst before setting up the new transaction */
    DL_I2C_disableControllerBurst(hwAttrs->i2c);
    /* Determine the size of this burst */
    if (object->writeCount > I2CMSPM0_MAX_BURST) {
        object->burstCount = I2CMSPM0_MAX_BURST;
    } else {
        object->burstCount = object->writeCount;
    }

    /* Write burst length */
    DL_I2C_setTransactionLength(hwAttrs->i2c, object->burstCount);

    /* If we will be sending multiple bursts */
    if (object->readCount || object->writeCount > I2CMSPM0_MAX_BURST) {
        DL_I2C_disableStopCondition(hwAttrs->i2c);
    } else {
        DL_I2C_enableStopCondition(hwAttrs->i2c);
    }

    /* Only generate a start condition if the burst hasn't started */
    if (!object->burstStarted) {
        object->burstStarted = true;
    }
    /*Before filling the FIFO, we need to clear the interrupt else it will trigger interrupt immediately*/
    DL_I2C_clearInterruptStatus(
        hwAttrs->i2c, DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_TRIGGER);
    /* Fill transmit FIFO. This will modify the object counts */
    I2CMSPM0_fillTransmitFifo(object, hwAttrs);

    /* Enable TXFIFOEMPTY interrupt and other standard transfer interrupts */
    DL_I2C_enableInterrupt(hwAttrs->i2c,
        DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_TRIGGER |
            DL_I2C_INTERRUPT_CONTROLLER_TX_DONE |
            DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_EMPTY | I2CMSPM0_TRANSFER_INTS);
    /* Set the target Address */
    DL_I2C_setTargetAddress(
        hwAttrs->i2c, object->currentTransaction->targetAddress);
    /* Set the controller direction */
    DL_I2C_setControllerDirection(
        hwAttrs->i2c, DL_I2C_CONTROLLER_DIRECTION_TX);
    /* Enable the start condition */
    
    DL_I2C_enableStartCondition(hwAttrs->i2c);
    /* Disable the manual ACK, hardware will ack automatically */
    DL_I2C_disableControllerACK(hwAttrs->i2c);
    /* Enable the burst run */
    DL_I2C_enableControllerBurst(hwAttrs->i2c);
}

 

Specifically,  burstStarted gets set, but it doesn't actually get checked/used anywhere. The DL_I2C_enableStartCondition function always gets called regardless. If I change it to this:

/*
 *  ======== I2CMSPM0_primeWriteBurst =======
 */
static void I2CMSPM0_primeWriteBurst(
    I2CMSPM0_Object *object, I2CMSPM0_HWAttrs const *hwAttrs)
{
    /* Wait until bus is available */
    I2C_waitTillBusAvailable(hwAttrs);
    /* Disable the burst before setting up the new transaction */
    DL_I2C_disableControllerBurst(hwAttrs->i2c);
    /* Determine the size of this burst */
    if (object->writeCount > I2CMSPM0_MAX_BURST) {
        object->burstCount = I2CMSPM0_MAX_BURST;
    } else {
        object->burstCount = object->writeCount;
    }

    /* Write burst length */
    DL_I2C_setTransactionLength(hwAttrs->i2c, object->burstCount);

    /* If we will be sending multiple bursts */
    if (object->readCount || object->writeCount > I2CMSPM0_MAX_BURST) {
        DL_I2C_disableStopCondition(hwAttrs->i2c);
    } else {
        DL_I2C_enableStopCondition(hwAttrs->i2c);
    }

    /* Only generate a start condition if the burst hasn't started */
    if(object->burstStarted == true)
    {
        DL_I2C_disableStartCondition(hwAttrs->i2c);
    }
    else
    {
        DL_I2C_enableStartCondition(hwAttrs->i2c);
    }

    if (!object->burstStarted) {
        object->burstStarted = true;
    }
    /*Before filling the FIFO, we need to clear the interrupt else it will trigger interrupt immediately*/
    DL_I2C_clearInterruptStatus(
        hwAttrs->i2c, DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_TRIGGER);
    /* Fill transmit FIFO. This will modify the object counts */
    I2CMSPM0_fillTransmitFifo(object, hwAttrs);

    /* Enable TXFIFOEMPTY interrupt and other standard transfer interrupts */
    DL_I2C_enableInterrupt(hwAttrs->i2c,
        DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_TRIGGER |
            DL_I2C_INTERRUPT_CONTROLLER_TX_DONE |
            DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_EMPTY | I2CMSPM0_TRANSFER_INTS);
    /* Set the target Address */
    DL_I2C_setTargetAddress(
        hwAttrs->i2c, object->currentTransaction->targetAddress);
    /* Set the controller direction */
    DL_I2C_setControllerDirection(
        hwAttrs->i2c, DL_I2C_CONTROLLER_DIRECTION_TX);
    /* Enable the start condition */

  
    /* Disable the manual ACK, hardware will ack automatically */
    DL_I2C_disableControllerACK(hwAttrs->i2c);
    /* Enable the burst run */
    DL_I2C_enableControllerBurst(hwAttrs->i2c);
}

.... specifically adding this:

    /* Only generate a start condition if the burst hasn't started */
    if(object->burstStarted == true)
    {
        DL_I2C_disableStartCondition(hwAttrs->i2c);
    }
    else
    {
        DL_I2C_enableStartCondition(hwAttrs->i2c);
    }

    if (!object->burstStarted) {
        object->burstStarted = true;
    }

.... everything appears to work and I can write the entire 16K without issue. I just copy the I2CMSPM0.c file into my workspace and all the symbols overwrite the ones from the SDK library. 

I just wanted to make sure I wasn't missing anything or misusing the driver in the first place. For firmware updates, I generally have to write >256byte transactions without repeated starts/stops.

Best Regards,
Tim