diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index 14b4a57763c58b07ab3144dc2a2767f50603ff3a..7499d4ea64413263ef522e7090ddf80efe15e0a5 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -150,6 +150,16 @@ ifneq (,$(filter l3g4200d,$(USEMODULE))) FEATURES_REQUIRED += periph_i2c endif +ifneq (,$(filter lis2dh12%,$(USEMODULE))) + ifneq (,$(filter lis2dh12_spi,$(USEMODULE))) + FEATURES_REQUIRED += periph_gpio + FEATURES_REQUIRED += periph_spi + else + FEATURES_REQUIRED += periph_i2c + endif + USEMODULE += lis2dh12 +endif + ifneq (,$(filter lis3dh,$(USEMODULE))) FEATURES_REQUIRED += periph_gpio FEATURES_REQUIRED += periph_spi diff --git a/drivers/Makefile.include b/drivers/Makefile.include index 124e19e7e43c93fa23ec9c613ac1fbcf0c412d21..e8b7d2160271f506d02a776f8aa8c129e5ad78dc 100644 --- a/drivers/Makefile.include +++ b/drivers/Makefile.include @@ -160,3 +160,6 @@ endif ifneq (,$(filter rn2%3,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/rn2xx3/include endif +ifneq (,$(filter lis2dh12,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/lis2dh12/include +endif diff --git a/drivers/include/lis2dh12.h b/drivers/include/lis2dh12.h new file mode 100644 index 0000000000000000000000000000000000000000..2d525dc2a3d8fe2f54cef34d52f4b5c1d839b25b --- /dev/null +++ b/drivers/include/lis2dh12.h @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2018 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup drivers_lis2dh12 LIS2DH12 Accelerometer + * @ingroup drivers_sensors + * @brief Driver for the STM LIS2DH12 accelerometer + * + * This device driver provides a minimal interface to LIS2DH12 devices. As of + * now, it only provides very basic access to the device. The driver configures + * the device to continuously read the acceleration data with statically + * defined scale and rate, and with a fixed 10-bit resolution. The LIS2DH12's + * FIFO is bypassed, so the driver might not be sufficient for use cases where + * the complete history of readings is of interest. + * + * Also, the current version of the driver supports only interfacing the sensor + * via SPI. The driver is however written in a way, that adding I2C interface + * support is quite simple, as all bus related functions (acquire, release, + * read, write) are cleanly separated in the code. + * + * @{ + * @file + * @brief Interface definition for the STM LIS2DH12 accelerometer + * + * @author Hauke Petersen <hauke.petersen@fu-berlin.de> + */ + +#ifndef LIS2DH12_H +#define LIS2DH12_H + +#include "periph/spi.h" +#include "periph/gpio.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* I2C support is not implemented (yet), so throw an error when selected */ +#ifndef MODULE_LIS2DH12_SPI +#error "LIS2DH12 error: I2C mode is not supported, yet. Use module li2dh12_spi" +#endif + +/** + * @brief Available scale values + */ +typedef enum { + LIS2DH12_SCALE_2G = 0x00, /**< +- 2g */ + LIS2DH12_SCALE_4G = 0x10, /**< +- 4g */ + LIS2DH12_SCALE_8G = 0x20, /**< +- 8g */ + LIS2DH12_SCALE_16G = 0x30, /**< +- 16g */ +} lis2dh12_scale_t; + +/** + * @brief Available sampling rates + * + * @note The device does also support some additional rates for specific low- + * power modes, but those are as of now not supported by this driver + */ +typedef enum { + LIS2DH12_RATE_1HZ = 0x17, /**< sample with 1Hz */ + LIS2DH12_RATE_10HZ = 0x27, /**< sample with 10Hz */ + LIS2DH12_RATE_25HZ = 0x37, /**< sample with 25Hz */ + LIS2DH12_RATE_50HZ = 0x47, /**< sample with 50Hz */ + LIS2DH12_RATE_100HZ = 0x57, /**< sample with 100Hz */ + LIS2DH12_RATE_200HZ = 0x67, /**< sample with 200Hz */ + LIS2DH12_RATE_400HZ = 0x77, /**< sample with 400Hz */ +} lis2dh12_rate_t; + +/** + * @brief LIS2DH12 configuration parameters + */ +typedef struct { + spi_t spi; /**< SPI bus the device is connected to */ + gpio_t cs; /**< connected chip select pin */ + lis2dh12_scale_t scale; /**< sampling sensitivity used */ + lis2dh12_rate_t rate; /**< sampling rate used */ +} lis2dh12_params_t; + +/** + * @brief LIS2DH12 device descriptor + */ +typedef struct { + const lis2dh12_params_t *p; /**< device configuration */ + uint16_t comp; /**< scale compensation factor */ +} lis2dh12_t; + +/** + * @brief Status and error return codes + */ +enum { + LIS2DH12_OK = 0, /**< everything was fine */ + LIS2DH12_NOBUS = -1, /**< bus interface error */ + LIS2DH12_NODEV = -2, /**< unable to talk to device */ +}; + +/** + * @brief Initialize the given LIS2DH12 sensor device + * + * @param[out] dev device descriptor + * @param[in] params static device configuration + * + * @return LIS2DH12_OK on success + * @return LIS2DH12_NOBUS on bus errors + * @return LIS2DH12_NODEV if no LIS2DH12 device was found on the bus + */ +int lis2dh12_init(lis2dh12_t *dev, const lis2dh12_params_t *params); + +/** + * @brief Read acceleration data from the given device + * + * @param[in] dev device descriptor + * @param[out] data acceleration data in mili-g, **MUST** hold 3 values + * + * @return LIS2DH12_OK on success + * @return LIS2DH12_NOBUS on bus error + */ +int lis2dh12_read(const lis2dh12_t *dev, int16_t *data); + +/** + * @brief Power on the given device + * + * @param[in] dev device descriptor + * + * @return LIS2DH12_OK on success + * @return LIS2DH12_NOBUS on bus error + */ +int lis2dh12_poweron(const lis2dh12_t *dev); + +/** + * @brief Power off the given device + * + * @param[in] dev device descriptor + * + * @return LIS2DH12_OK on success + * @return LIS2DH12_NOBUS on bus error + */ +int lis2dh12_poweroff(const lis2dh12_t *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* LIS2DH12_H */ +/** @} */ diff --git a/drivers/lis2dh12/Makefile b/drivers/lis2dh12/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..48422e909a47d7cd428d10fa73825060ccc8d8c2 --- /dev/null +++ b/drivers/lis2dh12/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/drivers/lis2dh12/include/lis2dh12_params.h b/drivers/lis2dh12/include/lis2dh12_params.h new file mode 100644 index 0000000000000000000000000000000000000000..d6bbd45aecf97ffb035849db9cc9753b557bbcce --- /dev/null +++ b/drivers/lis2dh12/include/lis2dh12_params.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2018 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_lis2dh12 + * + * @{ + * @file + * @brief Default configuration for LIS2DH12 devices + * + * @author Hauke Petersen <hauke.petersen@fu-berlin.de> + */ + +#ifndef LIS2DH12_PARAMS_H +#define LIS2DH12_PARAMS_H + +#include "board.h" +#include "lis2dh12.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Set default configuration parameters for LIS2DH12 devices + * @{ + */ +#ifndef LIS2DH12_PARAM_SPI +#define LIS2DH12_PARAM_SPI SPI_DEV(0) +#endif +#ifndef LIS2DH12_PARAM_CS +#define LIS2DH12_PARAM_CS GPIO_PIN(0, 0) +#endif +#ifndef LIS2DH12_PARAM_SCALE +#define LIS2DH12_PARAM_SCALE LIS2DH12_SCALE_2G +#endif +#ifndef LIS2DH12_PARAM_RATE +#define LIS2DH12_PARAM_RATE LIS2DH12_RATE_100HZ +#endif + +#define LIS2DH12_PARAMS_DEFAULT { .spi = LIS2DH12_PARAM_SPI, \ + .cs = LIS2DH12_PARAM_CS, \ + .scale = LIS2DH12_PARAM_SCALE, \ + .rate = LIS2DH12_PARAM_RATE } +/**@}*/ + +/** + * @brief LIS2DH12 configuration + */ +static const lis2dh12_params_t lis2dh12_params[] = +{ +#ifdef LIS2DH12_PARAMS_BOARD + LIS2DH12_PARAMS_BOARD, +#else + LIS2DH12_PARAMS_DEFAULT, +#endif +}; + +#ifdef __cplusplus +} +#endif + +#endif /* LIS2DH12_PARAMS_H */ +/** @} */ diff --git a/drivers/lis2dh12/lis2dh12.c b/drivers/lis2dh12/lis2dh12.c new file mode 100644 index 0000000000000000000000000000000000000000..9980a83f0147ffd14b23419c021c3e20baaf40ff --- /dev/null +++ b/drivers/lis2dh12/lis2dh12.c @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2018 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @ingroup drivers_lis2dh12 + * @{ + * + * @file + * @brief LIS2DH12 accelerometer driver implementation + * + * @author Hauke Petersen <hauke.petersen@fu-berlin.de> + * @} + */ + +#include "assert.h" + +#include "lis2dh12.h" +#include "lis2dh12_internal.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/* SPI bus speed and mode */ +#define BUS_CLK SPI_CLK_5MHZ +#define MODE SPI_MODE_0 + +#define BUS_OK SPI_OK + +/* shortcuts for SPI bus parameters */ +#define BUS (dev->p->spi) +#define CS (dev->p->cs) + +/* flag to set when reading from the device */ +#define FLAG_READ (0x80) + +/* flag to enable address auto incrementation on read or write */ +#define FLAG_AINC (0x40) + +static int _acquire(const lis2dh12_t *dev) +{ + return spi_acquire(BUS, CS, MODE, BUS_CLK); +} + +static void _release(const lis2dh12_t *dev) +{ + spi_release(BUS); +} + +static uint8_t _read(const lis2dh12_t *dev, uint8_t reg) +{ + return spi_transfer_reg(BUS, CS, (FLAG_READ | reg), 0); +} + +static void _read_burst(const lis2dh12_t *dev, uint8_t reg, + void *data, size_t len) +{ + spi_transfer_regs(BUS, CS, (FLAG_READ | FLAG_AINC | reg), NULL, data, len); +} + +static void _write(const lis2dh12_t *dev, uint8_t reg, uint8_t data) +{ + DEBUG("[lis2dh12] write: reg 0x%02x, val 0x%02x\n", (int)reg, (int)data); + spi_transfer_reg(BUS, CS, reg, data); +} + +int lis2dh12_init(lis2dh12_t *dev, const lis2dh12_params_t *params) +{ + assert(dev && params); + + dev->p = params; + dev->comp = (1000UL * (0x02 << (dev->p->scale >> 4))); + + /* start by setting up the chip select pin */ + if (spi_init_cs(BUS, CS) != SPI_OK) { + DEBUG("[lis2dh12] error: unable to initialize CS pin\n"); + return LIS2DH12_NOBUS; + } + + /* acquire the SPI bus and verify that our parameters are valid */ + if (_acquire(dev) != BUS_OK) { + DEBUG("[lis2dh12] error: unable to acquire SPI bus\n"); + return LIS2DH12_NOBUS; + } + + /* read the WHO_IM_I register to verify the connections to the device */ + if (_read(dev, REG_WHO_AM_I) != WHO_AM_I_VAL) { + DEBUG("[lis2dh12] error: invalid value read from WHO_AM_I register\n"); + _release(dev); + return LIS2DH12_NODEV; + } + + /* set sampling rate and scale. This also enables the device and starts + * sampling of data */ + _write(dev, REG_CTRL_REG4, dev->p->scale); + _write(dev, REG_CTRL_REG1, dev->p->rate); + + _release(dev); + return LIS2DH12_OK; +} + +int lis2dh12_read(const lis2dh12_t *dev, int16_t *data) +{ + assert(dev && data); + + /* allocate 6 byte to save the 6 RAW data registers */ + uint8_t raw[6]; + + /* read sampled data from the device */ + _acquire(dev); + _read_burst(dev, REG_OUT_X_L, raw, 6); + _release(dev); + + /* calculate the actual g-values for the x, y, and z dimension */ + for (int i = 0; i < 3; i++) { + int32_t tmp = ((raw[i * 2] >> 6) | (raw[(i * 2) + 1] << 2)); + if (tmp & 0x00000200) { + tmp |= 0xfffffc00; + } + data[i] = (int16_t)((tmp * dev->comp) / 512); + } + + return LIS2DH12_OK; +} + +int lis2dh12_poweron(const lis2dh12_t *dev) +{ + assert(dev); + + _acquire(dev); + _write(dev, REG_CTRL_REG1, dev->p->rate); + _release(dev); + + return LIS2DH12_OK; +} + +int lis2dh12_poweroff(const lis2dh12_t *dev) +{ + assert(dev); + + _acquire(dev); + _write(dev, REG_CTRL_REG1, 0); + _release(dev); + + return LIS2DH12_OK; +} diff --git a/drivers/lis2dh12/lis2dh12_internal.h b/drivers/lis2dh12/lis2dh12_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..0d72b40c8465e052836d3d2083550bac53ef9c1c --- /dev/null +++ b/drivers/lis2dh12/lis2dh12_internal.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2018 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_lis2dh12 + * @{ + * + * @file + * @brief Command definition for the LIS2DH12 accelerometer + * + * @author Hauke Petersen <hauke.petersen@fu-berlin.de> + */ + +#ifndef LIS2DH12_INTERNAL_H +#define LIS2DH12_INTERNAL_H + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name LIS2DH12 registers + * @{ + */ +#define REG_STATUS_REG_AUX (0x07) +#define REG_OUT_TEMP_L (0x0C) +#define REG_OUT_TEMP_H (0x0D) +#define REG_WHO_AM_I (0x0F) +#define REG_CTRL_REG0 (0x1E) +#define REG_TEMP_CFG_REG (0x1F) +#define REG_CTRL_REG1 (0x20) +#define REG_CTRL_REG2 (0x21) +#define REG_CTRL_REG3 (0x22) +#define REG_CTRL_REG4 (0x23) +#define REG_CTRL_REG5 (0x24) +#define REG_CTRL_REG6 (0x25) +#define REG_REFERENCE (0x26) +#define REG_STATUS_REG (0x27) +#define REG_OUT_X_L (0x28) +#define REG_OUT_X_H (0x29) +#define REG_OUT_Y_L (0x2A) +#define REG_OUT_Y_H (0x2B) +#define REG_OUT_Z_L (0x2C) +#define REG_OUT_Z_H (0x2D) +#define REG_FIFO_CTRL_REG (0x2E) +#define REG_FIFO_SRC_REG (0x2F) +#define REG_INT1_CFG (0x30) +#define REG_INT1_SRC (0x31) +#define REG_INT1_THS (0x32) +#define REG_INT1_DURATION (0x33) +#define REG_INT2_CFG (0x34) +#define REG_INT2_SRC (0x35) +#define REG_INT2_THS (0x36) +#define REG_INT2_DURATION (0x37) +#define REG_CLICK_CFG (0x38) +#define REG_CLICK_SRC (0x39) +#define REG_CLICK_THS (0x3A) +#define REG_TIME_LIMIT (0x3B) +#define REG_TIME_LATENCY (0x3C) +#define REG_TIME_WINDOW (0x3D) +#define REG_ACT_THS (0x3E) +#define REG_ACT_DUR (0x3F) +/** @} */ + +/** + * @name Selected register values + * @{ + */ +#define WHO_AM_I_VAL (0x33) +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* LIS2DH12_INTERNAL_H */ +/** @} */ diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index 887573a2bb0ea63a92ee23115d03bf3acb49dbba..868ed9b21ef5bc42c34d5f7dcb8b90af19b1bb3a 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -31,6 +31,7 @@ PSEUDOMODULES += gnrc_sock_check_reuse PSEUDOMODULES += gnrc_txtsnd PSEUDOMODULES += l2filter_blacklist PSEUDOMODULES += l2filter_whitelist +PSEUDOMODULES += lis2dh12_spi PSEUDOMODULES += log PSEUDOMODULES += log_printfnoformat PSEUDOMODULES += lora