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.

Why does I2C bus remain busy after first transaction?

Hello! I'm using MSP-EXP432P401R Launchpad with a BME280 sensor (breakout board). I'm trying to communicate using I2C, but after successfully performing a read or write, the I2C bus remains busy. The sensor board has 10kohm pull-ups mounted and I've set the clock at 400kHz. I'm using MSP432 DriverLib v3.21.00.05.

E.g., I've tried reading the chip ID two times consecutively, but my function hangs in while(I2C_isBusBusy(EUSCI_B1_BASE)) when reading the second time. If I remove this loop, then I2C_masterSendSingleByteWithTimeout() returns 0. The code I'm using:

int main(void)
{
	Clock_System_init();

	MAP_Interrupt_enableSleepOnIsrExit();
	MAP_Interrupt_enableMaster(); // Enabling MASTER interrupts

	Timer32_sleep(1000000);

	I2C_init();

	Timer32_sleep(1000000);

	char result;
	I2C_setslave(0x76); // BME280_SLAVE_ADDRESS
	if (!I2C_read8(0xD0, &result, 1000)) //BME280_REGISTER_CHIPID
		return false;
	if (result != 0x60) // Wrong chip ID
		return false;

	I2C_setslave(0x76); // BME280_SLAVE_ADDRESS
	if (!I2C_read8(0xD0, &result, 1000)) //BME280_REGISTER_CHIPID
		return false;
	if (result != 0x60) // Wrong chip ID
		return false;
        while(1) {};
}

const eUSCI_I2C_MasterConfig i2cConfig =
{
	EUSCI_B_I2C_CLOCKSOURCE_SMCLK,          // SMCLK Clock Source
	6000000,                                // SMCLK = 6MHz
	EUSCI_B_I2C_SET_DATA_RATE_400KBPS,      // Desired I2C Clock of 400khz
	0,                                      // No byte counter threshold
	EUSCI_B_I2C_NO_AUTO_STOP                // No Autostop
};

void I2C_init(void)
{
	/* Select I2C function for I2C_SCL(P6.5) & I2C_SDA(P6.4) */
	GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P6, GPIO_PIN5, GPIO_PRIMARY_MODULE_FUNCTION);
	GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P6, GPIO_PIN4, GPIO_PRIMARY_MODULE_FUNCTION);

	/* Initialize USCI_B0 and I2C Master to communicate with slave devices*/
	I2C_initMaster(EUSCI_B1_BASE, &i2cConfig);

    /* Disable I2C module to make changes */
    I2C_disableModule(EUSCI_B1_BASE);

    /* Enable I2C Module to start operations */
    I2C_enableModule(EUSCI_B1_BASE);

    return;
}

/***************************************************************************//**
 * @brief  Reads data from the sensor
 * @param  pointer Address of register to read from
 * @return Register contents
 ******************************************************************************/

bool I2C_read8(unsigned char pointer, char * result, unsigned int timeout)
{
	while(I2C_isBusBusy(EUSCI_B1_BASE));

    /* Set master to transmit mode PL */
	I2C_setMode(EUSCI_B1_BASE,
        EUSCI_B_I2C_TRANSMIT_MODE);

    /* Clear any existing interrupt flag PL */
	I2C_clearInterruptFlag(EUSCI_B1_BASE,
        EUSCI_B_I2C_TRANSMIT_INTERRUPT0);

    /* Initiate start and send first character */
    if (!I2C_masterSendSingleByteWithTimeout(EUSCI_B1_BASE,
        pointer, timeout))
    	return 0;

    *result = I2C_masterReceiveSingleByte(EUSCI_B1_BASE);

    return 1;
}

I've attached my I2C .c and .h files hoping that someone could reproduce the problem.

I've tried using the example "BOOSTXL-SENSORS_SensorGUI_MSP432P401R", but without success, because the program hangs in the following code from readI2C():

while(ui8Status == eUSCI_BUSY)
	{
		if(MAP_I2C_getInterruptStatus(EUSCI_B1_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0))
		{
			ui8Status = eUSCI_IDLE;
		}
	}

Does anybody know what is the problem?

/* --COPYRIGHT--,BSD
 * Copyright (c) 2015, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * --/COPYRIGHT--*/
//****************************************************************************
//
// SYSTEM_I2C.c - Hardware abstraction layer for I2C with MSP432P401R
//
//****************************************************************************

#include <driverlib.h>
#include <System/i2c.h>

/* I2C Master Configuration Parameter */
const eUSCI_I2C_MasterConfig i2cConfig =
{
	EUSCI_B_I2C_CLOCKSOURCE_SMCLK,          // SMCLK Clock Source
	6000000,                                // SMCLK = 6MHz
	EUSCI_B_I2C_SET_DATA_RATE_400KBPS,      // Desired I2C Clock of 400khz
	0,                                      // No byte counter threshold
	EUSCI_B_I2C_NO_AUTO_STOP                // No Autostop
};

/***************************************************************************//**
 * @brief  Configures I2C
 * @param  none
 * @return none
 ******************************************************************************/

void I2C_init(void)
{
	/* Select I2C function for I2C_SCL(P6.5) & I2C_SDA(P6.4) */
	GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P6, GPIO_PIN5, GPIO_PRIMARY_MODULE_FUNCTION);
	GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P6, GPIO_PIN4, GPIO_PRIMARY_MODULE_FUNCTION);

	/* Initialize USCI_B0 and I2C Master to communicate with slave devices*/
	I2C_initMaster(EUSCI_B1_BASE, &i2cConfig);

    /* Disable I2C module to make changes */
    I2C_disableModule(EUSCI_B1_BASE);

    /* Enable I2C Module to start operations */
    I2C_enableModule(EUSCI_B1_BASE);

    return;
}


/***************************************************************************//**
 * @brief  Writes data to the sensor
 * @param  pointer  Address of register you want to modify
 * @param  writeByte Data to be written to the specified register
 * @return none
 ******************************************************************************/

bool I2C_write8 (unsigned char pointer, unsigned char writeByte, unsigned int timeout)
{
	while(I2C_isBusBusy(EUSCI_B1_BASE));

    /* Set master to transmit mode PL */
	I2C_setMode(EUSCI_B1_BASE,
        EUSCI_B_I2C_TRANSMIT_MODE);

    /* Clear any existing interrupt flag PL */
	I2C_clearInterruptFlag(EUSCI_B1_BASE,
        EUSCI_B_I2C_TRANSMIT_INTERRUPT0);

    /* Initiate start and send first character */
    if (!I2C_masterSendMultiByteStartWithTimeout(EUSCI_B1_BASE,
        pointer, timeout))
    	return 0;

    if (!I2C_masterSendMultiByteFinishWithTimeout(EUSCI_B1_BASE,
        writeByte, timeout))
    	return 0;

    return 1;
}


/***************************************************************************//**
 * @brief  Writes data to the sensor
 * @param  pointer  Address of register you want to modify
 * @param  writeWord Data to be written to the specified register
 * @return none
 ******************************************************************************/

bool I2C_write16 (unsigned char pointer, unsigned short writeWord, unsigned int timeout)
{
	while(I2C_isBusBusy(EUSCI_B1_BASE));

    /* Set master to transmit mode PL */
	I2C_setMode(EUSCI_B1_BASE,
        EUSCI_B_I2C_TRANSMIT_MODE);

    /* Clear any existing interrupt flag PL */
	I2C_clearInterruptFlag(EUSCI_B1_BASE,
        EUSCI_B_I2C_TRANSMIT_INTERRUPT0);

    /* Initiate start and send first character */
    if (!I2C_masterSendMultiByteStartWithTimeout(EUSCI_B1_BASE,
        pointer, timeout))
    	return 0;

    /* Send the MSB of writeByte to SENSOR */
    if (!I2C_masterSendMultiByteNextWithTimeout(EUSCI_B1_BASE,
        (unsigned char)(writeWord&0xFF), timeout))
    	return 0;

    if (!I2C_masterSendMultiByteFinishWithTimeout(EUSCI_B1_BASE,
        (unsigned char)(writeWord>>8), timeout))
    	return 0;

    return 1;
}


/***************************************************************************//**
 * @brief  Reads data from the sensor
 * @param  pointer Address of register to read from
 * @return Register contents
 ******************************************************************************/

bool I2C_read8(unsigned char pointer, char * result, unsigned int timeout)
{
	volatile int val = 0;
	volatile int valScratch = 0;

	while(I2C_isBusBusy(EUSCI_B1_BASE));

    /* Set master to transmit mode PL */
	I2C_setMode(EUSCI_B1_BASE,
        EUSCI_B_I2C_TRANSMIT_MODE);

    /* Clear any existing interrupt flag PL */
	I2C_clearInterruptFlag(EUSCI_B1_BASE,
        EUSCI_B_I2C_TRANSMIT_INTERRUPT0);

    /* Initiate start and send first character */
    if (!I2C_masterSendSingleByteWithTimeout(EUSCI_B1_BASE,
        pointer, timeout))
    	return 0;

    /*
     * Generate Start condition and set it to receive mode.
     * This sends out the slave address and continues to read
     * until you issue a STOP
     */
//    I2C_masterReceiveStart(EUSCI_B1_BASE);
//
//    /* Read from I2C RX register */
//    if(!I2C_masterReceiveMultiByteFinishWithTimeout(EUSCI_B1_BASE, &val, timeout))
//    	return 0;
//
//    /* Return temperature value */
//    *result = val;

    *result = I2C_masterReceiveSingleByte(EUSCI_B1_BASE);

    return 1;
}


/***************************************************************************//**
 * @brief  Reads data from the sensor
 * @param  pointer Address of register to read from
 * @return Register contents
 ******************************************************************************/

bool I2C_read16(unsigned char pointer, short * result, unsigned int timeout)
{
	while(I2C_isBusBusy(EUSCI_B1_BASE));

    uint8_t val = 0;
    uint8_t valScratch = 0;
    short r = 0;

    /* Set master to transmit mode PL */
    I2C_setMode(EUSCI_B1_BASE,
        EUSCI_B_I2C_TRANSMIT_MODE);

    /* Clear any existing interrupt flag PL */
    I2C_clearInterruptFlag(EUSCI_B1_BASE,
        EUSCI_B_I2C_TRANSMIT_INTERRUPT0);

    /* Initiate start and send first character */
    if (!I2C_masterSendSingleByteWithTimeout(EUSCI_B1_BASE, pointer, timeout))
    	return 0;

    /*
     * Generate Start condition and set it to receive mode.
     * This sends out the slave address and continues to read
     * until you issue a STOP
     */
    I2C_masterReceiveStart(EUSCI_B1_BASE);

    /* Wait for RX buffer to fill */
    while(!(I2C_getInterruptStatus(EUSCI_B1_BASE,
        EUSCI_B_I2C_RECEIVE_INTERRUPT0)));

    /* Read from I2C RX register */
    valScratch = I2C_masterReceiveMultiByteNext(EUSCI_B1_BASE);

    /* Receive second byte then send STOP condition */
    if (!I2C_masterReceiveMultiByteFinishWithTimeout(EUSCI_B1_BASE, &val, timeout))
    	return 0;

    /* Shift val to top MSB */
    r = (val << 8);

    /* Read from I2C RX Register and write to LSB of r */
    r |= valScratch;

    /* Return temperature value */
    *result = r;

    return 1;
}

/***************************************************************************//**
 * @brief  Reads data from the slave
 * @param  pointer Address of register to read from
 * @return Register contents
 ******************************************************************************/
bool I2C_read24(unsigned char pointer, int * result, unsigned int timeout)
{
	while(I2C_isBusBusy(EUSCI_B1_BASE));

	uint8_t val = 0;
    int r = 0;

    /* Set master to transmit mode PL */
    MAP_I2C_setMode(EUSCI_B1_BASE, EUSCI_B_I2C_TRANSMIT_MODE);

    /* Clear any existing interrupt flag PL */
    MAP_I2C_clearInterruptFlag(EUSCI_B1_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0);

    /* Initiate start and send first character */
    if (!MAP_I2C_masterSendSingleByteWithTimeout(EUSCI_B1_BASE, pointer, timeout))
    	return 0;

    /*
     * Generate Start condition and set it to receive mode.
     * This sends out the slave address and continues to read
     * until you issue a STOP
     */
    MAP_I2C_masterReceiveStart(EUSCI_B1_BASE);

    /* Wait for RX buffer to fill */
    while(!(MAP_I2C_getInterruptStatus(EUSCI_B1_BASE,
        EUSCI_B_I2C_RECEIVE_INTERRUPT0)));

    /* Read from I2C RX register */
    val = MAP_I2C_masterReceiveMultiByteNext(EUSCI_B1_BASE);
    r = (val << 16);

    /* Read from I2C RX register */
    val = MAP_I2C_masterReceiveMultiByteNext(EUSCI_B1_BASE);
    r |= (val << 8);

    /* Receive third byte then send STOP condition */
    if (!MAP_I2C_masterReceiveMultiByteFinishWithTimeout(EUSCI_B1_BASE, &val, timeout))
    	return 0;
    r |= val;

    /* Return value */
    *result = r;

    return 1;
}

void I2C_setslave(unsigned short slaveAdr)
{
    /* Specify slave address for I2C */
	EUSCI_B_I2C_setSlaveAddress(EUSCI_B1_BASE,
        slaveAdr);

    /* Enable and clear the interrupt flag */
	EUSCI_B_I2C_clearInterruptFlag(EUSCI_B1_BASE,
        EUSCI_B_I2C_TRANSMIT_INTERRUPT0 + EUSCI_B_I2C_RECEIVE_INTERRUPT0);
    return;
}
i2c.h

  • UPDATE: After disconnecting and reconnecting the sensor, it seems that the example code from the booster pack works, but only if I read the sensor values once. On the second read using bme280_read_pressure_temperature_humidity(), the programs hangs in the while loop:

    //Poll for transmit interrupt flag.
     while (!BITBAND_PERI(EUSCI_B_CMSIS(moduleInstance)->rIFG.r, UCTXIFG_OFS));

    from MAP_I2C_masterSendMultiByteStart(EUSCI_B1_BASE,ui8Reg), called from the readI2C() function. Also, I think that the pressure value is incorrect (it reads 65345, which, according to the datasheet, is 65345/256 = 255 Pa - too small).

  • Hi Cristian,

    Which version of the MSP432 LP are you using?? (RED or BLACK)

    Regards,

    David
  • Hi! It's the red version.

  • I think found out what was the problem. I was also using the Sharp96 booster pack and its initialization set the I2C pins as inputs (for capacitive sensing), after setting them as I2C pins. However, this does not explain why the "BOOSTXL-SENSORS_SensorGUI_MSP432P401R" did not work.
  • Hi Cristian,

    That's a good point. Could you please run this example code:

    dev.ti.com/.../

    And let me know if you run into the same problem.

    Thanks,

    David
  • Hi! I cannot compile the code. It says:

    Description Resource Path Location Type
    gmake: *** [src/demo_sysctl.obj] Error 1 BOOSTXL-SENSORS_SensorGUI_MSP432P401R    C/C++ Problem

    ERROR! at line 48: [E0001] Address must be of a non-global defined in the current section

    bne.n SysCtlDelay

    If I comment the code in "demo_sysctl.c":

    /*#if defined(ccs)
    __asm("    .sect \".text:SysCtlDelay\"\n"
          "    .clink\n"
          "    .thumbfunc SysCtlDelay\n"
          "    .thumb\n"
          "    .global SysCtlDelay\n"
          "SysCtlDelay:\n"
          "    subs r0, #1\n"
          "    bne.n SysCtlDelay\n"
          "    bx lr\n");
    #endif*/

    then I get several errors (see attached image).

  • Hi Cristian,

    Interesting, I just built the example code using CCS cloud without any problem. But I'm getting the same error with my CCS.

    The reason is the compiler version, in my CCS Installation I have v16.6.0.STS and CCS Cloud uses v15.12.3.LTS.

    Anyway, please take a loot at this thread for more information:
    e2e.ti.com/.../548064

    Hopefully this helps.

    David

**Attention** This is a public forum