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.

Problem with I2C

Other Parts Discussed in Thread: EK-TM4C123GXL

Hi all,

I am trying to communicate with a H3LIS331DL accelerometer. Upon sending the very first Start and Slave address, the I2C0 bus becomes busy and is not able to exit the loop. I've checked out most of the threads but I still can't solve this problem. Does anyone have any suggestions ? I'm using CCS 5.2.1 and LM4F232 Evaluation board. Thanks.

Regards,

Tian Hao

Link to the accelerometer: http://www.st.com/st-web-ui/static/active/en/resource/technical/document/datasheet/DM00053090.pdf

#define I2C_ACCELEROMETER_ADDRESS   0x30
#define I2C_ACCELEROMETER_X_AXIS_L    0x28
#define NUM_I2C_DATA 512
static char DataRx[NUM_I2C_DATA];

// Init Code.
void
accelerometerI2CConfigure(void)
{
    // Enable I2C Module.
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);

    // Enable GPIO used.
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);

    // Configure Pins for I2C function and open-drain operation with weak
    // pull-ups.
    GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
    ROM_GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_2 | GPIO_PIN_3);
    ROM_GPIOPinConfigure(GPIO_PB2_I2C0SCL);

    // Use the system clock for the I2C module.  Set the I2C data transfer rate to 100kbps.
    ROM_I2CMasterInitExpClk(I2C0_MASTER_BASE, ROM_SysCtlClockGet(), false);

    return;
}

// Read
void
readAccelerometerI2C(void)
{
    // Tell the master module what address it will place on the bus when
    // communicating with the slave.
    ROM_I2CMasterSlaveAddrSet(I2C0_MASTER_BASE,
                              I2C_ACCELEROMETER_ADDRESS>>1,
                              false);

    // Write SUB to data register.
    ROM_I2CMasterDataPut(I2C0_MASTER_BASE, I2C_ACCELEROMETER_X_AXIS_L);

    // Send a start condition, slave address and first byte.
    ROM_I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_START);

    // Loop until transfer complete.
    while(ROM_I2CMasterBusy(I2C0_MASTER_BASE));

    // Set slave address with receive operation.
    ROM_I2CMasterSlaveAddrSet(I2C0_MASTER_BASE,
                              I2C_ACCELEROMETER_ADDRESS>>1,
                              true);

    // Send address again with repeated start condition.
    ROM_I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);

    // Loop until transfer complete.
    while(ROM_I2CMasterBusy(I2C0_MASTER_BASE));

    // Read data.
    DataRx[0] = ROM_I2CMasterDataGet(I2C0_MASTER_BASE);

    return;

}

  • Looking quickly @ your code - following "jumps out:"  (Note: ARM MCUs - this maker/others - are demanding - must attend to detail...)

       // Configure Pins for I2C function and open-drain operation with weak pull-ups.

        GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
        ROM_GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_2 | GPIO_PIN_3);
        ROM_GPIOPinConfigure(GPIO_PB2_I2C0SCL);

    So - you properly "PinType" PB_2 as I2CSCL - but next line down, "blow that up" w/older/inappropriate "PinType."  Not good!

    Then - you properly PinConfigure() PB2 - but poor PB3 remains "out in the cold!"  Again - not good!  Note: you cannot "bundle PinConfigure()" - one per pin! 

    You correctly:   ROM_GPIOPinConfigure(GPIO_PB2_I2C0SCL);

    But you must Add:  "ROM_GPIOPinConfigure(GPIO_PB3_I2C0SDA);"

    In summary - you need two (proper) calls to: GPIOPinType()... (one being GPIOPinTypeI2CSCL())  and you need 2 calls to "ROM_GPIOPinConfigure()."

    Special note:  GPIOPinTypeI2CSCL() function has not yet made it into Stellaris ROM.  (nor likely into that new, "re-branded" (tupper?) one.).  All other calls may use ROM - but single use of GPIO call removes any/all size benefits provided by ROM_GPIO...

    And - you,     // Loop until transfer complete.        Might something be "missing here?" 
        while(ROM_I2CMasterBusy(I2C0_MASTER_BASE));

            while(ROM_I2CMasterBusy(I2C1_MASTER_BASE)) {} // Delay till xmsn completes

    6+ months past I posted here (in now NRND "Sharing Forum") proper set-up/config for M4 I2C - search under I2C + cb1 should reveal.

    Haven't gone further - you're clearly, "dead in the water" with your listing ... and "land in sight" (starboard) this chart...

  • Hi cb1,


    Thanks for your help. It worked with the following.

    GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
    GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);
    GPIOPinConfigure(GPIO_PB2_I2C0SCL);
    GPIOPinConfigure(GPIO_PB3_I2C0SDA);

    I am still new to this and am confused by the two function names of GPIOPinTypeI2C() and GPIOPinTypeI2CSCL().

    I looked through the driverlib documentation and it simply states GPIOPinTypeI2C() configures the pin for use by I2C peripheral.

    That was what made me configure both pins using this function at first (in addition to GPIOPinTypeI2CSCL() for pb3 and also it was my fault for not looking into the functions).

    From the above, can I conclude that GPIOPinTypeI2CSCL() configures the pin for SCL function, and GPIOPinTypeI2C() configures the pin for SDA function only? Thanks.

    Regards,
    Tian Hao

  • HiTian Hao,

    have a look at the software for the new Tiva Series Launch Pad  the EK-TM4C123GXL - http://www.ti.com/tool/sw-ek-tm4c123gxl

    You'll find a nice interrupt bases I2C master API enclosed! You can use it with your LM4F232 Eval Board too!

    Kind regards
    aBUGSworstnightmare

  • @Tian:

    Thanks much your Verify award - always appreciated.

    Feel not bad - as stated atop my answering post - ARM MCUs are highly detailed - and demanding.

    6+ months ago I ran afoul w/new M4 under I2C - after enjoying much success w/M3.  (what's up w/that?)  And - one of the keys to solution was thorough/intense "re-read" of SW-DRL-latest/greatest  (9453 - my book).  As a result - following was noted:

    12.2.2.28 GPIOPinTypeI2CSCL

    Note:
    This function should only be used for Blizzard-class devices. It cannot be used to turn any
    pin into an I2C SCL pin; it only configures an I2C SCL pin for proper operation. Devices with
    flexible pin muxing also require a GPIOPinConfigure() function call.

    This explains your confusion - (and that of many - to include this reporter many months back)  Rather than "hoard" this knowledge - I shared it w/in the now NRND Sharing Forum - even risking vendor wrath as post by vendor conflicted w/my report/findings.  And - as you now confirm again - mine proved right...

    You've now learned that you also must learn to decode Stellaris (and new re-brand name - cannot recall) "Class" - to choose the appropriate function w/in StellarisWare.  Your original I2C Pin Type code would have worked for past M3s.

    This I2CSCL change likely arose from Stellaris designer's "extension" of I2C into the newer, higher speed ranges.  If you really want to know - you can examine the source code w/in i2c.c located w/in the driver.lib.

    Lesson learned?   Our group keeps MCU data manual, SW-DRL-UGxxxx and driver.lib source, "at the ready" - these are complex MCUs - demand precision...

    Bon chance et merci - mon ami...