6 years, 3 months ago.

I2C does not return data

I'm new to I2C protocol.

I want Nucleo L053R8 to communicate with LIS3DH(acceleration sensor) through I2C. However, it does not work.

For a simple test, I'm trying to get WHO_AM_I value of LIS3DH, which should be 0x33. The register is 0x0F

Here is my code. Please give me any advice.

#include "mbed.h"

Serial pc(SERIAL_TX, SERIAL_RX);
I2C i2c(PB_9, PB_8); // sda, scl
 
int main() {
    // char cmd = 0x05;
    char v;
    pc.printf("start!\r\n");
    // i2c.frequency(100000);
    
    while (1) {    
        // i2c.write( 0x0F, &cmd, 1, true );
        i2c.read( 0x0F, &v, 1 );
        pc.printf("%c\r\n",v);
        wait(2);
    }
}

1 Answer

6 years, 3 months ago.

The first parameter of the I2C operations is the slaveaddress. That address is 0x30 or 0x32 for the LIS3DH and depends of the logic level of the SA0 pin. Obviously you also need to make sure that the I2C pullup resistors are in place, use 4k7.

#include "mbed.h"
 
Serial pc(SERIAL_TX, SERIAL_RX);
I2C i2c(PB_9, PB_8); // sda, scl
const char address = 0x30;
 
int main() {
    char reg = 0x0F; // Register address
    char val;
    pc.printf ("start!\r\n");
    // i2c.frequency (100000);
    
    while (1) {    
        i2c.write (address, &reg, 1, true ); // Select the register
        i2c.read (address, &val, 1 ); // Read the value
        pc.printf ("Reg 0x%0x is 0x%0x\r\n", reg, val);
        wait(2);
    }
}

Accepted Answer

Thank you for your advice!

I'm trying to get WHO_AM_I value of LIS3DH, which should be 0x33. The register is 0x0F.

I don't get the value 0x33. Why?

posted by Yusuke Fukuhara 26 Aug 2018

Ah yes, the code above had the wrong register. Fixed now. Try again.

Make sure you have the I2C mode selected on the device (CS pin high) and the correct slaveaddress (SA0 pin low).

posted by Wim Huiskamp 26 Aug 2018

The above code works. Thanks a lot!

If possible, can you tell me how to get x acceleration data from LIS3DH? Here is my code. It doesn't work.

#include "mbed.h"
 
Serial pc(SERIAL_TX, SERIAL_RX);
I2C i2c(PB_9, PB_8); // sda, scl
const char read_address = 0x30;
const char write_address = 0x31;
 
int main() {
    char val_x_l;
    char val_x_h;
    char val_x;
    char reg_out_x_l = 0x28;
    char reg_out_x_h = 0x29;
    char dt[2];
    pc.printf ("start!\r\n");
    
    // enable x y z axis
    dt[0] = 0x20;
    dt[1] = 0x7F;
    i2c.write (write_address, dt, 2, false );
    
    while (1) {    
        i2c.write (read_address, &reg_out_x_l, 1, true );
        i2c.read (read_address, &val_x_l, 1 );
        
        i2c.write (read_address, &reg_out_x_h, 1, true ); 
        i2c.read (read_address, &val_x_h, 1); 
        
        val_x = val_x_h << 8 | val_x_l;
        
        pc.printf ("val_x is 0x%0x\r\n", val_x);
        wait(1);
    }
}
posted by Yusuke Fukuhara 27 Aug 2018

You dont need to use a separate read and write address for the slave. That is done automatically by the I2C read/write methods. The problem in your code is probably that val_x is declared as char (8 bits) and you try to force a 16bit value into that char by shifting/bit-or of 2 bytes. Declare val_x as short (int16) or int (int32) and try again:

#include "mbed.h"
 
Serial pc(SERIAL_TX, SERIAL_RX);
I2C i2c(PB_9, PB_8); // sda, scl
const char address = 0x30;
 
int main() {
    char val_x_l;
    char val_x_h;
    int val_x;
    char reg_out_x_l = 0x28;
    char reg_out_x_h = 0x29;
    char dt[2];
    pc.printf ("start!\r\n");
    
    // enable x y z axis
    dt[0] = 0x20;
    dt[1] = 0x7F;
    i2c.write (address, dt, 2, false );
    
    while (1) {    
        i2c.write (address, &reg_out_x_l, 1, true );
        i2c.read (address, &val_x_l, 1 );
        
        i2c.write (address, &reg_out_x_h, 1, true ); 
        i2c.read (address, &val_x_h, 1); 
        
        val_x = val_x_h << 8 | val_x_l;
        
        pc.printf ("val_x is 0x%0x\r\n", val_x);
        wait(1);
    }
}
posted by Wim Huiskamp 27 Aug 2018

Thanks! It works!

posted by Yusuke Fukuhara 28 Aug 2018