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.

TMS320F280049C: I2c signals being busy when it should not

Part Number: TMS320F280049C

Hello,

I am writing an i2c interface using the driver lib. In order to read the temperature of different "transistors" i need use the code from the driver lib:

uint16_t readData( struct I2CMsg *msg )
{
//
// Wait until the STP bit is cleared from any previous master
// communication.
if(I2C_getStopConditionStatus(I2CA_BASE))
{
return(ERROR_STOP_NOT_READY);
}

//
// Setup address of control of temp sensors
I2C_setSlaveAddress(I2CA_BASE, TMP_422_ADD);

// send address of register to read
// when this is ready, interrupt handles the read process
if(msg->msgStatus == MSG_STATUS_SEND_NOSTOP)
{
//
// Check if bus busy
if(I2C_isBusBusy(I2CA_BASE))
{
return(ERROR_BUS_BUSY);
}

//
// Send data to setup EEPROM address
I2C_setDataCount(I2CA_BASE, 1);
I2C_putData(I2CA_BASE, msg->pointer);

I2C_setConfig(I2CA_BASE, I2C_MASTER_SEND_MODE);
I2C_sendStartCondition(I2CA_BASE);
}

return(SUCCESS);
}

in the interrupt ISR:

i2cISR()
{
....
if(intSource == I2C_INTSRC_STOP_CONDITION)
    {
        //
        // If completed message was writing data, reset msg to inactive state
        if(currentMsgPtr->msgStatus == MSG_STATUS_WRITE_BUSY)
        {
            currentMsgPtr->msgStatus = MSG_STATUS_INACTIVE;
        }
        else
        {

            if(currentMsgPtr->msgStatus == MSG_STATUS_SEND_NOSTOP_BUSY)
            {
                currentMsgPtr->msgStatus = MSG_STATUS_SEND_NOSTOP;
            }
            //
            // If completed message read
            else if(currentMsgPtr->msgStatus == MSG_STATUS_READ_BUSY)
            {
                for(i=0; i < currentMsgPtr->numBytes; i++)
                {
                    currentMsgPtr->msgBuffer[i] = I2C_getData(I2CA_BASE);
                }
                // make possible to write message again
                currentMsgPtr->msgStatus = MSG_STATUS_SEND_NOSTOP;
            }
        }
    }
...
}

This works ok, if I time-out between sending the write condition:

write(sensorMsgs1)

timeout

write(sensoreMsg2)

timeout etc.

My idea was to :

void readPcBSensors( void )
{
    static pcbSelect selectedSensor = TEMP_1;

    if( I2C_isBusBusy(I2CA_BASE) )
    {
        switch( selectedSensor )
        {
            case TEMP_1:
                if( readPcbTemp1( ) == SUCCESS )
                {
                    selectedSensor = TEMP_2;
                }
                else
                {
                    NOP();
                }
                break;
            case TEMP_2:
 
......
    }
}

With:

uint16_t readPcbTempLoc( void )
{
    uint16_t error = 1;
    //
    // Check incoming message status
    if(i2cMsgInExTempLoc.msgStatus == MSG_STATUS_SEND_NOSTOP)
    {
        //
        // Send EEPROM address setup
        //
        currentMsgPtr = &i2cMsgInExTempLoc;

        error = readData( &i2cMsgInExTempLoc );

        //
        // Update current message pointer and message status if
        // read success else try again next time
        if( error == SUCCESS)
        {
            i2cMsgInExTempLoc.msgStatus = MSG_STATUS_SEND_NOSTOP_BUSY;
        }
        else
        {
            NOP;
        }
   }

   return error;
}

The Problem is, that i never get to writing data since:

if(I2C_isBusBusy(I2CA_BASE) is always true

What did i get wrong? If i remvove the condition:
if(I2C_isBusBusy(I2CA_BASE))

and time-out between the reads, it works, if i not time out, the program also gets stuck at
if(I2C_isBusBusy(I2CA_BASE)) in the readData function.

Thanks in advance.

  • Jan,

    F280049 device is running at 100 MHz. I2C when running in standard / fast mode transmits bits at 100 KHz / 400 KHz respectively.

    Since your device is running at much much higher rate, you will start running write(sensoreMsg2) before completion of transmission of write(sensoreMsg1). That is the reason why when you include timeout, it works.

    Regards,

    Manoj

  • Yes for sure, maybe but my question was not, why does it work with timeouts: 

    Why "I2C_isBusBusy(I2CA_BASE)" is not preventing from starting my communication, when it is not finished? 

    Why I2C_isBusBusy(I2CA_BASE) is when i did not start communication, (I tried to protect write access with this function)? When you read under "my idea was", there is the actual thing I am wondering about.

    How can I get ride of the  I2C_sendStopCondition(I2CA_BASE) condition? How can I prevent reading a new message (without time-out) , when I am still in a read/write process?

    Regards and thanks in advance

  • Jan,

    I2CSTR.BB bit tells whether I2C bus is free (or) busy. I2C_isBusBusy(I2CA_BASE) function checks the status of the I2CSTR.BB bit-field. This functions doesn't wait till the I2C bus is free to start another I2C transaction (write / read).

    You can keep waiting in an loop until I2C bus is free (or) you can have I2C trigger CPU interrupt when STOP condition is generated. This way you would know that previous I2C transaction is complete and then you can start new I2C transaction.

    Regards,

    Manoj

  • Hello,

    thanks for your fast reply, I already implemented that I wait for the CPU stop condition and only then start a new transmission.
    Everything is working fine, as long as both sensors are on connected to the I2C line, when I disconnect one (unfortunately only one sensor can be disconnected) the whole communication is off and I run with other sensor into the condition (it is in the stop condition) of the I2C ISR:
                if(currentMsgPtr->msgStatus == MSG_STATUS_SEND_NOSTOP_BUSY)
                {
                    // next attempt to read
                    currentMsgPtr->msgStatus = MSG_STATUS_READ_FAILED;
                    // update attemp counter if no message was received
                    currentMsgPtr->attemptCounter ++;
                }
    The stop condition gets triggered by:
            if((I2C_getStatus(I2CA_BASE) & I2C_STS_NO_ACK) != 0)
            {
                I2C_sendStopCondition(I2CA_BASE);
                I2C_clearStatus(I2CA_BASE, I2C_STS_NO_ACK);
            }
    Do you have any suggestions?
    Thanks for your time.
    Ja
  • The singnals look fine to me. Furthermore, I still have the problem, that when I write data to my sensor, the function: I2C_isBusBusy(I2CA_BASE) returns true.

    My sensor exspect: start, address, ack(sensor), pointer write address (1 Byte) , ack (sensor), data (1 Byte), ack by Sensor, stop by master. This is done as described in the example in the driverlib:

    / Setup number of bytes to send msgBuffer and address
    I2C_setDataCount(I2CA_BASE, (msg->numBytes + 1));
    
    // Setup adress of register to write to
    I2C_putData(I2CA_BASE, msg->pointer);
    
    // input data stored to adress
    for (i = 0; i < msg->numBytes; i++)
    {
    I2C_putData( I2CA_BASE, msg->msgBuffer[i] );
    }
    
    // Send start as master transmitter
    I2C_setConfig( I2CA_BASE, I2C_MASTER_SEND_MODE );
    
    //send start condition
    I2C_sendStartCondition( I2CA_BASE );
    
    // send stop condition
    I2C_sendStopCondition( I2CA_BASE );
    
    errorCode = SUCCESS;

    .... ISR:

        if(intSource == I2C_INTSRC_STOP_CONDITION)
        {
            //
            // If completed message was writing data, reset msg to inactive state
            if(currentMsgPtr->msgStatus == MSG_STATUS_WRITE_BUSY)
            {
                currentMsgPtr->msgStatus = MSG_STATUS_INACTIVE;
                // TODO: remove
                if((I2C_getStatus(I2CA_BASE) & I2C_STS_NO_ACK))
                    __asm("   ESTOP0");
            }

    Do you have a guess, why is the bus busy after writing? The NO_ACK flag is not set.

  • Jan,

    After each write / read transaction I would wait till the I2CBus is free as shown below. This way I would always make sure I don't initiate another I2C transaction before previous I2C transaction is complete.

    write(sensorMsgs1);

    while(I2C_isBusBusy(I2CA_BASE)); //Wait till I2CA bus is free and completes write(sensorMsg1) transaction)

    write(sensoreMsg2);

    while(I2C_isBusBusy(I2CA_BASE)); //Wait till I2CA bus is free and completes write(sensorMsg1) transaction)

    readPcBSensors();

    while(I2C_isBusBusy(I2CA_BASE)); //Wait till I2CA bus is free and completes write(sensorMsg1) transaction)

    Regards,

    Manoj

  • Hey,

    while(I2C_isBusBusy(I2CA_BASE)); won t help.

    I found the reason, a stop condtion was not send properly.So if anyone has the same problem that the bus ist busy it may be the stop condition. In this case while(I2C_isBusBusy(I2CA_BASE)); would just loop forever.

    But I wonder, why the bus is reporting busy and not via I2C_getStopConditionStatus(I2CA_BASE), is there any reason?

    What is still funny, that when I take one device off, that disconnecting one device will mess up the whole communication. Detecting the missing device is no problem, I should just restart the bus afterwards and communication between the devices still connected to the bus should be fine.

    What is the best way to reset the bus? 

    Thanks for your time.

  • Jan,

    What is the status of I2CMDR.STP bit when you see ERROR_BUS_BUSY failure and not ERROR_STOP_NOT_READY failure? If STP bit is 0, it just means that there is not pending STOP condition to be generated (or) STP bit was never set to begin with.

    When you remove one I2C slave from network, you should see NACK condition when you try to communicate to missing I2C slave. Do you see NACK condition being set? If NACK bit is set, are you making sure to generate STOP condition when you receive NACK condition.

    I2C_getStopConditionStatus(I2CA_BASE) function just provides the status of I2CMDR.STP bit.

    When I2CMDR.STP = 1, above function returns true '1' meaning there is a pending STOP condition to be generated.

    When I2CMDR.STP = 0, above function returns failse '0' meaning there is no pending STOP condition to be generated

    What is the best way to reset the bus? 

    If you I2C bus is stalled, you can always recover the I2C bus by clearing and setting I2C reset bit (I2caRegs.I2CMDR.IRS)

    From a driverlib perspective, you can need to disable and enable I2C module as shown below to recover the control of I2C bus and clear error conditions.

    I2C_disableModule(I2CA_BASE); //I2CA device held in reset

    I2C_enableModule(I2CA_BASE); //I2CA device release from reset

    Regards,

    Manoj