Skip navigation
Home > All Places > WICED Smart Bluetooth > WICED Smart Bluetooth Forums > Blog > 2014 > October
2014
jota_1939431

I2C Discussion

Posted by jota_1939431 Oct 27, 2014
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 >> 8) & 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;

}

 

 

 

RevisionChange DescriptionDate
1.0Initial - 15 minute video10/08/14

 

 

Michael L. takes us through a Schematic Review of the iBCN BCM20737 Reference Design.

 

Thank you Michael.

 

WICED Smart Documents & Downloads

 

The schematic is located:

iBeacon BCM20737 Reference Design PDF Schematic (SOC)

 

The Gerbers are listed here:

iBeacon BCM20737 Reference Design Gerber Files (SOC)

 

He discusses:

  1. The Baseband section of the BCM20737
  2. Recovery Process
  3. Common mistakes he has seen from designers
  4. Decoupling Caps for the Pins and RF section

 

 

 

Let us know if you have any questions

Thank you

 

JT

Filter Blog

By date:
By tag: