Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob

I2C Discussion

I2C Discussion

Anonymous
Not applicable
RevisionDescriptionDate
1.0I2C Description10/27/14

The I2C topics seem to be a bit confusing.

I am creating this Blog to address these concerns.

I will post a video shortly that will thru a Code Walk Thru.

NOTE:

There is a known issue with i2cm_* functions.

You must use cfa_* functions instead.

i2cm_* can only be used when patch enable_spiff1_i2c_interop.a is used *and* NV is serial flash on SPI1

Here are miscellaneous notes that have collected regarding the I2C Issues:

Both SCL and SDA should be high before I2C communication begins.

SPIFFY1 is shared with I2C, which is already being used to talk to the EEPROM on the module.

SPI-flash and I2C interfaces concurrent:

We don’t have the drive strength once to drive the I2C line hard enough with a total of 4 slaves on the bus.

How the SDA pin is sampled during boot by the firmware and how the I2C pins behave:

  • Connecting SDA to Vdd/Vio to recover is probably a bad idea
  • SCL and SDA are both open-drain
  • The pull-ups pull the signal high while the HW drives it low
  • It never drives high, but floats the output pad leaving the pull-up to pull the line high
  • If you put a scope to either of these lines on the board when the FW accesses these, high to low transitions will be very sharp while low to high transitions will be pretty slow due to the intrinsic RC
  • If you connect SCL/SDA to Vdd, then when the HW block drives SDA low, there will be a direct short (though momentary) between Vdd and GND - Not good
  • This will happen pretty early during boot because the ROM always uses 0xA0 as the slave address of the EEPROM and you can see that there are repeated 0s in this sequence (and the shorts) which could do bad things to the supply or the chip
  • Shorting to GND on the other hand, is safer because that is what happens when there is a 0 bit on the bus and there is a 10K pull-up which will limit the current to something within the max ratings of all components on this line

How to decrease the clock speed during programming (and for subsequent accesses to the EEPROM), because the faster clock speed seems to be causing another i2c device to lock up:

See i2cm.h, i2cm_setSpeed(). Use I2CM_SPEED_* from this header.

If you use cfa_* API that is used by the i2c_temperature_sensor sample, you cannot change the I2C bus speed (defaults to 400KHz). You can use the corresponding API in i2cm.h to read/write the same data and also change speed if required

I2C and P_UART Dependency:

  • PUART and I2C don't have any dependency. You can use both at the same time. SPI2 and PUART however do have some restrictions, see the datasheet or the HW interfaces document (in short - PUART RX and SI2 have to be on the same GPO bank).
  • I2C and SPI1 share GPIOs. With SDK 2.1 and above, there is an optional patch with which you can use I2C when SPI1 is used for NV storage (serial flash). But the other way where you want to use SPI1 as an SPI master when using I2C EPROM slave is not possible.

 

To use it, you just have to include the patch and use the API in i2cm.h:

 

# Add to application’s makefile.mk:

APP_PATCHES_AND_LIBS += enable_spiffy1_i2c_interop.a

The in application, #include “i2cm.h”  and use the I2C API in this header to access the I2C slaves. No changes to the way you access NV (using bleprofile_*)

The cfa.h interface is where most people failed in their code

Example Code:

// Reads 16 bits from the given register address in LM73.

// \param register_address The address to the register to read.

// \param data INOUT Pointer to a INT16 into which the data is to be read, valid only if return value is 1.

// \return 1 if successful, 0 on failure.

UINT8 temperature_sensor_read_16_bit_register(UINT8 register_address, INT16* data)

{

    UINT8 read_status;

    UINT8 return_value = 0;

    UINT8 reg_read_bytes_to_write[1];

    UINT8 reg_bytes_to_read[2];

    reg_read_bytes_to_write[0] = register_address;

    // Do a combo write then read operation

    read_status = i2cm_comboRead(reg_bytes_to_read, sizeof(reg_bytes_to_read), reg_read_bytes_to_write,

                                                        sizeof(reg_read_bytes_to_write), LM73_SLAVE_ADDR);

 

    switch(read_status)

    {

        case I2CM_BUSY:

            // Transaction did not go through. ERROR. Handle this case.

                // There is already a pending transaction.

            break;

        case I2CM_SUCCESS:

            // The read was successful.

            *data = (INT16)(reg_bytes_to_read[1] | reg_bytes_to_read[0] << 8);

            return_value = 1;

            break;

 

        case I2CM_OP_FAILED:

 

            // No slave device with this address exists on the I2C bus. ERROR. Handle this.

        default:

            break;

    }

    return return_value;

}

 

// Writes the given value ino the given 16 bit register.

// \param register_address The address of the register to write to.

// \param data The data to write.

// \return 1 on success; else 0.

UINT8 temperature_sensor_write_16_bit_register(UINT8 register_address, INT16 data)

{

    UINT8 read_status;

    UINT8 return_value = 0;

    UINT8 reg_bytes_to_write[3];

    reg_bytes_to_write[0] = register_address;

    reg_bytes_to_write[1] = (data >> 😎 & 0xFF;

    reg_bytes_to_write[2] = data & 0xFF;

    read_status = i2cm_write(reg_bytes_to_write, sizeof(reg_bytes_to_write), LM73_SLAVE_ADDR);

 

    switch(read_status)

    {

        case I2CM_BUSY:

            // Transaction did not go through. ERROR. Handle this case.

           // There is already a pending transaction.

 

            break;

 

        case I2CM_SUCCESS:

            // The read was successful.

            return_value = 1;

            break;

 

        case I2CM_OP_FAILED:

            // No slave device with this address exists on the I2C bus. ERROR. Handle this.

        default:

            break;

    }

    return return_value;

}

// Reads given register by first writing the pointer register

// then reading the register value. Leaves the pointer register as is when leaving

// \param register_address The register to read from

// \param data INOUT Pointer to a buffer into which to read. Valid only if the return value is 1

// \return 1 on success; else 0.

 

UINT8 temperature_sensor_read_8_bit_register(UINT8 register_address, UINT8* data)

{

                UINT8 read_status;

    UINT8 return_value = 0;

    UINT8 reg_bytes_to_read[1];

    // Do a combo write then read operation

    read_status = i2cm_comboRead(reg_bytes_to_read, sizeof(reg_bytes_to_read), &register_address,

                                                        sizeof(register_address), LM73_SLAVE_ADDR);

    switch(read_status)

    {

        case I2CM_BUSY:

            // Transaction did not go through. ERROR. Handle this case.

            break;

 

        case I2CM_SUCCESS:

            // The read was successful.

            *data = reg_bytes_to_read[0];

            return_value = 1;

            break;

 

        case I2CM_OP_FAILED:

            // No slave device with this address exists on the I2C bus. ERROR. Handle this.

        default:

 

            break;

    }

    return return_value;

 

}

// Writes the given value to the given register by first writing the pointer register

// then writing the value. Leaves the pointer register as is when leaving.

// \param register_address The address of the register to write to.

// \param data The data to write to the register.

// \return 1 on success; else 0.

 

UINT8 temperature_sensor_write_8_bit_register(UINT8 register_address, UINT8 data)

{

    UINT8 read_status;

    UINT8 return_value = 0;

    UINT8 reg_data_bytes[2];

    reg_data_bytes[0]= register_address;

    reg_data_bytes[1] = data;

    read_status = i2cm_write(reg_data_bytes, sizeof(reg_data_bytes), LM73_SLAVE_ADDR);

    switch(read_status)

 

    {

        case I2CM_BUSY:

            // Transaction did not go through. ERROR. Handle this case.

            break;

 

        case I2CM_SUCCESS:

            // The read was successful.

            return_value = 1;

            break;

 

        case I2CM_OP_FAILED:

            // No slave device with this address exists on the I2C bus. ERROR. Handle this.

        default:

            break;

    }

    return return_value;

}

 

 

0 Likes
1329 Views
Comments
StBa_721356
Level 5
Level 5
50 likes received 25 likes received 10 likes received

I don't know why but the i2cm functions just do not work for me here with SDK 2.1.1.

I am using a '36 SIP based device with several I2C chips on it.

When using the cfa_bsc_OpExtended() function for I2C access then everything works. But using for example i2cm_comboRead() always fails with status I2CM_BUSY.

I also added

APP_PATCHES_AND_LIBS += enable_spiffy1_i2c_interop.a

to my makefile but still no luck.

What am I doing wrong?

Anonymous
Not applicable

See my note above:

There is a known issue with i2cm_* functions.

You must use cfa_* functions instead.

i2cm_* can only be used when patch enable_spiff1_i2c_interop.a is used *and* NV is serial flash on SPI1

StBa_721356
Level 5
Level 5
50 likes received 25 likes received 10 likes received

Thanks for putting that additional information into the blog.

Are there plans to fix the i2cm_* functions in the near future? We are using an I2C chip which cannot be used together with the cfa_* functions because they cannot write more than 8 bytes in one hardware transaction. So we are currently out of luck with the BCM chips...

asridharan
Employee
Employee
10 comments on KBA 5 comments on KBA First comment on KBA

I2cm_* functions use cfa_* internally, so there really is no difference between using i2cm_* and cfa_* functions when you don't use SPI serial flash.

Anonymous
Not applicable

Hi j.t seyhan all,

I am using SDK-3.x and I am facing problems with I2C .

first I have download this example to the EVAL board. (BCM943362WCD4).

I2C Interface Example with WICED SDK-3.x

But, When I observe the SCK Pin on CRO , I am not finding Any clock signal from Described pin.
Also In My Example ( I am using tlc59116 I2C driver ic) . I have defined The device As below.

and Also Tried to probe the device. But Every time it's says .
"Probe is Unsuccessful " .
Need your help in this matter.

static wiced_i2c_device_t i2c_device =

{

    .port          = WICED_I2C_1,

    .address       = 0X61,

    .address_width = I2C_ADDRESS_WIDTH_7BIT,

    .speed_mode    = I2C_STANDARD_SPEED_MODE,

};

Thanking You,
Hinesh

Anonymous
Not applicable

We are finding in our application (SDK 2.1.1) which has an external I2C EEPROM connected to the 36S module:

1. Both i2cm.h and cfa.h work for reading and writing but only up to 14 bytes of data (two bytes of address for a total of 16). Attempting to write 15 or 16 bytes of data (or anything larger) will fail always.

2. The header files advertise that longer byte strings are supported but that they break them into separate 16 byte transactions.  We are finding that this is not the case, and the functions don't work as advertised. Only a single 16 byte transaction per function call is working.

3. In any case what we need is to write 128 bytes (page write to eeprom) of data in a single transaction.  This is not supported but needs to be as it is very inefficient to write to eeprom in other than page mode.

4. The cfa and i2cm function calls do not always work on the first try.  We have found success by embedding the calls in a loop with a max iteration of 20 with a wait of 1 millisecond between calls.  Exiting the loop when the return status is SUCCESS or max iterations reached.  This seems to be related to the internally timed page write cycle of the eeprom device, but it's not clear how.  The eeprom datasheet puts maximum write time at 5 milliseconds.

5. changing the speed with i2cm_setSpeed() did not seem to affect the above performance.  I will need to check with an oscilloscope to be sure the set Speed worked as advertised.  Have not done so yet.

6. Would like if Broadcom could expose some lower level I2C interface so we could write our own driver that supports page writes.

Thanks, hope this helps a few others.

Eric

MichaelF_56
Moderator
Moderator
Moderator
250 sign-ins 25 comments on blog 10 comments on blog

ehoffman

Can you re-post this as a new discussion.

I am the only ones that sees comments against blog posts, but the Apps team monitors discussions.

If they cannot answer, we will take this to our developer meeting tomorrow.

Contributors