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
main.cpp@0:9d83f04e179c, 2017-07-18 (annotated)
- Committer:
- ElectronicsSanta
- Date:
- Tue Jul 18 11:07:32 2017 +0000
- Revision:
- 0:9d83f04e179c
first commit
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
ElectronicsSanta | 0:9d83f04e179c | 1 | #include "mbed.h" |
ElectronicsSanta | 0:9d83f04e179c | 2 | #include <algorithm> // for min, max functions |
ElectronicsSanta | 0:9d83f04e179c | 3 | |
ElectronicsSanta | 0:9d83f04e179c | 4 | #define ACCEL_I2C_ADDRESS (0x19 << 1) |
ElectronicsSanta | 0:9d83f04e179c | 5 | #define ACCEL_CALIBRATE_TIME 5 // seconds |
ElectronicsSanta | 0:9d83f04e179c | 6 | |
ElectronicsSanta | 0:9d83f04e179c | 7 | // LPen Zen Yen Xen |
ElectronicsSanta | 0:9d83f04e179c | 8 | #define LSM303_REGISTER_ACCEL_CTRL_REG1_A_EN 0x07 // 0 1 1 1 |
ElectronicsSanta | 0:9d83f04e179c | 9 | |
ElectronicsSanta | 0:9d83f04e179c | 10 | // ODR3 ODR2 ODR1 ODR0 LPen Zen Yen Xen |
ElectronicsSanta | 0:9d83f04e179c | 11 | #define LSM303_REGISTER_ACCEL_CTRL_REG1_A_PDWN (0 << 4) // 0 0 0 0 x x x x |
ElectronicsSanta | 0:9d83f04e179c | 12 | #define LSM303_REGISTER_ACCEL_CTRL_REG1_A_1_HZ (1 << 4) // 0 0 0 1 x x x x |
ElectronicsSanta | 0:9d83f04e179c | 13 | #define LSM303_REGISTER_ACCEL_CTRL_REG1_A_10_HZ (2 << 4) // 0 0 1 0 x x x x |
ElectronicsSanta | 0:9d83f04e179c | 14 | #define LSM303_REGISTER_ACCEL_CTRL_REG1_A_25_HZ (3 << 4) // 0 0 1 1 x x x x |
ElectronicsSanta | 0:9d83f04e179c | 15 | #define LSM303_REGISTER_ACCEL_CTRL_REG1_A_50_HZ (4 << 4) // 0 1 0 0 x x x x |
ElectronicsSanta | 0:9d83f04e179c | 16 | #define LSM303_REGISTER_ACCEL_CTRL_REG1_A_100_HZ (5 << 4) // 0 1 0 1 x x x x |
ElectronicsSanta | 0:9d83f04e179c | 17 | #define LSM303_REGISTER_ACCEL_CTRL_REG1_A_200_HZ (6 << 4) // 0 1 1 0 x x x x |
ElectronicsSanta | 0:9d83f04e179c | 18 | #define LSM303_REGISTER_ACCEL_CTRL_REG1_A_400_HZ (7 << 4) // 0 1 1 1 x x x x |
ElectronicsSanta | 0:9d83f04e179c | 19 | |
ElectronicsSanta | 0:9d83f04e179c | 20 | #define LSM303_ACCEL_REFRESH_RATE (LSM303_REGISTER_ACCEL_CTRL_REG1_A_EN | LSM303_REGISTER_ACCEL_CTRL_REG1_A_100_HZ) |
ElectronicsSanta | 0:9d83f04e179c | 21 | |
ElectronicsSanta | 0:9d83f04e179c | 22 | #define LSM303_REGISTER_ACCEL_DEFAULT_CTRL_REG1_A 0x07 // default value |
ElectronicsSanta | 0:9d83f04e179c | 23 | |
ElectronicsSanta | 0:9d83f04e179c | 24 | #define LSM303_REGISTER_ACCEL_CTRL_REG1_A 0x20 |
ElectronicsSanta | 0:9d83f04e179c | 25 | #define LSM303_REGISTER_ACCEL_CTRL_REG4_A 0x23 |
ElectronicsSanta | 0:9d83f04e179c | 26 | |
ElectronicsSanta | 0:9d83f04e179c | 27 | // BDU BLE FS1 FS0 HR 0 0 SIM |
ElectronicsSanta | 0:9d83f04e179c | 28 | #define LSM303_ACCEL_FS_BIT_00 (0) | (1 << 3) // 0 0 0 0 1 0 0 0 |
ElectronicsSanta | 0:9d83f04e179c | 29 | |
ElectronicsSanta | 0:9d83f04e179c | 30 | #define LSM303_REGISTER_ACCEL_OUT_X_L_A 0x28 |
ElectronicsSanta | 0:9d83f04e179c | 31 | #define LSM303_REGISTER_ACCEL_OUT_X_H_A 0x29 |
ElectronicsSanta | 0:9d83f04e179c | 32 | #define LSM303_REGISTER_ACCEL_OUT_Y_L_A 0x2A |
ElectronicsSanta | 0:9d83f04e179c | 33 | #define LSM303_REGISTER_ACCEL_OUT_Y_H_A 0x2B |
ElectronicsSanta | 0:9d83f04e179c | 34 | #define LSM303_REGISTER_ACCEL_OUT_Z_L_A 0x2C |
ElectronicsSanta | 0:9d83f04e179c | 35 | #define LSM303_REGISTER_ACCEL_OUT_Z_H_A 0x2D |
ElectronicsSanta | 0:9d83f04e179c | 36 | |
ElectronicsSanta | 0:9d83f04e179c | 37 | Serial serial(SERIAL_TX, SERIAL_RX); |
ElectronicsSanta | 0:9d83f04e179c | 38 | I2C i2c(I2C_SDA, I2C_SCL); // PB_9, PB_8 |
ElectronicsSanta | 0:9d83f04e179c | 39 | Timer calibrate_t; |
ElectronicsSanta | 0:9d83f04e179c | 40 | |
ElectronicsSanta | 0:9d83f04e179c | 41 | int16_t running_min_x = 32767; |
ElectronicsSanta | 0:9d83f04e179c | 42 | int16_t running_min_y = 32767; |
ElectronicsSanta | 0:9d83f04e179c | 43 | int16_t running_min_z = 32767; |
ElectronicsSanta | 0:9d83f04e179c | 44 | int16_t running_max_x = -32768; |
ElectronicsSanta | 0:9d83f04e179c | 45 | int16_t running_max_y = -32768; |
ElectronicsSanta | 0:9d83f04e179c | 46 | int16_t running_max_z = -32768; |
ElectronicsSanta | 0:9d83f04e179c | 47 | int16_t running_avg_x = 0; |
ElectronicsSanta | 0:9d83f04e179c | 48 | int16_t running_avg_y = 0; |
ElectronicsSanta | 0:9d83f04e179c | 49 | int16_t running_avg_z = 0; |
ElectronicsSanta | 0:9d83f04e179c | 50 | int16_t raw_x; |
ElectronicsSanta | 0:9d83f04e179c | 51 | int16_t raw_y; |
ElectronicsSanta | 0:9d83f04e179c | 52 | int16_t raw_z; |
ElectronicsSanta | 0:9d83f04e179c | 53 | int16_t x; |
ElectronicsSanta | 0:9d83f04e179c | 54 | int16_t y; |
ElectronicsSanta | 0:9d83f04e179c | 55 | int16_t z; |
ElectronicsSanta | 0:9d83f04e179c | 56 | bool calibration_done = false; |
ElectronicsSanta | 0:9d83f04e179c | 57 | bool acc_found = false; |
ElectronicsSanta | 0:9d83f04e179c | 58 | |
ElectronicsSanta | 0:9d83f04e179c | 59 | uint8_t i2c_read8_reg(uint8_t address, int8_t reg) { |
ElectronicsSanta | 0:9d83f04e179c | 60 | char i2cBuffer[1]; |
ElectronicsSanta | 0:9d83f04e179c | 61 | i2cBuffer[0] = reg; |
ElectronicsSanta | 0:9d83f04e179c | 62 | i2c.write(address, i2cBuffer, 1); |
ElectronicsSanta | 0:9d83f04e179c | 63 | |
ElectronicsSanta | 0:9d83f04e179c | 64 | i2c.read(address, i2cBuffer, 1); |
ElectronicsSanta | 0:9d83f04e179c | 65 | |
ElectronicsSanta | 0:9d83f04e179c | 66 | return (uint8_t)i2cBuffer[0]; |
ElectronicsSanta | 0:9d83f04e179c | 67 | } |
ElectronicsSanta | 0:9d83f04e179c | 68 | |
ElectronicsSanta | 0:9d83f04e179c | 69 | void i2c_write8_reg(uint8_t address, int8_t reg, int8_t value) { |
ElectronicsSanta | 0:9d83f04e179c | 70 | char i2cBuffer[2]; |
ElectronicsSanta | 0:9d83f04e179c | 71 | i2cBuffer[0] = reg; |
ElectronicsSanta | 0:9d83f04e179c | 72 | i2cBuffer[1] = value; |
ElectronicsSanta | 0:9d83f04e179c | 73 | i2c.write(address, i2cBuffer, 2); |
ElectronicsSanta | 0:9d83f04e179c | 74 | } |
ElectronicsSanta | 0:9d83f04e179c | 75 | |
ElectronicsSanta | 0:9d83f04e179c | 76 | void read_accel() { |
ElectronicsSanta | 0:9d83f04e179c | 77 | char i2cBuffer[1]; |
ElectronicsSanta | 0:9d83f04e179c | 78 | |
ElectronicsSanta | 0:9d83f04e179c | 79 | raw_x = 0; |
ElectronicsSanta | 0:9d83f04e179c | 80 | raw_y = 0; |
ElectronicsSanta | 0:9d83f04e179c | 81 | raw_z = 0; |
ElectronicsSanta | 0:9d83f04e179c | 82 | x = 0; |
ElectronicsSanta | 0:9d83f04e179c | 83 | y = 0; |
ElectronicsSanta | 0:9d83f04e179c | 84 | z = 0; |
ElectronicsSanta | 0:9d83f04e179c | 85 | |
ElectronicsSanta | 0:9d83f04e179c | 86 | i2cBuffer[0] = LSM303_REGISTER_ACCEL_OUT_X_H_A; |
ElectronicsSanta | 0:9d83f04e179c | 87 | i2c.write(ACCEL_I2C_ADDRESS, i2cBuffer, 1); |
ElectronicsSanta | 0:9d83f04e179c | 88 | i2c.read(ACCEL_I2C_ADDRESS, i2cBuffer, 1); |
ElectronicsSanta | 0:9d83f04e179c | 89 | x = (i2cBuffer[0] << 8); |
ElectronicsSanta | 0:9d83f04e179c | 90 | |
ElectronicsSanta | 0:9d83f04e179c | 91 | i2cBuffer[0] = LSM303_REGISTER_ACCEL_OUT_X_L_A; |
ElectronicsSanta | 0:9d83f04e179c | 92 | i2c.write(ACCEL_I2C_ADDRESS, i2cBuffer, 1); |
ElectronicsSanta | 0:9d83f04e179c | 93 | i2c.read(ACCEL_I2C_ADDRESS, i2cBuffer, 1); |
ElectronicsSanta | 0:9d83f04e179c | 94 | x |= i2cBuffer[0]; |
ElectronicsSanta | 0:9d83f04e179c | 95 | |
ElectronicsSanta | 0:9d83f04e179c | 96 | x >>= 4; |
ElectronicsSanta | 0:9d83f04e179c | 97 | |
ElectronicsSanta | 0:9d83f04e179c | 98 | i2cBuffer[0] = LSM303_REGISTER_ACCEL_OUT_Y_H_A; |
ElectronicsSanta | 0:9d83f04e179c | 99 | i2c.write(ACCEL_I2C_ADDRESS, i2cBuffer, 1); |
ElectronicsSanta | 0:9d83f04e179c | 100 | i2c.read(ACCEL_I2C_ADDRESS, i2cBuffer, 1); |
ElectronicsSanta | 0:9d83f04e179c | 101 | y = (i2cBuffer[0] << 8); |
ElectronicsSanta | 0:9d83f04e179c | 102 | |
ElectronicsSanta | 0:9d83f04e179c | 103 | i2cBuffer[0] = LSM303_REGISTER_ACCEL_OUT_Y_L_A; |
ElectronicsSanta | 0:9d83f04e179c | 104 | i2c.write(ACCEL_I2C_ADDRESS, i2cBuffer, 1); |
ElectronicsSanta | 0:9d83f04e179c | 105 | i2c.read(ACCEL_I2C_ADDRESS, i2cBuffer, 1); |
ElectronicsSanta | 0:9d83f04e179c | 106 | y |= i2cBuffer[0]; |
ElectronicsSanta | 0:9d83f04e179c | 107 | |
ElectronicsSanta | 0:9d83f04e179c | 108 | y >>= 4; |
ElectronicsSanta | 0:9d83f04e179c | 109 | |
ElectronicsSanta | 0:9d83f04e179c | 110 | i2cBuffer[0] = LSM303_REGISTER_ACCEL_OUT_Z_H_A; |
ElectronicsSanta | 0:9d83f04e179c | 111 | i2c.write(ACCEL_I2C_ADDRESS, i2cBuffer, 1); |
ElectronicsSanta | 0:9d83f04e179c | 112 | i2c.read(ACCEL_I2C_ADDRESS, i2cBuffer, 1); |
ElectronicsSanta | 0:9d83f04e179c | 113 | z = (i2cBuffer[0] << 8); |
ElectronicsSanta | 0:9d83f04e179c | 114 | |
ElectronicsSanta | 0:9d83f04e179c | 115 | i2cBuffer[0] = LSM303_REGISTER_ACCEL_OUT_Z_L_A; |
ElectronicsSanta | 0:9d83f04e179c | 116 | i2c.write(ACCEL_I2C_ADDRESS, i2cBuffer, 1); |
ElectronicsSanta | 0:9d83f04e179c | 117 | i2c.read(ACCEL_I2C_ADDRESS, i2cBuffer, 1); |
ElectronicsSanta | 0:9d83f04e179c | 118 | z |= i2cBuffer[0]; |
ElectronicsSanta | 0:9d83f04e179c | 119 | |
ElectronicsSanta | 0:9d83f04e179c | 120 | z >>= 4; |
ElectronicsSanta | 0:9d83f04e179c | 121 | |
ElectronicsSanta | 0:9d83f04e179c | 122 | raw_x = x; |
ElectronicsSanta | 0:9d83f04e179c | 123 | raw_y = y; |
ElectronicsSanta | 0:9d83f04e179c | 124 | raw_z = z; |
ElectronicsSanta | 0:9d83f04e179c | 125 | |
ElectronicsSanta | 0:9d83f04e179c | 126 | if (calibration_done) { |
ElectronicsSanta | 0:9d83f04e179c | 127 | x -= running_avg_x; |
ElectronicsSanta | 0:9d83f04e179c | 128 | y -= running_avg_y; |
ElectronicsSanta | 0:9d83f04e179c | 129 | z -= running_avg_z; |
ElectronicsSanta | 0:9d83f04e179c | 130 | } |
ElectronicsSanta | 0:9d83f04e179c | 131 | } |
ElectronicsSanta | 0:9d83f04e179c | 132 | |
ElectronicsSanta | 0:9d83f04e179c | 133 | void calibrate() { |
ElectronicsSanta | 0:9d83f04e179c | 134 | read_accel(); |
ElectronicsSanta | 0:9d83f04e179c | 135 | |
ElectronicsSanta | 0:9d83f04e179c | 136 | running_min_x = min(running_min_x, x); |
ElectronicsSanta | 0:9d83f04e179c | 137 | running_min_y = min(running_min_y, y); |
ElectronicsSanta | 0:9d83f04e179c | 138 | running_min_z = min(running_min_z, z); |
ElectronicsSanta | 0:9d83f04e179c | 139 | |
ElectronicsSanta | 0:9d83f04e179c | 140 | running_max_x = max(running_max_x, x); |
ElectronicsSanta | 0:9d83f04e179c | 141 | running_max_y = max(running_max_y, y); |
ElectronicsSanta | 0:9d83f04e179c | 142 | running_max_z = max(running_max_z, z); |
ElectronicsSanta | 0:9d83f04e179c | 143 | } |
ElectronicsSanta | 0:9d83f04e179c | 144 | |
ElectronicsSanta | 0:9d83f04e179c | 145 | int16_t avg(int16_t a, int16_t b) { |
ElectronicsSanta | 0:9d83f04e179c | 146 | return (int16_t)((a + b) / 2); |
ElectronicsSanta | 0:9d83f04e179c | 147 | } |
ElectronicsSanta | 0:9d83f04e179c | 148 | |
ElectronicsSanta | 0:9d83f04e179c | 149 | int main() { |
ElectronicsSanta | 0:9d83f04e179c | 150 | serial.baud(115200); |
ElectronicsSanta | 0:9d83f04e179c | 151 | i2c.frequency((uint32_t)100e3); |
ElectronicsSanta | 0:9d83f04e179c | 152 | |
ElectronicsSanta | 0:9d83f04e179c | 153 | serial.printf("LSM303DLHC example with calibration...\n"); |
ElectronicsSanta | 0:9d83f04e179c | 154 | |
ElectronicsSanta | 0:9d83f04e179c | 155 | // who am i |
ElectronicsSanta | 0:9d83f04e179c | 156 | uint8_t default_val = i2c_read8_reg(ACCEL_I2C_ADDRESS, LSM303_REGISTER_ACCEL_CTRL_REG1_A); |
ElectronicsSanta | 0:9d83f04e179c | 157 | serial.printf("who am i: %d, 0x%X\n", default_val, default_val); |
ElectronicsSanta | 0:9d83f04e179c | 158 | |
ElectronicsSanta | 0:9d83f04e179c | 159 | if ((default_val & 0xF) == LSM303_REGISTER_ACCEL_DEFAULT_CTRL_REG1_A) { // least significant nibble is the default one |
ElectronicsSanta | 0:9d83f04e179c | 160 | acc_found = true; |
ElectronicsSanta | 0:9d83f04e179c | 161 | serial.printf("accel found\n"); |
ElectronicsSanta | 0:9d83f04e179c | 162 | } else { |
ElectronicsSanta | 0:9d83f04e179c | 163 | serial.printf("accel NOT found\n"); |
ElectronicsSanta | 0:9d83f04e179c | 164 | } |
ElectronicsSanta | 0:9d83f04e179c | 165 | |
ElectronicsSanta | 0:9d83f04e179c | 166 | if (acc_found) { |
ElectronicsSanta | 0:9d83f04e179c | 167 | // enable the accelerometer |
ElectronicsSanta | 0:9d83f04e179c | 168 | i2c_write8_reg(ACCEL_I2C_ADDRESS, LSM303_REGISTER_ACCEL_CTRL_REG1_A, LSM303_ACCEL_REFRESH_RATE); |
ElectronicsSanta | 0:9d83f04e179c | 169 | |
ElectronicsSanta | 0:9d83f04e179c | 170 | // set accelerometer full-scale bits |
ElectronicsSanta | 0:9d83f04e179c | 171 | i2c_write8_reg(ACCEL_I2C_ADDRESS, LSM303_REGISTER_ACCEL_CTRL_REG4_A, LSM303_ACCEL_FS_BIT_00); |
ElectronicsSanta | 0:9d83f04e179c | 172 | |
ElectronicsSanta | 0:9d83f04e179c | 173 | calibrate_t.start(); |
ElectronicsSanta | 0:9d83f04e179c | 174 | |
ElectronicsSanta | 0:9d83f04e179c | 175 | serial.printf("calibrating accel..."); |
ElectronicsSanta | 0:9d83f04e179c | 176 | |
ElectronicsSanta | 0:9d83f04e179c | 177 | while (true) { |
ElectronicsSanta | 0:9d83f04e179c | 178 | if (!calibration_done) { |
ElectronicsSanta | 0:9d83f04e179c | 179 | if (calibrate_t.read() < ACCEL_CALIBRATE_TIME) { // x sec calibration |
ElectronicsSanta | 0:9d83f04e179c | 180 | calibrate(); |
ElectronicsSanta | 0:9d83f04e179c | 181 | } else { |
ElectronicsSanta | 0:9d83f04e179c | 182 | calibration_done = true; |
ElectronicsSanta | 0:9d83f04e179c | 183 | |
ElectronicsSanta | 0:9d83f04e179c | 184 | serial.printf("done\n"); |
ElectronicsSanta | 0:9d83f04e179c | 185 | |
ElectronicsSanta | 0:9d83f04e179c | 186 | running_avg_x = avg(running_min_x, running_max_x); |
ElectronicsSanta | 0:9d83f04e179c | 187 | running_avg_y = avg(running_min_y, running_max_y); |
ElectronicsSanta | 0:9d83f04e179c | 188 | running_avg_z = avg(running_min_z, running_max_z); |
ElectronicsSanta | 0:9d83f04e179c | 189 | |
ElectronicsSanta | 0:9d83f04e179c | 190 | serial.printf("calibration results: "); |
ElectronicsSanta | 0:9d83f04e179c | 191 | serial.printf("min_x %d, ", running_min_x); |
ElectronicsSanta | 0:9d83f04e179c | 192 | serial.printf("min_y %d, ", running_min_y); |
ElectronicsSanta | 0:9d83f04e179c | 193 | serial.printf("min_z %d, ", running_min_z); |
ElectronicsSanta | 0:9d83f04e179c | 194 | serial.printf("max_x %d, ", running_max_x); |
ElectronicsSanta | 0:9d83f04e179c | 195 | serial.printf("max_y %d, ", running_max_y); |
ElectronicsSanta | 0:9d83f04e179c | 196 | serial.printf("max_z %d", running_max_z); |
ElectronicsSanta | 0:9d83f04e179c | 197 | serial.printf("avg_x %d, ", running_avg_x); |
ElectronicsSanta | 0:9d83f04e179c | 198 | serial.printf("avg_y %d, ", running_avg_y); |
ElectronicsSanta | 0:9d83f04e179c | 199 | serial.printf("avg_z %d\n", running_avg_z); |
ElectronicsSanta | 0:9d83f04e179c | 200 | |
ElectronicsSanta | 0:9d83f04e179c | 201 | calibrate_t.reset(); |
ElectronicsSanta | 0:9d83f04e179c | 202 | } |
ElectronicsSanta | 0:9d83f04e179c | 203 | } else { |
ElectronicsSanta | 0:9d83f04e179c | 204 | if (calibrate_t.read_ms() > 200) { // print x ms |
ElectronicsSanta | 0:9d83f04e179c | 205 | read_accel(); |
ElectronicsSanta | 0:9d83f04e179c | 206 | calibrate_t.reset(); |
ElectronicsSanta | 0:9d83f04e179c | 207 | serial.printf("raw x: %d; raw y: %d; raw z: %d\n", raw_x, raw_y, raw_z); |
ElectronicsSanta | 0:9d83f04e179c | 208 | serial.printf("x: %d; y: %d; z: %d\n", x, y, z); |
ElectronicsSanta | 0:9d83f04e179c | 209 | serial.printf("**************************\n"); |
ElectronicsSanta | 0:9d83f04e179c | 210 | } |
ElectronicsSanta | 0:9d83f04e179c | 211 | } |
ElectronicsSanta | 0:9d83f04e179c | 212 | } |
ElectronicsSanta | 0:9d83f04e179c | 213 | } |
ElectronicsSanta | 0:9d83f04e179c | 214 | } |