An example on how to read raw data with calibration

Dependencies:   mbed

In order to have a valid reading with calibration, i had to read multiple sources on how to drive this IC. The following sources have helped me:

main.cpp

Committer:
ElectronicsSanta
Date:
2017-07-18
Revision:
0:9d83f04e179c

File content as of revision 0:9d83f04e179c:

#include "mbed.h"
#include <algorithm> // for min, max functions

#define ACCEL_I2C_ADDRESS (0x19 << 1)
#define ACCEL_CALIBRATE_TIME 5 // seconds

                                                      // LPen Zen Yen Xen
#define LSM303_REGISTER_ACCEL_CTRL_REG1_A_EN     0x07 //    0   1   1   1

                                                          // ODR3 ODR2 ODR1 ODR0 LPen Zen Yen Xen
#define LSM303_REGISTER_ACCEL_CTRL_REG1_A_PDWN   (0 << 4) //    0    0    0    0    x   x   x   x
#define LSM303_REGISTER_ACCEL_CTRL_REG1_A_1_HZ   (1 << 4) //    0    0    0    1    x   x   x   x
#define LSM303_REGISTER_ACCEL_CTRL_REG1_A_10_HZ  (2 << 4) //    0    0    1    0    x   x   x   x
#define LSM303_REGISTER_ACCEL_CTRL_REG1_A_25_HZ  (3 << 4) //    0    0    1    1    x   x   x   x
#define LSM303_REGISTER_ACCEL_CTRL_REG1_A_50_HZ  (4 << 4) //    0    1    0    0    x   x   x   x
#define LSM303_REGISTER_ACCEL_CTRL_REG1_A_100_HZ (5 << 4) //    0    1    0    1    x   x   x   x
#define LSM303_REGISTER_ACCEL_CTRL_REG1_A_200_HZ (6 << 4) //    0    1    1    0    x   x   x   x
#define LSM303_REGISTER_ACCEL_CTRL_REG1_A_400_HZ (7 << 4) //    0    1    1    1    x   x   x   x

#define LSM303_ACCEL_REFRESH_RATE (LSM303_REGISTER_ACCEL_CTRL_REG1_A_EN | LSM303_REGISTER_ACCEL_CTRL_REG1_A_100_HZ)

#define LSM303_REGISTER_ACCEL_DEFAULT_CTRL_REG1_A  0x07 // default value

#define LSM303_REGISTER_ACCEL_CTRL_REG1_A 0x20
#define LSM303_REGISTER_ACCEL_CTRL_REG4_A 0x23

                                              // BDU BLE FS1 FS0 HR 0 0 SIM
#define LSM303_ACCEL_FS_BIT_00 (0) | (1 << 3) //    0  0   0   0  1 0 0   0

#define LSM303_REGISTER_ACCEL_OUT_X_L_A 0x28
#define LSM303_REGISTER_ACCEL_OUT_X_H_A 0x29
#define LSM303_REGISTER_ACCEL_OUT_Y_L_A 0x2A
#define LSM303_REGISTER_ACCEL_OUT_Y_H_A 0x2B
#define LSM303_REGISTER_ACCEL_OUT_Z_L_A 0x2C
#define LSM303_REGISTER_ACCEL_OUT_Z_H_A 0x2D

Serial serial(SERIAL_TX, SERIAL_RX);
I2C i2c(I2C_SDA, I2C_SCL); // PB_9, PB_8
Timer calibrate_t;

int16_t running_min_x = 32767;
int16_t running_min_y = 32767;
int16_t running_min_z = 32767;
int16_t running_max_x = -32768;
int16_t running_max_y = -32768;
int16_t running_max_z = -32768;
int16_t running_avg_x = 0;
int16_t running_avg_y = 0;
int16_t running_avg_z = 0;
int16_t raw_x;
int16_t raw_y;
int16_t raw_z;
int16_t x;
int16_t y;
int16_t z;
bool calibration_done = false;
bool acc_found = false;

uint8_t i2c_read8_reg(uint8_t address, int8_t reg) {
    char i2cBuffer[1];
    i2cBuffer[0] = reg;
    i2c.write(address, i2cBuffer, 1);

    i2c.read(address, i2cBuffer, 1);

    return (uint8_t)i2cBuffer[0];
}

void i2c_write8_reg(uint8_t address, int8_t reg, int8_t value) {
    char i2cBuffer[2];
    i2cBuffer[0] = reg;
    i2cBuffer[1] = value;
    i2c.write(address, i2cBuffer, 2);
}

void read_accel() {
    char i2cBuffer[1];

    raw_x = 0;
    raw_y = 0;
    raw_z = 0;
    x = 0;
    y = 0;
    z = 0;

    i2cBuffer[0] = LSM303_REGISTER_ACCEL_OUT_X_H_A;
    i2c.write(ACCEL_I2C_ADDRESS, i2cBuffer, 1);
    i2c.read(ACCEL_I2C_ADDRESS, i2cBuffer, 1);
    x = (i2cBuffer[0] << 8);

    i2cBuffer[0] = LSM303_REGISTER_ACCEL_OUT_X_L_A;
    i2c.write(ACCEL_I2C_ADDRESS, i2cBuffer, 1);
    i2c.read(ACCEL_I2C_ADDRESS, i2cBuffer, 1);
    x |= i2cBuffer[0];

    x >>= 4;

    i2cBuffer[0] = LSM303_REGISTER_ACCEL_OUT_Y_H_A;
    i2c.write(ACCEL_I2C_ADDRESS, i2cBuffer, 1);
    i2c.read(ACCEL_I2C_ADDRESS, i2cBuffer, 1);
    y = (i2cBuffer[0] << 8);

    i2cBuffer[0] = LSM303_REGISTER_ACCEL_OUT_Y_L_A;
    i2c.write(ACCEL_I2C_ADDRESS, i2cBuffer, 1);
    i2c.read(ACCEL_I2C_ADDRESS, i2cBuffer, 1);
    y |= i2cBuffer[0];

    y >>= 4;

    i2cBuffer[0] = LSM303_REGISTER_ACCEL_OUT_Z_H_A;
    i2c.write(ACCEL_I2C_ADDRESS, i2cBuffer, 1);
    i2c.read(ACCEL_I2C_ADDRESS, i2cBuffer, 1);
    z = (i2cBuffer[0] << 8);

    i2cBuffer[0] = LSM303_REGISTER_ACCEL_OUT_Z_L_A;
    i2c.write(ACCEL_I2C_ADDRESS, i2cBuffer, 1);
    i2c.read(ACCEL_I2C_ADDRESS, i2cBuffer, 1);
    z |= i2cBuffer[0];

    z >>= 4;

    raw_x = x;
    raw_y = y;
    raw_z = z;

    if (calibration_done) {
        x -= running_avg_x;
        y -= running_avg_y;
        z -= running_avg_z;
    }
}

void calibrate() {
    read_accel();

    running_min_x = min(running_min_x, x);
    running_min_y = min(running_min_y, y);
    running_min_z = min(running_min_z, z);

    running_max_x = max(running_max_x, x);
    running_max_y = max(running_max_y, y);
    running_max_z = max(running_max_z, z);
}

int16_t avg(int16_t a, int16_t b) {
    return (int16_t)((a + b) / 2);
}

int main() {
    serial.baud(115200);
    i2c.frequency((uint32_t)100e3);

    serial.printf("LSM303DLHC example with calibration...\n");

    // who am i
    uint8_t default_val = i2c_read8_reg(ACCEL_I2C_ADDRESS, LSM303_REGISTER_ACCEL_CTRL_REG1_A);
    serial.printf("who am i: %d, 0x%X\n", default_val, default_val);

    if ((default_val & 0xF) == LSM303_REGISTER_ACCEL_DEFAULT_CTRL_REG1_A) { // least significant nibble is the default one
        acc_found = true;
        serial.printf("accel found\n");
    } else {
        serial.printf("accel NOT found\n");
    }

    if (acc_found) {
        // enable the accelerometer
        i2c_write8_reg(ACCEL_I2C_ADDRESS, LSM303_REGISTER_ACCEL_CTRL_REG1_A, LSM303_ACCEL_REFRESH_RATE);

        // set accelerometer full-scale bits
        i2c_write8_reg(ACCEL_I2C_ADDRESS, LSM303_REGISTER_ACCEL_CTRL_REG4_A, LSM303_ACCEL_FS_BIT_00);

        calibrate_t.start();

        serial.printf("calibrating accel...");

        while (true) {
            if (!calibration_done) {
                if (calibrate_t.read() < ACCEL_CALIBRATE_TIME) { // x sec calibration
                    calibrate();
                } else {
                    calibration_done = true;

                    serial.printf("done\n");

                    running_avg_x = avg(running_min_x, running_max_x);
                    running_avg_y = avg(running_min_y, running_max_y);
                    running_avg_z = avg(running_min_z, running_max_z);

                    serial.printf("calibration results: ");
                    serial.printf("min_x %d, ", running_min_x);
                    serial.printf("min_y %d, ", running_min_y);
                    serial.printf("min_z %d, ", running_min_z);
                    serial.printf("max_x %d, ", running_max_x);
                    serial.printf("max_y %d, ", running_max_y);
                    serial.printf("max_z %d", running_max_z);
                    serial.printf("avg_x %d, ", running_avg_x);
                    serial.printf("avg_y %d, ", running_avg_y);
                    serial.printf("avg_z %d\n", running_avg_z);

                    calibrate_t.reset();
                }
            } else {
                if (calibrate_t.read_ms() > 200) { // print x ms
                    read_accel();
                    calibrate_t.reset();
                    serial.printf("raw x: %d; raw y: %d; raw z: %d\n", raw_x, raw_y, raw_z);
                    serial.printf("x: %d; y: %d; z: %d\n", x, y, z);
                    serial.printf("**************************\n");
                }
            }
        }
    }
}