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.

I2C bus lost sends while(I2CMasterBusy()) into infinite loop on Tiva Launchpad, need escape plan

If the bus has issues like copper connection is cut on the I2C bus, then while I2CMasterBusy() seems to get stuck in an infinite loop.  Is there a best practice way to keep

I2CMasterSlaveAddrSet(I2C0_BASE, SERIAL_SLAVE_ADDRESS, false);
I2CMasterDataPut(I2C0_BASE, 0xFA);
I2CMasterControl(I2C0_BASE,I2C_MASTER_CMD_SINGLE_SEND);
while(I2CMasterBusy(I2C0_BASE));

from getting stuck.  My instinct is to set a limit to how long it can be in the while loop using a timer interrupt.

  • Hello Brandon

    Yes, that would be a solution. Or you can check the Clock Low Timeout feature.

    Regards
    Amit
  • I ended up going with the Clock Timeout feature.   For anyone who wants to do the same.  You need to add a clock time limit using:

    I2CMasterTimeoutSet(I2C0_BASE, 0xFF);

    I just used the max value of 0xFF.

    I then created a new test modeledafter the driverlib function I2CMasterBusy() and called it I2CMasterTimeout()

    //*****************************************************************************
    //! Indicates whether or not the I2C bus has timed out.
    //!
    //! \param ui32Base is the base address of the I2C module.
    //!
    //! This function returns an indication of whether or not the I2C bus has time
    //!  out.  The I2C Master Timeout Value must be set.
    //!
    //! \return Returns \b true if the I2C bus has timed out; otherwise, returns
    //! \b false.
    //*****************************************************************************
    bool I2CMasterTimeout(uint32_t ui32Base)
    {
        // Return the bus timeout status
        if(HWREG(ui32Base + I2C_O_MCS) & I2C_MCS_CLKTO)
        {
            return(true);
        }
        else
        {
           return(false);
        }
    }

    When the timeout value occurs, the value returned is true.  So my escape plan for a bad bus connection looks like:

    while ( I2CMasterBusy(I2C0_BASE) && !I2CMasterTimeout( I2C0_BASE) );

    Which exists when bus is not bus or when a timeout has occurred.

  • Hello Brandon,

    Thanks for posting back a "code".

    Regards
    Amit
  • Hi,
    I also struck with same while loop. and i tried with I2CMasterTimeoutSet(I2C0_BASE, 0xFF); by seting the clock timing limit. still i' m struck in same while loop. below i given the code. plz help me

    #define Master_SYSCTL_PERIPH_GPIOx SYSCTL_PERIPH_GPIOD
    #define Master_GPIO_PGx_I2CxSCL GPIO_PD0_I2C3SCL
    #define Master_GPIO_PGx_I2CxSDA GPIO_PD1_I2C3SDA
    #define Master_GPIO_PORTx_BASE GPIO_PORTD_BASE
    #define Master_MTPR_R I2C3_MTPR_R
    #define Master_SCL_Pin GPIO_PIN_0
    #define Master_DTA_Pin GPIO_PIN_1
    #define Master_SYSCTL_PERIPH_I2Cx SYSCTL_PERIPH_I2C3
    #define Master_I2Cx_BASE I2C3_BASE
    #define Master_INT_I2Cx INT_I2C3

    // I2C Init function

    void Init_I2C(void)
    {
    // Master - I2C3
    SysCtlPeripheralEnable(Master_SYSCTL_PERIPH_I2Cx);
    SysCtlPeripheralEnable(Master_SYSCTL_PERIPH_GPIOx);
    GPIOPinConfigure(Master_GPIO_PGx_I2CxSCL);
    GPIOPinConfigure(Master_GPIO_PGx_I2CxSDA);
    GPIOPinTypeI2CSCL(Master_GPIO_PORTx_BASE, Master_SCL_Pin); // PD0 - SCL
    GPIOPinTypeI2C(Master_GPIO_PORTx_BASE, Master_DTA_Pin); // PD1 - DATA
    I2CMasterInitExpClk(Master_I2Cx_BASE, SysCtlClockGet(), false);

    I2CMasterTimeoutSet(Master_I2Cx_BASE, 0xFF);

    I2CMasterIntEnable(Master_I2Cx_BASE);
    IntEnable(Master_INT_I2Cx);
    }

    void I2C_Master_interrupt(void)
    {
    I2CMasterIntClear(Master_I2Cx_BASE);

    I2CMasterSlaveAddrSet(Master_I2Cx_BASE, Slave_Address, true); // Master Receive mode
    I2CMasterControl(Master_I2Cx_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);
    while(I2CMasterBusy(Master_I2Cx_BASE));
    Ms_rx_data[i] = I2CMasterDataGet(Master_I2Cx_BASE);
    }

    int main(void)
    {
    Init_I2C();
    while (1)
    {}
    }

    Regards,

    Yuvaraj N

  • Hello Yiuvraj,

    And which of the two while loops is it? The master cannot generate an interrupt on configuration. It has to be primed by a I2C transaction. The Clock Low Timeout feature is applicable only when a transaction has been initiated on the bus and it causes the bus to get stuck due to the fact that the Slave is holding the line low.

    Regards
    Amit
  • Hi Amit,

                            thanks for reply. if the master cannot generate an interrupt means, i can't able to generate the interrupt using below mentioned functions? 

    I2CMasterIntEnable(Master_I2Cx_BASE);

    IntEnable(Master_INT_I2Cx);

    Regards,

    Yuvaraj N

  • Hi Amit,

    I configured my I2C as a master and i try to transfer one byte data to slave, after that i am reading one byte data from slave. either when i am transfer the data from master to slave or read data from slave individually(any one of the transaction) i can able to do. suppose if i want to transfer data from master to slave and also read data from slave, that time i am facing problem. that time i struck in following loop while(I2CMasterBusy(Master_I2Cx_BASE)) ;

    // I2C Port configuration - I2C3 (Tiva C series - Development Board)
    #define Master_SYSCTL_PERIPH_GPIOx SYSCTL_PERIPH_GPIOD
    #define Master_GPIO_PGx_I2CxSCL GPIO_PD0_I2C3SCL
    #define Master_GPIO_PGx_I2CxSDA GPIO_PD1_I2C3SDA
    #define Master_GPIO_PORTx_BASE GPIO_PORTD_BASE
    #define Master_MTPR_R I2C3_MTPR_R
    #define Master_SCL_Pin GPIO_PIN_0
    #define Master_DTA_Pin GPIO_PIN_1
    #define Master_SYSCTL_PERIPH_I2Cx SYSCTL_PERIPH_I2C3
    #define Master_I2Cx_BASE I2C3_BASE
    #define Master_INT_I2Cx INT_I2C3

    // I2C Init function
    void Init_I2C(void)
    {
    // Master - I2C3
    SysCtlPeripheralEnable(Master_SYSCTL_PERIPH_I2Cx);
    SysCtlPeripheralEnable(Master_SYSCTL_PERIPH_GPIOx);
    GPIOPinConfigure(Master_GPIO_PGx_I2CxSCL);
    GPIOPinConfigure(Master_GPIO_PGx_I2CxSDA);
    GPIOPinTypeI2CSCL(Master_GPIO_PORTx_BASE, Master_SCL_Pin); // PD0 - SCL
    GPIOPinTypeI2C(Master_GPIO_PORTx_BASE, Master_DTA_Pin); // PD1 - DATA
    I2CMasterInitExpClk(Master_I2Cx_BASE, SysCtlClockGet(), false);

    I2CMasterTimeoutSet(Master_I2Cx_BASE, 0xFF);
    }

    void I2C_Master(void)
    {
    for(i = 0; i < Number_of_Bytes; i++)
    {
    I2CMasterSlaveAddrSet(Master_I2Cx_BASE, Slave_Address, false); // Master transmit mode
    I2CMasterDataPut(Master_I2Cx_BASE, Ms_tx_data[i]);
    SysCtlDelay(5000);
    I2CMasterControl(Master_I2Cx_BASE, I2C_MASTER_CMD_SINGLE_SEND);
    while(I2CMasterBusy(Master_I2Cx_BASE));
    SysCtlDelay(5000);

    I2CMasterSlaveAddrSet(Master_I2Cx_BASE, Slave_Address, true); // Master Receive mode
    I2CMasterControl(Master_I2Cx_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);
    while(I2CMasterBusy(Master_I2Cx_BASE));
    SysCtlDelay(5000);
    Ms_rx_data[i] = I2CMasterDataGet(Master_I2Cx_BASE);
    SysCtlDelay(5000);
    }
    }

    int main(void)
    {
    SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
    Init_I2C();

    Ms_tx_data[0] = 'A'; // Mater I2C transmit data
    Ms_tx_data[1] = 'B';
    Ms_tx_data[2] = 'C';
    Ms_tx_data[3] = 'D';
    Ms_tx_data[4] = 'E';
    Ms_tx_data[5] = 'F';
    Ms_tx_data[6] = 'G';
    Ms_tx_data[7] = 'H';
    Ms_tx_data[8] = 'I';

    while (1)
    {
    I2C_Master();
    }
    }

    Another one board i configured I2C as a slave. below i mentioned the following slave code for your reference.

    #define Slave_SYSCTL_PERIPH_GPIOx SYSCTL_PERIPH_GPIOE
    #define Slave_GPIO_PGx_I2CxSCL GPIO_PE4_I2C2SCL
    #define Slave_GPIO_PGx_I2CxSDA GPIO_PE5_I2C2SDA
    #define Slave_GPIO_PORTx_BASE GPIO_PORTE_BASE
    #define Slave_MTPR_R I2C2_MTPR_R
    #define Slave_SCL_Pin GPIO_PIN_4
    #define Slave_DTA_Pin GPIO_PIN_5
    #define Slave_SYSCTL_PERIPH_I2Cx SYSCTL_PERIPH_I2C2
    #define Slave_I2Cx_BASE I2C2_BASE
    #define Slave_INT_I2Cx INT_I2C2

    void init_I2C_slave(void)
    {
    // Slave Transmit and Master Receive

    SysCtlPeripheralEnable(Slave_SYSCTL_PERIPH_I2Cx);
    SysCtlPeripheralEnable(Slave_SYSCTL_PERIPH_GPIOx);
    GPIOPinConfigure(Slave_GPIO_PGx_I2CxSCL);
    GPIOPinConfigure(Slave_GPIO_PGx_I2CxSDA);
    GPIOPinTypeI2CSCL(Slave_GPIO_PORTx_BASE, Slave_SCL_Pin); // PG6 - SCL
    GPIOPinTypeI2C(Slave_GPIO_PORTx_BASE, Slave_DTA_Pin); // PG7 - DATA

    I2CSlaveEnable(Slave_I2Cx_BASE);
    I2CSlaveInit(Slave_I2Cx_BASE, Slave_Addres);

    I2CSlaveIntEnable(Slave_I2Cx_BASE);
    IntEnable(Slave_INT_I2Cx);
    }

    void i2c_slave_interrupt(void)
    {
    I2CSlaveIntClear(Slave_I2Cx_BASE); // Clears I2C Master interrupt sources.

    while(!(I2CSlaveStatus(Slave_I2Cx_BASE) & I2C_SLAVE_ACT_RREQ)); // Slave Receive
    Sl_rx_data[0] = I2CSlaveDataGet(Slave_I2Cx_BASE);
    SysCtlDelay(5000);

    if(Sl_rx_data[0] == 'A')
    {
    while(!(I2CSlaveStatus(Slave_I2Cx_BASE) & I2C_SLAVE_ACT_TREQ));
    I2CSlaveDataPut(Slave_I2Cx_BASE, Sl_tx_data[0]);
    SysCtlDelay(5000);
    }

    else if(Sl_rx_data[0] == 'B')
    {
    while(!(I2CSlaveStatus(Slave_I2Cx_BASE) & I2C_SLAVE_ACT_TREQ));
    I2CSlaveDataPut(Slave_I2Cx_BASE, Sl_tx_data[1]);
    SysCtlDelay(5000);
    }

    else if(Sl_rx_data[0] == 'C')
    {
    while(!(I2CSlaveStatus(Slave_I2Cx_BASE) & I2C_SLAVE_ACT_TREQ));
    I2CSlaveDataPut(Slave_I2Cx_BASE, Sl_tx_data[2]);
    SysCtlDelay(5000);
    }

    else if(Sl_rx_data[0] == 'D')
    {
    while(!(I2CSlaveStatus(Slave_I2Cx_BASE) & I2C_SLAVE_ACT_TREQ));
    I2CSlaveDataPut(Slave_I2Cx_BASE, Sl_tx_data[3]);
    SysCtlDelay(5000);
    }

    else if(Sl_rx_data[0] == 'E')
    {
    while(!(I2CSlaveStatus(Slave_I2Cx_BASE) & I2C_SLAVE_ACT_TREQ));
    I2CSlaveDataPut(Slave_I2Cx_BASE, Sl_tx_data[4]);
    SysCtlDelay(5000);
    }

    else if(Sl_rx_data[0] == 'F')
    {
    while(!(I2CSlaveStatus(Slave_I2Cx_BASE) & I2C_SLAVE_ACT_TREQ));
    I2CSlaveDataPut(Slave_I2Cx_BASE, Sl_tx_data[5]);
    SysCtlDelay(5000);
    }

    else if(Sl_rx_data[0] == 'G')
    {
    while(!(I2CSlaveStatus(Slave_I2Cx_BASE) & I2C_SLAVE_ACT_TREQ));
    I2CSlaveDataPut(Slave_I2Cx_BASE, Sl_tx_data[6]);
    SysCtlDelay(5000);
    }

    else if(Sl_rx_data[0] == 'H')
    {
    while(!(I2CSlaveStatus(Slave_I2Cx_BASE) & I2C_SLAVE_ACT_TREQ));
    I2CSlaveDataPut(Slave_I2Cx_BASE, Sl_tx_data[7]);
    SysCtlDelay(5000);
    }

    else if(Sl_rx_data[0] == 'I')
    {
    while(!(I2CSlaveStatus(Slave_I2Cx_BASE) & I2C_SLAVE_ACT_TREQ));
    I2CSlaveDataPut(Slave_I2Cx_BASE, Sl_tx_data[8]);
    SysCtlDelay(5000);
    }
    }

    int main (void)
    {
    SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |SYSCTL_XTAL_8MHZ);

    Sl_tx_data[0] = '0';
    Sl_tx_data[1] = '1';
    Sl_tx_data[2] = '2';
    Sl_tx_data[3] = '3';
    Sl_tx_data[4] = '4';
    Sl_tx_data[5] = '5';
    Sl_tx_data[6] = '6';
    Sl_tx_data[7] = '7';
    Sl_tx_data[8] = '8';

    init_I2C_slave();

    while(1)
    {}
    }

    Please give me the solution. i waiting for your reply.

    Regards,

    Yuvaraj N
  • Hello Yuvaraj,

    You would need to trigger an interrupt using IntTrigger(INT_I2Cx).

    Regards
    Amit
  • Hello Yuvaraj,

    Please connect the I2C SCL and SDA on the scope and then check what is the transaction generating. Also note that there is an application note on TM4C web page for I2C basics, that would be pretty helpful in the diagnostics.

    Regards
    Amit
  • hi Yuvaraj,
    verify once that your your pullups res are connected properly.
    i was facing same issue found out my pullup res was disconnected .
  • Hi Rohit,

    Thanks for your suggestion. Yes there is mistake in pull up. I connected two different pull up resistor in master and also slave. i removed slave side pull up resistor. now it's working fine. Thank you so much.

    Regards,

    Yuvaraj N

  • Hello Yuvaraj

    2 different pull up on the master and slave side will increase the strength of pull up. I guess it is working for you would mean that you would not be investigating why stronger pull up are not working!!! An interesting debug it would have been

    Regards
    Amit