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.

TMS320F28388D: CM I2C Reading Bad Data

Part Number: TMS320F28388D
Other Parts Discussed in Thread: TMP101, C2000WARE

Tool/software:

I am accessing an I2C temperature device (TMP101) from CM. The CM is setup as I2C Master on the bus. It just configures the I2C slave device and then reads out temperature data every second.

When looking at the traffic on a logic analyzer, it looks exactly as expected and the device is returning the correct data. This tells me that the bus transactions are correct (the device ACKs correctly). But in the CM firmware, I often get duplicate values when reading the 2 bytes of data from the I2CMDR register. I am not using the interrupt or FIFO mechanisms and just doing a background polling loop. I noticed that the last valid value is kept in the MDR register, so reading the register at the wrong time (or if it isn't being updated as expected) would result in duplicate values.

I was following the documented flow charts from the TRM. Is there an example of how these APIs are to be used? When is the data in the MDR valid and ready, and how can the firmware tell? The only one in the C2000Ware example area is not applicable.

void i2cTemperaturePoll(uint32_t i2cInstance)
{
    if(I2C_isMasterBusy(TEMPERATURE_I2C_BASE))
    {
        return;
    };

    // Set I2C target address
    // FC: write slave address to I2CMSA
    I2C_setSlaveAddress(TEMPERATURE_I2C_BASE, i2cAddresses[i2cInstance], I2C_MASTER_READ);

    // FC: Check busy (may be omitted in single master system)
    while(I2C_isBusBusy(TEMPERATURE_I2C_BASE));

    // Start transaction
    // FC: write xxx0_1011 to I2CMCS
    I2C_setMasterConfig(TEMPERATURE_I2C_BASE, I2C_MASTER_CMD_BURST_RECEIVE_START);

    for (int i = 0; i < TEMPERATURE_I2C_DATA_BYTES; i++)
    {
        // FC: read I2CMCS
        while(I2C_isMasterBusy(TEMPERATURE_I2C_BASE));

        // FC: ERROR bit == 0?
        i2cBusStatus[i2cInstance] |= I2C_getMasterErr(TEMPERATURE_I2C_BASE);

        // Grab read first data byte
        // FC: Read data from I2CMDR
        rawData[i] = I2C_getMasterData(TEMPERATURE_I2C_BASE);

        if (i < TEMPERATURE_I2C_DATA_BYTES - 1)
        {
            // Continue transaction and STOP
            // FC: write xxx0_1001 to I2CMCS
            I2C_setMasterConfig(TEMPERATURE_I2C_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT);
        }
        else
        {
            // FC: last byte
            // FC: write xxx0_1101 to I2CMCS
            I2C_setMasterConfig(TEMPERATURE_I2C_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH_ACK);
        }
    }

    // FC: Check busy
    while(I2C_isMasterBusy(TEMPERATURE_I2C_BASE));

    // FC: ERROR bit == 0?
    i2cBusStatus[i2cInstance] |= I2C_getMasterErr(TEMPERATURE_I2C_BASE);
}

I did edit the CM I2C API to define the config type I2C_MASTER_CMD_BURST_RECEIVE_FINISH_ACK. This type is defined as:

    //! BURST RECEIVE FINISH
    I2C_MASTER_CMD_BURST_RECEIVE_FINISH          = 0x00000005U,
    //! BURST RECEIVE FINISH WITH ACK
    I2C_MASTER_CMD_BURST_RECEIVE_FINISH_ACK      = 0x0000000dU,

This config ACKs the data from the device. Its not 100% necessary, but matches the expected bus transactions.

Thanks!

  • Hi Jay,

    Let me get back to you on this tomorrow.

    Best Regards,

    Aishwarya

  • Jay,

    Apologies for the delay due to the U.S. Holidays. It is possible to read duplicate values when polling for data readiness without synchronizing with the I2C module's current state. I would recommend first polling the RRDY flag and then check the MDR to ensure it contains valid data. You could also use a logic analyzer to verify the timing of the I2C bus. 

    Polling based approach will work with some tweaks to this code, but using interrupts would provide a more reliable way to synchronize reads, specifically during these burst transactions. 

    Best Regards,

    Aishwarya

  • Where is the RRDY flag? I don't see one in the CM implementation of the I2C module. There is one for the C2000 implementation.

  • Jay,

    That's right, can you actually try polling the appropriate flag in the I2CMRIS register until it has been cleared? Are these interrupts even being set as expected?

    Best Regards,

    Aishwarya

  • Thanks, Aishwarya. I changed my code poll on the general interrupt (I2C_MRIS_RIS) instead of just the C2000Ware I2C_isMasterBusy API. This change appears to function better and can read good data. Below is a summary of the transaction flow:

    // Set I2C target address
    I2C_setSlaveAddress(I2C_BASE, i2cAddress, I2C_MASTER_READ);
    while(I2C_isBusBusy(I2C_BASE));
    
    // Start transaction
    I2C_clearMasterInt(I2C_BASE);
    
    
    I2C_setMasterConfig(I2C_BASE, I2C_MASTER_CMD_BURST_RECEIVE_START);
    
    // FC: read I2CMCS
    while(I2C_isMasterBusy(I2C_BASE));
    
    // FC: ERROR bit == 0?
    i2cBusStatus |= I2C_getMasterErr(I2C_BASE);
    
    while(!isI2CDataReady()); // wait for ISR
    
    // Grab read first data byte
    rawData = I2C_getMasterData(I2C_BASE);
    
    ....

    I will do some more testing (problem was exaggerated on RELEASE builds) and update if I encounter any more issues.

    Jay

  • Jay,

    Thanks for the update. 

    Best Regards,

    Aishwarya 

  • So far, it appears to work correctly. I may look into the different interrupt flags more, but the general Raw Interrupt Status (RIS) works. Thanks for the help.

    Jay

  • Jay,

    I will go ahead and mark this thread as resolved. You can start a new thread if anything else comes up.

    Best Regards,

    Aishwarya