Because of the holidays, TI E2E™ design support forum responses will be delayed from Dec. 25 through Jan. 2. Thank you for your patience.

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.

TMS320F28027F: I2C sets Stop condition without being commanded to

Part Number: TMS320F28027F

I'm using a TMS320 launchpad board to try to talk to a simple external device. This device's default setup is that it is ready with data, all you have to do is address the device, select the register (reg 0) and read two bytes of data.

Having had problems with stop conditions failing to be generated in FIFO mode I have set the 320 up to have normal mode and Repeat Message, which, as I understand it, gives manual control over the generation of stop conditions.

So what we should see is address 0x48 writing to register 0, then another message with the same address and reading back two bytes, but the stop condition occurs before the second byte is sent. I put a breakpoint in CCS on the section of code that generates the stop condition and it never hits it. How can the I2C module generate its own stop condition?

You can see the second red blob indicating a stop condition.

The code looks like this:

bool hal_I2CMasterRx( uint8_t MsgLength )
{
    static bool MsgStarted = false;
    bool MsgFinished = false;
    static uint8_t RxByte = 0;
    uint16_t Dly = 1000;


    I2caRegs.I2CSAR = 0x48;

    if( MsgStarted )
    {

        if( BytesToSend == 0 )
        {
            if( I2caRegs.I2CSTR.bit.XRDY )  // has it finished the last byte?
            {
                I2caRegs.I2CSTR.bit.XRDY = 1;
                RxData[ RxByte ] = I2caRegs.I2CDRR;
                RxByte++;
                I2caRegs.I2CMDR.bit.STP = 1;    // send a stop condition
                MsgStarted = false;          // A BREAKPOINT HERE NEVER GETS HIT
                MsgFinished = true;
            }
        }
        else
        {
            if( I2caRegs.I2CSTR.bit.XRDY )  // are we ready to Tx?
            {
//                I2caRegs.I2CSTR.bit.XRDY = 1;
                RxData[ RxByte ] = I2caRegs.I2CDRR;
                RxByte++;
                I2caRegs.I2CDXR = 0;
                BytesSent++;
                BytesToSend--;
            }
        }
    }
    else
    {
        if( I2caRegs.I2CSTR.bit.SCD )
        {
            I2caRegs.I2CSTR.bit.SCD = 1;
        }

        if( I2caRegs.I2CSTR.bit.BB == 0 )     // wait for bus busy = false
        {
            I2caRegs.I2CMDR.bit.MST = 1;    // set Master mode
            I2caRegs.I2CMDR.bit.RM = 1;
            I2caRegs.I2CMDR.bit.STT = 1;    // send Start condition
            I2caRegs.I2CMDR.bit.TRX = 0;    // receive (read) mode

            if( I2caRegs.I2CSTR.bit.XRDY )  // are we ready to Tx?
            {
                while( Dly-- )
                {}
//                I2caRegs.I2CSTR.bit.XRDY = 1;
                Status[BytesToSend] = I2caRegs.I2CSTR.all;
                RxByte = 0;
                MsgStarted = true;
                BytesToSend = MsgLength;
                I2caRegs.I2CDXR = 0;
                BytesSent++;
                BytesToSend--;
            }
        }
    }
    return MsgFinished;
}

Any help you can give me on this would be appreciated.

  • Hi Andy,

    I'd recommend looking at the example code I provided at the end of the prior E2E post below:

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

    You're issue may be related to setting I2CCNT before writing/reading bytes. The peripheral may be configured to generate a STOP when I2CCNT reaches zero.

    Best,

    Kevin

  • The datasheet says that in Repeat mode i2ccnt isn't used, but just to prove that it isn't something to do with this I put a line in to set i2ccnt to longer than the message length, so that it should see the stop command before the cnt has gone to zero. The result was the same; one byte sent, then stop.

    There are several things I don't understand.

    The example code is using FIFO mode, right? I tried using FIFO mode before and I found that although it sent the right number of bytes, the stop condition didn't occur. This is bad if you're trying to setup a multi master bus. I found the only way to get the stop condition to happen was in RM mode.

    If you're not using FIFO mode and you're doing a Master Read to initiate the data transfer do you still write to the DXR register?

  • Hi Andy,

    Maybe your BytesToSend variable is reaching 0 and the STP bit is getting sent after reading only the first byte.

    Andy Worsley89 said:
    The example code is using FIFO mode, right? I tried using FIFO mode before and I found that although it sent the right number of bytes, the stop condition didn't occur. This is bad if you're trying to setup a multi master bus. I found the only way to get the stop condition to happen was in RM mode.

    Which example are you talking about? The one I linked to does not use the FIFO. For FIFO mode you typically have to utilize I2CCNT for generating the STOP.

    Andy Worsley89 said:
    If you're not using FIFO mode and you're doing a Master Read to initiate the data transfer do you still write to the DXR register?

    Maybe if you were sending a command byte first, but not when you are doing the actual read portion.The slave address with the Read bit set will be transmitted when the STT bit is set.

    Best,

    Kevin

  • Hi Kevin,

    the data transfer stops after 1 byte regardless of how many byte are to be sent. When I set the BytesToSend to 4 and let it fly it will decrement to 2. It thinks it has sent 2 bytes, but the logic analyser shows only one byte being transferred (ignoring the address byte). In all cases the STP command is not executed. If you look at the code that I pasted in a previous message you'll see a line with a comment saying a breakpoint here is never hit.

    The stop condition aside, it doesn't transfer the correct number of bytes. What could cause the transfer to stop before it has come to the end of the queue?

    Regards

    Andy

  • Hi Andy,

    What I2C slave device are you communicating with? Maybe checking the expected protocol in the slave device datasheet will give some answers. The Stop/NACK condition you're concerned about is when the F28027 is receiving bytes from the slave device correct?

    Andy Worsley89 said:
    The stop condition aside, it doesn't transfer the correct number of bytes. What could cause the transfer to stop before it has come to the end of the queue?

    You can see section 10.3.6, "NACK Bit Generation" within the device TRM for information on how the F28027 generates a NACK while receiving.

    http://www.ti.com/lit/sprui09

    I'm having trouble understanding your code. Why are you checking XRDY (Transmit ready) instead of RRDY (Receive ready) in your if( BytesToSend == 0 ) section? This portion of code if for when in Master Receiver mode correct?

    Best,

    Kevin

  • Hi Kevin,

    if I am to do a master read the master has to clock the data back from the slave device and, correct me if I'm wrong, this is done by writing to DXR. So my code checks that the transmitter is ready. I have also tried using RRDY and ARDY, none work.

    Andy

  • Hi Andy,

    Sorry for the delay in response. DXR is not needed to be used when clocking data into the device, but it would be used when sending a command byte. Typical I2C master read from slave comms look like the below:

    Start condition + Slave address + write bit ==> Master sends command byte(s) ==> Stop condition ==> Start Condition + SA + read bit ==> Master clocks in data from slave ==> Stop

    See the function below:

    uint16_t I2CA_WriteToManyRegs(uint16_t slave_addr, uint16_t reg[],
                   uint16_t reg_size, uint16_t data[], uint16_t data_size)
    {
        uint16_t i, Status;
    
        Status = I2C_SUCCESS;
    
        //
        // Wait until the STP bit is cleared from any previous master communication
        // Clearing of this bit by the module is delayed until after the SCD bit is
        // set. If this bit is not checked prior to initiating a new message, the
        // I2C could get confused.
        //
        if (I2caRegs.I2CMDR.bit.STP == 1)
        {
            return I2C_STP_NOT_READY_ERROR;
        }
    
        //
        // Setup slave address
        //
        I2caRegs.I2CSAR = slave_addr;
    
        //
        // Check if bus busy
        //
        if (I2caRegs.I2CSTR.bit.BB == 1)
        {
            return I2C_BUS_BUSY_ERROR;
        }
    
        //
        // Set up as master transmitter
        // FREE + MST + TRX + IRS
        //
        I2caRegs.I2CMDR.all = 0x4620;
    
        //
        // Setup number of bytes to send
        // == (# of register bytes) + (# of data[] buffer bytes)
        //
        I2caRegs.I2CCNT = reg_size + data_size;
    
        I2caRegs.I2CMDR.bit.STT = 0x1; // Send START condition
        I2caRegs.I2CMDR.bit.STP = 0x1; // STOP condition will be
                                       // generated when I2CCNT is zero
    
        //
        // I2C module will send the following:
        // register bytes ==> data bytes ==> STOP condition
        //
    
        // Transmit Register Bytes
        for (i=0; i< reg_size; i++)
        {
            while(!I2caRegs.I2CSTR.bit.XRDY){} // Make sure data
                                               // is ready to be written
            I2caRegs.I2CDXR = reg[i];
    
            #if NACK_CHECK // check if NACK was received
                if(I2caRegs.I2CSTR.bit.NACK == 1)
                {
                    I2caRegs.I2CMDR.bit.STP = 1;
                    I2caRegs.I2CSTR.all = I2C_CLR_NACK_BIT;
    
                    Status = I2C_ERROR;
                    return Status;
                }
            #endif
        }
    
        // Transmit Data Bytes followed by STOP condition
        for (i=0; i< data_size; i++)
        {
            while(!I2caRegs.I2CSTR.bit.XRDY){} // Make sure data
                                               // is ready to be written
            I2caRegs.I2CDXR = data[i];
    
            #if NACK_CHECK // check if NACK was received
                if(I2caRegs.I2CSTR.bit.NACK == 1)
                {
                    I2caRegs.I2CMDR.bit.STP = 1;
                    I2caRegs.I2CSTR.all = I2C_CLR_NACK_BIT;
    
                    Status = I2C_ERROR;
                    return Status;
                }
            #endif
        }
    
    
        // Data successfully written
        return Status;
    }

    Best,

    Kevin