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:

Revision:
0:9d83f04e179c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Tue Jul 18 11:07:32 2017 +0000
@@ -0,0 +1,214 @@
+#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");
+                }
+            }
+        }
+    }
+}
\ No newline at end of file