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.

TMS570LC4357: Generic Interrupt driven I2C read function

Part Number: TMS570LC4357
Other Parts Discussed in Thread: HALCOGEN

I want to create a generic interrupt driven I2C read function and have done the following so far:

I call i2cInit() which adopts the following HALCoGen settings for I2C_2:

  • Enable I2C2 driver
  • I2C2:
    • Enable Master Mode
    • Tx/Rx: TRANSMITTER
    • Add Mode: 7_BIT_AMODE
    • Bit Count: 8_BIT
    • ICRRDY enabled
    • ICXRDY enabled
    • I2C Pin Mode: I2C Functional
  • Pin Muxing:
    • I2C2 checked (SDA @ G17 and SCL @ G16)

My read function does the following calls:

uint8 ch;

i2cSetSlaveAdd( i2cREG2, SLAVE_ADDR );
i2cSetDirection( i2cREG2, I2C_TRANSMITTER );
i2cSetCount( i2cREG2, 2 );
i2cSetMode( i2cREG2, I2C_MASTER );
i2cSetStop( i2cREG2 );
i2cSetStart( i2cREG2 );
i2cSend( i2cREG2, 1u, REGISTER_ADDR );
while ( i2cIsBusBusy( i2cREG2 ) == TRUE );
while ( i2cIsStopDetected( i2cREG2 ) == TRUE );
i2cClearSCD( i2cREG2 );

i2cSetSlaveAdd( i2cREG2, SLAVE_ADDR );
i2cSetDirection( i2cREG2, I2C_RECEIVER );
i2cSetCount( i2cREG2, 2u );
i2cSetMode( i2cREG2, I2C_MASTER );
i2cSetStart( i2cREG2 );
i2cReceive( i2cREG2, 1u, &ch );
i2cClearSCD( i2cREG2 );

My i2cNotification function is as follows:

void i2cNotification( i2cBASE_t *i2c, uint32 flags )
{


uint8 ch;

if ( flags & I2C_RX_INT )

{

i2cReceive( i2cREG2, 1, &ch );

}


}

Running the above code on the HDK, the interrupt service routine (ic2Notification) receives 4 bytes (All wrongly zero) from a BME280 sensor that I request its ID which is one byte!

Can someone please comment on errors in my function call sequence above?
What should the i2cSetCount value be?  Does it need to take into consideration the Slave Address?

Thank you.

  • Hi Jerry,

    Just make sure you are doing these things correctly

    1. Did you select the i2c interface correctly, by connecting CSB pin to the VDDIO

    2. Did you set the slave address correctly? If SDO connected to ground, then slave address will be 0x76. If SDO connected to VDDIO then slave address will be 0x77. And SDO should not be left floating.

    3. And the main issue i am suspecting is that for read operation we should not send stop condition after we send the register address.

    As you can see in above picture, after sending a register address and getting ACK from slave we just send start again not stop condition right? this is nothing but a repeated start condtion.

    But if i verified your code, you are giving stop condition after sending the register address?

    Just try to modify as below and see the result:

    i2cSetSlaveAdd( i2cREG2, SLAVE_ADDR );
    i2cSetDirection( i2cREG2, I2C_TRANSMITTER );
    i2cSetCount( i2cREG2, 1 );
    i2cSetMode( i2cREG2, I2C_MASTER );
    i2cSetStart( i2cREG2 );
    i2cSend( i2cREG2, 1u, REGISTER_ADDR );
    while ( i2cIsBusBusy( i2cREG2 ) == TRUE );

    i2cSetSlaveAdd( i2cREG2, SLAVE_ADDR );
    i2cSetDirection( i2cREG2, I2C_RECEIVER );
    i2cSetCount( i2cREG2, 1u );
    i2cSetStop( i2cREG2 );

    i2cSetStart( i2cREG2 );
    i2cReceive( i2cREG2, 1u, &ch );
    i2cClearSCD( i2cREG2 );

    --
    Thanks & regards,
    Jagadish.

  • Hi Jagadish,

    Thank you for the prompt reply.

    Yes, I have CSB and SDO to VDDIO on the BME280 such that the I2C interface is enabled and the Slave Address is 0x77.

    I modified the code based on your directions and will do tests and get back to you.

    Kind regards,

    Jerry

  • Hi Jagadish,

    Based on your code snippet I was able to communicate with the BME280 I2C device with the following code:
    ___________________________________________________________

    #define SLAVE_ADDR 0x77

    uint8_t ch;
    uint32_t i;
    uint8_t tx_data[ 2 ] = { 0xE0, 0xD0 }; /* 0xE0: reset BME280, 0xD0: BME280 ID register */

    _enable_interrupt_();

    i2cInit();

    i2cSetSlaveAdd( i2cREG2, SLAVE_ADDR );
    i2cSetDirection( i2cREG2, I2C_TRANSMITTER );
    i2cSetMode( i2cREG2, I2C_MASTER );

    i2cSetCount( i2cREG2, 1u );
    i2cSetStart( i2cREG2 );
    i2cSend( i2cREG2, 1u, &tx_data[ 0 ] );    /* Send BME280 reset command */
    // while ( i2cIsBusBusy( i2cREG2 ) == TRUE );

    for ( i = 0; i < 10000; i++ );

    i2cSetCount( i2cREG2, 1u );
    i2cSetStart( i2cREG2 );
    i2cSend( i2cREG2, 1u, &tx_data[ 1 ] );    /* Send BME280 ID register */
    // while ( i2cIsBusBusy( i2cREG2 ) == TRUE );

    for ( i = 0; i < 10000; i++ );

    i2cSetSlaveAdd( i2cREG2, SLAVE_ADDR );
    i2cSetDirection( i2cREG2, I2C_RECEIVER );
    i2cSetStop( i2cREG2 );

    i2cSetCount( i2cREG2, 1u );
    i2cSetStart( i2cREG2 );
    i2cReceive( i2cREG2, 1u, &ch );

    i2cClearSCD( i2cREG2 );
    ___________________________________________________________

    Leaving the 1st i2cIsBusBusy check had no problem but the second caused the program to wait indefinitely.  Hence I put a small delay after each i2cSend.
    What check is suitable such that the program doesn't wait indefinitely?  Maybe a Tx complete?

    Following is a snapshot of the SDA and SCL signals if you care to check the validity of the data please.

    Kind reagrds,
    Jerry

  • Hi Jerry,

    Don't combine ID read command with reset command. The reset command is not useful there because reset the sensor have different procedure.

    As you can see to reset the device we have to send 0xB6 along with the command 0xE0 and then we have to send stop condition, this process is different. So just remove the sending 0xE0 command while sending ID read command and modify the code as below and update me the result.

    #define SLAVE_ADDR 0x77

    uint8_t ch;
    uint32_t i;
    uint8_t tx_data[ 2 ] = { 0xE0, 0xD0 }; /* 0xE0: reset BME280, 0xD0: BME280 ID register */

    _enable_interrupt_();

    i2cInit();

    i2cSetSlaveAdd( i2cREG2, SLAVE_ADDR );
    i2cSetDirection( i2cREG2, I2C_TRANSMITTER );
    i2cSetMode( i2cREG2, I2C_MASTER );

    i2cSetCount( i2cREG2, 1u );
    i2cSetStart( i2cREG2 );
    i2cSend( i2cREG2, 1u, &tx_data[ 1 ] );    /* Send BME280 ID register */
    while ( i2cIsBusBusy( i2cREG2 ) == TRUE );

    i2cSetSlaveAdd( i2cREG2, SLAVE_ADDR );
    i2cSetDirection( i2cREG2, I2C_RECEIVER );
    i2cSetStop( i2cREG2 );

    i2cSetCount( i2cREG2, 1u );
    i2cSetStart( i2cREG2 );
    i2cReceive( i2cREG2, 1u, &ch );

    i2cClearSCD( i2cREG2 );

    --
    Thanks & regards,
    Jagadish.

  • Hi Jagadish,

    Excellent that you noted the reset procedure and its independence to the generic Read.  I will test the above and advise.

    Kind regards,
    Jerry

  • Hi Jagadish,

    Thank you for the help, the above code resolved the communication issues.

    Kind regards,
    Jerry