diff --git a/examples/c++/lsm303d.cxx b/examples/c++/lsm303d.cxx new file mode 100644 index 00000000..255ee12b --- /dev/null +++ b/examples/c++/lsm303d.cxx @@ -0,0 +1,87 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2017 Intel Corporation. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include "lsm303d.hpp" + +using namespace std; + +int shouldRun = true; + +void sig_handler(int signo) +{ + if (signo == SIGINT) + shouldRun = false; +} + + +int main(int argc, char **argv) +{ + signal(SIGINT, sig_handler); +//! [Interesting] + + // Instantiate an LSM303D using default I2C parameters + upm::LSM303D sensor; + + // now output data every 250 milliseconds + while (shouldRun) + { + float x, y, z; + + sensor.update(); + + sensor.getAccelerometer(&x, &y, &z); + cout << "Accelerometer x: " << x + << " y: " << y + << " z: " << z + << " g" + << endl; + + sensor.getMagnetometer(&x, &y, &z); + cout << "Magnetometer x: " << x + << " y: " << y + << " z: " << z + << " uT" + << endl; + + cout << "Temperature: " + << sensor.getTemperature() + << " C" + << endl; + + cout << endl; + + usleep(250000); + } + +//! [Interesting] + + cout << "Exiting..." << endl; + + return 0; +} diff --git a/examples/c/lsm303d.c b/examples/c/lsm303d.c new file mode 100644 index 00000000..ddaf5c92 --- /dev/null +++ b/examples/c/lsm303d.c @@ -0,0 +1,89 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2017 Intel Corporation. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +#include "upm_utilities.h" +#include "lsm303d.h" + +bool shouldRun = true; + +void sig_handler(int signo) +{ + if (signo == SIGINT) + shouldRun = false; +} + + +int main(int argc, char **argv) +{ + signal(SIGINT, sig_handler); +//! [Interesting] + + // Instantiate a LSM303D instance using default i2c bus and addresses + lsm303d_context sensor = lsm303d_init(LSM303D_DEFAULT_I2C_BUS, + LSM303D_DEFAULT_I2C_ADDR); + + if (!sensor) + { + printf("lsm303d_init() failed.\n"); + return 1; + } + + // now output data every 250 milliseconds + while (shouldRun) + { + float x, y, z; + + if (lsm303d_update(sensor)) + { + printf("lsm303d_update() failed\n"); + return 1; + } + + lsm303d_get_accelerometer(sensor, &x, &y, &z); + printf("Accelerometer x: %f y: %f z: %f g\n", + x, y, z); + + lsm303d_get_magnetometer(sensor, &x, &y, &z); + printf("Magnetometer x: %f y: %f z: %f uT\n", + x, y, z); + + printf("Temperature: %f C\n\n", lsm303d_get_temperature(sensor)); + + upm_delay_ms(250); + } + + printf("Exiting...\n"); + + lsm303d_close(sensor); + +//! [Interesting] + + return 0; +} diff --git a/examples/java/CMakeLists.txt b/examples/java/CMakeLists.txt index 05400ff2..aa9e55c1 100644 --- a/examples/java/CMakeLists.txt +++ b/examples/java/CMakeLists.txt @@ -170,6 +170,7 @@ add_example(BMG160_Example bmg160) add_example(BMA250E_Example bma250e) add_example(BMM150_Example bmm150) add_example(LSM303AGR_Example lsm303agr) +add_example(LSM303D_Example lsm303d) add_example_with_path(Jhd1313m1_lcdSample jhd1313m1 jhd1313m1) add_example_with_path(Jhd1313m1Sample jhd1313m1 jhd1313m1) diff --git a/examples/java/LSM303D_Example.java b/examples/java/LSM303D_Example.java new file mode 100644 index 00000000..1c9b1deb --- /dev/null +++ b/examples/java/LSM303D_Example.java @@ -0,0 +1,65 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2017 Intel Corporation. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import upm_lsm303d.LSM303D; + +public class LSM303D_Example +{ + public static void main(String[] args) throws InterruptedException + { +// ! [Interesting] + + // Instantiate a LSM303D instance using default i2c bus and address + LSM303D sensor = new LSM303D(); + + while (true) + { + // update our values from the sensor + sensor.update(); + + upm_lsm303d.floatVector data = sensor.getAccelerometer(); + + System.out.println("Accelerometer x: " + data.get(0) + + " y: " + data.get(1) + + " z: " + data.get(2) + + " g"); + + data = sensor.getMagnetometer(); + System.out.println("Magnetometer x: " + data.get(0) + + " y: " + data.get(1) + + " z: " + data.get(2) + + " uT"); + + System.out.println("Temperature: " + + sensor.getTemperature()); + + System.out.println(); + Thread.sleep(250); + } + +// ! [Interesting] + } +} diff --git a/examples/javascript/lsm303d.js b/examples/javascript/lsm303d.js new file mode 100644 index 00000000..c9ff59e8 --- /dev/null +++ b/examples/javascript/lsm303d.js @@ -0,0 +1,67 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2017 Intel Corporation. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +var sensorObj = require('jsupm_lsm303d'); + +// Instantiate a LSM303D instance using default i2c bus and address +var sensor = new sensorObj.LSM303D(); + +// now output data every 250 milliseconds +setInterval(function() +{ + // update our values from the sensor + sensor.update(); + + var data = sensor.getAccelerometer(); + console.log("Accelerometer x: " + + data.get(0) + + " y: " + data.get(1) + + " z: " + data.get(2) + + " g"); + + data = sensor.getMagnetometer(); + console.log("Magnetometer x: " + + data.get(0) + + " y: " + data.get(1) + + " z: " + data.get(2) + + " uT"); + + console.log("Temperature: " + + sensor.getTemperature()); + + console.log(); + +}, 250); + +// exit on ^C +process.on('SIGINT', function() +{ + sensor = null; + sensorObj.cleanUp(); + sensorObj = null; + console.log("Exiting."); + process.exit(0); +}); diff --git a/examples/python/lsm303d.py b/examples/python/lsm303d.py new file mode 100755 index 00000000..8af31c43 --- /dev/null +++ b/examples/python/lsm303d.py @@ -0,0 +1,71 @@ +#!/usr/bin/python +# Author: Jon Trulson +# Copyright (c) 2017 Intel Corporation. +# +# The MIT License +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +from __future__ import print_function +import time, sys, signal, atexit +from upm import pyupm_lsm303d as sensorObj + +def main(): + # Instantiate a BMP250E instance using default i2c bus and address + sensor = sensorObj.LSM303D() + + ## Exit handlers ## + # This function stops python from printing a stacktrace when you + # hit control-C + def SIGINTHandler(signum, frame): + raise SystemExit + + # This function lets you run code on exit + def exitHandler(): + print("Exiting") + sys.exit(0) + + # Register exit handlers + atexit.register(exitHandler) + signal.signal(signal.SIGINT, SIGINTHandler) + + # now output data every 250 milliseconds + while (1): + sensor.update() + + data = sensor.getAccelerometer() + print("Accelerometer x:", data[0], end=' ') + print(" y:", data[1], end=' ') + print(" z:", data[2], end=' ') + print(" g") + + data = sensor.getMagnetometer() + print("Magnetometer x:", data[0], end=' ') + print(" y:", data[1], end=' ') + print(" z:", data[2], end=' ') + print(" uT") + + print("Temperature: ", sensor.getTemperature()) + + print() + time.sleep(.250) + +if __name__ == '__main__': + main() diff --git a/src/lsm303d/CMakeLists.txt b/src/lsm303d/CMakeLists.txt new file mode 100644 index 00000000..fd3be399 --- /dev/null +++ b/src/lsm303d/CMakeLists.txt @@ -0,0 +1,8 @@ +upm_mixed_module_init (NAME lsm303d + DESCRIPTION "3-Axis eCompass module" + C_HDR lsm303d.h lsm303d_defs.h + C_SRC lsm303d.c + CPP_HDR lsm303d.hpp + CPP_SRC lsm303d.cxx + CPP_WRAPS_C + REQUIRES mraa) diff --git a/src/lsm303d/javaupm_lsm303d.i b/src/lsm303d/javaupm_lsm303d.i new file mode 100644 index 00000000..474b3e99 --- /dev/null +++ b/src/lsm303d/javaupm_lsm303d.i @@ -0,0 +1,24 @@ +%module javaupm_lsm303d +%include "../upm.i" +%include "typemaps.i" +%include "../upm_vectortypes.i" + +%ignore getMagnetometer(float *, float *, float *); +%ignore getAccelerometer(float *, float *, float *); + +%include "lsm303d_defs.h" +%include "lsm303d.hpp" +%{ + #include "lsm303d.hpp" +%} + +%pragma(java) jniclasscode=%{ + static { + try { + System.loadLibrary("javaupm_lsm303d"); + } catch (UnsatisfiedLinkError e) { + System.err.println("Native code library failed to load. \n" + e); + System.exit(1); + } + } +%} diff --git a/src/lsm303d/jsupm_lsm303d.i b/src/lsm303d/jsupm_lsm303d.i new file mode 100644 index 00000000..755ca61d --- /dev/null +++ b/src/lsm303d/jsupm_lsm303d.i @@ -0,0 +1,9 @@ +%module jsupm_lsm303d +%include "../upm.i" +%include "../upm_vectortypes.i" + +%include "lsm303d_defs.h" +%include "lsm303d.hpp" +%{ + #include "lsm303d.hpp" +%} diff --git a/src/lsm303d/lsm303d.c b/src/lsm303d/lsm303d.c new file mode 100644 index 00000000..24901bc3 --- /dev/null +++ b/src/lsm303d/lsm303d.c @@ -0,0 +1,417 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2017 Intel Corporation. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#include +#include + +#include "upm_utilities.h" + +#include "lsm303d.h" + + +// some useful macros to save on typing and text wrapping +#undef _SHIFT +#define _SHIFT(x) (_LSM303D_##x##_SHIFT) + +#undef _MASK +#define _MASK(x) (_LSM303D_##x##_MASK) + +#undef _SHIFTMASK +#define _SHIFTMASK(x) (_MASK(x) << _SHIFT(x)) + + +// init +lsm303d_context lsm303d_init(int bus, int addr) +{ + lsm303d_context dev = + (lsm303d_context)malloc(sizeof(struct _lsm303d_context)); + + if (!dev) + return NULL; + + // zero out context + memset((void *)dev, 0, sizeof(struct _lsm303d_context)); + + // make sure MRAA is initialized + if (mraa_init() != MRAA_SUCCESS) + { + printf("%s: mraa_init() failed.\n", __FUNCTION__); + lsm303d_close(dev); + return NULL; + } + + if (!(dev->i2c = mraa_i2c_init(bus))) + { + printf("%s: mraa_i2c_init() failed.\n", __FUNCTION__); + lsm303d_close(dev); + return NULL; + } + + if (mraa_i2c_address(dev->i2c, addr)) + { + printf("%s: mraa_i2c_address() failed.\n", __FUNCTION__); + lsm303d_close(dev); + return NULL; + } + + // check the chip id + uint8_t chipID = lsm303d_read_reg(dev, LSM303D_REG_WHO_AM_I); + + if (chipID != LSM303D_CHIPID) + { + printf("%s: invalid chip id: %02x. Expected %02x\n", + __FUNCTION__, chipID, LSM303D_CHIPID); + lsm303d_close(dev); + return NULL; + } + + // call devinit with a default high resolution mode + if (lsm303d_devinit(dev, LSM303D_M_RES_HIGH)) + { + printf("%s: lsm303d_devinit() failed.\n", __FUNCTION__); + lsm303d_close(dev); + return NULL; + } + + return dev; +} + +void lsm303d_close(lsm303d_context dev) +{ + assert(dev != NULL); + + if (dev->i2c) + mraa_i2c_stop(dev->i2c); + + free(dev); +} + +upm_result_t lsm303d_devinit(const lsm303d_context dev, + LSM303D_M_RES_T res) +{ + assert(dev != NULL); + + // enable all axes and BDU + uint8_t reg = lsm303d_read_reg(dev, LSM303D_REG_CTRL1); + + reg |= LSM303D_CTRL1_AXEN + | LSM303D_CTRL1_AYEN + | LSM303D_CTRL1_AZEN + | LSM303D_CTRL1_BDU; + + if (lsm303d_write_reg(dev, LSM303D_REG_CTRL1, reg)) + { + printf("%s: lsm303d_write_reg() failed.\n", __FUNCTION__); + return UPM_ERROR_OPERATION_FAILED; + } + + // enable temperature measurement and set mag resolution + reg = lsm303d_read_reg(dev, LSM303D_REG_CTRL5); + reg &= ~_SHIFTMASK(CTRL5_MRES); + reg |= LSM303D_CTRL5_TEMP_EN + | (res << _SHIFT(CTRL5_MRES)); + + if (lsm303d_write_reg(dev, LSM303D_REG_CTRL5, reg)) + { + printf("%s: lsm303d_write_reg() failed.\n", __FUNCTION__); + return UPM_ERROR_OPERATION_FAILED; + } + + // set magnetometer to continuous mode + reg = lsm303d_read_reg(dev, LSM303D_REG_CTRL7); + reg &= ~_SHIFTMASK(CTRL7_MD); + reg |= (LSM303D_MD_CONTINUOUS << _SHIFT(CTRL7_MD)); + + if (lsm303d_write_reg(dev, LSM303D_REG_CTRL7, reg)) + { + printf("%s: lsm303d_write_reg() failed.\n", __FUNCTION__); + return UPM_ERROR_OPERATION_FAILED; + } + + // set ACC ODR to 100Hz by default + if (lsm303d_set_acc_odr(dev, LSM303D_AODR_100HZ)) + { + printf("%s: lsm303d_set_acc_odr() failed.\n", __FUNCTION__); + return UPM_ERROR_OPERATION_FAILED; + } + + // set MAG ODR to 12.5Hz by default + if (lsm303d_set_mag_odr(dev, LSM303D_MODR_12_5HZ)) + { + printf("%s: lsm303d_set_acc_odr() failed.\n", __FUNCTION__); + return UPM_ERROR_OPERATION_FAILED; + } + + // default to 2G acc sensitivity + if (lsm303d_set_acc_full_scale(dev, LSM303D_AFS_2G)) + { + printf("%s: lsm303d_set_acc_full_scale() failed.\n", __FUNCTION__); + return UPM_ERROR_OPERATION_FAILED; + } + + // default to 2 Gauss mag sensitivity + if (lsm303d_set_mag_full_scale(dev, LSM303D_MFS_2)) + { + printf("%s: lsm303d_set_acc_full_scale() failed.\n", __FUNCTION__); + return UPM_ERROR_OPERATION_FAILED; + } + + upm_delay_ms(10); + + return UPM_SUCCESS; +} + +upm_result_t lsm303d_set_acc_full_scale(const lsm303d_context dev, + LSM303D_AFS_T fs) +{ + assert(dev != NULL); + + uint8_t reg = lsm303d_read_reg(dev, LSM303D_REG_CTRL2); + + reg &= ~_SHIFTMASK(CTRL2_AFS); + reg |= (fs << _SHIFT(CTRL2_AFS)); + + if (lsm303d_write_reg(dev, LSM303D_REG_CTRL2, reg)) + return UPM_ERROR_OPERATION_FAILED; + + upm_delay_ms(50); + + // set our scaling factor depending on current FS + switch(fs) + { + case LSM303D_AFS_2G: + dev->accScale = 0.061; + break; + + case LSM303D_AFS_4G: + dev->accScale = 0.122; + break; + + case LSM303D_AFS_6G: + dev->accScale = 0.183; + break; + + case LSM303D_AFS_8G: + dev->accScale = 0.320; + break; + + case LSM303D_AFS_16G: + dev->accScale = 0.732; + break; + } + + return UPM_SUCCESS; +} + +upm_result_t lsm303d_set_mag_full_scale(const lsm303d_context dev, + LSM303D_MFS_T fs) +{ + assert(dev != NULL); + + uint8_t reg = lsm303d_read_reg(dev, LSM303D_REG_CTRL6); + + reg &= ~_SHIFTMASK(CTRL6_MFS); + reg |= (fs << _SHIFT(CTRL6_MFS)); + + if (lsm303d_write_reg(dev, LSM303D_REG_CTRL6, reg)) + return UPM_ERROR_OPERATION_FAILED; + + upm_delay_ms(50); + + // set our scaling factor depending on current FS + switch(fs) + { + case LSM303D_MFS_2: + dev->magScale = 0.080; + break; + + case LSM303D_MFS_4: + dev->magScale = 0.160; + break; + + case LSM303D_MFS_8: + dev->magScale = 0.320; + break; + + case LSM303D_MFS_12: + dev->magScale = 0.479; + break; + } + + return UPM_SUCCESS; +} + +upm_result_t lsm303d_update(const lsm303d_context dev) +{ + assert(dev != NULL); + + const int maxLen = 6; + uint8_t buf[maxLen]; + + // get the temperature first, only 2 bytes + if (lsm303d_read_regs(dev, LSM303D_REG_TEMP_OUT_L, buf, 2) != 2) + { + printf("%s: lsm303d_read_regs(temp) failed.\n", __FUNCTION__); + return UPM_ERROR_OPERATION_FAILED; + } + + dev->temperature = (float)( (int16_t)(buf[0] | (buf[1] << 8)) << 4); + + // next, acc data + if (lsm303d_read_regs(dev, LSM303D_REG_OUT_X_L_A, buf, + maxLen) != maxLen) + { + printf("%s: lsm303d_read_regs(acc) failed.\n", __FUNCTION__); + return UPM_ERROR_OPERATION_FAILED; + } + + dev->accX = (float)((int16_t)(buf[0] | (buf[1] << 8))); + dev->accY = (float)((int16_t)(buf[2] | (buf[3] << 8))); + dev->accZ = (float)((int16_t)(buf[4] | (buf[5] << 8))); + + // now mag data + if (lsm303d_read_regs(dev, LSM303D_REG_OUT_X_L_M, buf, + maxLen) != maxLen) + { + printf("%s: lsm303d_read_regs(mag) failed.\n", __FUNCTION__); + return UPM_ERROR_OPERATION_FAILED; + } + + dev->magX = (float)((int16_t)(buf[0] | (buf[1] << 8))); + dev->magY = (float)((int16_t)(buf[2] | (buf[3] << 8))); + dev->magZ = (float)((int16_t)(buf[4] | (buf[5] << 8))); + + return UPM_SUCCESS; +} + +uint8_t lsm303d_read_reg(const lsm303d_context dev, uint8_t reg) +{ + assert(dev != NULL); + + int rv = mraa_i2c_read_byte_data(dev->i2c, reg); + if (rv < 0) + { + printf("%s: mraa_i2c_read_byte_data() failed\n", __FUNCTION__); + return 0xff; + } + + return (uint8_t)rv; +} + +int lsm303d_read_regs(const lsm303d_context dev, uint8_t reg, + uint8_t *buffer, int len) +{ + assert(dev != NULL); + + reg |= 0x80; // enable auto-increment + if (mraa_i2c_read_bytes_data(dev->i2c, reg, buffer, len) != len) + return -1; + + return len; +} + +upm_result_t lsm303d_write_reg(const lsm303d_context dev, + uint8_t reg, uint8_t val) +{ + assert(dev != NULL); + + if (mraa_i2c_write_byte_data(dev->i2c, val, reg)) + { + printf("%s: mraa_i2c_write_byte_data() failed.\n", + __FUNCTION__); + return UPM_ERROR_OPERATION_FAILED; + } + + return UPM_SUCCESS; +} + +float lsm303d_get_temperature(const lsm303d_context dev) +{ + assert(dev != NULL); + + // It's not clear how to compute this from the datasheet, but this + // seems to give a reasonably accurate result. + return (dev->temperature / 128.0) + 25.0; +} + +void lsm303d_get_magnetometer(const lsm303d_context dev, + float *x, float *y, float *z) +{ + assert(dev != NULL); + + // Output is in milli-Gauss - we convert and return it in uT (SI + // micro-teslas) instead. + if (x) + *x = (dev->magX * dev->magScale) / 10.0; + if (y) + *y = (dev->magY * dev->magScale) / 10.0; + if (z) + *z = (dev->magZ * dev->magScale) / 10.0; +} + +void lsm303d_get_accelerometer(const lsm303d_context dev, + float *x, float *y, float *z) +{ + assert(dev != NULL); + + if (x) + *x = (dev->accX * dev->accScale) / 1000.0; + if (y) + *y = (dev->accY * dev->accScale) / 1000.0; + if (z) + *z = (dev->accZ * dev->accScale) / 1000.0; +} + +upm_result_t lsm303d_set_acc_odr(const lsm303d_context dev, + LSM303D_AODR_T odr) +{ + assert(dev != NULL); + + uint8_t reg = lsm303d_read_reg(dev, LSM303D_REG_CTRL1); + reg &= ~_SHIFTMASK(CTRL1_AODR); + reg |= (odr << _SHIFT(CTRL1_AODR)); + + if (lsm303d_write_reg(dev, LSM303D_REG_CTRL1, reg)) + return UPM_ERROR_OPERATION_FAILED; + + return UPM_SUCCESS; +} + +upm_result_t lsm303d_set_mag_odr(const lsm303d_context dev, + LSM303D_MODR_T odr) +{ + assert(dev != NULL); + + uint8_t reg = lsm303d_read_reg(dev, LSM303D_REG_CTRL5); + reg &= ~_SHIFTMASK(CTRL5_MODR); + reg |= (odr << _SHIFT(CTRL5_MODR)); + + if (lsm303d_write_reg(dev, LSM303D_REG_CTRL5, reg)) + return UPM_ERROR_OPERATION_FAILED; + + return UPM_SUCCESS; +} diff --git a/src/lsm303d/lsm303d.cxx b/src/lsm303d/lsm303d.cxx new file mode 100644 index 00000000..13639e57 --- /dev/null +++ b/src/lsm303d/lsm303d.cxx @@ -0,0 +1,142 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2017 Intel Corporation. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "lsm303d.hpp" + +using namespace upm; +using namespace std; + +LSM303D::LSM303D(int bus, int addr) : + m_lsm303d(lsm303d_init(bus, addr)) +{ + if (!m_lsm303d) + throw std::runtime_error(string(__FUNCTION__) + + ": lsm303d_init() failed"); +} + +LSM303D::~LSM303D() +{ + lsm303d_close(m_lsm303d); +} + +void LSM303D::init(LSM303D_M_RES_T res) +{ + if (lsm303d_devinit(m_lsm303d, res)) + throw std::runtime_error(string(__FUNCTION__) + + ": lsm303d_devinit() failed"); +} + +void LSM303D::update() +{ + if (lsm303d_update(m_lsm303d)) + throw std::runtime_error(string(__FUNCTION__) + + ": lsm303d_update() failed"); +} + +uint8_t LSM303D::readReg(uint8_t reg) +{ + return lsm303d_read_reg(m_lsm303d, reg); +} + +int LSM303D::readRegs(uint8_t reg, uint8_t *buffer, int len) +{ + int rv = lsm303d_read_regs(m_lsm303d, reg, buffer, len); + if (rv < 0) + throw std::runtime_error(string(__FUNCTION__) + + ": lsm303d_read_regs() failed"); + + return rv; +} + +void LSM303D::writeReg(uint8_t reg, uint8_t val) +{ + if (lsm303d_write_reg(m_lsm303d, reg, val)) + throw std::runtime_error(string(__FUNCTION__) + + ": lsm303d_write_reg() failed"); +} + +void LSM303D::getMagnetometer(float *x, float *y, float *z) +{ + lsm303d_get_magnetometer(m_lsm303d, x, y, z); +} + +std::vector LSM303D::getMagnetometer() +{ + float v[3]; + + getMagnetometer(&v[0], &v[1], &v[2]); + return std::vector(v, v+3); +} + +void LSM303D::getAccelerometer(float *x, float *y, float *z) +{ + lsm303d_get_accelerometer(m_lsm303d, x, y, z); +} + +std::vector LSM303D::getAccelerometer() +{ + float v[3]; + + getAccelerometer(&v[0], &v[1], &v[2]); + return std::vector(v, v+3); +} + +float LSM303D::getTemperature() +{ + return lsm303d_get_temperature(m_lsm303d); +} + +void LSM303D::setAccelerometerFullScale(LSM303D_AFS_T fs) +{ + if (lsm303d_set_acc_full_scale(m_lsm303d, fs)) + throw std::runtime_error(string(__FUNCTION__) + + ": lsm303d_set_acc_full_scale() failed"); +} + +void LSM303D::setMagnetometerFullScale(LSM303D_MFS_T fs) +{ + if (lsm303d_set_mag_full_scale(m_lsm303d, fs)) + throw std::runtime_error(string(__FUNCTION__) + + ": lsm303d_set_mag_full_scale() failed"); +} +void LSM303D::setAccelerometerODR(LSM303D_AODR_T odr) +{ + if (lsm303d_set_acc_odr(m_lsm303d, odr)) + throw std::runtime_error(string(__FUNCTION__) + + ": lsm303d_set_acc_odr() failed"); +} + +void LSM303D::setMagnetometerODR(LSM303D_MODR_T odr) +{ + if (lsm303d_set_mag_odr(m_lsm303d, odr)) + throw std::runtime_error(string(__FUNCTION__) + + ": lsm303d_set_mag_odr() failed"); +} diff --git a/src/lsm303d/lsm303d.h b/src/lsm303d/lsm303d.h new file mode 100644 index 00000000..b156ae49 --- /dev/null +++ b/src/lsm303d/lsm303d.h @@ -0,0 +1,238 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2017 Intel Corporation. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#pragma once + +#include +#include + +#include +#include + +#include "upm.h" + +#include "lsm303d_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + + /** + * @file lsm303d.h + * @library lsm303d + * @brief C API for the lsm303d driver + * + * @include lsm303d.c + */ + + /** + * Device context + */ + typedef struct _lsm303d_context { + mraa_i2c_context i2c; + + // uncompensated temperature in C + float temperature; + + // accelerometer scaling + float accScale; + + // magnetometer scaling + float magScale; + + // uncompensated acc data + float accX; + float accY; + float accZ; + + // uncompensated mag data + float magX; + float magY; + float magZ; + } *lsm303d_context; + + + /** + * LSM303D initialization + * + * This driver only supports I2C. + * + * Due to the fact that this chip is currently obsolete, we only + * support minimum functionality. + * + * @param bus I2C bus to use + * @param addr The I2C address of the device + * @return The device context, or NULL if an error occurred + */ + lsm303d_context lsm303d_init(int bus, int addr); + + /** + * LSM303D Destructor + * + * @param dev The device context + */ + void lsm303d_close(lsm303d_context dev); + + /** + * Update the internal stored values from sensor data + * + * @param dev The device context + * @return UPM result + */ + upm_result_t lsm303d_update(const lsm303d_context dev); + + /** + * Return magnetometer data in micro-Teslas (uT). update() must + * have been called prior to calling this function. + * + * @param dev The device context + * @param x Pointer to a floating point value that will have the + * current x component placed into it + * @param y Pointer to a floating point value that will have the + * current y component placed into it + * @param z Pointer to a floating point value that will have the + * current z component placed into it + */ + void lsm303d_get_magnetometer(const lsm303d_context dev, + float *x, float *y, float *z); + + /** + * Return accelerometer data in gravities. update() must have + * been called prior to calling this function. + * + * @param dev The device context + * @param x Pointer to a floating point value that will have the + * current x component placed into it + * @param y Pointer to a floating point value that will have the + * current y component placed into it + * @param z Pointer to a floating point value that will have the + * current z component placed into it + */ + void lsm303d_get_accelerometer(const lsm303d_context dev, + float *x, float *y, float *z); + + /** + * Return temperature data in degrees Celsius.. update() must + * have been called prior to calling this function. + * + * @param dev The device context + * @return Temperature in degrees Celsius + */ + float lsm303d_get_temperature(const lsm303d_context dev); + + /** + * Set the full scale (sensitivity) value for the accelerometer. + * This device supports 2G, 4G, 6G, 8G, and 16G full scale modes. + * + * @param dev The device context + * @param fs One of the LSM303D_AFS_T values + * @return UPM result + */ + upm_result_t lsm303d_set_acc_full_scale(const lsm303d_context dev, + LSM303D_AFS_T fs); + + /** + * Set the full scale (sensitivity) value for the magnetometer. + * This device supports 2, 4, 8, and 16 Gauss. + * + * @param dev The device context + * @param fs One of the LSM303D_MFS_T values + * @return UPM result + */ + upm_result_t lsm303d_set_mag_full_scale(const lsm303d_context dev, + LSM303D_MFS_T fs); + + /** + * Initialize the device and start operation. This function is + * called from the constructor so it will not typically need to be + * called by a user unless the device is reset. It will + * initialize the accelerometer and magnetometer (if enabled) to + * certain default running modes. + * + * @param dev The device context + * @param res One of the LSM303D_M_RES_T values. This value sets + * the resolution of the magnetometer. At init time, this value + * is set to LSM303D_M_RES_HIGH. + * @return UPM result + */ + upm_result_t lsm303d_devinit(const lsm303d_context dev, + LSM303D_M_RES_T res); + + /** + * Set the accelerometer (acc) output data rate (odr) + * + * @param dev The device context + * @param odr One of the LSM303D_AODR_T values. The default + * set at initialization time is LSM303D_AODR_100HZ. + * @return UPM result + */ + upm_result_t lsm303d_set_acc_odr(const lsm303d_context dev, + LSM303D_AODR_T odr); + + /** + * Set the magnetometer (mag) output data rate (odr) + * + * @param dev The device context + * @param odr One of the LSM303D_MODR_T values. The default + * set at initialization time is LSM303D_MODR_12_5HZ. + * @return UPM result + */ + upm_result_t lsm303d_set_mag_odr(const lsm303d_context dev, + LSM303D_MODR_T odr); + + /** + * Read a register. + * + * @param dev The device context + * @param reg The register to read + * @return The value of the register + */ + uint8_t lsm303d_read_reg(const lsm303d_context dev, uint8_t reg); + + /** + * Read contiguous registers into a buffer + * + * @param dev The device context + * @param buffer The buffer to store the results + * @param len The number of registers to read + * @return The number of bytes read, or -1 on error + */ + int lsm303d_read_regs(const lsm303d_context dev, uint8_t reg, + uint8_t *buffer, int len); + + /** + * Write to a register + * + * @param dev The device context + * @param reg The register to write to + * @param val The value to write + * @return UPM result + */ + upm_result_t lsm303d_write_reg(const lsm303d_context dev, + uint8_t reg, uint8_t val); + +#ifdef __cplusplus +} +#endif diff --git a/src/lsm303d/lsm303d.hpp b/src/lsm303d/lsm303d.hpp new file mode 100644 index 00000000..3f0e3ffd --- /dev/null +++ b/src/lsm303d/lsm303d.hpp @@ -0,0 +1,242 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2017 Intel Corporation. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#pragma once + +#include +#include + +#include +#include "lsm303d.h" + +namespace upm { + + /** + * @brief ST Microelectronics Ultra-compact high-performance + * eCompass module + * @defgroup lsm303d libupm-lsm303d + * @ingroup i2c gpio stmicro compass accelerometer + */ + + /** + * @library lsm303d + * @sensor lsm303d + * @comname Ultra-compact high-performance eCompass module + * @type compass + * @man stmicro + * @con i2c gpio + * @web http://www.st.com/en/mems-and-sensors/lsm303d.html + * + * @brief API for the LSM303D 3-Axis Geomagnetic Sensor + * + * The LSM303D is an ultra-low-power high-performance + * system-in-package featuring a 3D digital linear acceleration + * sensor and a 3D digital magnetic sensor. The LSM303D has + * linear acceleration full scales of 2g/4g/8g/16g and a + * magnetic field dynamic range of 50 Gauss. + * + * Not all functionality of this chip has been implemented in this + * driver, however all the pieces are present to add any desired + * functionality. This driver supports only I2C operation. + * + * This device requires 3.3v operation. + * + * @snippet lsm303d.cxx Interesting + */ + + class LSM303D { + public: + /** + * LSM303D constructor + * + * This driver only supports I2C. + * + * Due to the fact that this chip is currently obsolete, we only + * support minimum functionality. + * + * @param bus I2C bus to use + * @param addr The I2C address of the device + * @return The device context, or NULL if an error occurred + * @throws std::runtime_error on failure. + */ + LSM303D(int bus=LSM303D_DEFAULT_I2C_BUS, + int addr=LSM303D_DEFAULT_I2C_ADDR); + + /** + * LSM303D Destructor + */ + ~LSM303D(); + + /** + * Update the internal stored values from sensor data. This + * method must be called before querying the acceleration, + * magnetometer, or temperature. + * + * @throws std::runtime_error on failure + */ + void update(); + + /** + * Return magnetometer data in micro-Teslas (uT). update() must + * have been called prior to calling this method. + * + * @param x Pointer to a floating point value that will have the + * current x component placed into it + * @param y Pointer to a floating point value that will have the + * current y component placed into it + * @param z Pointer to a floating point value that will have the + * current z component placed into it + */ + void getMagnetometer(float *x, float *y, float *z); + + /** + * Return magnetometer data in micro-Teslas (uT) in the form + * of a floating point vector. update() must have been called + * prior to calling this method. + * + * @return A floating point vector containing x, y, and z in + * that order + */ + std::vector getMagnetometer(); + + /** + * Return acceleration data in gravities. update() must have + * been called prior to calling this method. + * + * @param x Pointer to a floating point value that will have the + * current x component placed into it + * @param y Pointer to a floating point value that will have the + * current y component placed into it + * @param z Pointer to a floating point value that will have the + * current z component placed into it + */ + void getAccelerometer(float *x, float *y, float *z); + + /** + * Return acceleration data in gravities in the form of a + * floating point vector. update() must have been called + * prior to calling this method. + * + * @return A floating point vector containing x, y, and z in + * that order + */ + std::vector getAccelerometer(); + + /** + * Return temperature data in degrees Celsius. NOTE: This is + * not the ambient room temperature. update() must have been + * called prior to calling this method. + * + * @return Temperature in degrees Celsius + */ + float getTemperature(); + + /** + * Initialize the device and start operation. This function + * is called from the constructor so it will not typically + * need to be called by a user unless the device is reset. It + * will initialize the accelerometer and magnetometer (if + * enabled) to certain default running modes. + * + * @param res One of the LSM303D_M_RES_T values. This value + * sets the resolution of the magnetometer. At init time, + * this value is set to LSM303D_M_RES_HIGH. + * @throws std::runtime_error on failure + */ + void init(LSM303D_M_RES_T res); + + /** + * Set the full scale (sensitivity) value for the + * accelerometer. This device supports 2G, 4G, 6G, 8G, and + * 16G full scale modes. + * + * @param fs One of the LSM303D_AFS_T values + * @throws std::runtime_error on failure + */ + void setAccelerometerFullScale(LSM303D_AFS_T fs); + + /** + * Set the full scale (sensitivity) value for the + * magnetometer. This device supports 2, 4, 8, and + * 16 Gauss full scale modes. + * + * @param fs One of the LSM303D_MFS_T values + * @throws std::runtime_error on failure + */ + void setMagnetometerFullScale(LSM303D_MFS_T fs); + + /** + * Set the accelerometer output data rate (ODR) + * + * @param odr One of the LSM303D_AODR_T values. The default + * set at initialization time is LSM303D_AODR_100HZ. + * @throws std::runtime_error on failure + */ + void setAccelerometerODR(LSM303D_AODR_T odr); + + /** + * Set the magnetometer output data rate (ODR) + * + * @param odr One of the LSM303D_MODR_T values. + * The default set at initialization time is + * LSM303D_MODR_12_5HZ. + * @throws std::runtime_error on failure + */ + void setMagnetometerODR(LSM303D_MODR_T odr); + + protected: + // our underlying device context + lsm303d_context m_lsm303d; + + /** + * Read a register + * + * @param reg The register to read + * @return The value of the register + */ + uint8_t readReg(uint8_t reg); + + /** + * Read contiguous registers into a buffer + * + * @param buffer The buffer to store the results + * @param len The number of registers to read + * @return The number of bytes read + * @throws std::runtime_error on failure + */ + int readRegs(uint8_t reg, uint8_t *buffer, int len); + + /** + * Write to a register + * + * @param reg The register to write to + * @param val The value to write + * @throws std::runtime_error on failure + */ + void writeReg(uint8_t reg, uint8_t val); + + private: + }; +} diff --git a/src/lsm303d/lsm303d_defs.h b/src/lsm303d/lsm303d_defs.h new file mode 100644 index 00000000..ccbcef7a --- /dev/null +++ b/src/lsm303d/lsm303d_defs.h @@ -0,0 +1,301 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2017 Intel Corporation. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + + +#define LSM303D_DEFAULT_I2C_BUS 0 +#define LSM303D_DEFAULT_I2C_ADDR 0x1e + +// from the WHO_AM_I_* register +#define LSM303D_CHIPID 0x49 + + + // Due to the fact that this chip is currently obsolete, we only + // support minimum functionality. This register map is not + // complete. While all registers are specified, bitfields and + // enumerants are only specified for certain registers of + // interest. Feel free to add what you need. + + // NOTE: Reserved registers must not be written into or permanent + // damage to the device can result. Reading from them may return + // indeterminate values. Registers containing reserved bitfields + // must be written as 0. + + /** + * LSM303D registers + */ + typedef enum { + + // 0x00-0x04 reserved + + LSM303D_REG_TEMP_OUT_L = 0x05, + LSM303D_REG_TEMP_OUT_H = 0x06, + + LSM303D_REG_STATUS_M = 0x07, + + LSM303D_REG_OUT_X_L_M = 0x08, + LSM303D_REG_OUT_X_H_M = 0x09, + LSM303D_REG_OUT_Y_L_M = 0x0a, + LSM303D_REG_OUT_Y_H_M = 0x0b, + LSM303D_REG_OUT_Z_L_M = 0x0c, + LSM303D_REG_OUT_Z_H_M = 0x0d, + + // 0x0e reserved + + LSM303D_REG_WHO_AM_I = 0x0f, + + // 0x10-0x11 reserved + + LSM303D_REG_INT_CTRL_M = 0x12, + LSM303D_REG_INT_SRC_M = 0x13, + LSM303D_REG_INT_THS_L_M = 0x14, + LSM303D_REG_INT_THS_H_M = 0x15, + + LSM303D_REG_OFFSET_X_L_M = 0x16, + LSM303D_REG_OFFSET_X_H_M = 0x17, + LSM303D_REG_OFFSET_Y_L_M = 0x18, + LSM303D_REG_OFFSET_Y_H_M = 0x19, + LSM303D_REG_OFFSET_Z_L_M = 0x1a, + LSM303D_REG_OFFSET_Z_H_M = 0x1b, + + LSM303D_REG_REFERENCE_X = 0x1c, + LSM303D_REG_REFERENCE_Y = 0x1d, + LSM303D_REG_REFERENCE_Z = 0x1e, + + LSM303D_REG_CTRL0 = 0x1f, + LSM303D_REG_CTRL1 = 0x20, + LSM303D_REG_CTRL2 = 0x21, + LSM303D_REG_CTRL3 = 0x22, + LSM303D_REG_CTRL4 = 0x23, + LSM303D_REG_CTRL5 = 0x24, + LSM303D_REG_CTRL6 = 0x25, + LSM303D_REG_CTRL7 = 0x26, + + LSM303D_REG_STATUS_A = 0x27, + + LSM303D_REG_OUT_X_L_A = 0x28, + LSM303D_REG_OUT_X_H_A = 0x29, + LSM303D_REG_OUT_Y_L_A = 0x2a, + LSM303D_REG_OUT_Y_H_A = 0x2b, + LSM303D_REG_OUT_Z_L_A = 0x2c, + LSM303D_REG_OUT_Z_H_A = 0x2d, + + LSM303D_REG_FIFO_CTRL = 0x2e, + LSM303D_REG_FIFO_SRC = 0x2f, + + LSM303D_REG_IG_CFG1 = 0x30, + LSM303D_REG_IG_SRC1 = 0x31, + LSM303D_REG_IG_THS1 = 0x32, + LSM303D_REG_IG_DUR1 = 0x33, + LSM303D_REG_IG_CFG2 = 0x34, + LSM303D_REG_IG_SRC2 = 0x35, + LSM303D_REG_IG_THS2 = 0x36, + LSM303D_REG_IG_DUR2 = 0x37, + + LSM303D_REG_CLICK_CFG = 0x38, + LSM303D_REG_CLICK_SRC = 0x39, + LSM303D_REG_CLICK_THS = 0x3a, + + LSM303D_REG_TIME_LIMIT = 0x3b, + LSM303D_REG_TIME_LATENCY = 0x3c, + LSM303D_REG_TIME_WINDOW = 0x3d, + + LSM303D_REG_ACT_THS = 0x3e, + LSM303D_REG_ACT_DUR = 0x3f, + } LSM303D_REGS_T; + + // Accelerometer registers + + /** + * CTRL1 bits + */ + typedef enum { + LSM303D_CTRL1_AXEN = 0x01, // axis enables + LSM303D_CTRL1_AYEN = 0x02, + LSM303D_CTRL1_AZEN = 0x04, + + LSM303D_CTRL1_BDU = 0x08, + + LSM303D_CTRL1_AODR0 = 0x10, + LSM303D_CTRL1_AODR1 = 0x20, + LSM303D_CTRL1_AODR2 = 0x40, + LSM303D_CTRL1_AODR3 = 0x80, + _LSM303D_CTRL1_AODR_MASK = 15, + _LSM303D_CTRL1_AODR_SHIFT = 4, + } LSM303D_CTRL1_BITS_T; + + /** + * CTRL1_AODR values (and power mode) + */ + typedef enum { + LSM303D_AODR_POWER_DOWN = 0, + LSM303D_AODR_3_125HZ = 1, // 3.125Hz + LSM303D_AODR_6_25HZ = 2, + LSM303D_AODR_12_5HZ = 3, + LSM303D_AODR_25HZ = 4, + LSM303D_AODR_50HZ = 5, + LSM303D_AODR_100HZ = 6, + LSM303D_AODR_200HZ = 7, + LSM303D_AODR_400HZ = 8, + LSM303D_AODR_800HZ = 9, + LSM303D_AODR_1600HZ = 10, + } LSM303D_AODR_T; + + /** + * CTRL2 bits + */ + typedef enum { + LSM303D_CTRL2_SIM = 0x01, + LSM303D_CTRL2_AST = 0x02, + + // 0x04 reserved + + LSM303D_CTRL2_AFS0 = 0x08, // full scale + LSM303D_CTRL2_AFS1 = 0x10, + LSM303D_CTRL2_AFS2 = 0x20, + _LSM303D_CTRL2_AFS_MASK = 7, + _LSM303D_CTRL2_AFS_SHIFT = 3, + + LSM303D_CTRL2_ABW0 = 0x40, + LSM303D_CTRL2_ABW1 = 0x80, + _LSM303D_CTRL2_ABW_MASK = 3, + _LSM303D_CTRL2_ABW_SHIFT = 6, + } LSM303D_CTRL2_BITS_T; + + /** + * CTRL2_AFS values (full scale) + */ + typedef enum { + LSM303D_AFS_2G = 0, // 2G + LSM303D_AFS_4G = 1, + LSM303D_AFS_6G = 2, + LSM303D_AFS_8G = 3, + LSM303D_AFS_16G = 4, + } LSM303D_AFS_T; + + /** + * CTRL5 bits + */ + typedef enum { + LSM303D_CTRL5_LIR1 = 0x01, + LSM303D_CTRL5_LIR2 = 0x02, + + LSM303D_CTRL5_MODR0 = 0x04, // mag odr + LSM303D_CTRL5_MODR1 = 0x08, + LSM303D_CTRL5_MODR2 = 0x10, + _LSM303D_CTRL5_MODR_MASK = 7, + _LSM303D_CTRL5_MODR_SHIFT = 2, + + LSM303D_CTRL5_M_RES0 = 0x20, // resolution + LSM303D_CTRL5_M_RES1 = 0x40, + _LSM303D_CTRL5_MRES_MASK = 3, + _LSM303D_CTRL5_MRES_SHIFT = 6, + + LSM303D_CTRL5_TEMP_EN = 0x80, + } LSM303D_CTRL5_BITS_T; + + /** + * CTRL5_MODR values (mag output data rate) + */ + typedef enum { + LSM303D_MODR_3_125HZ = 0, // 3.125Hz + LSM303D_MODR_6_25HZ = 1, + LSM303D_MODR_12_5HZ = 2, + LSM303D_MODR_25HZ = 3, + LSM303D_MODR_50HZ = 4, + LSM303D_MODR_100HZ = 5, + } LSM303D_MODR_T; + + /** + * CTRL5_M_RES values (resolution) + */ + typedef enum { + LSM303D_M_RES_LOW = 0, + LSM303D_M_RES_HIGH = 3, + } LSM303D_M_RES_T; + + /** + * CTRL6 bits + */ + typedef enum { + // 0x01-0x10 reserved + + LSM303D_CTRL6_MFS0 = 0x20, + LSM303D_CTRL6_MFS1 = 0x40, + _LSM303D_CTRL6_MFS_MASK = 3, + _LSM303D_CTRL6_MFS_SHIFT = 5, + + // 0x80 reserved + } LSM303D_CTRL6_BITS_T; + + /** + * CTRL6_MFS values (mag full scale) + */ + typedef enum { + LSM303D_MFS_2 = 0, // 2 Gauss + LSM303D_MFS_4 = 1, + LSM303D_MFS_8 = 2, + LSM303D_MFS_12 = 3, + } LSM303D_MFS_T; + + /** + * CTRL7 bits + */ + typedef enum { + LSM303D_CTRL7_MD0 = 0x01, + LSM303D_CTRL7_MD1 = 0x02, + _LSM303D_CTRL7_MD_MASK = 3, + _LSM303D_CTRL7_MD_SHIFT = 0, + + LSM303D_CTRL7_MLP = 0x04, + + // 0x08 reserved + + LSM303D_CTRL7_T_ONLY = 0x10, + LSM303D_CTRL7_AFDS = 0x20, + + LSM303D_CTRL7_AHPM0 = 0x40, + LSM303D_CTRL7_AHPM1 = 0x80, + _LSM303D_CTRL7_AHPM_MASK = 3, + _LSM303D_CTRL7_AHPM_SHIFT = 6, + } LSM303D_CTRL7_BITS_T; + + /** + * CTRL7_MD values (power mode) + */ + typedef enum { + LSM303D_MD_CONTINUOUS = 0, + LSM303D_MD_SINGLE = 1, + LSM303D_MD_POWER_DOWN = 3, // 2 is pwr down too + } LSM303D_MD_T; + +#ifdef __cplusplus +} +#endif diff --git a/src/lsm303d/pyupm_lsm303d.i b/src/lsm303d/pyupm_lsm303d.i new file mode 100644 index 00000000..3f6d849b --- /dev/null +++ b/src/lsm303d/pyupm_lsm303d.i @@ -0,0 +1,17 @@ +// Include doxygen-generated documentation +%include "pyupm_doxy2swig.i" +%module pyupm_lsm303d +%include "../upm.i" +%include "../upm_vectortypes.i" + +%feature("autodoc", "3"); + +#ifdef DOXYGEN +%include "lsm303d_doc.i" +#endif + +%include "lsm303d_defs.h" +%include "lsm303d.hpp" +%{ + #include "lsm303d.hpp" +%}