lis3dh: add sensor support based on lis2ds12 module

Adding STMicro LIS3DH sensor support. This module is based on
the one for lis2ds12 (thanks, jontrulson!), but as sensors are
noticeably different, the contents underwent major rework.

Examples and basic API are left the same.

Tested on Intel Edison with Arduino board using both I2C and SPI.

Signed-off-by: Alex Tereschenko <alext.mkrs@gmail.com>
This commit is contained in:
Alex Tereschenko 2017-12-03 18:46:15 +00:00 committed by Noel Eck
parent 76949d9358
commit a842898bd5
16 changed files with 2954 additions and 0 deletions

81
examples/c++/lis3dh.cxx Normal file
View File

@ -0,0 +1,81 @@
/*
* Author: Alex Tereschenko <alext.mkrs@gmail.com>
* Copyright (c) 2018 Alex Tereschenko.
*
* Based on LIS2DS12 example by
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 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.
*/
#include <iostream>
#include <signal.h>
#include "lis3dh.hpp"
#include "upm_utilities.h"
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 LIS3DH using default I2C parameters
upm::LIS3DH sensor;
// For SPI, bus 0, you would pass -1 as the address, and a valid pin
// for CS: LIS3DH(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;
upm_delay_us(250000);
}
//! [Interesting]
cout << "Exiting..." << endl;
return 0;
}

97
examples/c/lis3dh.c Normal file
View File

@ -0,0 +1,97 @@
/*
* Author: Alex Tereschenko <alext.mkrs@gmail.com>
* Copyright (c) 2018 Alex Tereschenko.
*
* Based on LIS2DS12 example by
* Author: Jon Trulson <jtrulson@ics.com>
* 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 <signal.h>
#include <stdio.h>
#include <unistd.h>
#include "lis3dh.h"
#include "upm_utilities.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 LIS3DH instance using default i2c bus and address
lis3dh_context sensor = lis3dh_init(LIS3DH_DEFAULT_I2C_BUS, LIS3DH_DEFAULT_I2C_ADDR, -1);
#elif defined(CONFIG_BOARD_ARDUINO_101)
// ARDUINO_101 (Quark core) must use SPI
// Instantiate a LIS3DH instance using default SPI bus and pin 10 as CS
lis3dh_context sensor = lis3dh_init(LIS3DH_DEFAULT_SPI_BUS, -1, 10);
#else
// everything else use I2C by default
// Instantiate a LIS3DH instance using default i2c bus and address
lis3dh_context sensor = lis3dh_init(LIS3DH_DEFAULT_I2C_BUS, LIS3DH_DEFAULT_I2C_ADDR, -1);
#endif
if (!sensor) {
printf("lis3dh_init() failed.\n");
return 1;
}
// now output data every 250 milliseconds
while (shouldRun) {
float x, y, z;
if (lis3dh_update(sensor)) {
printf("lis3dh_update() failed\n");
lis3dh_close(sensor);
return 1;
}
lis3dh_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", lis3dh_get_temperature(sensor));
upm_delay_ms(250);
}
printf("Exiting...\n");
lis3dh_close(sensor);
//! [Interesting]
return 0;
}

View File

@ -0,0 +1,68 @@
/*
* Author: Alex Tereschenko <alext.mkrs@gmail.com>
* Copyright (c) 2018 Alex Tereschenko.
*
* Based on LIS2DS12 example by
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 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_lis3dh.*;
public class LIS3DH_Example
{
public static void main(String[] args) throws InterruptedException
{
// ! [Interesting]
// Instantiate a LIS3DH instance using default i2c bus and address
LIS3DH sensor = new LIS3DH();
// For SPI, bus 0, you would pass -1 as the address, and a
// valid pin for CS:
// LIS3DH(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]
}
}

View File

@ -0,0 +1,69 @@
/*
* Author: Alex Tereschenko <alext.mkrs@gmail.com>
* Copyright (c) 2018 Alex Tereschenko.
*
* Based on LIS2DS12 example by
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 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_lis3dh');
// Instantiate a LIS3DH instance using default i2c bus and address
var sensor = new sensorObj.LIS3DH();
// For SPI, bus 0, you would pass -1 as the address, and a valid pin for CS:
// LIS3DH(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);
});

72
examples/python/lis3dh.py Executable file
View File

@ -0,0 +1,72 @@
#!/usr/bin/env python
# Author: Alex Tereschenko <alext.mkrs@gmail.com>
# Copyright (c) 2018 Alex Tereschenko.
#
# Based on LIS2DS12 example by
# Author: Jon Trulson <jtrulson@ics.com>
# Copyright (c) 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_lis3dh as sensorObj
def main():
# Instantiate a LIS3DH instance using default i2c bus and address
sensor = sensorObj.LIS3DH()
# For SPI, bus 0, you would pass -1 as the address, and a valid pin for CS:
# LIS3DH(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()

View File

@ -0,0 +1,9 @@
upm_mixed_module_init (NAME lis3dh
DESCRIPTION "3-Axis Digital Accelerometer"
C_HDR lis3dh.h lis3dh_defs.h
C_SRC lis3dh.c
CPP_HDR lis3dh.hpp
CPP_SRC lis3dh.cxx
FTI_SRC lis3dh_fti.c
CPP_WRAPS_C
REQUIRES mraa utilities-c)

View File

@ -0,0 +1,23 @@
%module javaupm_lis3dh
%include "../upm.i"
%include "typemaps.i"
%include "../upm_vectortypes.i"
%ignore getAccelerometer(float *, float *, float *);
%include "lis3dh_defs.h"
%include "lis3dh.hpp"
%{
#include "lis3dh.hpp"
%}
%pragma(java) jniclasscode=%{
static {
try {
System.loadLibrary("javaupm_lis3dh");
} catch (UnsatisfiedLinkError e) {
System.err.println("Native code library failed to load. \n" + e);
System.exit(1);
}
}
%}

10
src/lis3dh/jsupm_lis3dh.i Normal file
View File

@ -0,0 +1,10 @@
%module jsupm_lis3dh
%include "../upm.i"
%include "../upm_vectortypes.i"
%include "lis3dh_defs.h"
%include "lis3dh.hpp"
%{
#include "lis3dh.hpp"
%}

809
src/lis3dh/lis3dh.c Normal file
View File

@ -0,0 +1,809 @@
/*
* Author: Alex Tereschenko <alext.mkrs@gmail.com>
* Copyright (c) 2018 Alex Tereschenko.
*
* Based on LIS2DS12 module by
* Author: Jon Trulson <jtrulson@ics.com>
* 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 <assert.h>
#include <unistd.h>
#include "lis3dh.h"
#include "upm_utilities.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) (_LIS3DH_##x##_SHIFT)
#undef _MASK
#define _MASK(x) (_LIS3DH_##x##_MASK)
#undef _SHIFTMASK
#define _SHIFTMASK(x) (_MASK(x) << _SHIFT(x))
// SPI CS on and off functions
static void
_csOn(const lis3dh_context dev)
{
assert(dev != NULL);
if (dev->gpioCS) {
mraa_gpio_write(dev->gpioCS, 0);
}
}
static void
_csOff(const lis3dh_context dev)
{
assert(dev != NULL);
if (dev->gpioCS) {
mraa_gpio_write(dev->gpioCS, 1);
}
}
// Init
lis3dh_context
lis3dh_init(int bus, int addr, int cs)
{
lis3dh_context dev = (lis3dh_context) malloc(sizeof(struct _lis3dh_context));
if (!dev) {
return NULL;
}
// Zero out context
memset((void*) dev, 0, sizeof(struct _lis3dh_context));
// Make sure MRAA is initialized
if (mraa_init() != MRAA_SUCCESS) {
printf("%s: mraa_init() failed\n", __FUNCTION__);
lis3dh_close(dev);
return NULL;
}
if (addr < 0) {
// SPI
if (!(dev->spi = mraa_spi_init(bus))) {
printf("%s: mraa_spi_init() for bus %d failed\n", __FUNCTION__, bus);
lis3dh_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() for CS pin %d failed\n", __FUNCTION__, cs);
lis3dh_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__);
lis3dh_close(dev);
return NULL;
}
} else {
// I2C
if (!(dev->i2c = mraa_i2c_init(bus))) {
printf("%s: mraa_i2c_init() for bus %d failed\n", __FUNCTION__, bus);
lis3dh_close(dev);
return NULL;
}
if (mraa_i2c_address(dev->i2c, addr)) {
printf("%s: mraa_i2c_address() for address 0x%x failed\n", __FUNCTION__, addr);
lis3dh_close(dev);
return NULL;
}
}
// Check the chip id
uint8_t chipID = lis3dh_get_chip_id(dev);
if (chipID != LIS3DH_CHIPID) {
printf("%s: invalid chip id: %02x, expected %02x\n", __FUNCTION__, chipID, LIS3DH_CHIPID);
lis3dh_close(dev);
return NULL;
}
// Call devinit with default options
if (lis3dh_devinit(dev, LIS3DH_ODR_100HZ, LIS3DH_FS_2G, true)) {
printf("%s: lis3dh_devinit() failed\n", __FUNCTION__);
lis3dh_close(dev);
return NULL;
}
return dev;
}
void
lis3dh_close(lis3dh_context dev)
{
assert(dev != NULL);
lis3dh_uninstall_isr(dev, LIS3DH_INTERRUPT_INT1);
lis3dh_uninstall_isr(dev, LIS3DH_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
lis3dh_devinit(const lis3dh_context dev, LIS3DH_ODR_T odr, LIS3DH_FS_T fs, bool high_res)
{
assert(dev != NULL);
// Set high resolution mode, ODR and FS using passed values.
// Also unconditionally enable X, Y and Z axes, temperature sensor (and ADC),
// BDU mode as well as disable output high-pass filter.
if (lis3dh_enable_lp_mode(dev, false) ||
lis3dh_enable_hr_mode(dev, high_res) ||
lis3dh_enable_axes(dev, true, true, true) ||
lis3dh_enable_bdu_mode(dev, true) ||
lis3dh_set_odr(dev, odr) ||
lis3dh_set_full_scale(dev, fs) ||
lis3dh_enable_hp_filtering(dev, false) ||
lis3dh_enable_temperature(dev, true)) {
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
lis3dh_enable_axes(const lis3dh_context dev,
bool x_axis_enable,
bool y_axis_enable,
bool z_axis_enable)
{
assert(dev != NULL);
uint8_t reg = lis3dh_read_reg(dev, LIS3DH_REG_CTRL_REG1);
// X axis
if (x_axis_enable) {
reg |= LIS3DH_CTRL_REG1_XEN;
} else {
reg &= ~LIS3DH_CTRL_REG1_XEN;
}
// Y axis
if (y_axis_enable) {
reg |= LIS3DH_CTRL_REG1_YEN;
} else {
reg &= ~LIS3DH_CTRL_REG1_YEN;
}
// Z axis
if (z_axis_enable) {
reg |= LIS3DH_CTRL_REG1_ZEN;
} else {
reg &= ~LIS3DH_CTRL_REG1_ZEN;
}
if (lis3dh_write_reg(dev, LIS3DH_REG_CTRL_REG1, reg)) {
printf("%s: failed to enable axes\n", __FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
return UPM_SUCCESS;
}
upm_result_t
lis3dh_enable_bdu_mode(const lis3dh_context dev, bool bdu_enable)
{
assert(dev != NULL);
uint8_t reg = lis3dh_read_reg(dev, LIS3DH_REG_CTRL_REG4);
if (bdu_enable) {
reg |= LIS3DH_CTRL_REG4_BDU;
} else {
reg &= ~LIS3DH_CTRL_REG4_BDU;
}
if (lis3dh_write_reg(dev, LIS3DH_REG_CTRL_REG4, reg)) {
printf("%s: failed to set BDU mode\n", __FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
return UPM_SUCCESS;
}
upm_result_t
lis3dh_enable_lp_mode(const lis3dh_context dev, bool lp_enable)
{
assert(dev != NULL);
uint8_t reg = lis3dh_read_reg(dev, LIS3DH_REG_CTRL_REG1);
if (lp_enable) {
// Check whether high resolution mode is enabled - enabling both LP and HR is not allowed
uint8_t tmp_reg = lis3dh_read_reg(dev, LIS3DH_REG_CTRL_REG4);
if (tmp_reg & LIS3DH_CTRL_REG4_HR) {
printf("%s: can't enable low power mode, high resolution mode is already enabled\n",
__FUNCTION__);
return UPM_ERROR_INVALID_PARAMETER;
} else {
// We are good - enable low power mode
reg |= LIS3DH_CTRL_REG1_LPEN;
// Set temperatureFactor according to LP mode bit width (8b).
// This is needed to account for left alignment of the temperature data.
// We have to shift the data right (== divide by a factor in case of float)
// to eliminate "dead" bits.
dev->temperatureFactor = 256;
}
} else {
reg &= ~LIS3DH_CTRL_REG1_LPEN;
// Set temperatureFactor according to Normal mode bit width (10b)
dev->temperatureFactor = 64;
}
if (lis3dh_write_reg(dev, LIS3DH_REG_CTRL_REG1, reg)) {
printf("%s: failed to set low power mode\n", __FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
return UPM_SUCCESS;
}
upm_result_t
lis3dh_enable_hr_mode(const lis3dh_context dev, bool hr_enable)
{
assert(dev != NULL);
uint8_t reg = lis3dh_read_reg(dev, LIS3DH_REG_CTRL_REG4);
if (hr_enable) {
// Check whether low power mode is enabled - enabling both LP and HR is not allowed
uint8_t tmp_reg = lis3dh_read_reg(dev, LIS3DH_REG_CTRL_REG1);
if (tmp_reg & LIS3DH_CTRL_REG1_LPEN) {
printf("%s: can't enable high resolution mode, low power mode is already enabled\n",
__FUNCTION__);
return UPM_ERROR_INVALID_PARAMETER;
} else {
// We are good - enable high resolution mode
reg |= LIS3DH_CTRL_REG4_HR;
}
} else {
reg &= ~LIS3DH_CTRL_REG4_HR;
}
// Set the temperature sensor scaling factor appropriately.
// Its max is 10 bit for both normal and HR modes.
dev->temperatureFactor = 64;
if (lis3dh_write_reg(dev, LIS3DH_REG_CTRL_REG4, reg)) {
printf("%s: failed to set high resolution mode\n", __FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
return UPM_SUCCESS;
}
upm_result_t
lis3dh_enable_normal_mode(const lis3dh_context dev)
{
assert(dev != NULL);
// There's no special mode bit for Normal - just disable LP and HR
if (lis3dh_enable_lp_mode(dev, false) || lis3dh_enable_hr_mode(dev, false)) {
printf("%s: failed to enable normal mode\n", __FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
return UPM_SUCCESS;
}
upm_result_t
lis3dh_enable_hp_filtering(const lis3dh_context dev, bool filter)
{
assert(dev != NULL);
uint8_t reg = lis3dh_read_reg(dev, LIS3DH_REG_CTRL_REG2);
if (filter) {
reg |= LIS3DH_CTRL_REG2_FDS;
} else {
reg &= ~LIS3DH_CTRL_REG2_FDS;
}
if (lis3dh_write_reg(dev, LIS3DH_REG_CTRL_REG2, reg)) {
printf("%s: failed to set HP filter mode\n", __FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
return UPM_SUCCESS;
}
upm_result_t
lis3dh_enable_interrupt_latching(const lis3dh_context dev, bool int1_latch, bool int2_latch)
{
assert(dev != NULL);
uint8_t reg = lis3dh_read_reg(dev, LIS3DH_REG_CTRL_REG5);
if (int1_latch) {
reg |= LIS3DH_CTRL_REG5_LIR_INT1;
} else {
reg &= ~LIS3DH_CTRL_REG5_LIR_INT1;
}
if (int2_latch) {
reg |= LIS3DH_CTRL_REG5_LIR_INT2;
} else {
reg &= ~LIS3DH_CTRL_REG5_LIR_INT2;
}
if (lis3dh_write_reg(dev, LIS3DH_REG_CTRL_REG5, reg)) {
printf("%s: failed to set interrupt latching mode\n", __FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
return UPM_SUCCESS;
}
upm_result_t
lis3dh_enable_adc(const lis3dh_context dev, bool adc_enable)
{
assert(dev != NULL);
// BDU mode is a prerequisite
if (adc_enable && lis3dh_enable_bdu_mode(dev, true)) {
printf("%s: failed to enable BDU mode - a prerequisite for enabling ADC\n", __FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
uint8_t reg = lis3dh_read_reg(dev, LIS3DH_REG_TEMP_CFG_REG);
if (adc_enable) {
reg |= LIS3DH_TEMP_CFG_REG_ADC_EN;
} else {
reg &= ~LIS3DH_TEMP_CFG_REG_ADC_EN;
}
if (lis3dh_write_reg(dev, LIS3DH_REG_TEMP_CFG_REG, reg)) {
printf("%s: failed to set ADC mode\n", __FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
return UPM_SUCCESS;
}
upm_result_t
lis3dh_enable_temperature(const lis3dh_context dev, bool temperature_enable)
{
assert(dev != NULL);
// ADC must be enabled for temperature readings to work
if (temperature_enable && lis3dh_enable_adc(dev, true)) {
printf("%s: failed to enable ADC - a prerequisite for enabling temperature sensor\n",
__FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
uint8_t reg = lis3dh_read_reg(dev, LIS3DH_REG_TEMP_CFG_REG);
if (temperature_enable) {
reg |= LIS3DH_TEMP_CFG_REG_TEMP_EN;
} else {
reg &= ~LIS3DH_TEMP_CFG_REG_TEMP_EN;
}
if (lis3dh_write_reg(dev, LIS3DH_REG_TEMP_CFG_REG, reg)) {
printf("%s: failed to set temperature sensor mode\n", __FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
return UPM_SUCCESS;
}
upm_result_t
lis3dh_set_odr(const lis3dh_context dev, LIS3DH_ODR_T odr)
{
assert(dev != NULL);
bool lp_mode = false;
uint8_t reg = lis3dh_read_reg(dev, LIS3DH_REG_CTRL_REG1);
// Zero out ODR bits
reg &= ~_SHIFTMASK(CTRL_REG1_ODR);
// We encoded an extra bit in LIS3DH_ODR_T indicating an LP mode. Check for it here.
if ((int) odr > (int) _MASK(CTRL_REG1_ODR)) {
lp_mode = true;
}
// Mask it off and set it
odr &= _MASK(CTRL_REG1_ODR);
reg |= (odr << _SHIFT(CTRL_REG1_ODR));
// Set the LPEN bit appropriately
lis3dh_enable_lp_mode(dev, lp_mode);
// Commit our changes
if (lis3dh_write_reg(dev, LIS3DH_REG_CTRL_REG1, reg)) {
printf("%s: failed to set ODR configuration\n", __FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
return UPM_SUCCESS;
}
upm_result_t
lis3dh_set_full_scale(const lis3dh_context dev, LIS3DH_FS_T fs)
{
assert(dev != NULL);
uint8_t reg = lis3dh_read_reg(dev, LIS3DH_REG_CTRL_REG4);
// Mask out FS bits, add our own
reg &= ~_SHIFTMASK(CTRL_REG4_FS);
reg |= (fs << _SHIFT(CTRL_REG4_FS));
if (lis3dh_write_reg(dev, LIS3DH_REG_CTRL_REG4, reg)) {
printf("%s: failed to set FS configuration\n", __FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
// Basic sensitivity in g/LSB, calculated for a full 16b resolution.
switch (fs) {
case LIS3DH_FS_2G:
// (2*2) / 2^16
dev->accScale = 0.000061;
break;
case LIS3DH_FS_4G:
// (4*2) / 2^16
dev->accScale = 0.000122;
break;
case LIS3DH_FS_8G:
// (8*2) / 2^16
dev->accScale = 0.000244;
break;
case LIS3DH_FS_16G:
// (16*2) / 2^16
dev->accScale = 0.000488;
break;
}
return UPM_SUCCESS;
}
upm_result_t
lis3dh_set_interrupt_active_high(const lis3dh_context dev, bool high)
{
assert(dev != NULL);
uint8_t reg = lis3dh_read_reg(dev, LIS3DH_REG_CTRL_REG6);
if (high) {
reg &= ~LIS3DH_CTRL_REG6_INT_POLARITY;
} else {
reg |= LIS3DH_CTRL_REG6_INT_POLARITY;
}
if (lis3dh_write_reg(dev, LIS3DH_REG_CTRL_REG6, reg)) {
printf("%s: failed to set interrupt polarity mode\n", __FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
return UPM_SUCCESS;
}
upm_result_t
lis3dh_set_int1_config(const lis3dh_context dev, uint8_t cfg)
{
assert(dev != NULL);
if (lis3dh_write_reg(dev, LIS3DH_REG_CTRL_REG3, cfg)) {
printf("%s: failed to set interrupt 1 configuration\n", __FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
return UPM_SUCCESS;
}
upm_result_t
lis3dh_set_int2_config(const lis3dh_context dev, uint8_t cfg)
{
assert(dev != NULL);
if (lis3dh_write_reg(dev, LIS3DH_REG_CTRL_REG6, cfg)) {
printf("%s: failed to set interrupt 2 configuration\n", __FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
return UPM_SUCCESS;
}
uint8_t
lis3dh_read_reg(const lis3dh_context dev, uint8_t reg)
{
assert(dev != NULL);
if (dev->spi) {
// Needed for read
reg |= 0x80;
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
lis3dh_read_regs(const lis3dh_context dev, uint8_t reg, uint8_t* buffer, int len)
{
assert(dev != NULL);
if (dev->spi) {
// Needed for read with address autoincrement
reg |= 0xC0;
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; i < len; i++) {
buffer[i] = sbuf[i + 1];
}
} else {
// Needed for read with address autoincrement
reg |= 0x80;
if (mraa_i2c_read_bytes_data(dev->i2c, reg, buffer, len) != len) {
return -1;
}
}
return len;
}
upm_result_t
lis3dh_write_reg(const lis3dh_context dev, uint8_t reg, uint8_t val)
{
assert(dev != NULL);
if (dev->spi) {
// Mask off 0x80 for writing
reg &= 0x7F;
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;
}
upm_result_t
lis3dh_update(const lis3dh_context dev)
{
assert(dev != NULL);
// Max axes data length, 2 bytes per axis * 3 axes
const int bufLen = 6;
// Max temperature data length
const int temperatureBufLen = 2;
// We reuse the same array when reading acceleration and then temperature data
uint8_t buf[bufLen];
if (lis3dh_read_regs(dev, LIS3DH_REG_OUT_X_L, buf, bufLen) != bufLen) {
printf("%s: lis3dh_read_regs() failed to read %d bytes of axes data\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
if (lis3dh_read_regs(dev, LIS3DH_REG_OUT_ADC3_L, buf, temperatureBufLen) != temperatureBufLen) {
printf("%s: lis3dh_read_regs() failed to read %d bytes of temperature data\n",
__FUNCTION__,
temperatureBufLen);
return UPM_ERROR_OPERATION_FAILED;
}
dev->temperature = INT16_TO_FLOAT(buf[1], buf[0]);
return UPM_SUCCESS;
}
uint8_t
lis3dh_get_chip_id(const lis3dh_context dev)
{
assert(dev != NULL);
return lis3dh_read_reg(dev, LIS3DH_REG_WHO_AM_I);
}
void
lis3dh_get_accelerometer(const lis3dh_context dev, float* x, float* y, float* z)
{
assert(dev != NULL);
if (x) {
*x = dev->accX * dev->accScale;
}
if (y) {
*y = dev->accY * dev->accScale;
}
if (z) {
*z = dev->accZ * dev->accScale;
}
}
float
lis3dh_get_temperature(const lis3dh_context dev)
{
assert(dev != NULL);
return (dev->temperature / dev->temperatureFactor);
}
uint8_t
lis3dh_get_status(const lis3dh_context dev)
{
assert(dev != NULL);
return lis3dh_read_reg(dev, LIS3DH_REG_STATUS_REG);
}
uint8_t
lis3dh_get_status_aux(const lis3dh_context dev)
{
assert(dev != NULL);
return lis3dh_read_reg(dev, LIS3DH_REG_STATUS_REG_AUX);
}
upm_result_t
lis3dh_install_isr(const lis3dh_context dev,
LIS3DH_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
lis3dh_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 LIS3DH_INTERRUPT_INT1:
dev->gpioINT1 = gpio_isr;
break;
case LIS3DH_INTERRUPT_INT2:
dev->gpioINT2 = gpio_isr;
break;
}
return UPM_SUCCESS;
}
void
lis3dh_uninstall_isr(const lis3dh_context dev, LIS3DH_INTERRUPT_PINS_T intr)
{
assert(dev != NULL);
switch (intr) {
case LIS3DH_INTERRUPT_INT1:
if (dev->gpioINT1) {
mraa_gpio_isr_exit(dev->gpioINT1);
mraa_gpio_close(dev->gpioINT1);
dev->gpioINT1 = NULL;
}
break;
case LIS3DH_INTERRUPT_INT2:
if (dev->gpioINT2) {
mraa_gpio_isr_exit(dev->gpioINT2);
mraa_gpio_close(dev->gpioINT2);
dev->gpioINT2 = NULL;
}
break;
}
}

276
src/lis3dh/lis3dh.cxx Normal file
View File

@ -0,0 +1,276 @@
/*
* Author: Alex Tereschenko <alext.mkrs@gmail.com>
* Copyright (c) 2018 Alex Tereschenko.
*
* Based on LIS2DS12 module by
* Author: Jon Trulson <jtrulson@ics.com>
* 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 <iostream>
#include <stdexcept>
#include <string>
#include <unistd.h>
#include "lis3dh.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);
}
LIS3DH::LIS3DH(int bus, int addr, int cs) : m_lis3dh(lis3dh_init(bus, addr, cs))
{
if (!m_lis3dh) {
throw std::runtime_error(string(__FUNCTION__) + ": lis3dh_init() failed");
}
}
LIS3DH::~LIS3DH()
{
lis3dh_close(m_lis3dh);
}
void
LIS3DH::init(LIS3DH_ODR_T odr, LIS3DH_FS_T fs, bool high_res)
{
if (lis3dh_devinit(m_lis3dh, odr, fs, high_res)) {
throw std::runtime_error(string(__FUNCTION__) + ": lis3dh_devinit() failed");
}
}
void
LIS3DH::enableAxes(bool x_axis_enable, bool y_axis_enable, bool z_axis_enable)
{
if (lis3dh_enable_axes(m_lis3dh, x_axis_enable, y_axis_enable, z_axis_enable)) {
throw std::runtime_error(string(__FUNCTION__) + ": lis3dh_enable_axes() failed");
}
}
void
LIS3DH::enableBDUMode(bool bdu_enable)
{
if (lis3dh_enable_bdu_mode(m_lis3dh, bdu_enable)) {
throw std::runtime_error(string(__FUNCTION__) + ": lis3dh_enable_bdu_mode() failed");
}
}
void
LIS3DH::enableLPMode(bool lp_enable)
{
if (lis3dh_enable_lp_mode(m_lis3dh, lp_enable)) {
throw std::runtime_error(string(__FUNCTION__) + ": lis3dh_enable_lp_mode() failed");
}
}
void
LIS3DH::enableHRMode(bool hr_enable)
{
if (lis3dh_enable_hr_mode(m_lis3dh, hr_enable)) {
throw std::runtime_error(string(__FUNCTION__) + ": lis3dh_enable_hr_mode() failed");
}
}
void
LIS3DH::enableNormalMode()
{
if (lis3dh_enable_normal_mode(m_lis3dh)) {
throw std::runtime_error(string(__FUNCTION__) + ": lis3dh_enable_normal_mode() failed");
}
}
void
LIS3DH::enableHPFiltering(bool filter)
{
if (lis3dh_enable_hp_filtering(m_lis3dh, filter)) {
throw std::runtime_error(string(__FUNCTION__) + ": lis3dh_enable_hp_filtering() failed");
}
}
void
LIS3DH::enableInterruptLatching(bool int1_latch, bool int2_latch)
{
if (lis3dh_enable_interrupt_latching(m_lis3dh, int1_latch, int2_latch)) {
throw std::runtime_error(string(__FUNCTION__) +
": lis3dh_enable_interrupt_latching() failed");
}
}
void
LIS3DH::enableADC(bool adc_enable)
{
if (lis3dh_enable_adc(m_lis3dh, adc_enable)) {
throw std::runtime_error(string(__FUNCTION__) + ": lis3dh_enable_adc() failed");
}
}
void
LIS3DH::enableTemperature(bool temperature_enable)
{
if (lis3dh_enable_temperature(m_lis3dh, temperature_enable)) {
throw std::runtime_error(string(__FUNCTION__) + ": lis3dh_enable_temperature() failed");
}
}
void
LIS3DH::setODR(LIS3DH_ODR_T odr)
{
if (lis3dh_set_odr(m_lis3dh, odr)) {
throw std::runtime_error(string(__FUNCTION__) + ": lis3dh_set_odr() failed");
}
}
void
LIS3DH::setFullScale(LIS3DH_FS_T fs)
{
if (lis3dh_set_full_scale(m_lis3dh, fs)) {
throw std::runtime_error(string(__FUNCTION__) + ": lis3dh_set_full_scale() failed");
}
}
void
LIS3DH::setInterruptActiveHigh(bool high)
{
if (lis3dh_set_interrupt_active_high(m_lis3dh, high)) {
throw std::runtime_error(string(__FUNCTION__) +
": lis3dh_set_interrupt_active_high() failed");
}
}
void
LIS3DH::setInt1Config(uint8_t cfg)
{
if (lis3dh_set_int1_config(m_lis3dh, cfg)) {
throw std::runtime_error(string(__FUNCTION__) + ": lis3dh_set_int1_config() failed");
}
}
void
LIS3DH::setInt2Config(uint8_t cfg)
{
if (lis3dh_set_int2_config(m_lis3dh, cfg)) {
throw std::runtime_error(string(__FUNCTION__) + ": lis3dh_set_int2_config() failed");
}
}
uint8_t
LIS3DH::readReg(uint8_t reg)
{
return lis3dh_read_reg(m_lis3dh, reg);
}
int
LIS3DH::readRegs(uint8_t reg, uint8_t* buffer, int len)
{
int rv = lis3dh_read_regs(m_lis3dh, reg, buffer, len);
if (rv != len) {
throw std::runtime_error(string(__FUNCTION__) + ": lis3dh_read_regs() failed");
}
return rv;
}
void
LIS3DH::writeReg(uint8_t reg, uint8_t val)
{
if (lis3dh_write_reg(m_lis3dh, reg, val)) {
throw std::runtime_error(string(__FUNCTION__) + ": lis3dh_write_reg() failed");
}
}
void
LIS3DH::update()
{
if (lis3dh_update(m_lis3dh)) {
throw std::runtime_error(string(__FUNCTION__) + ": lis3dh_update() failed");
}
}
uint8_t
LIS3DH::getChipID()
{
return lis3dh_get_chip_id(m_lis3dh);
}
void
LIS3DH::getAccelerometer(float* x, float* y, float* z)
{
lis3dh_get_accelerometer(m_lis3dh, x, y, z);
}
std::vector<float>
LIS3DH::getAccelerometer()
{
float v[3];
getAccelerometer(&v[0], &v[1], &v[2]);
return std::vector<float>(v, v + 3);
}
float
LIS3DH::getTemperature(bool fahrenheit)
{
float temperature = lis3dh_get_temperature(m_lis3dh);
if (fahrenheit) {
return c2f(temperature);
} else {
return temperature;
}
}
uint8_t
LIS3DH::getStatus()
{
return lis3dh_get_status(m_lis3dh);
}
uint8_t
LIS3DH::getStatusAux()
{
return lis3dh_get_status_aux(m_lis3dh);
}
void
LIS3DH::installISR(LIS3DH_INTERRUPT_PINS_T intr,
int gpio,
mraa::Edge level,
void (*isr)(void*),
void* arg)
{
if (lis3dh_install_isr(m_lis3dh, intr, gpio, (mraa_gpio_edge_t) level, isr, arg)) {
throw std::runtime_error(string(__FUNCTION__) + ": lis3dh_install_isr() failed");
}
}
void
LIS3DH::uninstallISR(LIS3DH_INTERRUPT_PINS_T intr)
{
lis3dh_uninstall_isr(m_lis3dh, intr);
}

382
src/lis3dh/lis3dh.h Normal file
View File

@ -0,0 +1,382 @@
/*
* Author: Alex Tereschenko <alext.mkrs@gmail.com>
* Copyright (c) 2018 Alex Tereschenko.
*
* Based on LIS2DS12 module by
* Author: Jon Trulson <jtrulson@ics.com>
* 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 <string.h>
#include <unistd.h>
#include <mraa/gpio.h>
#include <mraa/i2c.h>
#include <mraa/spi.h>
#include "upm.h"
#include "lis3dh_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file lis3dh.h
* @library lis3dh
* @brief C API for the lis3dh driver
*
* @include lis3dh.c
*/
/**
* Device context
*/
typedef struct _lis3dh_context {
mraa_i2c_context i2c;
mraa_spi_context spi;
mraa_gpio_context gpioCS; // SPI CS pin
mraa_gpio_context gpioINT1; // Interrupt 1
mraa_gpio_context gpioINT2; // Interrupt 2
// Uncompensated temperature data
float temperature;
// Temperature scaling factor. It accounts for storing 8b or 10b actual
// data in 16b register pair.
float temperatureFactor;
// Uncompensated acceleration data
float accX;
float accY;
float accZ;
// Acceleration scaling - used to calculate actual acceleration,
// depending on sensor working mode (low power/normal/high resolution)
float accScale;
} * lis3dh_context;
/**
* LIS3DH 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
*/
lis3dh_context lis3dh_init(int bus, int addr, int cs);
/**
* LIS3DH Destructor
*
* @param dev The device context
*/
void lis3dh_close(lis3dh_context dev);
/**
* Initialize the device and start operation. This function is
* called from lis3dh_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 LIS3DH_ODR_T values
* @param fs One of the LIS3DH_FS_T values
* @param high_res true to enable high resolution mode, false to disable
* @return UPM result
*/
upm_result_t
lis3dh_devinit(const lis3dh_context dev, LIS3DH_ODR_T odr, LIS3DH_FS_T fs, bool high_res);
/**
* Enable or disable specific axes.
*
* @param dev The device context
* @param x_axis_enable true to enable X axis, false to disable
* @param y_axis_enable true to enable Y axis, false to disable
* @param z_axis_enable true to enable Z axis, false to disable
* @return UPM result
*/
upm_result_t lis3dh_enable_axes(const lis3dh_context dev,
bool x_axis_enable,
bool y_axis_enable,
bool z_axis_enable);
/**
* Enable or disable Block Data Update (BDU) mode.
*
* @param dev The device context
* @param bdu_enable true to enable BDU mode, false to disable
* @return UPM result
*/
upm_result_t lis3dh_enable_bdu_mode(const lis3dh_context dev, bool bdu_enable);
/**
* Enable or disable Low Power (LP) mode. Checks if mutually exclusive
* High Resolution (HR) mode is enabled and bails out if yes.
*
* @param dev The device context
* @param lp_enable true to enable LP mode, false to disable
* @return UPM result
*/
upm_result_t lis3dh_enable_lp_mode(const lis3dh_context dev, bool lp_enable);
/**
* Enable or disable High Resolution (HR) mode. Checks if mutually exclusive
* Low Power (LP) mode is enabled and bails out if yes.
*
* @param dev The device context
* @param hr_enable true to enable HR mode, false to disable
* @return UPM result
*/
upm_result_t lis3dh_enable_hr_mode(const lis3dh_context dev, bool hr_enable);
/**
* Enable Normal mode by explicitly disabling LP and HR ones.
* Note that there's no "disable" part as it's generally unknown, which mode
* we were in previously. To get out of Normal mode, just enable HR or LP one.
*
* @param dev The device context
* @return UPM result
*/
upm_result_t lis3dh_enable_normal_mode(const lis3dh_context dev);
/**
* Enable high pass filtering of the accelerometer axis data.
* lis3dh_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 lis3dh_enable_hp_filtering(const lis3dh_context dev, bool filter);
/**
* Enable or disable built-in Analog-to-Digital Converter (ADC).
*
* @param dev The device context
* @param adc_enable true to enable ADC, false to disable
* @return UPM result
*/
upm_result_t lis3dh_enable_adc(const lis3dh_context dev, bool adc_enable);
/**
* Enable or disable built-in temperature sensor. It depends on ADC being
* enabled, so we enable it unconditionally. See datasheet for details.
*
* @param dev The device context
* @param temperature_enable true to enable temp sensor, false to disable
* @return UPM result
*/
upm_result_t lis3dh_enable_temperature(const lis3dh_context dev, bool temperature_enable);
/**
* Enable or disable interrupt latching for INT1 and INT2.
* See the datasheet for details.
*
* @param dev The device context
* @param int1_latch true to enable latching for INT1, false to disable
* @param int2_latch true to enable latching for INT2, false to disable
* @return UPM result
*/
upm_result_t
lis3dh_enable_interrupt_latching(const lis3dh_context dev, bool int1_latch, bool int2_latch);
/**
* Set the output data rate (ODR) of the device
*
* @param dev The device context
* @param odr One of the LIS3DH_ODR_T values
* @return UPM result
*/
upm_result_t lis3dh_set_odr(const lis3dh_context dev, LIS3DH_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 LIS3DH_FS_T values
* @return UPM result
*/
upm_result_t lis3dh_set_full_scale(const lis3dh_context dev, LIS3DH_FS_T fs);
/**
* Indicate whether INT1 and INT2 interrupts 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 lis3dh_set_interrupt_active_high(const lis3dh_context dev, bool high);
/**
* Set interrupt 1 configuration. See the datasheet for details.
*
* @param dev The device context
* @param cfg A bitmask of values from LIS3DH_CTRL_REG3_BITS_T
* @return UPM result
*/
upm_result_t lis3dh_set_int1_config(const lis3dh_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 LIS3DH_CTRL_REG6_BITS_T
* @return UPM result
*/
upm_result_t lis3dh_set_int2_config(const lis3dh_context dev, uint8_t cfg);
/**
* Read a register
*
* @param dev The device context
* @param reg The register to read
* @return The value of the register
*/
uint8_t lis3dh_read_reg(const lis3dh_context dev, uint8_t reg);
/**
* Read contiguous registers into a buffer
*
* @param dev The device context
* @param reg The register to start the read from
* @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 lis3dh_read_regs(const lis3dh_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 lis3dh_write_reg(const lis3dh_context dev, uint8_t reg, uint8_t val);
/**
* Update the internal stored values from sensor data
*
* @param dev The device context
* @return UPM result
*/
upm_result_t lis3dh_update(const lis3dh_context dev);
/**
* Return the chip ID
*
* @param dev The device context
* @return The chip ID (LIS3DH_CHIPID)
*/
uint8_t lis3dh_get_chip_id(const lis3dh_context dev);
/**
* Return accelerometer data gravities (g). lis3dh_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 lis3dh_get_accelerometer(const lis3dh_context dev, float* x, float* y, float* z);
/**
* Return the current measured temperature. Note, this is not
* ambient temperature. lis3dh_update() must have been called
* prior to calling this method.
*
* @param dev The device context
* @return The temperature in degrees Celsius
*/
float lis3dh_get_temperature(const lis3dh_context dev);
/**
* Return the contents of the status register
*
* @param dev The device context
* @return A bitmask of values from LIS3DH_STATUS_REG_BITS_T
*/
uint8_t lis3dh_get_status(const lis3dh_context dev);
/**
* Return the contents of the status aux register
*
* @param dev The device context
* @return A bitmask of values from LIS3DH_STATUS_REG_AUX_BITS_T
*/
uint8_t lis3dh_get_status_aux(const lis3dh_context dev);
/**
* Install an interrupt handler
*
* @param dev The device context
* @param intr One of the LIS3DH_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 lis3dh_install_isr(const lis3dh_context dev,
LIS3DH_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 LIS3DH_INTERRUPT_PINS_T values
* specifying which interrupt pin you are removing
*/
void lis3dh_uninstall_isr(const lis3dh_context dev, LIS3DH_INTERRUPT_PINS_T intr);
#ifdef __cplusplus
}
#endif

384
src/lis3dh/lis3dh.hpp Normal file
View File

@ -0,0 +1,384 @@
/*
* Author: Alex Tereschenko <alext.mkrs@gmail.com>
* Copyright (c) 2018 Alex Tereschenko.
*
* Based on LIS2DS12 module by
* Author: Jon Trulson <jtrulson@ics.com>
* 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 <string>
#include <vector>
#include "lis3dh.h"
#include <mraa/gpio.hpp>
namespace upm
{
/**
* @brief ST Micro 3-axis Accelerometer
* @defgroup lis3dh libupm-lis3dh
* @ingroup i2c spi gpio stmicro accelerometer
*/
/**
* @library lis3dh
* @sensor lis3dh
* @comname Digital 3-axis Accelerometer
* @type accelerometer
* @man stmicro
* @con i2c spi gpio
* @web http://www.st.com/en/mems-and-sensors/lis3dh.html
*
* @brief API for the LIS3DH 3-axis Accelerometer
*
* The LIS3DH is an ultra-low-power high performance three-axis
* linear accelerometer belonging to the "nano" family which
* leverages on the robust and mature manufacturing processes
* already used for the production of micromachined
* accelerometers.
*
* The LIS3DH has user-selectable full scales of
* 2g/4g/8g/16g and is capable of measuring accelerations with
* output data rates from 1 Hz to 5300 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.
*
* @snippet lis3dh.cxx Interesting
*/
class LIS3DH
{
public:
/**
* LIS3DH 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
*/
LIS3DH(int bus = LIS3DH_DEFAULT_I2C_BUS, int addr = LIS3DH_DEFAULT_I2C_ADDR, int cs = -1);
/**
* LIS3DH destructor
*/
virtual ~LIS3DH();
/**
* 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 LIS3DH_ODR_T values. The default is
* LIS3DH_ODR_100HZ
* @param fs One of the LIS3DH_FS_T values. The default is
* LIS3DH_FS_2G
* @param high_res true to enable high resolution mode,
* false to disable. The default is true.
* @throws std::runtime_error on failure
*/
void
init(LIS3DH_ODR_T odr = LIS3DH_ODR_100HZ, LIS3DH_FS_T fs = LIS3DH_FS_2G, bool high_res = true);
/**
* Enable or disable specific axes.
* init() enables all three by default.
*
* @param x_axis_enable true to enable X axis, false to disable
* @param y_axis_enable true to enable Y axis, false to disable
* @param z_axis_enable true to enable Z axis, false to disable
* @throws std::runtime_error on failure
*/
void enableAxes(bool x_axis_enable, bool y_axis_enable, bool z_axis_enable);
/**
* Enable or disable Block Data Update (BDU) mode.
*
* @param bdu_enable true to enable BDU mode, false to disable
* @throws std::runtime_error on failure
*/
void enableBDUMode(bool bdu_enable);
/**
* Enable or disable Low Power (LP) mode. Checks if mutually exclusive
* High Resolution (HR) mode is enabled and bails out if yes.
*
* @param lp_enable true to enable LP mode, false to disable
* @throws std::runtime_error on failure
*/
void enableLPMode(bool lp_enable);
/**
* Enable or disable High Resolution (HR) mode. Checks if mutually exclusive
* Low Power (LP) mode is enabled and bails out if yes.
*
* @param hr_enable true to enable HR mode, false to disable
* @throws std::runtime_error on failure
*/
void enableHRMode(bool hr_enable);
/**
* Enable Normal mode by explicitly disabling LP and HR ones.
* Note that there's no "disable" part as it's generally unknown, which mode
* we were in previously. To get out of Normal mode, just enable HR or LP one.
*
* @throws std::runtime_error on failure
*/
void enableNormalMode();
/**
* 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 for INT1 and INT2.
* See the datasheet for details.
*
* @param int1_latch true to enable latching for INT1, false to disable
* @param int2_latch true to enable latching for INT2, false to disable
* @throws std::runtime_error on failure
*/
void enableInterruptLatching(bool int1_latch, bool int2_latch);
/**
* Enable or disable built-in Analog-to-Digital Converter (ADC).
*
* @param adc_enable true to enable ADC, false to disable
* @throws std::runtime_error on failure
*/
void enableADC(bool adc_enable);
/**
* Enable or disable built-in temperature sensor. It depends on ADC being
* enabled, so we enable it unconditionally. See datasheet for details.
*
* @param temperature_enable true to enable temp sensor, false to disable
* @throws std::runtime_error on failure
*/
void enableTemperature(bool temperature_enable);
/**
* Set the output data rate (ODR) of the device
*
* @param odr One of the LIS3DH_ODR_T values
* @throws std::runtime_error on failure
*/
void setODR(LIS3DH_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 LIS3DH_FS_T values
* @throws std::runtime_error on failure
*/
void setFullScale(LIS3DH_FS_T fs);
/**
* Indicate whether INT1 and INT2 interrupts 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);
/**
* Set interrupt 1 configuration. See the datasheet for details.
*
* @param cfg A bitmask of values from LIS3DH_CTRL_REG3_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 LIS3DH_CTRL_REG6_BITS_T
* @throws std::runtime_error on failure
*/
void setInt2Config(uint8_t cfg);
/**
* 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 reg The register to start the read from
* @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);
/**
* 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<float> 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);
/**
* Return the contents of the status register
*
* @return A bitmask of values from LIS3DH_STATUS_REG_BITS_T
*/
uint8_t getStatus();
/**
* Return the contents of the status aux register
*
* @return A bitmask of values from LIS3DH_STATUS_REG_AUX_BITS_T
*/
uint8_t getStatusAux();
#if defined(SWIGJAVA) || defined(JAVACALLBACK)
void
installISR(LIS3DH_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 LIS3DH_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(LIS3DH_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 LIS3DH_INTERRUPT_PINS_T values,
* specifying which interrupt pin you are removing
*/
void uninstallISR(LIS3DH_INTERRUPT_PINS_T intr);
protected:
lis3dh_context m_lis3dh;
private:
// Disable implicit copy and assignment operators
LIS3DH(const LIS3DH&) = delete;
LIS3DH& operator=(const LIS3DH&) = delete;
// Adding a private function definition for Java bindings
#if defined(SWIGJAVA) || defined(JAVACALLBACK)
void installISR(LIS3DH_INTERRUPT_PINS_T intr,
int gpio,
mraa::Edge level,
void (*isr)(void*),
void* arg);
#endif
};
}

38
src/lis3dh/lis3dh.json Normal file
View File

@ -0,0 +1,38 @@
{
"Library": "lis3dh",
"Description": "API for the LIS3DH 3-axis Accelerometer",
"Sensor Class":
{
"lis3dh":
{
"Name": "Digital 3-axis Accelerometer",
"Description": "The LIS3DH is an ultra-low-power high performance three-axis linear accelerometer belonging to the \"nano\" family which leverages the robust and mature manufacturing processes already used for the production of micromachined accelerometers. The LIS3DH has user-selectable full scales of 2g/4g/8g/16g and is capable of measuring accelerations with output data rates from 1 Hz to 5300 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.",
"Aliases": ["lis3dh"],
"Categories": ["accelerometer"],
"Connections": ["i2c", "spi", "gpio"],
"Project Type": ["imu", "prototyping"],
"Manufacturers": ["stmicro"],
"Kits": [],
"Examples":
{
"Java": ["LIS3DH_Example.java"],
"Python": ["lis3dh.py"],
"Node.js": ["lis3dh.js"],
"C++": ["lis3dh.cxx"],
"C": ["lis3dh.c"]
},
"Specifications":
{
"Operating Voltage": {"unit": "V", "low": 1.71, "high": 3.6},
"Operating Current": {"unit": "uA", "low": 0.5, "high": 11},
"Operating Temperature": {"unit": "degC", "low": -40, "high": 85}
},
"Urls" :
{
"Product Pages": ["http://www.st.com/en/mems-and-sensors/lis3dh.html"],
"Datasheets": ["http://www.st.com/resource/en/datasheet/lis3dh.pdf"],
"Schematics": []
}
}
}
}

505
src/lis3dh/lis3dh_defs.h Normal file
View File

@ -0,0 +1,505 @@
/*
* Author: Alex Tereschenko <alext.mkrs@gmail.com>
* Copyright (c) 2018 Alex Tereschenko.
*
* Based on LIS2DS12 module by
* Author: Jon Trulson <jtrulson@ics.com>
* 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 LIS3DH_DEFAULT_I2C_BUS 0
#define LIS3DH_DEFAULT_SPI_BUS 0
#define LIS3DH_DEFAULT_I2C_ADDR 0x18
#define LIS3DH_CHIPID 0x33
// 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, except for CTRL_REG0 - see datasheet for that one.
/**
* LIS3DH registers
*/
typedef enum {
// 0x00-0x06 reserved
LIS3DH_REG_STATUS_REG_AUX = 0x07,
LIS3DH_REG_OUT_ADC1_L = 0x08,
LIS3DH_REG_OUT_ADC1_H = 0x09,
LIS3DH_REG_OUT_ADC2_L = 0x0A,
LIS3DH_REG_OUT_ADC2_H = 0x0B,
LIS3DH_REG_OUT_ADC3_L = 0x0C,
LIS3DH_REG_OUT_ADC3_H = 0x0D,
// 0x0E reserved
LIS3DH_REG_WHO_AM_I = 0x0F,
// 0x10-0x1D reserved
LIS3DH_REG_CTRL_REG0 = 0x1E,
LIS3DH_REG_TEMP_CFG_REG = 0x1F,
LIS3DH_REG_CTRL_REG1 = 0x20,
LIS3DH_REG_CTRL_REG2 = 0x21,
LIS3DH_REG_CTRL_REG3 = 0x22,
LIS3DH_REG_CTRL_REG4 = 0x23,
LIS3DH_REG_CTRL_REG5 = 0x24,
LIS3DH_REG_CTRL_REG6 = 0x25,
LIS3DH_REG_REFERENCE = 0x26,
LIS3DH_REG_STATUS_REG = 0x27,
LIS3DH_REG_OUT_X_L = 0x28,
LIS3DH_REG_OUT_X_H = 0x29,
LIS3DH_REG_OUT_Y_L = 0x2A,
LIS3DH_REG_OUT_Y_H = 0x2B,
LIS3DH_REG_OUT_Z_L = 0x2C,
LIS3DH_REG_OUT_Z_H = 0x2D,
LIS3DH_REG_FIFO_CTRL_REG = 0x2E,
LIS3DH_REG_FIFO_SRC_REG = 0x2F,
LIS3DH_REG_INT1_CFG = 0x30,
LIS3DH_REG_INT1_SRC = 0x31,
LIS3DH_REG_INT1_THS = 0x32,
LIS3DH_REG_INT1_DURATION = 0x33,
LIS3DH_REG_INT2_CFG = 0x34,
LIS3DH_REG_INT2_SRC = 0x35,
LIS3DH_REG_INT2_THS = 0x36,
LIS3DH_REG_INT2_DURATION = 0x37,
LIS3DH_REG_CLICK_CFG = 0x38,
LIS3DH_REG_CLICK_SRC = 0x39,
LIS3DH_REG_CLICK_THS = 0x3A,
LIS3DH_REG_TIME_LIMIT = 0x3B,
LIS3DH_REG_TIME_LATENCY = 0x3C,
LIS3DH_REG_TIME_WINDOW = 0x3D,
LIS3DH_REG_ACT_THS = 0x3E,
LIS3DH_REG_ACT_DUR = 0x3F,
} LIS3DH_REGS_T;
/**
* REG_STATUS_REG_AUX bits
*/
typedef enum {
LIS3DH_STATUS_REG_AUX_1DA = 0x01,
LIS3DH_STATUS_REG_AUX_2DA = 0x02,
LIS3DH_STATUS_REG_AUX_3DA = 0x04,
LIS3DH_STATUS_REG_AUX_321DA = 0x08,
LIS3DH_STATUS_REG_AUX_1OR = 0x10,
LIS3DH_STATUS_REG_AUX_2OR = 0x20,
LIS3DH_STATUS_REG_AUX_3OR = 0x40,
LIS3DH_STATUS_REG_AUX_321OR = 0x80,
} LIS3DH_STATUS_REG_AUX_BITS_T;
/**
* REG_CTRL_REG0 bits
*/
typedef enum {
// 0x01-0x40 reserved
LIS3DH_CTRL_REG0_SDO_PU_DISC = 0x80,
} LIS3DH_CTRL_REG0_BITS_T;
/**
* REG_TEMP_CFG_REG bits
*/
typedef enum {
// 0x01-0x20 reserved
LIS3DH_TEMP_CFG_REG_TEMP_EN = 0x40,
LIS3DH_TEMP_CFG_REG_ADC_EN = 0x80,
} LIS3DH_TEMP_CFG_REG_BITS_T;
/**
* REG_CTRL_REG1 bits
*/
typedef enum {
LIS3DH_CTRL_REG1_XEN = 0x01,
LIS3DH_CTRL_REG1_YEN = 0x02,
LIS3DH_CTRL_REG1_ZEN = 0x04,
LIS3DH_CTRL_REG1_LPEN = 0x08,
LIS3DH_CTRL_REG1_ODR0 = 0x10,
LIS3DH_CTRL_REG1_ODR1 = 0x20,
LIS3DH_CTRL_REG1_ODR2 = 0x40,
LIS3DH_CTRL_REG1_ODR3 = 0x80,
_LIS3DH_CTRL_REG1_ODR_MASK = 0xF,
_LIS3DH_CTRL_REG1_ODR_SHIFT = 4,
} LIS3DH_CTRL_REG1_BITS_T;
/**
* CTRL_REG1_ODR (Output Data Rate) values
*/
typedef enum {
LIS3DH_ODR_POWER_DOWN = 0x0, // 0b0000
// These are allowed in all modes (high resolution/normal/low power)
LIS3DH_ODR_1HZ = 0x1, // 0b0001
LIS3DH_ODR_10HZ = 0x2, // 0b0010
LIS3DH_ODR_25HZ = 0x3, // 0b0011
LIS3DH_ODR_50HZ = 0x4, // 0b0100
LIS3DH_ODR_100HZ = 0x5, // 0b0101
LIS3DH_ODR_200HZ = 0x6, // 0b0110
LIS3DH_ODR_400HZ = 0x7, // 0b0111
// The following two items have a dual meaning depending
// on whether the LPEN 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 LP versions. This is then screened out in the
// code and will set the LPEN bit according to what is selected
// here.
// CTRL_REG1_LPEN == 0 (high resolution/normal mode)
LIS3DH_ODR_1344HZ = 0x9, // 0b1001
// CTRL_REG1_LPEN == 1 (low power mode). Add 'virtual' bit 5
// value (0x10) for these LP modes, which we will detect and
// screen out in the driver. This simplifies the ODR API.
LIS3DH_ODR_5376HZ = (0x10 + 0x9), // 0b1001
// Low power-only mode, requires LPEN == 1, so add the virtual bit
LIS3DH_ODR_LP_1600HZ = (0x10 + 0x8), // 0b1000
} LIS3DH_ODR_T;
/**
* REG_CTRL_REG2 bits
*/
typedef enum {
LIS3DH_CTRL_REG2_HP_IA1 = 0x01,
LIS3DH_CTRL_REG2_HP_IA2 = 0x02,
LIS3DH_CTRL_REG2_HPCLICK = 0x04,
LIS3DH_CTRL_REG2_FDS = 0x08,
LIS3DH_CTRL_REG2_HPCF0 = 0x10,
LIS3DH_CTRL_REG2_HPCF1 = 0x20,
_LIS3DH_CTRL_REG2_HPCF_MASK = 0x3, // 0b11
_LIS3DH_CTRL_REG2_HPCF_SHIFT = 4,
LIS3DH_CTRL_REG2_HPM0 = 0x40,
LIS3DH_CTRL_REG2_HPM1 = 0x80,
_LIS3DH_CTRL_REG2_HPM_MASK = 0x3, // 0b11
_LIS3DH_CTRL_REG2_HPM_SHIFT = 6,
} LIS3DH_CTRL_REG2_BITS_T;
/**
* CTRL_REG2_HPM (High-pass filter mode) values
*/
typedef enum {
LIS3DH_HPM_NORMAL_RST_REF_READ = 0x0, // 0b00, Normal mode (reset by reading REFERENCE)
LIS3DH_HPM_REF_SIGNAL = 0x1, // 0b01, Reference signal for filtering
LIS3DH_HPM_NORMAL = 0x2, // 0b10, Normal mode
LIS3DH_HPM_AUTORST = 0x3, // 0b11, Autoreset on interrupt event
} LIS3DH_HPM_T;
/**
* REG_CTRL_REG3 bits
*/
typedef enum {
// 0x01 reserved
LIS3DH_CTRL_REG3_I1_OVERRUN = 0x02,
LIS3DH_CTRL_REG3_I1_WTM = 0x04,
LIS3DH_CTRL_REG3_I1_321DA = 0x08,
LIS3DH_CTRL_REG3_I1_ZYXDA = 0x10,
LIS3DH_CTRL_REG3_I1_IA2 = 0x20,
LIS3DH_CTRL_REG3_I1_IA1 = 0x40,
LIS3DH_CTRL_REG3_I1_CLICK = 0x80,
} LIS3DH_CTRL_REG3_BITS_T;
/**
* REG_CTRL_REG4 bits
*/
typedef enum {
LIS3DH_CTRL_REG4_SIM = 0x01,
LIS3DH_CTRL_REG4_ST0 = 0x02,
LIS3DH_CTRL_REG4_ST1 = 0x04,
_LIS3DH_CTRL_REG4_ST_MASK = 0x3, // 0b11
_LIS3DH_CTRL_REG4_ST_SHIFT = 1,
LIS3DH_CTRL_REG4_HR = 0x08,
LIS3DH_CTRL_REG4_FS0 = 0x10,
LIS3DH_CTRL_REG4_FS1 = 0x20,
_LIS3DH_CTRL_REG4_FS_MASK = 0x3, // 0b11
_LIS3DH_CTRL_REG4_FS_SHIFT = 4,
LIS3DH_CTRL_REG4_BLE = 0x40,
LIS3DH_CTRL_REG4_BDU = 0x80,
} LIS3DH_CTRL_REG4_BITS_T;
/**
* CTRL_REG4_ST (Self Test) values
*/
typedef enum {
LIS3DH_ST_NORMAL = 0x0, // 0b00
LIS3DH_ST_ST0 = 0x1, // 0b01
LIS3DH_ST_ST1 = 0x2, // 0b10
} LIS3DH_ST_T;
/**
* CTRL_REG4_FS (Full Scale) values
*/
typedef enum {
LIS3DH_FS_2G = 0x0, // 0b00
LIS3DH_FS_4G = 0x1, // 0b01
LIS3DH_FS_8G = 0x2, // 0b10
LIS3DH_FS_16G = 0x3, // 0b11
} LIS3DH_FS_T;
/**
* REG_CTRL_REG5 bits
*/
typedef enum {
LIS3DH_CTRL_REG5_D4D_INT2 = 0x01,
LIS3DH_CTRL_REG5_LIR_INT2 = 0x02,
LIS3DH_CTRL_REG5_D4D_INT1 = 0x04,
LIS3DH_CTRL_REG5_LIR_INT1 = 0x08,
// 0x10-0x20 reserved
LIS3DH_CTRL_REG5_FIFO_EN = 0x40,
LIS3DH_CTRL_REG5_BOOT = 0x80,
} LIS3DH_CTRL_REG5_BITS_T;
/**
* REG_CTRL_REG6 bits
*/
typedef enum {
// 0x01 reserved
LIS3DH_CTRL_REG6_INT_POLARITY = 0x02,
// 0x04 reserved
LIS3DH_CTRL_REG6_I2_ACT = 0x08,
LIS3DH_CTRL_REG6_I2_BOOT = 0x10,
LIS3DH_CTRL_REG6_I2_IA2 = 0x20,
LIS3DH_CTRL_REG6_I2_IA1 = 0x40,
LIS3DH_CTRL_REG6_I2_CLICK = 0x80,
} LIS3DH_CTRL_REG6_BITS_T;
/**
* REG_STATUS_REG bits
*/
typedef enum {
LIS3DH_STATUS_REG_XDA = 0x01,
LIS3DH_STATUS_REG_YDA = 0x02,
LIS3DH_STATUS_REG_ZDA = 0x04,
LIS3DH_STATUS_REG_ZYXDA = 0x08,
LIS3DH_STATUS_REG_XOR = 0x10,
LIS3DH_STATUS_REG_YOR = 0x20,
LIS3DH_STATUS_REG_ZOR = 0x40,
LIS3DH_STATUS_REG_ZYXOR = 0x80,
} LIS3DH_STATUS_REG_BITS_T;
/**
* REG_FIFO_CTRL_REG bits
*/
typedef enum {
LIS3DH_FIFO_CTRL_REG_FTH0 = 0x01,
LIS3DH_FIFO_CTRL_REG_FTH1 = 0x02,
LIS3DH_FIFO_CTRL_REG_FTH2 = 0x04,
LIS3DH_FIFO_CTRL_REG_FTH3 = 0x08,
LIS3DH_FIFO_CTRL_REG_FTH4 = 0x10,
_LIS3DH_FIFO_CTRL_REG_FTH_MASK = 0x1F, // 0b11111
_LIS3DH_FIFO_CTRL_REG_FTH_SHIFT = 0,
LIS3DH_FIFO_CTRL_REG_TR = 0x20,
LIS3DH_FIFO_CTRL_REG_FM0 = 0x40,
LIS3DH_FIFO_CTRL_REG_FM1 = 0x80,
_LIS3DH_FIFO_CTRL_REG_FM_MASK = 0x3, // 0b11
_LIS3DH_FIFO_CTRL_REG_FM_SHIFT = 6,
} LIS3DH_FIFO_CTRL_REG_BITS_T;
/**
* FIFO_CTRL_REG_FM (FIFO Mode) values
*/
typedef enum {
LIS3DH_FM_BYPASS = 0x0, // 0b00
LIS3DH_FM_FIFO = 0x1, // 0b01
LIS3DH_FM_STREAM = 0x2, // 0b10
LIS3DH_FM_STREAM_TO_FIFO = 0x3, // 0b11
} LIS3DH_FM_T;
/**
* REG_FIFO_SRC_REG bits
*/
typedef enum {
LIS3DH_FIFO_SRC_REG_FSS0 = 0x01,
LIS3DH_FIFO_SRC_REG_FSS1 = 0x02,
LIS3DH_FIFO_SRC_REG_FSS2 = 0x04,
LIS3DH_FIFO_SRC_REG_FSS3 = 0x08,
LIS3DH_FIFO_SRC_REG_FSS4 = 0x10,
_LIS3DH_FIFO_SRC_REG_FSS_MASK = 0x1F, // 0b11111
_LIS3DH_FIFO_SRC_REG_FSS_SHIFT = 0,
LIS3DH_FIFO_SRC_REG_EMPTY = 0x20,
LIS3DH_FIFO_SRC_REG_OVRN_FIFO = 0x40,
LIS3DH_FIFO_SRC_REG_WTM = 0x80,
} LIS3DH_FIFO_SRC_REG_BITS_T;
/**
* REG_INT1_CFG bits
*/
typedef enum {
LIS3DH_INT1_CFG_XLIE = 0x01,
LIS3DH_INT1_CFG_XHIE = 0x02,
LIS3DH_INT1_CFG_YLIE = 0x04,
LIS3DH_INT1_CFG_YHIE = 0x08,
LIS3DH_INT1_CFG_ZLIE = 0x10,
LIS3DH_INT1_CFG_ZHIE = 0x20,
LIS3DH_INT1_CFG_6D = 0x40,
LIS3DH_INT1_CFG_AOI = 0x80,
} LIS3DH_INT1_CFG_BITS_T;
/**
* REG_INT1_SRC bits
*/
typedef enum {
LIS3DH_INT1_SRC_XL = 0x01,
LIS3DH_INT1_SRC_XH = 0x02,
LIS3DH_INT1_SRC_YL = 0x04,
LIS3DH_INT1_SRC_YH = 0x08,
LIS3DH_INT1_SRC_ZL = 0x10,
LIS3DH_INT1_SRC_ZH = 0x20,
LIS3DH_INT1_SRC_IA = 0x40,
// 0x80 reserved
} LIS3DH_INT1_SRC_BITS_T;
/**
* REG_INT2_CFG bits
*/
typedef enum {
LIS3DH_INT2_CFG_XLIE = 0x01,
LIS3DH_INT2_CFG_XHIE = 0x02,
LIS3DH_INT2_CFG_YLIE = 0x04,
LIS3DH_INT2_CFG_YHIE = 0x08,
LIS3DH_INT2_CFG_ZLIE = 0x10,
LIS3DH_INT2_CFG_ZHIE = 0x20,
LIS3DH_INT2_CFG_6D = 0x40,
LIS3DH_INT2_CFG_AOI = 0x80,
} LIS3DH_INT2_CFG_BITS_T;
/**
* REG_INT2_SRC bits
*/
typedef enum {
LIS3DH_INT2_SRC_XL = 0x01,
LIS3DH_INT2_SRC_XH = 0x02,
LIS3DH_INT2_SRC_YL = 0x04,
LIS3DH_INT2_SRC_YH = 0x08,
LIS3DH_INT2_SRC_ZL = 0x10,
LIS3DH_INT2_SRC_ZH = 0x20,
LIS3DH_INT2_SRC_IA = 0x40,
// 0x80 reserved
} LIS3DH_INT2_SRC_BITS_T;
/**
* REG_CLICK_CFG bits
*/
typedef enum {
LIS3DH_CLICK_CFG_XS = 0x01,
LIS3DH_CLICK_CFG_XD = 0x02,
LIS3DH_CLICK_CFG_YS = 0x04,
LIS3DH_CLICK_CFG_YD = 0x08,
LIS3DH_CLICK_CFG_ZS = 0x10,
LIS3DH_CLICK_CFG_ZD = 0x20,
// 0x40-0x80 reserved
} LIS3DH_CLICK_CFG_BITS_T;
/**
* REG_CLICK_SRC bits
*/
typedef enum {
LIS3DH_CLICK_SRC_X = 0x01,
LIS3DH_CLICK_SRC_Y = 0x02,
LIS3DH_CLICK_SRC_Z = 0x04,
LIS3DH_CLICK_SRC_SIGN = 0x08,
LIS3DH_CLICK_SRC_SCLICK = 0x10,
LIS3DH_CLICK_SRC_DCLICK = 0x20,
LIS3DH_CLICK_SRC_IA = 0x40,
// 0x80 reserved
} LIS3DH_CLICK_SRC_BITS_T;
/**
* REG_CLICK_THS bits
*/
typedef enum {
LIS3DH_CLICK_THS_THS0 = 0x01,
LIS3DH_CLICK_THS_THS1 = 0x02,
LIS3DH_CLICK_THS_THS2 = 0x04,
LIS3DH_CLICK_THS_THS3 = 0x08,
LIS3DH_CLICK_THS_THS4 = 0x10,
LIS3DH_CLICK_THS_THS5 = 0x20,
LIS3DH_CLICK_THS_THS6 = 0x40,
_LIS3DH_CLICK_THS_THS_MASK = 0x7F, // 0b1111111
_LIS3DH_CLICK_THS_THS_SHIFT = 0,
LIS3DH_CLICK_THS_LIR_CLICK = 0x80,
} LIS3DH_CLICK_THS_BITS_T;
// Interrupt selection for installISR() and uninstallISR()
typedef enum { LIS3DH_INTERRUPT_INT1, LIS3DH_INTERRUPT_INT2 } LIS3DH_INTERRUPT_PINS_T;
#ifdef __cplusplus
}
#endif

116
src/lis3dh/lis3dh_fti.c Normal file
View File

@ -0,0 +1,116 @@
/*
* Author: Alex Tereschenko <alext.mkrs@gmail.com>
* Copyright (c) 2018 Alex Tereschenko.
*
* Based on LIS2DS12 module by
* Author: Jon Trulson <jtrulson@ics.com>
* 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 "lis3dh.h"
#include "upm_fti.h"
/**
* This file implements the Function Table Interface (FTI) for this sensor
*/
const char upm_lis3dh_name[] = "LIS3DH";
const char upm_lis3dh_description[] = "Triple Axis Digital Accelerometer";
const upm_protocol_t upm_lis3dh_protocol[] = { UPM_I2C, UPM_SPI, UPM_GPIO };
const upm_sensor_t upm_lis3dh_category[] = { UPM_ACCELEROMETER };
// Forward declarations
const void* upm_lis3dh_get_ft(upm_sensor_t sensor_type);
void* upm_lis3dh_init_name();
void upm_lis3dh_close(void* dev);
upm_result_t upm_lis3dh_get_value(void* dev, float* value, upm_acceleration_u unit);
const upm_sensor_descriptor_t
upm_lis3dh_get_descriptor()
{
upm_sensor_descriptor_t usd;
usd.name = upm_lis3dh_name;
usd.description = upm_lis3dh_description;
usd.protocol_size = 3;
usd.protocol = upm_lis3dh_protocol;
usd.category_size = 1;
usd.category = upm_lis3dh_category;
return usd;
}
static const upm_sensor_ft ft = {
.upm_sensor_init_name = upm_lis3dh_init_name,
.upm_sensor_close = upm_lis3dh_close,
};
static const upm_acceleration_ft aft = {.upm_acceleration_get_value = upm_lis3dh_get_value };
const void*
upm_lis3dh_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_lis3dh_init_name()
{
return NULL;
}
void
upm_lis3dh_close(void* dev)
{
lis3dh_close((lis3dh_context) dev);
}
upm_result_t
upm_lis3dh_get_value(void* dev, float* value, upm_acceleration_u unit)
{
if (lis3dh_update((lis3dh_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;
lis3dh_get_accelerometer(dev, &x, &y, &z);
value[0] = x;
value[1] = y;
value[2] = z;
return UPM_SUCCESS;
}

15
src/lis3dh/pyupm_lis3dh.i Normal file
View File

@ -0,0 +1,15 @@
// Include doxygen-generated documentation
%include "pyupm_doxy2swig.i"
%module pyupm_lis3dh
%include "../upm.i"
%include "../upm_vectortypes.i"
#ifdef DOXYGEN
%include "lis3dh_doc.i"
#endif
%include "lis3dh_defs.h"
%include "lis3dh.hpp"
%{
#include "lis3dh.hpp"
%}