diff --git a/examples/c++/lis2ds12.cxx b/examples/c++/lis2ds12.cxx new file mode 100644 index 00000000..8845027a --- /dev/null +++ b/examples/c++/lis2ds12.cxx @@ -0,0 +1,81 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016 Intel Corporation. + * + * 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 "lis2ds12.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 LIS2DS12 using default I2C parameters + upm::LIS2DS12 sensor; + + // For SPI, bus 0, you would pass -1 as the address, and a valid pin + // for CS: LIS2DS12(0, -1, 10); + + // 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; + + // we show both C and F for temperature + cout << "Compensation Temperature: " << sensor.getTemperature() + << " C / " << sensor.getTemperature(true) << " F" + << endl; + + cout << endl; + + usleep(250000); + } + +//! [Interesting] + + cout << "Exiting..." << endl; + + return 0; +} diff --git a/examples/c/lis2ds12.c b/examples/c/lis2ds12.c new file mode 100644 index 00000000..6a395585 --- /dev/null +++ b/examples/c/lis2ds12.c @@ -0,0 +1,100 @@ +/* + * 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 "lis2ds12.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] + +#if defined(CONFIG_BOARD_ARDUINO_101_SSS) + // ARDUINO_101_SSS (ARC core) must use I2C + // Instantiate a LIS2DS12 instance using default i2c bus and address + lis2ds12_context sensor = lis2ds12_init(LIS2DS12_DEFAULT_I2C_BUS, + LIS2DS12_DEFAULT_I2C_ADDR, -1); +#elif defined(CONFIG_BOARD_ARDUINO_101) + // ARDUINO_101 (Quark core) must use SPI + // Instantiate a LIS2DS12 instance using default SPI bus and pin 10 as CS + lis2ds12_context sensor = lis2ds12_init(LIS2DS12_DEFAULT_SPI_BUS, + -1, 10); +#else + // everything else use I2C by default + // Instantiate a LIS2DS12 instance using default i2c bus and address + lis2ds12_context sensor = lis2ds12_init(LIS2DS12_DEFAULT_I2C_BUS, + LIS2DS12_DEFAULT_I2C_ADDR, -1); +#endif + + if (!sensor) + { + printf("lis2ds12_init() failed.\n"); + return 1; + } + + // now output data every 250 milliseconds + while (shouldRun) + { + float x, y, z; + + if (lis2ds12_update(sensor)) + { + printf("lis2ds12_update() failed\n"); + lis2ds12_close(sensor); + return 1; + } + + lis2ds12_get_accelerometer(sensor, &x, &y, &z); + printf("Acceleration x: %f y: %f z: %f g\n", + x, y, z); + + printf("Compensation Temperature: %f C\n\n", + lis2ds12_get_temperature(sensor)); + + upm_delay_ms(250); + } + + printf("Exiting...\n"); + + lis2ds12_close(sensor); + +//! [Interesting] + + return 0; +} diff --git a/examples/java/CMakeLists.txt b/examples/java/CMakeLists.txt index e3f6fd66..3437fd02 100644 --- a/examples/java/CMakeLists.txt +++ b/examples/java/CMakeLists.txt @@ -190,6 +190,7 @@ add_example(LSM303AGR_Example lsm303agr) add_example(LSM303D_Example lsm303d) add_example(VEML6070Sample veml6070) add_example(RN2903_Example rn2903) +add_example(LIS2DS12_Example lis2ds12) add_example_with_path(Jhd1313m1_lcdSample jhd1313m1 jhd1313m1) add_example_with_path(Jhd1313m1Sample jhd1313m1 jhd1313m1) diff --git a/examples/java/LIS2DS12_Example.java b/examples/java/LIS2DS12_Example.java new file mode 100644 index 00000000..b56d307e --- /dev/null +++ b/examples/java/LIS2DS12_Example.java @@ -0,0 +1,64 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016-2017 Intel Corporation. + * + * 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_lis2ds12.*; + +public class LIS2DS12_Example +{ + public static void main(String[] args) throws InterruptedException + { +// ! [Interesting] + + // Instantiate a LIS2DS12 instance using default i2c bus and address + LIS2DS12 sensor = new LIS2DS12(); + + // For SPI, bus 0, you would pass -1 as the address, and a + // valid pin for CS: + // LIS2DS12(0, -1, 10); + + while (true) + { + // update our values from the sensor + sensor.update(); + + floatVector dataA = sensor.getAccelerometer(); + + System.out.println("Accelerometer x: " + dataA.get(0) + + " y: " + dataA.get(1) + + " z: " + dataA.get(2) + + " g"); + + System.out.println("Compensation Temperature: " + + sensor.getTemperature() + + " C / " + + sensor.getTemperature(true) + + " F"); + + System.out.println(); + Thread.sleep(250); + } + +// ! [Interesting] + } +} diff --git a/examples/javascript/lis2ds12.js b/examples/javascript/lis2ds12.js new file mode 100644 index 00000000..f1a96bc5 --- /dev/null +++ b/examples/javascript/lis2ds12.js @@ -0,0 +1,65 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016-2017 Intel Corporation. + * + * 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_lis2ds12'); + +// Instantiate a LIS2DS12 instance using default i2c bus and address +var sensor = new sensorObj.LIS2DS12(); + +// For SPI, bus 0, you would pass -1 as the address, and a valid pin for CS: +// LIS2DS12(0, -1, 10); + +// 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"); + + // we show both C and F for temperature + console.log("Compensation Temperature: " + + sensor.getTemperature() + + " C / " + + sensor.getTemperature(true) + + " F"); + + 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/lis2ds12.py b/examples/python/lis2ds12.py new file mode 100755 index 00000000..5c0543ea --- /dev/null +++ b/examples/python/lis2ds12.py @@ -0,0 +1,68 @@ +#!/usr/bin/python +# Author: Jon Trulson +# Copyright (c) 2016-2017 Intel Corporation. +# +# 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_lis2ds12 as sensorObj + +def main(): + # Instantiate a BMP250E instance using default i2c bus and address + sensor = sensorObj.LIS2DS12() + + # For SPI, bus 0, you would pass -1 as the address, and a valid pin for CS: + # LIS2DS12(0, -1, 10); + + ## 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") + + # we show both C and F for temperature + print("Compensation Temperature:", sensor.getTemperature(), "C /", end=' ') + print(sensor.getTemperature(True), "F") + + print() + time.sleep(.250) + +if __name__ == '__main__': + main() diff --git a/src/lis2ds12/CMakeLists.txt b/src/lis2ds12/CMakeLists.txt new file mode 100644 index 00000000..324e052c --- /dev/null +++ b/src/lis2ds12/CMakeLists.txt @@ -0,0 +1,9 @@ +upm_mixed_module_init (NAME lis2ds12 + DESCRIPTION "3-Axis Digital Accelerometer" + C_HDR lis2ds12.h lis2ds12_defs.h + C_SRC lis2ds12.c + CPP_HDR lis2ds12.hpp + CPP_SRC lis2ds12.cxx + FTI_SRC lis2ds12_fti.c + CPP_WRAPS_C + REQUIRES mraa utilities-c) diff --git a/src/lis2ds12/javaupm_lis2ds12.i b/src/lis2ds12/javaupm_lis2ds12.i new file mode 100644 index 00000000..ed6ee92b --- /dev/null +++ b/src/lis2ds12/javaupm_lis2ds12.i @@ -0,0 +1,23 @@ +%module javaupm_lis2ds12 +%include "../upm.i" +%include "typemaps.i" +%include "../upm_vectortypes.i" + +%ignore getAccelerometer(float *, float *, float *); + +%include "lis2ds12_defs.h" +%include "lis2ds12.hpp" +%{ + #include "lis2ds12.hpp" +%} + +%pragma(java) jniclasscode=%{ + static { + try { + System.loadLibrary("javaupm_lis2ds12"); + } catch (UnsatisfiedLinkError e) { + System.err.println("Native code library failed to load. \n" + e); + System.exit(1); + } + } +%} diff --git a/src/lis2ds12/jsupm_lis2ds12.i b/src/lis2ds12/jsupm_lis2ds12.i new file mode 100644 index 00000000..5804336e --- /dev/null +++ b/src/lis2ds12/jsupm_lis2ds12.i @@ -0,0 +1,10 @@ +%module jsupm_lis2ds12 +%include "../upm.i" +%include "../upm_vectortypes.i" + + +%include "lis2ds12_defs.h" +%include "lis2ds12.hpp" +%{ + #include "lis2ds12.hpp" +%} diff --git a/src/lis2ds12/lis2ds12.c b/src/lis2ds12/lis2ds12.c new file mode 100644 index 00000000..9d5a7254 --- /dev/null +++ b/src/lis2ds12/lis2ds12.c @@ -0,0 +1,658 @@ +/* + * 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 "lis2ds12.h" + +// macro for converting a uint8_t low/high pair into a float +#define INT16_TO_FLOAT(h, l) \ + (float)( (int16_t)( (l) | ((h) << 8) ) ) + +// some useful macros to save on typing and text wrapping +#undef _SHIFT +#define _SHIFT(x) (_LIS2DS12_##x##_SHIFT) + +#undef _MASK +#define _MASK(x) (_LIS2DS12_##x##_MASK) + +#undef _SHIFTMASK +#define _SHIFTMASK(x) (_MASK(x) << _SHIFT(x)) + +// SPI CS on and off functions +static void _csOn(const lis2ds12_context dev) +{ + assert(dev != NULL); + + if (dev->gpioCS) + mraa_gpio_write(dev->gpioCS, 0); +} + +static void _csOff(const lis2ds12_context dev) +{ + assert(dev != NULL); + + if (dev->gpioCS) + mraa_gpio_write(dev->gpioCS, 1); +} + +// init +lis2ds12_context lis2ds12_init(int bus, int addr, int cs) +{ + lis2ds12_context dev = + (lis2ds12_context)malloc(sizeof(struct _lis2ds12_context)); + + if (!dev) + return NULL; + + // zero out context + memset((void *)dev, 0, sizeof(struct _lis2ds12_context)); + + // make sure MRAA is initialized + if (mraa_init() != MRAA_SUCCESS) + { + printf("%s: mraa_init() failed.\n", __FUNCTION__); + lis2ds12_close(dev); + return NULL; + } + + if (addr < 0) + { + // SPI + if (!(dev->spi = mraa_spi_init(bus))) + { + printf("%s: mraa_spi_init() failed.\n", __FUNCTION__); + lis2ds12_close(dev); + return NULL; + } + + // Only create cs context if we are actually using a valid pin. + // A hardware controlled pin should specify cs as -1. + if (cs >= 0) + { + if (!(dev->gpioCS = mraa_gpio_init(cs))) + { + printf("%s: mraa_gpio_init() failed.\n", __FUNCTION__); + lis2ds12_close(dev); + return NULL; + } + mraa_gpio_dir(dev->gpioCS, MRAA_GPIO_OUT); + } + + mraa_spi_mode(dev->spi, MRAA_SPI_MODE0); + if (mraa_spi_frequency(dev->spi, 5000000)) + { + printf("%s: mraa_spi_frequency() failed.\n", __FUNCTION__); + lis2ds12_close(dev); + return NULL; + } + } + else + { + // I2C + if (!(dev->i2c = mraa_i2c_init(bus))) + { + printf("%s: mraa_i2c_init() failed.\n", __FUNCTION__); + lis2ds12_close(dev); + return NULL; + } + + if (mraa_i2c_address(dev->i2c, addr)) + { + printf("%s: mraa_i2c_address() failed.\n", __FUNCTION__); + lis2ds12_close(dev); + return NULL; + } + } + + // check the chip id + + uint8_t chipID = lis2ds12_get_chip_id(dev); + if (chipID != LIS2DS12_CHIPID) + { + printf("%s: invalid chip id: %02x. Expected %02x\n", + __FUNCTION__, chipID, LIS2DS12_CHIPID); + lis2ds12_close(dev); + return NULL; + } + + // reset + if (lis2ds12_reset(dev)) + { + printf("%s: lis2ds12_reset() failed.\n", __FUNCTION__); + lis2ds12_close(dev); + return NULL; + } + + // call devinit with default options + if (lis2ds12_devinit(dev, LIS2DS12_ODR_100HZ, LIS2DS12_FS_2G)) + { + printf("%s: lis2ds12_devinit() failed.\n", __FUNCTION__); + lis2ds12_close(dev); + return NULL; + } + + return dev; +} + +void lis2ds12_close(lis2ds12_context dev) +{ + assert(dev != NULL); + + lis2ds12_uninstall_isr(dev, LIS2DS12_INTERRUPT_INT1); + lis2ds12_uninstall_isr(dev, LIS2DS12_INTERRUPT_INT2); + + if (dev->i2c) + mraa_i2c_stop(dev->i2c); + if (dev->spi) + mraa_spi_stop(dev->spi); + if (dev->gpioCS) + mraa_gpio_close(dev->gpioCS); + + free(dev); +} + +upm_result_t lis2ds12_devinit(const lis2ds12_context dev, + LIS2DS12_ODR_T odr, + LIS2DS12_FS_T fs) +{ + assert(dev != NULL); + + // enable register auto-increment + uint8_t reg = lis2ds12_read_reg(dev, LIS2DS12_REG_CTRL2); + reg |= LIS2DS12_CTRL2_IF_ADD_INC; + + if (lis2ds12_write_reg(dev, LIS2DS12_REG_CTRL2, reg)) + return UPM_ERROR_OPERATION_FAILED; + + // set our ODR and FS. Disable output high-pass filter. + if (lis2ds12_set_odr(dev, odr) + || lis2ds12_set_full_scale(dev, fs) + || lis2ds12_enable_hp_filtering(dev, false)) + { + printf("%s: failed to set configuration parameters.\n", + __FUNCTION__); + return UPM_ERROR_OPERATION_FAILED; + } + + // settle + upm_delay_ms(50); + + return UPM_SUCCESS; +} + +upm_result_t lis2ds12_set_odr(const lis2ds12_context dev, + LIS2DS12_ODR_T odr) +{ + assert(dev != NULL); + + bool hf_mode = false; + uint8_t reg = lis2ds12_read_reg(dev, LIS2DS12_REG_CTRL1); + + // mask out ODR bits + reg &= ~_SHIFTMASK(CTRL1_ODR); + + // we encoded an extra bit in LIS2DS12_ODR_T indicating an HF + // mode. Check for it here. + if ((int)odr > (int)_MASK(CTRL1_ODR)) + hf_mode = true; + + // mask it off and set it + odr &= _MASK(CTRL1_ODR); + reg |= (odr << _SHIFT(CTRL1_ODR)); + + // set the HF bit appropriately + if (hf_mode) + reg |= LIS2DS12_CTRL1_HF_ODR; + else + reg &= ~LIS2DS12_CTRL1_HF_ODR; + + // we always set the BDU (Block Data Update) bit + reg |= LIS2DS12_CTRL1_BDU; + + if (lis2ds12_write_reg(dev, LIS2DS12_REG_CTRL1, reg)) + return UPM_ERROR_OPERATION_FAILED; + + switch(odr) + { + case LIS2DS12_ODR_12_5HZ: + case LIS2DS12_ODR_25HZ: + case LIS2DS12_ODR_50HZ: + case LIS2DS12_ODR_100HZ: + // 14b + dev->accFactor = 4.0; + break; + + // these are special - possibly HF modes. Since we've already + // stripped the HF indicator, we check the hf_mode here. HF + // modes are 12b resolution, otherwise resolution is 14b. + case LIS2DS12_ODR_200HZ: + case LIS2DS12_ODR_400HZ: + case LIS2DS12_ODR_800HZ: + if (hf_mode) + dev->accFactor = 16.0; + else + dev->accFactor = 4.0; + break; + + // choose something safe + case LIS2DS12_ODR_POWER_DOWN: + dev->accFactor = 1.0; + break; + + // the rest are low power modes, 10b + default: + dev->accFactor = 64.0; + break; + } + + + return UPM_SUCCESS; +} + +upm_result_t lis2ds12_set_full_scale(const lis2ds12_context dev, + LIS2DS12_FS_T fs) +{ + assert(dev != NULL); + + uint8_t reg = lis2ds12_read_reg(dev, LIS2DS12_REG_CTRL1); + + // mask out FS bits, add our own + reg &= ~_SHIFTMASK(CTRL1_FS); + reg |= (fs << _SHIFT(CTRL1_FS)); + + if (lis2ds12_write_reg(dev, LIS2DS12_REG_CTRL1, reg)) + return UPM_ERROR_OPERATION_FAILED; + + // assumes a 16b resolution + switch(fs) + { + case LIS2DS12_FS_2G: + dev->accScale = 0.061; + break; + + case LIS2DS12_FS_4G: + dev->accScale = 0.122; + break; + + case LIS2DS12_FS_8G: + dev->accScale = 0.244; + break; + + case LIS2DS12_FS_16G: + dev->accScale = 0.488; + break; + + } + + return UPM_SUCCESS; +} + +upm_result_t lis2ds12_update(const lis2ds12_context dev) +{ + assert(dev != NULL); + + int bufLen = 6; // max + uint8_t buf[bufLen]; + + if (lis2ds12_read_regs(dev, LIS2DS12_REG_OUT_X_L, buf, bufLen) != bufLen) + { + printf("%s: lis2ds12_read_regs() failed to read %d bytes\n", + __FUNCTION__, bufLen); + return UPM_ERROR_OPERATION_FAILED; + } + + // x msb lsb + dev->accX = INT16_TO_FLOAT(buf[1], buf[0]); + + // y + dev->accY = INT16_TO_FLOAT(buf[3], buf[2]); + + // z + dev->accZ = INT16_TO_FLOAT(buf[5], buf[4]); + + // get the temperature... + + int8_t temp = 0; + temp = (int8_t)lis2ds12_read_reg(dev, LIS2DS12_REG_OUT_T); + + // 1K/LSB, 25C center point + dev->temperature = ((float)temp / 256.0) + 25.0; + + return UPM_SUCCESS; +} + +uint8_t lis2ds12_read_reg(const lis2ds12_context dev, uint8_t reg) +{ + assert(dev != NULL); + + if (dev->spi) + { + reg |= 0x80; // needed for read + uint8_t pkt[2] = {reg, 0}; + + _csOn(dev); + if (mraa_spi_transfer_buf(dev->spi, pkt, pkt, 2)) + { + _csOff(dev); + printf("%s: mraa_spi_transfer_buf() failed.\n", __FUNCTION__); + return 0xff; + } + _csOff(dev); + + return pkt[1]; + } + else + return (uint8_t)mraa_i2c_read_byte_data(dev->i2c, reg); +} + +int lis2ds12_read_regs(const lis2ds12_context dev, uint8_t reg, + uint8_t *buffer, int len) +{ + assert(dev != NULL); + + if (dev->spi) + { + reg |= 0x80; // needed for read + + uint8_t sbuf[len + 1]; + memset((char *)sbuf, 0, len + 1); + sbuf[0] = reg; + + _csOn(dev); + if (mraa_spi_transfer_buf(dev->spi, sbuf, sbuf, len + 1)) + { + _csOff(dev); + printf("%s: mraa_spi_transfer_buf() failed.\n", __FUNCTION__); + return -1; + } + _csOff(dev); + + // now copy it into user buffer + for (int i=0; ii2c, reg, buffer, len) != len) + return -1; + } + + return len; +} + +upm_result_t lis2ds12_write_reg(const lis2ds12_context dev, + uint8_t reg, uint8_t val) +{ + assert(dev != NULL); + + if (dev->spi) + { + reg &= 0x7f; // mask off 0x80 for writing + uint8_t pkt[2] = {reg, val}; + + _csOn(dev); + if (mraa_spi_transfer_buf(dev->spi, pkt, NULL, 2)) + { + _csOff(dev); + printf("%s: mraa_spi_transfer_buf() failed.", + __FUNCTION__); + + return UPM_ERROR_OPERATION_FAILED; + } + _csOff(dev); + } + else + { + if (mraa_i2c_write_byte_data(dev->i2c, val, reg)) + { + printf("%s: mraa_i2c_write_byte_data() failed.", + __FUNCTION__); + return UPM_ERROR_OPERATION_FAILED; + } + } + + return UPM_SUCCESS; +} + +uint8_t lis2ds12_get_chip_id(const lis2ds12_context dev) +{ + assert(dev != NULL); + + return lis2ds12_read_reg(dev, LIS2DS12_REG_WHO_AM_I); +} + +void lis2ds12_get_accelerometer(const lis2ds12_context dev, + float *x, float *y, float *z) +{ + assert(dev != NULL); + + float scale = (dev->accScale * dev->accFactor) / 1000.0; + + if (x) + *x = (dev->accX / dev->accFactor) * scale; + + if (y) + *y = (dev->accY / dev->accFactor) * scale; + + if (z) + *z = (dev->accZ / dev->accFactor) * scale; +} + +float lis2ds12_get_temperature(const lis2ds12_context dev) +{ + assert(dev != NULL); + + return dev->temperature; +} + +upm_result_t lis2ds12_reset(const lis2ds12_context dev) +{ + assert(dev != NULL); + + uint8_t reg = lis2ds12_read_reg(dev, LIS2DS12_REG_CTRL2); + + reg |= LIS2DS12_CTRL2_SOFT_RESET; + + if (lis2ds12_write_reg(dev, LIS2DS12_REG_CTRL2, reg)) + return UPM_ERROR_OPERATION_FAILED; + + upm_delay_ms(100); + + return UPM_SUCCESS; +} + +upm_result_t lis2ds12_enable_hp_filtering(const lis2ds12_context dev, + bool filter) +{ + assert(dev != NULL); + + uint8_t reg = lis2ds12_read_reg(dev, LIS2DS12_REG_CTRL2); + + if (filter) + reg |= LIS2DS12_CTRL2_FDS_SLOPE; + else + reg &= ~LIS2DS12_CTRL2_FDS_SLOPE; + + if (lis2ds12_write_reg(dev, LIS2DS12_REG_CTRL2, reg)) + return UPM_ERROR_OPERATION_FAILED; + + return UPM_SUCCESS; +} + +upm_result_t lis2ds12_enable_interrupt_latching(const lis2ds12_context dev, + bool latch) +{ + assert(dev != NULL); + + uint8_t reg = lis2ds12_read_reg(dev, LIS2DS12_REG_CTRL3); + + if (latch) + reg |= LIS2DS12_CTRL3_LIR; + else + reg &= ~LIS2DS12_CTRL3_LIR; + + if (lis2ds12_write_reg(dev, LIS2DS12_REG_CTRL3, reg)) + return UPM_ERROR_OPERATION_FAILED; + + return UPM_SUCCESS; +} + +upm_result_t lis2ds12_set_interrupt_active_high(const lis2ds12_context dev, + bool high) +{ + assert(dev != NULL); + + uint8_t reg = lis2ds12_read_reg(dev, LIS2DS12_REG_CTRL3); + + if (high) + reg &= ~LIS2DS12_CTRL3_H_LACTIVE; + else + reg |= LIS2DS12_CTRL3_H_LACTIVE; + + if (lis2ds12_write_reg(dev, LIS2DS12_REG_CTRL3, reg)) + return UPM_ERROR_OPERATION_FAILED; + + return UPM_SUCCESS; +} + +upm_result_t lis2ds12_set_interrupt_push_pull(const lis2ds12_context dev, + bool pp) +{ + assert(dev != NULL); + + uint8_t reg = lis2ds12_read_reg(dev, LIS2DS12_REG_CTRL3); + + if (pp) + reg &= ~LIS2DS12_CTRL3_PP_OD; + else + reg |= LIS2DS12_CTRL3_PP_OD; + + if (lis2ds12_write_reg(dev, LIS2DS12_REG_CTRL3, reg)) + return UPM_ERROR_OPERATION_FAILED; + + return UPM_SUCCESS; +} + +upm_result_t lis2ds12_set_int1_config(const lis2ds12_context dev, + uint8_t cfg) +{ + assert(dev != NULL); + + if (lis2ds12_write_reg(dev, LIS2DS12_REG_CTRL4, cfg)) + return UPM_ERROR_OPERATION_FAILED; + + return UPM_SUCCESS; +} + +upm_result_t lis2ds12_set_int2_config(const lis2ds12_context dev, + uint8_t cfg) +{ + assert(dev != NULL); + + if (lis2ds12_write_reg(dev, LIS2DS12_REG_CTRL5, cfg)) + return UPM_ERROR_OPERATION_FAILED; + + return UPM_SUCCESS; +} + +uint8_t lis2ds12_get_status(const lis2ds12_context dev) +{ + assert(dev != NULL); + + return lis2ds12_read_reg(dev, LIS2DS12_REG_STATUS); +} + +upm_result_t lis2ds12_install_isr(const lis2ds12_context dev, + LIS2DS12_INTERRUPT_PINS_T intr, int gpio, + mraa_gpio_edge_t level, + void (*isr)(void *), void *arg) +{ + assert(dev != NULL); + + // delete any existing ISR and GPIO context for this interrupt + lis2ds12_uninstall_isr(dev, intr); + + mraa_gpio_context gpio_isr = NULL; + + // create gpio context + if (!(gpio_isr = mraa_gpio_init(gpio))) + { + printf("%s: mraa_gpio_init() failed.\n", __FUNCTION__); + return UPM_ERROR_OPERATION_FAILED; + } + + mraa_gpio_dir(gpio_isr, MRAA_GPIO_IN); + + if (mraa_gpio_isr(gpio_isr, level, isr, arg)) + { + mraa_gpio_close(gpio_isr); + printf("%s: mraa_gpio_isr() failed.\n", __FUNCTION__); + return UPM_ERROR_OPERATION_FAILED; + } + + switch (intr) + { + case LIS2DS12_INTERRUPT_INT1: + dev->gpioINT1 = gpio_isr; + break; + + case LIS2DS12_INTERRUPT_INT2: + dev->gpioINT2 = gpio_isr; + break; + } + + return UPM_SUCCESS; +} + +void lis2ds12_uninstall_isr(const lis2ds12_context dev, + LIS2DS12_INTERRUPT_PINS_T intr) +{ + assert(dev != NULL); + + switch (intr) + { + case LIS2DS12_INTERRUPT_INT1: + if (dev->gpioINT1) + { + mraa_gpio_isr_exit(dev->gpioINT1); + mraa_gpio_close(dev->gpioINT1); + dev->gpioINT1 = NULL; + } + break; + + case LIS2DS12_INTERRUPT_INT2: + if (dev->gpioINT2) + { + mraa_gpio_isr_exit(dev->gpioINT2); + mraa_gpio_close(dev->gpioINT2); + dev->gpioINT2 = NULL; + } + break; + } +} diff --git a/src/lis2ds12/lis2ds12.cxx b/src/lis2ds12/lis2ds12.cxx new file mode 100644 index 00000000..086df551 --- /dev/null +++ b/src/lis2ds12/lis2ds12.cxx @@ -0,0 +1,201 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016-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 "lis2ds12.hpp" + +using namespace upm; +using namespace std; + +// conversion from Celsius to Fahrenheit + +static float c2f(float c) +{ + return (c * (9.0 / 5.0) + 32.0); +} + +LIS2DS12::LIS2DS12(int bus, int addr, int cs) : + m_lis2ds12(lis2ds12_init(bus, addr, cs)) +{ + if (!m_lis2ds12) + throw std::runtime_error(string(__FUNCTION__) + + ": lis2ds12_init() failed"); +} + +LIS2DS12::~LIS2DS12() +{ + lis2ds12_close(m_lis2ds12); +} + +void LIS2DS12::init(LIS2DS12_ODR_T odr, LIS2DS12_FS_T fs) +{ + if (lis2ds12_devinit(m_lis2ds12, odr, fs)) + throw std::runtime_error(string(__FUNCTION__) + + ": lis2ds12_devinit() failed"); +} + +void LIS2DS12::update() +{ + if (lis2ds12_update(m_lis2ds12)) + throw std::runtime_error(string(__FUNCTION__) + + ": lis2ds12_update() failed"); +} + +uint8_t LIS2DS12::readReg(uint8_t reg) +{ + return lis2ds12_read_reg(m_lis2ds12, reg); +} + +int LIS2DS12::readRegs(uint8_t reg, uint8_t *buffer, int len) +{ + int rv = lis2ds12_read_regs(m_lis2ds12, reg, buffer, len); + if (rv != len) + throw std::runtime_error(string(__FUNCTION__) + + ": lis2ds12_read_regs() failed"); + + return rv; +} + +void LIS2DS12::writeReg(uint8_t reg, uint8_t val) +{ + if (lis2ds12_write_reg(m_lis2ds12, reg, val)) + throw std::runtime_error(string(__FUNCTION__) + + ": lis2ds12_write_reg() failed"); +} + +uint8_t LIS2DS12::getChipID() +{ + return lis2ds12_get_chip_id(m_lis2ds12); +} + +void LIS2DS12::getAccelerometer(float *x, float *y, float *z) +{ + lis2ds12_get_accelerometer(m_lis2ds12, x, y, z); +} + +std::vector LIS2DS12::getAccelerometer() +{ + float v[3]; + + getAccelerometer(&v[0], &v[1], &v[2]); + return std::vector(v, v+3); +} + +float LIS2DS12::getTemperature(bool fahrenheit) +{ + float temperature = lis2ds12_get_temperature(m_lis2ds12); + if (fahrenheit) + return c2f(temperature); + else + return temperature; +} + +void LIS2DS12::reset() +{ + if (lis2ds12_reset(m_lis2ds12)) + throw std::runtime_error(string(__FUNCTION__) + + ": lis2ds12_reset() failed"); +} + +void LIS2DS12::setODR(LIS2DS12_ODR_T odr) +{ + if (lis2ds12_set_odr(m_lis2ds12, odr)) + throw std::runtime_error(string(__FUNCTION__) + + ": lis2ds12_set_odr() failed"); +} + +void LIS2DS12::setFullScale(LIS2DS12_FS_T fs) +{ + if (lis2ds12_set_full_scale(m_lis2ds12, fs)) + throw std::runtime_error(string(__FUNCTION__) + + ": lis2ds12_set_full_scale() failed"); +} + +void LIS2DS12::enableHPFiltering(bool filter) +{ + if (lis2ds12_enable_hp_filtering(m_lis2ds12, filter)) + throw std::runtime_error(string(__FUNCTION__) + + ": lis2ds12_enable_hp_filtering() failed"); +} + +void LIS2DS12::enableInterruptLatching(bool latch) +{ + if (lis2ds12_enable_interrupt_latching(m_lis2ds12, latch)) + throw std::runtime_error(string(__FUNCTION__) + + ": lis2ds12_enable_interrupt_latching() failed"); +} + +void LIS2DS12::setInterruptActiveHigh(bool high) +{ + if (lis2ds12_set_interrupt_active_high(m_lis2ds12, high)) + throw std::runtime_error(string(__FUNCTION__) + + ": lis2ds12_set_interrupt_active_high() failed"); +} + +void LIS2DS12::setInterruptPushPull(bool pp) +{ + if (lis2ds12_set_interrupt_push_pull(m_lis2ds12, pp)) + throw std::runtime_error(string(__FUNCTION__) + + ": lis2ds12_set_interrupt_push_pull() failed"); +} + +void LIS2DS12::setInt1Config(uint8_t cfg) +{ + if (lis2ds12_set_int1_config(m_lis2ds12, cfg)) + throw std::runtime_error(string(__FUNCTION__) + + ": lis2ds12_set_int1_config() failed"); +} + +void LIS2DS12::setInt2Config(uint8_t cfg) +{ + if (lis2ds12_set_int2_config(m_lis2ds12, cfg)) + throw std::runtime_error(string(__FUNCTION__) + + ": lis2ds12_set_int2_config() failed"); +} + +uint8_t LIS2DS12::getStatus() +{ + return lis2ds12_get_status(m_lis2ds12); +} + +void LIS2DS12::installISR(LIS2DS12_INTERRUPT_PINS_T intr, int gpio, + mraa::Edge level, + void (*isr)(void *), void *arg) +{ + if (lis2ds12_install_isr(m_lis2ds12, intr, gpio, + (mraa_gpio_edge_t)level, isr, arg)) + throw std::runtime_error(string(__FUNCTION__) + + ": lis2ds12_install_isr() failed"); +} + +void LIS2DS12::uninstallISR(LIS2DS12_INTERRUPT_PINS_T intr) +{ + lis2ds12_uninstall_isr(m_lis2ds12, intr); +} diff --git a/src/lis2ds12/lis2ds12.h b/src/lis2ds12/lis2ds12.h new file mode 100644 index 00000000..865cbded --- /dev/null +++ b/src/lis2ds12/lis2ds12.h @@ -0,0 +1,323 @@ +/* + * 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 + +#include "upm.h" + +#include "lis2ds12_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + + /** + * @file lis2ds12.h + * @library lis2ds12 + * @brief C API for the lis2ds12 driver + * + * @include lis2ds12.c + */ + + /** + * Device context + */ + typedef struct _lis2ds12_context { + mraa_i2c_context i2c; + mraa_spi_context spi; + + mraa_gpio_context gpioCS; // SPI CS pin + mraa_gpio_context gpioINT1; // intr 1 + mraa_gpio_context gpioINT2; // intr 2 + + // temperature + float temperature; + + // uncompensated acc data + float accX; + float accY; + float accZ; + + // acc scaling + float accScale; + float accFactor; + } *lis2ds12_context; + + /** + * LIS2DS12 initialization. + * + * This device can support both I2C and SPI. For SPI, set the addr + * to -1, and specify a positive integer representing the Chip + * Select (CS) pin for the cs argument. If you are using a + * hardware CS pin (like Intel Edison with Arduino breakout), then + * you can connect the proper pin to the hardware CS pin on your + * MCU and supply -1 for cs. + * + * @param bus I2C or SPI bus to use + * @param addr The address for this device, or -1 for SPI + * @param cs The gpio pin to use for the SPI Chip Select. Use -1 for + * I2C or for SPI with a hardware controlled pin. + * @return The device context, or NULL on error + */ + lis2ds12_context lis2ds12_init(int bus, int addr, int cs); + + /** + * LIS2DS12 Destructor + * + * @param dev The device context + */ + void lis2ds12_close(lis2ds12_context dev); + + /** + * Update the internal stored values from sensor data + * + * @param dev The device context + * @return UPM result + */ + upm_result_t lis2ds12_update(const lis2ds12_context dev); + + /** + * Return the chip ID + * + * @param dev The device context + * @return The chip ID (LIS2DS12_CHIPID) + */ + uint8_t lis2ds12_get_chip_id(const lis2ds12_context dev); + + /** + * Initialize the device and start operation. This function is + * called from lis2ds12_init(), so it will not need to be called by + * a user unless the device is reset. + * + * @param dev The device context + * @param odr One of the LIS2DS12_ODR_T values + * @param fs One of the LIS2DS12_FS_T values + * @return UPM result + */ + upm_result_t lis2ds12_devinit(const lis2ds12_context dev, + LIS2DS12_ODR_T odr, + LIS2DS12_FS_T fs); + + /** + * Set the output data rate (ODR) of the device + * + * @param dev The device context + * @param odr One of the LIS2DS12_ODR_T values + * @return UPM result + */ + upm_result_t lis2ds12_set_odr(const lis2ds12_context dev, + LIS2DS12_ODR_T odr); + + /** + * Set the full scale (FS) of the device. This device supports a + * full scale of 2, 4, 8, and 16G. + * + * @param dev The device context + * @param fs One of the LIS2DS12_FS_T values + * @return UPM result + */ + upm_result_t lis2ds12_set_full_scale(const lis2ds12_context dev, + LIS2DS12_FS_T fs); + + /** + * Return accelerometer data gravities (g). lis2ds12_update() + * must have been called prior to calling this method. + * + * @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 lis2ds12_get_accelerometer(const lis2ds12_context dev, + float *x, float *y, float *z); + + /** + * Return the current measured temperature. Note, this is not + * ambient temperature. lis2ds12_update() must have been called + * prior to calling this method. + * + * @param dev The device context + * @return The temperature in degrees Celsius + */ + float lis2ds12_get_temperature(const lis2ds12_context dev); + + /** + * Reset the device as if during a power on reset. All configured + * values are lost when this happens. You should call + * lis2ds12_devinit() afterwards, or at least perform the same + * initialization lis2ds12_devinit() does before continuing. + * + * @param dev The device context + * @return UPM result + */ + upm_result_t lis2ds12_reset(const lis2ds12_context dev); + + /** + * Enable high pass filtering of the accelerometer axis data. + * lis2ds12_devinit() disables this by default. See the datasheet + * for details. + * + * @param dev The device context + * @param filter true to enable filtering, false to disable + * @return UPM result + */ + upm_result_t lis2ds12_enable_hp_filtering(const lis2ds12_context dev, + bool filter); + + /** + * Enable or disable interrupt latching. If latching is disabled, + * pulsed is enabled. See the datasheet for details. + * + * @param dev The device context + * @param latch true to enable latching, false to disable + * @return UPM result + */ + upm_result_t lis2ds12_enable_interrupt_latching(const lis2ds12_context dev, + bool latch); + + /** + * Indicate whether the interrupt should be active high (default) + * or active low. See the datasheet for details. + * + * @param dev The device context + * @param high true for active high, false for active low + * @return UPM result + */ + upm_result_t lis2ds12_set_interrupt_active_high(const lis2ds12_context dev, + bool high); + + /** + * Indicate whether interrupts are push-pull (default) or open + * drain. See the datasheet for details. + * + * @param dev The device context + * @param pp true for push-pull, false for open-drain + * @return UPM result + */ + upm_result_t lis2ds12_set_interrupt_push_pull(const lis2ds12_context dev, + bool pp); + + /** + * Set interrupt 1 configuration. See the datasheet for details. + * + * @param dev The device context + * @param cfg A bitmask of values from LIS2DS12_CTRL4_BITS_T + * @return UPM result + */ + upm_result_t lis2ds12_set_int1_config(const lis2ds12_context dev, + uint8_t cfg); + + /** + * Set interrupt 2 configuration. See the datasheet for details. + * + * @param dev The device context + * @param cfg A bitmask of values from LIS2DS12_CTRL5_BITS_T + * @return UPM result + */ + upm_result_t lis2ds12_set_int2_config(const lis2ds12_context dev, + uint8_t cfg); + + /** + * Return the contents of the status register + * + * @param dev The device context + * @return A bitmask of values from LIS2DS12_STATUS_BITS_T + */ + uint8_t lis2ds12_get_status(const lis2ds12_context dev); + + /** + * Install an interrupt handler + * + * @param dev The device context + * @param intr One of the LIS2DS12_INTERRUPT_PINS_T values + * specifying which interrupt pin you are installing + * @param gpio GPIO pin to use as interrupt pin + * @param level The interrupt trigger level (one of mraa_gpio_edge_t + * values). Make sure that you have configured the interrupt pin + * properly for whatever level you choose. + * @param isr The interrupt handler, accepting a void * argument + * @param arg The argument to pass the the interrupt handler + * @return UPM result + */ + upm_result_t lis2ds12_install_isr(const lis2ds12_context dev, + LIS2DS12_INTERRUPT_PINS_T intr, int gpio, + mraa_gpio_edge_t level, + void (*isr)(void *), void *arg); + + /** + * Uninstall a previously installed interrupt handler + * + * @param dev The device context + * @param intr One of the LIS2DS12_INTERRUPT_PINS_T values + * specifying which interrupt pin you are removing + */ + void lis2ds12_uninstall_isr(const lis2ds12_context dev, + LIS2DS12_INTERRUPT_PINS_T intr); + + /** + * Read a register + * + * @param dev The device context + * @param reg The register to read + * @return The value of the register + */ + uint8_t lis2ds12_read_reg(const lis2ds12_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 lis2ds12_read_regs(const lis2ds12_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 lis2ds12_write_reg(const lis2ds12_context dev, + uint8_t reg, uint8_t val); + + +#ifdef __cplusplus +} +#endif diff --git a/src/lis2ds12/lis2ds12.hpp b/src/lis2ds12/lis2ds12.hpp new file mode 100644 index 00000000..953dbe2b --- /dev/null +++ b/src/lis2ds12/lis2ds12.hpp @@ -0,0 +1,322 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016-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 "lis2ds12.h" + +namespace upm { + + /** + * @brief ST Micro 3-axis Accelerometer + * @defgroup lis2ds12 libupm-lis2ds12 + * @ingroup i2c spi gpio bosch accelerometer + */ + + /** + * @library lis2ds12 + * @sensor lis2ds12 + * @comname Digital 3-axis Accelerometer + * @type accelerometer + * @man stmicro + * @con i2c spi gpio + * @web http://www.st.com/en/mems-and-sensors/lis2ds12.html + * + * @brief API for the LIS2DS12 3-axis Accelerometer + * + * The LIS2DS12 is an ultra-low-power high performance three-axis + * linear accelerometer belonging to the "pico" family which + * leverages on the robust and mature manufacturing processes + * already used for the production of micromachined + * accelerometers. + * + * The LIS2DS12 has user-selectable full scales of + * 2g/4g/8g/16g and is capable of measuring accelerations with + * output data rates from 1 Hz to 6400 Hz. + + * 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 both I2C (default) and SPI + * operation. + * + * This device requires 1.8v operation. + * + * @snippet lis2ds12.cxx Interesting + */ + + class LIS2DS12 { + public: + + /** + * LIS2DS12 constructor. + * + * This device can support both I2C and SPI. For SPI, set the addr + * to -1, and specify a positive integer representing the Chip + * Select (CS) pin for the cs argument. If you are using a + * hardware CS pin (like edison with arduino breakout), then you + * can connect the proper pin to the hardware CS pin on your MCU + * and supply -1 for cs. The default operating mode is I2C. + * + * @param bus I2C or SPI bus to use + * @param addr The address for this device. -1 for SPI + * @param cs The gpio pin to use for the SPI Chip Select. -1 for + * I2C or for SPI with a hardware controlled pin. + * @throws std::runtime_error on initialization failure + */ + LIS2DS12(int bus=LIS2DS12_DEFAULT_I2C_BUS, + int addr=LIS2DS12_DEFAULT_I2C_ADDR, + int cs=-1); + + /** + * LIS2DS12 destructor + */ + virtual ~LIS2DS12(); + + /** + * Update the internal stored values from sensor data + * + * @throws std::runtime_error on failure + */ + void update(); + + /** + * Return the chip ID + * + * @return The chip ID + */ + uint8_t getChipID(); + + /** + * Return accelerometer 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 accelerometer 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 the current measured temperature. Note, this is not + * ambient temperature. update() must have been called prior to + * calling this method. + * + * @param fahrenheit true to return data in Fahrenheit, false for + * Celicus. Celsius is the default. + * @return The temperature in degrees Celsius or Fahrenheit + */ + float getTemperature(bool fahrenheit=false); + + /** + * Initialize the device and start operation. This function is + * called from the constructor so will not typically need to be + * called by a user unless the device is reset. + * + * @param odr One of the LIS2DS12_ODR_T values. The default is + * LIS2DS12_ODR_100HZ + * @param fs One of the LIS2DS12_FS_T values. The default is + * LIS2DS12_FS_2G + * @throws std::runtime_error on failure + */ + void init(LIS2DS12_ODR_T odr=LIS2DS12_ODR_100HZ, + LIS2DS12_FS_T fs=LIS2DS12_FS_2G); + + /** + * Reset the device as if during a power on reset. All configured + * values are lost when this happens. You should call init() + * afterwards, or at least perform the same initialization init() + * does before continuing. + * + * @throws std::runtime_error on failure + */ + void reset(); + + /** + * Set the output data rate (ODR) of the device + * + * @param odr One of the LIS2DS12_ODR_T values + * @throws std::runtime_error on failure + */ + void setODR(LIS2DS12_ODR_T odr); + + /** + * Set the full scale (FS) of the device. This device supports a + * full scale of 2, 4, 8, and 16G. + * + * @param fs One of the LIS2DS12_FS_T values + * @throws std::runtime_error on failure + */ + void setFullScale(LIS2DS12_FS_T fs); + + /** + * Enable high pass filtering of the accelerometer axis data. + * init() disables this by default. See the datasheet for + * details. + * + * @param filter true to enable filtering, false to disable + * @throws std::runtime_error on failure + */ + void enableHPFiltering(bool filter); + + /** + * Enable or disable interrupt latching. If latching is disabled, + * pulsed is enabled. See the datasheet for details. + * + * @param latch true to enable latching, false to disable + * @throws std::runtime_error on failure + */ + void enableInterruptLatching(bool latch); + + /** + * Indicate whether the interrupt should be active high (default) + * or active low. See the datasheet for details. + * + * @param high true for active high, false for active low + * @throws std::runtime_error on failure + */ + void setInterruptActiveHigh(bool high); + + /** + * Indicate whether interrupts are push-pull (default) or open + * drain. See the datasheet for details. + * + * @param pp true for push-pull, false for open-drain + * @throws std::runtime_error on failure + */ + void setInterruptPushPull(bool pp); + + /** + * Set interrupt 1 configuration. See the datasheet for details. + * + * @param cfg A bitmask of values from LIS2DS12_CTRL4_BITS_T + * @throws std::runtime_error on failure + */ + void setInt1Config(uint8_t cfg); + + /** + * Set interrupt 2 configuration. See the datasheet for details. + * + * @param cfg A bitmask of values from LIS2DS12_CTRL5_BITS_T + * @throws std::runtime_error on failure + */ + void setInt2Config(uint8_t cfg); + + /** + * Return the contents of the status register + * + * @return A bitmask of values from LIS2DS12_STATUS_BITS_T + */ + uint8_t getStatus(); + +#if defined(SWIGJAVA) || defined(JAVACALLBACK) + void installISR(LIS2DS12_INTERRUPT_PINS_T intr, int gpio, + mraa::Edge level, jobject runnable) + { + installISR(intr, gpio, level, mraa_java_isr_callback, + runnable); + } +#else + /** + * install an interrupt handler + * + * @param intr One of the LIS2DS12_INTERRUPT_PINS_T values + * specifying which interrupt pin you are installing + * @param gpio GPIO pin to use as interrupt pin + * @param level The interrupt trigger level (one of mraa::Edge + * values). Make sure that you have configured the interrupt pin + * properly for whatever level you choose. + * @param isr The interrupt handler, accepting a void * argument + * @param arg The argument to pass the the interrupt handler + * @throws std::runtime_error on failure + */ + void installISR(LIS2DS12_INTERRUPT_PINS_T intr, int gpio, + mraa::Edge level, + void (*isr)(void *), void *arg); +#endif + + /** + * uninstall a previously installed interrupt handler + * + * @param intr One of the LIS2DS12_INTERRUPT_PINS_T values + * specifying which interrupt pin you are removing + */ + void uninstallISR(LIS2DS12_INTERRUPT_PINS_T intr); + + /** + * 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); + + protected: + lis2ds12_context m_lis2ds12; + + private: + // Adding a private function definition for java bindings +#if defined(SWIGJAVA) || defined(JAVACALLBACK) + void installISR(LIS2DS12_INTERRUPT_PINS_T intr, int gpio, + mraa::Edge level, + void (*isr)(void *), void *arg); +#endif + }; +} diff --git a/src/lis2ds12/lis2ds12_defs.h b/src/lis2ds12/lis2ds12_defs.h new file mode 100644 index 00000000..22e27f61 --- /dev/null +++ b/src/lis2ds12/lis2ds12_defs.h @@ -0,0 +1,561 @@ +/* + * 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 LIS2DS12_DEFAULT_I2C_BUS 0 +#define LIS2DS12_DEFAULT_SPI_BUS 0 +#define LIS2DS12_DEFAULT_I2C_ADDR 0x1e + + +#define LIS2DS12_CHIPID 0x43 + + // NOTE: Reserved registers must not be written into or permanent + // damage can result. Reading from them may return indeterminate + // values. Registers containing reserved bitfields must be + // written as 0. + + /** + * LIS2DS12 registers + */ + typedef enum { + // 0x00-0x05 reserved + + LIS2DS12_REG_SENSORHUB1_REG = 0x06, + LIS2DS12_REG_SENSORHUB2_REG = 0x07, + LIS2DS12_REG_SENSORHUB3_REG = 0x08, + LIS2DS12_REG_SENSORHUB4_REG = 0x09, + LIS2DS12_REG_SENSORHUB5_REG = 0x0a, + LIS2DS12_REG_SENSORHUB6_REG = 0x0b, + + LIS2DS12_REG_MODULE_8BIT = 0x0c, + + // 0x0d-0x0e reserved + + LIS2DS12_REG_WHO_AM_I = 0x0f, + + // 0x10-0x1f reserved + + LIS2DS12_REG_CTRL1 = 0x20, + LIS2DS12_REG_CTRL2 = 0x21, + LIS2DS12_REG_CTRL3 = 0x22, + LIS2DS12_REG_CTRL4 = 0x23, + LIS2DS12_REG_CTRL5 = 0x24, + + LIS2DS12_REG_FIFO_CTRL = 0x25, + + LIS2DS12_REG_OUT_T = 0x26, + + LIS2DS12_REG_STATUS = 0x27, + + LIS2DS12_REG_OUT_X_L = 0x28, + LIS2DS12_REG_OUT_X_H = 0x29, + LIS2DS12_REG_OUT_Y_L = 0x2a, + LIS2DS12_REG_OUT_Y_H = 0x2b, + LIS2DS12_REG_OUT_Z_L = 0x2c, + LIS2DS12_REG_OUT_Z_H = 0x2d, + + LIS2DS12_REG_FIFO_THS = 0x2e, + LIS2DS12_REG_FIFO_SRC = 0x2f, + LIS2DS12_REG_FIFO_SAMPLES = 0x30, + + LIS2DS12_REG_TAP_6D_THS = 0x31, + LIS2DS12_REG_INT_DUR = 0x32, + + LIS2DS12_REG_WAKE_UP_THS = 0x33, + LIS2DS12_REG_WAKE_UP_DUR = 0x34, + + LIS2DS12_REG_FREE_FALL = 0x35, + + LIS2DS12_REG_STATUS_DUP = 0x36, + + LIS2DS12_REG_WAKE_UP_SRC = 0x37, + + LIS2DS12_REG_TAP_SRC = 0x38, + LIS2DS12_REG_6D_SRC = 0x39, + + LIS2DS12_REG_STEP_COUNTER_MINTHS = 0x3a, + LIS2DS12_REG_STEP_COUNTER_L = 0x3b, + LIS2DS12_REG_STEP_COUNTER_H = 0x3c, + + LIS2DS12_REG_FUNC_CK_GATE = 0x3d, + LIS2DS12_REG_FUNC_SRC = 0x3e, + LIS2DS12_REG_FUNC_CTRL = 0x3f, + } LIS2DS12_REGS_T; + + /** + * REG_CTRL1 bits + */ + typedef enum { + LIS2DS12_CTRL1_BDU = 0x01, + LIS2DS12_CTRL1_HF_ODR = 0x02, + + LIS2DS12_CTRL1_FS0 = 0x04, + LIS2DS12_CTRL1_FS1 = 0x08, + _LIS2DS12_CTRL1_FS_MASK = 3, + _LIS2DS12_CTRL1_FS_SHIFT = 2, + + LIS2DS12_CTRL1_ODR0 = 0x10, + LIS2DS12_CTRL1_ODR1 = 0x20, + LIS2DS12_CTRL1_ODR2 = 0x40, + LIS2DS12_CTRL1_ODR3 = 0x80, + _LIS2DS12_CTRL1_ODR_MASK = 15, + _LIS2DS12_CTRL1_ODR_SHIFT = 4, + } LIS2DS12_CTRL1_BITS_T; + + /** + * CTRL1_FS (full scale) values + */ + typedef enum { + LIS2DS12_FS_2G = 0, + // odd ordering in the DS... + LIS2DS12_FS_16G = 1, + LIS2DS12_FS_4G = 2, + LIS2DS12_FS_8G = 3, + } LIS2DS12_FS_T; + + /** + * CTRL1_ODR (Output Data Rate) values + */ + typedef enum { + LIS2DS12_ODR_POWER_DOWN = 0, + + // high resolution modes (14 bit resolution) + + LIS2DS12_ODR_12_5HZ = 1, + LIS2DS12_ODR_25HZ = 2, + LIS2DS12_ODR_50HZ = 3, + LIS2DS12_ODR_100HZ = 4, + + // The following items (5, 6, 7) have a dual meaning depending + // on whether the HF_ODR bit is set, but they use the same + // overlapping ODR values for the ODR bitfield. Since the + // bitfield is only 4 bits wide, we add a "virtual" 5th bit to + // indicate the HF versions. This is then screened out in the + // code and will set the HF bit according to what is selected + // here. + + // CTRL1_HF_ODR == 0 (14 bit resolution) + LIS2DS12_ODR_200HZ = 5, + LIS2DS12_ODR_400HZ = 6, + LIS2DS12_ODR_800HZ = 7, + + // CTRL1_HF_ODR == 1 (12bit resolution). Add 'virtual' bit 5 + // value (16) for these HF modes, which we will detect and + // screen out in the driver. This simplifies the ODR API. + LIS2DS12_ODR_1600HZ = (16 + 5), + LIS2DS12_ODR_3200HZ = (16 + 6), + LIS2DS12_ODR_6400HZ = (16 + 7), + + // low power modes (10 bit resolution) + LIS2DS12_ODR_LP_1HZ = 8, + LIS2DS12_ODR_LP_12_5HZ = 9, + LIS2DS12_ODR_LP_25HZ = 10, + LIS2DS12_ODR_LP_50HZ = 11, + LIS2DS12_ODR_LP_100HZ = 12, + LIS2DS12_ODR_LP_200HZ = 13, + LIS2DS12_ODR_LP_400HZ = 14, + LIS2DS12_ODR_LP_800HZ = 15, + } LIS2DS12_ODR_T; + + /** + * REG_CTRL2 bits + */ + typedef enum { + LIS2DS12_CTRL2_SIM = 0x01, // SPI 3 wire enable + LIS2DS12_CTRL2_I2C_DISABLE = 0x02, + LIS2DS12_CTRL2_IF_ADD_INC = 0x04, // auto-increment + LIS2DS12_CTRL2_FDS_SLOPE = 0x08, + LIS2DS12_CTRL2_FUNC_CFG_ENABLE = 0x10, + + // 0x20 reserved + + LIS2DS12_CTRL2_SOFT_RESET = 0x40, + LIS2DS12_CTRL2_BOOT = 0x80, + } LIS2DS12_CTRL2_BITS_T; + + /** + * REG_CTRL3 bits + */ + typedef enum { + LIS2DS12_CTRL3_PP_OD = 0x01, //push-pull/open-drain + LIS2DS12_CTRL3_H_LACTIVE = 0x02, + LIS2DS12_CTRL3_LIR = 0x04, + LIS2DS12_CTRL3_TAP_Z_EN = 0x08, + LIS2DS12_CTRL3_TAP_Y_EN = 0x10, + LIS2DS12_CTRL3_TAP_X_EN = 0x20, + + LIS2DS12_CTRL3_ST0 = 0x40, + LIS2DS12_CTRL3_ST1 = 0x80, + _LIS2DS12_CTRL3_ST_MASK = 3, + _LIS2DS12_CTRL3_ST_SHIFT = 6, + } LIS2DS12_CTRL3_BITS_T; + + /** + * CTRL3_ST (Self Test) values + */ + typedef enum { + LIS2DS12_ST_NORMAL = 0, + LIS2DS12_ST_POS_SIGN = 1, + LIS2DS12_ST_NEG_SIGN = 2 + } LIS2DS12_ST_T; + + /** + * REG_CTRL4 bits + */ + typedef enum { + LIS2DS12_CTRL4_INT1_DRDY = 0x01, + LIS2DS12_CTRL4_INT1_FTH = 0x02, + LIS2DS12_CTRL4_INT1_6D = 0x04, + LIS2DS12_CTRL4_INT1_TAP = 0x08, + LIS2DS12_CTRL4_INT1_FF = 0x10, + LIS2DS12_CTRL4_INT1_WU = 0x20, + LIS2DS12_CTRL4_INT1_S_TAP = 0x40, + LIS2DS12_CTRL4_INT1_MASTER_DRDY = 0x80, + } LIS2DS12_CTRL4_BITS_T; + + /** + * REG_CTRL5 bits + */ + typedef enum { + LIS2DS12_CTRL5_INT2_DRDY = 0x01, + LIS2DS12_CTRL5_INT2_FTH = 0x02, + LIS2DS12_CTRL5_INT2_STEP_DET = 0x04, + LIS2DS12_CTRL5_INT2_SIG_MOT = 0x08, + LIS2DS12_CTRL5_INT2_TILT = 0x10, + LIS2DS12_CTRL5_INT2_ON_INT1 = 0x20, + LIS2DS12_CTRL5_INT2_BOOT = 0x40, + LIS2DS12_CTRL5_INT2_DRDY_PULSED = 0x80, + } LIS2DS12_CTRL5_BITS_T; + + /** + * REG_FIFO_CTRL bits + */ + typedef enum { + LIS2DS12_FIFO_CTRL_IF_CS_PU_DIS = 0x01, + + // 0x02-0x04 reserved + + LIS2DS12_FIFO_CTRL_MODULE_TO_FIFO = 0x08, + LIS2DS12_FIFO_CTRL_INT2_STEP_COUNT_OV = 0x10, + + LIS2DS12_FIFO_CTRL_FMODE0 = 0x20, + LIS2DS12_FIFO_CTRL_FMODE1 = 0x40, + LIS2DS12_FIFO_CTRL_FMODE2 = 0x80, + _LIS2DS12_FIFO_CTRL_FMODE_MASK = 7, + _LIS2DS12_FIFO_CTRL_FMODE_SHIFT = 5, + } LIS2DS12_FIFO_CTRL_BITS_T; + + /** + * FIFO_CTRL_FMODE (FIFO mode) values + */ + typedef enum { + LIS2DS12_FMODE_BYPASS = 0, + LIS2DS12_FMODE_FIFO = 1, + // 2 reserved + LIS2DS12_FMODE_CONT_TO_FIFO = 3, + LIS2DS12_FMODE_BYPASS_TO_CONT = 4, + // 5 reserved + LIS2DS12_FMODE_CONT = 6, + // 7 reserved + } LIS2DS12_FMODE_T; + + /** + * REG_STATUS bits + */ + typedef enum { + LIS2DS12_STATUS_DRDY = 0x01, + LIS2DS12_STATUS_FF_IA = 0x02, + LIS2DS12_STATUS_6D_IA = 0x04, + LIS2DS12_STATUS_SINGLE_TAP = 0x08, + LIS2DS12_STATUS_DOUBLE_TAP = 0x10, + LIS2DS12_STATUS_SLEEP_STATE = 0x20, + LIS2DS12_STATUS_WU_IA = 0x40, + LIS2DS12_STATUS_FIFO_THS = 0x80, + } LIS2DS12_STATUS_BITS_T; + + /** + * REG_FIFO_SRC bits + */ + typedef enum { + // 0x01-0x10 reserved + LIS2DS12_FIFO_SRC_DIFF8 = 0x20, + LIS2DS12_FIFO_SRC_FIFO_OVR = 0x40, + LIS2DS12_FIFO_SRC_FTH = 0x80, + } LIS2DS12_FIFO_SRC_BITS_T; + + /** + * REG_TAP_6D_THS bits + */ + typedef enum { + LIS2DS12_TAP_6D_THS_TAP_THS0 = 0x01, + LIS2DS12_TAP_6D_THS_TAP_THS1 = 0x02, + LIS2DS12_TAP_6D_THS_TAP_THS2 = 0x04, + LIS2DS12_TAP_6D_THS_TAP_THS3 = 0x08, + LIS2DS12_TAP_6D_THS_TAP_THS4 = 0x10, + _LIS2DS12_TAP_6D_THS_TAP_THS_MASK = 31, + _LIS2DS12_TAP_6D_THS_TAP_THS_SHIFT = 0, + + LIS2DS12_TAP_6D_THS_6D_THS0 = 0x20, + LIS2DS12_TAP_6D_THS_6D_THS1 = 0x40, + _LIS2DS12_TAP_6D_THS_6D_THS_MASK = 3, + _LIS2DS12_TAP_6D_THS_6D_THS_SHIFT = 5, + + LIS2DS12_TAP_6D_THS_6D_4D_EN = 0x80, + + } LIS2DS12_TAP_6D_THS_BITS_T; + + /** + * TAP_6D_THS_6D_THS values + */ + typedef enum { + LIS2DS12_6D_THS_6 = 0, // 80 degrees + LIS2DS12_6D_THS_11 = 1, // 70 degrees + LIS2DS12_6D_THS_16 = 2, // 60 degrees + LIS2DS12_6D_THS_21 = 3, // 50 degrees + } LIS2DS12_6D_THS_T; + + /** + * REG_INT_DUR bits + */ + typedef enum { + LIS2DS12_INT_DUR_SHOCK0 = 0x01, + LIS2DS12_INT_DUR_SHOCK1 = 0x02, + _LIS2DS12_INT_DUR_SHOCK_MASK = 3, + _LIS2DS12_INT_DUR_SHOCK_SHIFT = 0, + + LIS2DS12_INT_DUR_QUIET0 = 0x04, + LIS2DS12_INT_DUR_QUIET1 = 0x08, + _LIS2DS12_INT_DUR_QUIET_MASK = 3, + _LIS2DS12_INT_DUR_QUIET_SHIFT = 2, + + LIS2DS12_INT_DUR_LAT0 = 0x10, + LIS2DS12_INT_DUR_LAT1 = 0x20, + LIS2DS12_INT_DUR_LAT2 = 0x40, + LIS2DS12_INT_DUR_LAT3 = 0x80, + _LIS2DS12_INT_DUR_LAT_MASK = 15, + _LIS2DS12_INT_DUR_LAT_SHIFT = 4, + + } LIS2DS12_INT_DUR_BITS_T; + + /** + * REG_WAKE_UP_THS bits + */ + typedef enum { + LIS2DS12_WAKE_UP_THS_WU_THS0 = 0x01, + LIS2DS12_WAKE_UP_THS_WU_THS1 = 0x02, + LIS2DS12_WAKE_UP_THS_WU_THS2 = 0x04, + LIS2DS12_WAKE_UP_THS_WU_THS3 = 0x08, + LIS2DS12_WAKE_UP_THS_WU_THS4 = 0x10, + LIS2DS12_WAKE_UP_THS_WU_THS5 = 0x20, + _LIS2DS12_WAKE_UP_THS_WU_THS_MASK = 63, + _LIS2DS12_WAKE_UP_THS_WU_THS_SHIFT = 0, + + LIS2DS12_WAKE_UP_THS_SLEEP_ON = 0x40, + LIS2DS12_WAKE_UP_THS_SINGLE_DOUBLE_TAP = 0x80, + } LIS2DS12_WAKE_UP_THS_BITS_T; + + /** + * REG_WAKE_UP_DUR bits + */ + typedef enum { + LIS2DS12_WAKE_UP_DUR_SLEEP_DUR0 = 0x01, + LIS2DS12_WAKE_UP_DUR_SLEEP_DUR1 = 0x02, + LIS2DS12_WAKE_UP_DUR_SLEEP_DUR2 = 0x04, + LIS2DS12_WAKE_UP_DUR_SLEEP_DUR3 = 0x08, + _LIS2DS12_WAKE_UP_DUR_SLEEP_DUR_MASK = 15, + _LIS2DS12_WAKE_UP_DUR_SLEEP_DUR_SHIFT = 0, + + LIS2DS12_WAKE_UP_DUR_INT1_FSS7 = 0x10, + + LIS2DS12_WAKE_UP_DUR_WU_DUR0 = 0x20, + LIS2DS12_WAKE_UP_DUR_WU_DUR1 = 0x40, + _LIS2DS12_WAKE_UP_DUR_WU_DUR_MASK = 3, + _LIS2DS12_WAKE_UP_DUR_WU_DUR_SHIFT = 5, + + LIS2DS12_WAKE_UP_DUR_FF_DUR5 = 0x80, + } LIS2DS12_WAKE_UP_DUR_BITS_T; + + /** + * REG_FREE_FALL bits + */ + typedef enum { + LIS2DS12_FREE_FALL_FF_THS0 = 0x01, + LIS2DS12_FREE_FALL_FF_THS1 = 0x02, + LIS2DS12_FREE_FALL_FF_THS2 = 0x04, + _LIS2DS12_FREE_FALL_FF_THS_MASK = 7, + _LIS2DS12_FREE_FALL_FF_THS_SHIFT = 0, + + LIS2DS12_FREE_FALL_FF_DUR0 = 0x08, + LIS2DS12_FREE_FALL_FF_DUR1 = 0x10, + LIS2DS12_FREE_FALL_FF_DUR2 = 0x20, + LIS2DS12_FREE_FALL_FF_DUR3 = 0x40, + LIS2DS12_FREE_FALL_FF_DUR4 = 0x80, + _LIS2DS12_FREE_FALL_FF_MASK = 31, + _LIS2DS12_FREE_FALL_FF_SHIFT = 3, + } LIS2DS12_FREE_FALL_BITS_T; + + /** + * REG_STATUS_DUP bits + */ + typedef enum { + LIS2DS12_STATUS_DUP_DRDY = 0x01, + LIS2DS12_STATUS_DUP_FF_IA = 0x02, + LIS2DS12_STATUS_DUP_6D_IA = 0x04, + LIS2DS12_STATUS_DUP_SINGLE_TAP = 0x08, + LIS2DS12_STATUS_DUP_DOUBLE_TAP = 0x10, + LIS2DS12_STATUS_DUP_SLEEP_STATE = 0x20, + LIS2DS12_STATUS_DUP_WU_IA = 0x40, + LIS2DS12_STATUS_DUP_OVR = 0x80, + } LIS2DS12_STATUS_DUP_BITS_T; + + /** + * REG_WAKE_UP_SRC bits + */ + typedef enum { + LIS2DS12_WAKE_UP_SRC_Z_WU = 0x01, + LIS2DS12_WAKE_UP_SRC_Y_WU = 0x02, + LIS2DS12_WAKE_UP_SRC_X_WU = 0x04, + + LIS2DS12_WAKE_UP_SRC_WU_IA = 0x08, + LIS2DS12_WAKE_UP_SRC_SLEEP_STATE_IA = 0x10, + LIS2DS12_WAKE_UP_SRC_FF_IA = 0x20, + + // 0x40-0x80 reserved + } LIS2DS12_WAKE_UP_SRC_BITS_T; + + /** + * REG_TAP_SRC bits + */ + typedef enum { + LIS2DS12_TAP_SRC_Z_TAP = 0x01, + LIS2DS12_TAP_SRC_Y_TAP = 0x02, + LIS2DS12_TAP_SRC_X_TAP = 0x04, + LIS2DS12_TAP_SRC_TAP_SIGN = 0x08, + LIS2DS12_TAP_SRC_DOUBLE_TAP = 0x10, + LIS2DS12_TAP_SRC_SINGLE_TAP = 0x20, + LIS2DS12_TAP_SRC_TAP_IA = 0x40, + + // 0x80 reserved + } LIS2DS12_TAP_SRC_BITS_T; + + /** + * REG_6D_SRC bits + */ + typedef enum { + LIS2DS12_6D_SRC_XL = 0x01, + LIS2DS12_6D_SRC_XH = 0x02, + LIS2DS12_6D_SRC_YL = 0x04, + LIS2DS12_6D_SRC_YH = 0x08, + LIS2DS12_6D_SRC_ZL = 0x10, + LIS2DS12_6D_SRC_ZH = 0x20, + + LIS2DS12_6D_IA = 0x40, + + // 0x80 reserved + } LIS2DS12_6D_SRC_BITS_T; + + /** + * REG_STEP_COUNTER_MINTHS bits + */ + typedef enum { + LIS2DS12_STEP_COUNTER_MINTHS_SC_MTHS0 = 0x01, + LIS2DS12_STEP_COUNTER_MINTHS_SC_MTHS1 = 0x02, + LIS2DS12_STEP_COUNTER_MINTHS_SC_MTHS2 = 0x04, + LIS2DS12_STEP_COUNTER_MINTHS_SC_MTHS3 = 0x08, + LIS2DS12_STEP_COUNTER_MINTHS_SC_MTHS4 = 0x10, + LIS2DS12_STEP_COUNTER_MINTHS_SC_MTHS5 = 0x20, + _LIS2DS12_STEP_COUNTER_MINTHS_SC_MTHS5_MASK = 63, + _LIS2DS12_STEP_COUNTER_MINTHS_SC_MTHS5_SHIFT = 0, + + LIS2DS12_STEP_COUNTER_MINTHS_PEDO4G = 0x40, + LIS2DS12_STEP_COUNTER_MINTHS_RST_NSTEP = 0x80, + } LIS2DS12_STEP_COUNTER_MINTHS_BITS_T; + + /** + * REG_FUNC_CK_GATE bits + */ + typedef enum { + LIS2DS12_FUNC_CK_GATE_CK_GATE_FUNC = 0x01, + LIS2DS12_FUNC_CK_GATE_STEP_DETECT = 0x02, + LIS2DS12_FUNC_CK_GATE_RST_PEDO = 0x04, + LIS2DS12_FUNC_CK_GATE_RST_SIGN_MOT = 0x08, + LIS2DS12_FUNC_CK_GATE_SIG_MOT_DETECT = 0x10, + + LIS2DS12_FUNC_CK_GATE_FS_SRC0 = 0x20, + LIS2DS12_FUNC_CK_GATE_FS_SRC1 = 0x40, + _LIS2DS12_FUNC_CK_GATE_FS_SRC_MASK = 3, + _LIS2DS12_FUNC_CK_GATE_FS_SRC_SHIFT = 5, + + LIS2DS12_FUNC_CK_GATE_TILT_INT = 0x80, + } LIS2DS12_FUNC_CK_GATE_BITS_T; + + /** + * FUNC_CK_GATE_FS_SRC values + */ + typedef enum { + LIS2DS12_FS_SRC_NO_SCALE = 0, + LIS2DS12_FS_SRC_2G = 1, + LIS2DS12_FS_SRC_4G = 2, + } LIS2DS12_FS_SRC_T; + + /** + * REG_FUNC_SRC bits + */ + typedef enum { + LIS2DS12_FUNC_SRC_SENSORHUB_END_OP = 0x01, + LIS2DS12_FUNC_SRC_MODULE_READY = 0x02, + LIS2DS12_FUNC_SRC_RST_TILT = 0x04, + + // 0x08-0x80 reserved + } LIS2DS12_FUNC_SRC_BITS_T; + + /** + * REG_FUNC_CTRL bits + */ + typedef enum { + LIS2DS12_FUNC_CTRL_STEP_CNT_ON = 0x01, + LIS2DS12_FUNC_CTRL_SIGN_MOT_ON = 0x02, + LIS2DS12_FUNC_CTRL_MASTER_ON = 0x04, + LIS2DS12_FUNC_CTRL_TUD_EN = 0x08, + LIS2DS12_FUNC_CTRL_TILT_ON = 0x10, + LIS2DS12_FUNC_CTRL_MODULE_ON = 0x20, + + // 0x40-0x80 reserved + } LIS2DS12_FUNC_CTRL_BITS_T; + + // interrupt selection for installISR() and uninstallISR() + typedef enum { + LIS2DS12_INTERRUPT_INT1, + LIS2DS12_INTERRUPT_INT2 + } LIS2DS12_INTERRUPT_PINS_T; + +#ifdef __cplusplus +} +#endif diff --git a/src/lis2ds12/lis2ds12_fti.c b/src/lis2ds12/lis2ds12_fti.c new file mode 100644 index 00000000..6373f1e8 --- /dev/null +++ b/src/lis2ds12/lis2ds12_fti.c @@ -0,0 +1,113 @@ +/* + * 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 "lis2ds12.h" +#include "upm_fti.h" + +/** + * This file implements the Function Table Interface (FTI) for this sensor + */ + +const char upm_lis2ds12_name[] = "LIS2DS12"; +const char upm_lis2ds12_description[] = "Triple Axis Digital Accelerometer"; +const upm_protocol_t upm_lis2ds12_protocol[] = {UPM_I2C, UPM_SPI, UPM_GPIO}; +const upm_sensor_t upm_lis2ds12_category[] = {UPM_ACCELEROMETER}; + +// forward declarations +const void *upm_lis2ds12_get_ft(upm_sensor_t sensor_type); +void *upm_lis2ds12_init_name(); +void upm_lis2ds12_close(void *dev); +upm_result_t upm_lis2ds12_get_value(void *dev, float *value, + upm_acceleration_u unit); + +const upm_sensor_descriptor_t upm_lis2ds12_get_descriptor() +{ + upm_sensor_descriptor_t usd; + usd.name = upm_lis2ds12_name; + usd.description = upm_lis2ds12_description; + usd.protocol_size = 3; + usd.protocol = upm_lis2ds12_protocol; + usd.category_size = 1; + usd.category = upm_lis2ds12_category; + return usd; +} + +static const upm_sensor_ft ft = +{ + .upm_sensor_init_name = upm_lis2ds12_init_name, + .upm_sensor_close = upm_lis2ds12_close, +}; + +static const upm_acceleration_ft aft = +{ + .upm_acceleration_get_value = upm_lis2ds12_get_value +}; + +const void *upm_lis2ds12_get_ft(upm_sensor_t sensor_type) +{ + switch(sensor_type) + { + case UPM_SENSOR: + return &ft; + + case UPM_ACCELEROMETER: + return &aft; + + default: + return NULL; + } +} + +void *upm_lis2ds12_init_name() +{ + return NULL; +} + + +void upm_lis2ds12_close(void *dev) +{ + lis2ds12_close((lis2ds12_context)dev); +} + +upm_result_t upm_lis2ds12_get_value(void *dev, float *value, + upm_acceleration_u unit) +{ + if (lis2ds12_update((lis2ds12_context)dev)) + return UPM_ERROR_OPERATION_FAILED; + + // no conversion facility in place yet, so we don't do anything + // with units + + float x, y, z; + + lis2ds12_get_accelerometer(dev, &x, &y, &z); + + value[0] = x; + value[1] = y; + value[2] = z; + + return UPM_SUCCESS; +} diff --git a/src/lis2ds12/pyupm_lis2ds12.i b/src/lis2ds12/pyupm_lis2ds12.i new file mode 100644 index 00000000..f8e580ec --- /dev/null +++ b/src/lis2ds12/pyupm_lis2ds12.i @@ -0,0 +1,17 @@ +// Include doxygen-generated documentation +%include "pyupm_doxy2swig.i" +%module pyupm_lis2ds12 +%include "../upm.i" +%include "../upm_vectortypes.i" + +%feature("autodoc", "3"); + +#ifdef DOXYGEN +%include "lis2ds12_doc.i" +#endif + +%include "lis2ds12_defs.h" +%include "lis2ds12.hpp" +%{ + #include "lis2ds12.hpp" +%}