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 I2C STELLARIS LM4F120 LaunchPad (Master) and LSM303 (Accelerometer Slave)

Hi everybody, I new here and I need your experience and assistance. I'm in a new project (Self Leveling Platform) and I'm having many troubles with I2C module. In the first instance I want to write and read data from a register of my accelerometer (whichever), but in Code Composer Studio I see in I2C0 register, I2C_MCS_STOP = I2C_MCS_ADRACK = I2C_MCS_ERROR = 0 always and it never changes, and I don't know why, here is my code:

#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "inc/hw_i2c.h"
#include "driverlib/i2c.h"

#include "inc/hw_i2c.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/debug.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/i2c.h"
#include "driverlib/systick.h"
#include "string.h"

int a;

void bus(void){
HWREG(I2C0_MASTER_BASE + I2C_O_MCR) |= 0x01;
I2CMasterEnable(I2C0_MASTER_BASE);
//delay();
I2CMasterInitExpClk(I2C0_MASTER_BASE, SysCtlClockGet(), true);
I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, (0x30 >> 1), false);
I2CMasterDataPut(I2C0_MASTER_BASE, 0x20);
I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_SINGLE_SEND);
while(I2CMasterBusy(I2C0_MASTER_BASE)) {}
I2CMasterDataPut(I2C0_MASTER_BASE, 0x27);
I2CMasterDataPut(I2C0_MASTER_BASE, 0x23);
I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_SINGLE_SEND);
while(I2CMasterBusy(I2C0_MASTER_BASE)) {}
I2CMasterDataPut(I2C0_MASTER_BASE, 0x30);
I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_SINGLE_SEND);
while(I2CMasterBusy(I2C0_MASTER_BASE)) {}
I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, (0x32 >> 1), true);
I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);
while(I2CMasterBusy(I2C0_MASTER_BASE)) {}
a=I2CMasterDataGet(I2C0_MASTER_BASE);
while (I2CMasterBusBusy(I2C0_MASTER_BASE)){}
}

int main(void)

{
//
// Setup the system clock to run at 50 Mhz from PLL with crystal reference
//
SysCtlClockSet(SYSCTL_SYSDIV_4|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|
SYSCTL_OSC_MAIN);

//SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);


//
//SysCtlPeripheralPowerOn(SYSCTL_PERIPH_I2C0);

SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);

//
// Enable port PB2 for I2C0 I2C0SCL
//
GPIOPinConfigure(GPIO_PB2_I2C0SCL);
GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);

//
// Enable port PB3 for I2C0 I2C0SDA
//
GPIOPinConfigure(GPIO_PB3_I2C0SDA);
GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);

SysCtlPeripheralReady(SYSCTL_PERIPH_I2C0);


//
// Loop Forever
//
while(1)
{
bus();

 }
}

I have no idea what is wrong. 

Here is the link of the accelerometer datasheet, http://www.pololu.com/file/download/LSM303DLM.pdf?file_id=0J514

BTW, I have not much experience in bus I2C, I'm learning about it. 

Sorry for my English. 

thank you very much in advance!!

  • There are a couple of things I see here that will cause you problems. The first, and most obvious is the line:

    HWREG(I2C0_MASTER_BASE + I2C_O_MCR) |= 0x01;

    This puts the I2C controller into a test mode which loops transmitted data back to the receiver. You definitely want to remove this line.

    Looking at the sensor spec you linked to, I also suspect that your I2C transaction code in bus() isn't correct. By using I2C_MASTER_CMD_SINGLE_SEND every time you want to send a byte, you send both a start and stop condition on every byte. The sensor datasheet, however, shows that the stop condition is only sent at the end of the whole transaction (as is normal for the I2C devices I've used). To control the placement of start and stop conditions when you are performing a multi-byte transaction, you should use I2C_MASTER_CMD_BURST_SEND_START one the first transaction (when you send the slave address), I2C_MASTER_CMD_BURST_SEND_CONT for each following byte you transmit then I2C_MASTER_CMD_BURST_SEND_FINISH on sending the final byte. You also need to make sure you call I2CMasterControl() once for every byte you want to read or write (I see at least one case above where you write 2 bytes between calls to the function). Note that the slave address is automatically sent when you send a start condition so the first call to I2CMasterControl() will send both the address byte and the first data byte.

    Here's what I think you want to read a single byte from the sensor (though, please note that I've not used this device and have not compiled this code!):

    tBoolean ReadSensorRegister(unsigned char slaveAddress, unsigned char Reg_Addr,
                                unsigned char *pucData)
    {
        //
        // Tell the master module what address it will place on the bus when
        // communicating with the slave.
        //
        I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, slaveAddress, false);

        //
        // Write the register addresss byte to the sensor.
        //
        I2CMasterDataPut(I2C0_MASTER_BASE, Reg_Addr);

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

        //
        // Wait until the current byte has been transferred.
        //
        while(I2CMasterIntStatus(I2C0_MASTER_BASE, false) == 0)
        {
        }

        //
        // Check for errors and abort if one occurred.
        //
        if(I2CMasterErr(I2C0_MASTER_BASE) != I2C_MASTER_ERR_NONE)
        {
            I2CMasterIntClear(I2C0_MASTER_BASE);
            return(false);
        }

        //
        // Set the slave address but this time we will be reading from the device.
        //
        I2CMasterSlaveAddrSet(I2C0_MASTER_BASE, slaveAddress, true);

        //
        // Send the adderss again with a (repeated) start condition. Read one
        // byte then send a stop condition.
        //
        I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);

        //
        // Wait until the current byte has been transferred.
        //
        while(I2CMasterIntStatus(I2C0_MASTER_BASE, false) == 0)
        {
        }

        //
        // Check for errors and abort if one occurred.
        //
        if(I2CMasterErr(I2C0_MASTER_BASE) != I2C_MASTER_ERR_NONE)
        {
            I2CMasterIntClear(I2C0_MASTER_BASE);
            return(false);
        }

        //
        // Read the value received.
        //
        *pucData = I2CMasterDataGet(I2C0_MASTER_BASE);

        //
        // All is well.
        //
        return(true);
    }
  • Thanks a lot!! This is what I'm looking for. Very good explanation, now I understand many things about it. 

    I've reprogrammed my code and It's working, thanks a lot.

  • Hi Dave,

    Thanks for such a brief explanation. But I am facing one problem. I am communicating LM3S5R31 microcontroller with 24c512. I am using your code. But results are not as expected. If I placed 5 ms delay after following command then it is working ok.

    I2CMasterControl(I2C0_MASTER_BASE, I2C_MASTER_CMD_BURST_SEND_START);

    Following command is not working.
    while(I2CMasterIntStatus(I2C0_MASTER_BASE, false) == 0)
        {
        }
    I checked signals on DSO but there is no signals. I think above while loop is executing.

    Thanks in advance.

    Somnath Barge

  • My only suggestion here would be to check that there wasn't some other bit set in the the interrupt status before you call I2CMasterControl(). If some other interrupt had fired, your test loop would drop through immediately. I generally add code during initialization that clears any and all bits that may be set in the interrupt status register just in case.