SparkFun Forums 

Where electronics enthusiasts find answers.

Have questions about a SparkFun product or board? This is the place to be.
By leinardi
#197276
I'm currently getting inconsistent data from the accelerometer of my LSM9DS1. To be more precise I either get a value close to the correct gravity (eg. 9.496515) or some reading like it was in space (eg. -0.023928225).

This seems to happen on all three the axes (I tried rotating the LSM9DS1).

I get the same behavior with FIFO enabled or not.

This is a set of 32 consecutive samples that I read from the FIFO memory:
Code: Select all
result = {float[32][]@5092} 
 0 = {float[3]@5100} 
  0 = -0.41754755
  1 = 0.19501504
  2 = 9.519247
 1 = {float[3]@5112} 
  0 = -0.421735
  1 = 0.19980069
  2 = 9.51805
 2 = {float[3]@5120} 
  0 = -0.4229314
  1 = 0.20757735
  2 = 9.510274
 3 = {float[3]@5128} 
  0 = -0.4127619
  1 = 0.2207379
  2 = 9.502497
 4 = {float[3]@5139} 
  0 = -0.39302114
  1 = -0.06580262
  2 = -0.0017946169
 5 = {float[3]@5140} 
  0 = -0.06939186
  1 = -0.045463633
  2 = -0.020937197
 6 = {float[3]@5141} 
  0 = -0.05742774
  1 = -0.03469593
  2 = -0.0317049
 7 = {float[3]@5142} 
  0 = -0.053838514
  1 = -0.039481573
  2 = -0.041874394
 8 = {float[3]@5143} 
  0 = -0.054436717
  1 = -0.052642096
  2 = -0.043669015
 9 = {float[3]@5144} 
  0 = -0.059820566
  1 = -0.068793654
  2 = -0.03469593
 10 = {float[3]@5145} 
  0 = -0.06819545
  1 = 0.22731815
  2 = -0.019142581
 11 = {float[3]@5146} 
  0 = -0.38644087
  1 = 0.2225325
  2 = -0.00418744
 12 = {float[3]@5147} 
  0 = -0.40079778
  1 = 0.21535406
  2 = 9.505488
 13 = {float[3]@5148} 
  0 = -0.40977085
  1 = 0.21355942
  2 = 9.525827
 14 = {float[3]@5149} 
  0 = -0.40917268
  1 = 0.21296123
  2 = 9.540783
 15 = {float[3]@5150} 
  0 = -0.40558344
  1 = 0.2207379
  2 = 9.5455675
 16 = {float[3]@5151} 
  0 = -0.39960137
  1 = 0.22671993
  2 = 9.544371
 17 = {float[3]@5152} 
  0 = -0.39302114
  1 = 0.22791636
  2 = 9.534203
 18 = {float[3]@5153} 
  0 = -0.3906283
  1 = 0.21535406
  2 = 9.517452
 19 = {float[3]@5154} 
  0 = -0.38584265
  1 = 0.19441684
  2 = 9.496515
 20 = {float[3]@5155} 
  0 = -0.384048
  1 = 0.17347965
  2 = -0.023928225
 21 = {float[3]@5156} 
  0 = -0.38883367
  1 = 0.15553348
  2 = -0.042472597
 22 = {float[3]@5157} 
  0 = -0.39541394
  1 = -0.014356935
  2 = -0.05802595
 23 = {float[3]@5158} 
  0 = -0.40259242
  1 = -0.026919257
  2 = -0.06580262
 24 = {float[3]@5159} 
  0 = -0.40977085
  1 = -0.03589234
  2 = -0.071186475
 25 = {float[3]@5160} 
  0 = -0.4151547
  1 = -0.040677987
  2 = -0.062213387
 26 = {float[3]@5161} 
  0 = -0.421735
  1 = -0.03888337
  2 = -0.04965107
 27 = {float[3]@5162} 
  0 = -0.42831525
  1 = -0.040677987
  2 = -0.032303106
 28 = {float[3]@5163} 
  0 = -0.4372883
  1 = -0.04426722
  2 = -0.014356935
 29 = {float[3]@5164} 
  0 = -0.445065
  1 = -0.04785645
  2 = 9.496515
 30 = {float[3]@5165} 
  0 = -0.44865423
  1 = -0.04666004
  2 = 9.503693
 31 = {float[3]@5166} 
  0 = -0.44865423
  1 = -0.04426722
  2 = 9.506086
As you can see sometime the Z axis shows the correct value and sometime not.

This is how I'm initializing the sensors:
Code: Select all
        // soft reset & reboot accel/gyro
        writeRegByte(SensorType.XG, REGISTER_CTRL_REG8, (byte) 0b00000101);
        // soft reset & reboot magnetometer
        writeRegByte(SensorType.MAG, REGISTER_CTRL_REG2_M, (byte) 0b00001100);

        SystemClock.sleep(10);

        byte idXg = readRegByte(SensorType.XG, REGISTER_WHO_AM_I_XG);
        byte idMag = readRegByte(SensorType.MAG, REGISTER_WHO_AM_I_M);
        if (idXg != XG_ID || idMag != MAG_ID) {
            throw new IllegalStateException("Could not find LSM9DS1, check wiring!");
        }

        setFifoMemoryEnabled(false);

        // enable gyro continuous
        writeRegByte(SensorType.XG, REGISTER_CTRL_REG1_G, (byte) 0b11000000); // on XYZ

        // Enable the accelerometer continuous
        writeRegByte(SensorType.XG, REGISTER_CTRL_REG5_XL,
                (byte) (CTRL_REG5_XL_ZEN_XL | CTRL_REG5_XL_YEN_XL | CTRL_REG5_XL_XEN_XL)); // enable X Y and Z axis
        writeRegByte(SensorType.XG, REGISTER_CTRL_REG6_XL, (byte) 0b11000000); // 1 KHz out data rate, BW set by ODR, 408Hz anti-aliasing
        writeRegByte(SensorType.XG, REGISTER_CTRL_REG7_XL, (byte) 0b10000000); // HR - High resolution mode

        // enable mag continuous
        writeRegByte(SensorType.MAG, REGISTER_CTRL_REG3_M, (byte) 0x00); // continuous mode
And this is how I'm reading the accelerometer data:
Code: Select all
        byte[] buffer = new byte[6];
        int[] result = new int[3];
        readRegBuffer(SensorType.XG, REGISTER_OUT_X_L_XL, buffer, buffer.length);
        result[0] = (buffer[1] << 8) | buffer[0]; // Store x-axis values
        result[1] = (buffer[3] << 8) | buffer[2]; // Store y-axis values
        result[2] = (buffer[5] << 8) | buffer[4]; // Store z-axis values
        return result;
I'm then converting the raw values with this formula (but this is a constant change so it should not matter):
Code: Select all
rawAccelerometerData[i] * mAccelMgLsb / 1000f * mGravity;
I currently have only one LSM9DS1 so I have no clue if this is a defective product or an expected behavior and if this can be fixed with a different configuration.
By leinardi
#197291
Hi jremington, I first found out about the issue with requests on demand. I enabled the FIFO only to fetch consecutive samples to gather some data. Normally the FIFO is disabled by default in my driver.

But anyway I have good news because I found the issue!

The problem is how the accelerometer data is read, to be precise is in these lines:
Code: Select all
    result[0] = (buffer[1] << 8) | buffer[0]; // Store x-axis values
    result[1] = (buffer[3] << 8) | buffer[2]; // Store y-axis values
    result[2] = (buffer[5] << 8) | buffer[4]; // Store z-axis values
What I'm getting from the sensor is a 16bit in two’s complement spitted in 2 bytes, for example `buffer[4]` and `buffer[5]` where 4 is the low byte and 5 is the high.

In Java the `&` and `|` are defined to operate only on `int` and `long` values, so what happens is that the `byte` is always promoted to signed `int`:
Code: Select all
    buffer[5] = 00111100 
    buffer[4] = 11110110
    (int)buffer[4] = 11111111111111111111111111110110 = FF FF FF F6
    (buffer[5] << 8) | buffer[4] = FF FF FF F6
With the original code both bytes are handled has two’s complement when actually only the high byte is holding the sign.

Long story short, I have to keep the sign for the high byte (cast to `int`) and threat the low as unsigned (autocast to `int` using the `&` and keeping only the original byte with `0xFF`):
Code: Select all
    result[0] = (((int) buffer[1]) << 8) | (buffer[0] & 0xFF); // Store x-axis values
    result[1] = (((int) buffer[3]) << 8) | (buffer[2] & 0xFF); // Store y-axis values
    result[2] = (((int) buffer[5]) << 8) | (buffer[4] & 0xFF); // Store z-axis values