An example on how to read raw data with calibration
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:
- https://stackoverflow.com/a/19164062
- http://forum.arduino.cc/index.php?topic=216145.0
- https://www.pololu.com/product/2124
- https://forum.arduino.cc/index.php?topic=265541.0
- https://github.com/elechouse/LSM303/blob/master/LSM303/LSM303.cpp
- https://github.com/praneshkmr/node-lsm303/wiki/Understanding-the-calibration-of-the-LSM303-magnetometer-%28compass%29
Revision 0:9d83f04e179c, committed 2017-07-18
- Comitter:
- ElectronicsSanta
- Date:
- Tue Jul 18 11:07:32 2017 +0000
- Commit message:
- first commit
Changed in this revision
main.cpp | Show annotated file Show diff for this revision Revisions of this file |
mbed.bld | Show annotated file Show diff for this revision Revisions of this file |
diff -r 000000000000 -r 9d83f04e179c main.cpp --- /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
diff -r 000000000000 -r 9d83f04e179c mbed.bld --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Tue Jul 18 11:07:32 2017 +0000 @@ -0,0 +1,1 @@ +https://mbed.org/users/mbed_official/code/mbed/builds/22da6e220af6 \ No newline at end of file