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.

TMS320F28035 I2C Master Hang

I am struggling right now with an intermittent failure on the 28035 I2C bus.  The system will randomly hang during the check of the BB bit, and this is never cleared once asserted.  The code is polled, and admittedly brute force, but is a first stab at understanding the I2C peripheral.  I have not been able to find a reproducible set of events that re-creates the issue reliably so grabbing a scope capture has evaded me.  The 28035 is the only master on the bus with 2 slave devices.

Code:

void Write7SegDisplayMem(uint8_t *buf_ptr, uint16_t length)
{
    uint16_t i;

    // Wait until the STP bit is clear from any prior communications
    while(I2caRegs.I2CMDR.bit.STP == 1);

    // Setup slave address
    I2caRegs.I2CSAR = SEVEN_SEG_ADDR;

    // Check if the bus is busy
    while(I2caRegs.I2CSTR.bit.BB == 1);

    // Make sure we are a transmitter
    I2caRegs.I2CMDR.bit.TRX = 1;

    // FREE, STT, MST, TRX, RM, IRS
    I2caRegs.I2CMDR.all = 0x66A0;

    // Now insert bytes as required
    while((I2caRegs.I2CSTR.bit.XRDY == 0) || (I2caRegs.I2CSTR.bit.ARDY == 0));
    I2caRegs.I2CDXR = 0x00;  // Start at beginning of display memory
    if(I2caRegs.I2CSTR.bit.NACK == 1)
    {
        I2caRegs.I2CSTR.bit.NACK = 1;
    }
    // Now the display buffer
    for(i = 0; i < length; i++)
    {
        while((I2caRegs.I2CSTR.bit.XRDY == 0) || (I2caRegs.I2CSTR.bit.ARDY == 0));
        I2caRegs.I2CDXR = ((*(buf_ptr + i)) & 0x00FF);
        if(I2caRegs.I2CSTR.bit.NACK == 1)
        {
            I2caRegs.I2CSTR.bit.NACK = 1;
        }
    }

    // Clear NACK if received
    while(I2caRegs.I2CSTR.bit.NACK == 1)
    {
        I2caRegs.I2CSTR.bit.NACK = 1;
    }

    // FREE, STP, MST, TRX, RM, IRS
    I2caRegs.I2CMDR.all = 0x4EA0;

    // Wait for the STOP to be issued
    while(I2caRegs.I2CSTR.bit.SCD != 1);
    // And clear it
    I2caRegs.I2CSTR.bit.SCD = 1;
}

Basically, I check for STP being cleared and pass that check, but then hang on the check for BB.  From the documentation it seems like the STP being issued (and cleared by the hardware) should allow the BB to clear, but that doesn't seem to be happening.  Since I wrote this polled, it hangs my code.  My first thought is to add a timeout and if I hang on that line for too long, to reset the I2C device.  I'm still perplexed as to what is going on though.


I have found similar posts on this issue in the past, but none were ever answered.  See here:

https://e2e.ti.com/support/microcontrollers/c2000/f/171/t/164613

https://e2e.ti.com/support/microcontrollers/c2000/f/171/t/47556

https://e2e.ti.com/support/microcontrollers/c2000/f/171/t/162457

Any guidance greatly appreciated.

Thanks,

Mike

  • Mike,

    When the code hangs, what's the state of the SCL and SDA lines? Are they both high?
  • Hi Adam,

    Have seen it stop in multiple ways.

    Some recent captures I have:
    SCL high, SDA high, I2CSTR = 0x1430, I2CMDR = 0x42A0

    SCL high, SDA low, I2CSTR = 0x0430, I2CMDR = 0x42A0

    Has also hung now on the check for XRDY and ARDY with SCL high, SDA low, I2CSTR = 0x1411; didn't record Mode Register.

    There does seem to be some correlation to when I have power/load steps in the system. Starting to suspect this may be a noise issue where the I2C is triggering false transitions from an external aggressor.

    Best,
    Mike
  • Mike,

    I agree; outside interference is a good thing to look at. You didn't say what bit rate or pull-up resistance you were using. Have you tried using a stronger pull-up?
  • Hi Adam,

    4.7K pull-up. Have tried 100k, 200k, and 400kHz. No real difference based on bus speed. Bus capacitance does seem to have some positive effect so I think I'm on the right track with noise.

    Is it possible for the master-transmitter state machine of the peripheral to terminate it's transaction based on external noise, but not release the SCL/SDA lines under any condition? Does the BB bit setting logic live outside of the peripheral's primary state machine?

    Thanks,
    Mike
  • BB is set whenever SCL goes low or a start condition is detected -- basically, anything that looks like another master being active on the bus. So it's possible for a glitch on SCL or maybe SDA to set BB. BB is only cleared by a stop condition.

    The module will terminate its transaction if arbitration is lost, but there's a status bit for that.