diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index e73ef4c55d..7edbff1a29 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -323,14 +323,18 @@ ifneq (,$(filter lc709203f,$(USEMODULE))) FEATURES_REQUIRED += periph_gpio_irq endif +ifneq (,$(filter lis2dh12_int,$(USEMODULE))) + FEATURES_REQUIRED += periph_gpio_irq +endif + ifneq (,$(filter lis2dh12%,$(USEMODULE))) + USEMODULE += lis2dh12 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))) diff --git a/drivers/include/lis2dh12.h b/drivers/include/lis2dh12.h index 2b9c995889..d88bd885c7 100644 --- a/drivers/include/lis2dh12.h +++ b/drivers/include/lis2dh12.h @@ -40,9 +40,9 @@ #include "saul.h" +#include "periph/gpio.h" #ifdef MODULE_LIS2DH12_SPI #include "periph/spi.h" -#include "periph/gpio.h" #else #include "periph/i2c.h" #endif @@ -88,12 +88,16 @@ typedef enum { * @brief LIS2DH12 configuration parameters */ typedef struct { -#ifdef MODULE_LIS2DH12_SPI +#if MODULE_LIS2DH12_SPI || DOXYGEN spi_t spi; /**< SPI bus the device is connected to */ gpio_t cs; /**< connected chip select pin */ #else i2c_t i2c; /**< I2C bus the device is connected to */ uint8_t addr; /**< device address on the I2C bus */ +#endif +#if MODULE_LIS2DH12_INT || DOXYGEN + gpio_t int1_pin; /**< first interrupt pin */ + gpio_t int2_pin; /**< second interrupt pin */ #endif lis2dh12_scale_t scale; /**< sampling sensitivity used */ lis2dh12_rate_t rate; /**< sampling rate used */ @@ -114,13 +118,121 @@ enum { LIS2DH12_OK = 0, /**< everything was fine */ LIS2DH12_NOBUS = -1, /**< bus interface error */ LIS2DH12_NODEV = -2, /**< unable to talk to device */ + LIS2DH12_NOINT = -3, /**< wrong interrupt line (has to be LIS2DH12_INT1 or LIS2DH12_INT2) */ + LIS2DH12_NODATA= -4, /**< no data available */ }; +#if MODULE_LIS2DH12_INT || DOXYGEN +/* + * @brief Interrupt lines + */ +enum{ + LIS2DH12_INT1 = 1, /**< first interrupt line */ + LIS2DH12_INT2 = 2, /**< second interrupt line */ +}; + +/** + * @brief Interrupt config register values + */ +enum { + LIS2DH12_INT_CFG_XLIE = 0x01, /**< enable X low evnt */ + LIS2DH12_INT_CFG_XHIE = 0x02, /**< enable X high event */ + LIS2DH12_INT_CFG_YLIE = 0x04, /**< enable Y low event */ + LIS2DH12_INT_CFG_YHIE = 0x08, /**< enable Y high event */ + LIS2DH12_INT_CFG_ZLIE = 0x10, /**< enable Z low event */ + LIS2DH12_INT_CFG_ZHIE = 0x20, /**< enable Z high event */ + LIS2DH12_INT_CFG_6D = 0x40, /**< enable 6-direction detection */ + LIS2DH12_INT_CFG_AOI = 0x80, /**< and/or combination interrupt events */ +}; + +/** + * @brief Interrupt type values + */ +enum { + /* for interrupt 1 (CTRL_REG3) */ + LIS2DH12_INT_TYPE_I1_OVERRUN = 0x02, /**< FIFO overrun interrupt on INT1 */ + LIS2DH12_INT_TYPE_I1_WTM = 0x04, /**< FIFO watermark inter. on INT1 */ + LIS2DH12_INT_TYPE_I1_ZYXDA = 0x10, /**< ZYXDA interrupt on INT1 */ + LIS2DH12_INT_TYPE_I1_IA2 = 0x20, /**< IA2 interrupt on INT1 */ + LIS2DH12_INT_TYPE_I1_IA1 = 0x40, /**< IA1 interrupt on INT1 */ + LIS2DH12_INT_TYPE_I1_CLICK = 0x80, /**< click interrupt on INT1 */ + + /* for interrupt 2 (CTRL_REG6) */ + LIS2DH12_INT_TYPE_INT_POLARITY = 0x02, /**< INT1 and INT2 pin polarity */ + LIS2DH12_INT_TYPE_I2_ACT = 0x08, /**< enable activity interrupt on INT2 */ + LIS2DH12_INT_TYPE_I2_BOOT = 0x10, /**< enable boot on INT2 */ + LIS2DH12_INT_TYPE_I2_IA2 = 0x20, /**< IA2 on INT2 */ + LIS2DH12_INT_TYPE_I2_IA1 = 0x40, /**< IA1 on INT2 */ + LIS2DH12_INT_TYPE_I2_CLICK = 0x80, /**< click interrupt on INT2 */ +}; + +/** + * @brief Parameter for interrupt configuration + */ +typedef struct { + uint8_t int_config; /**< values for configuration */ + uint8_t int_threshold:7; /**< the threshold for triggering interrupt, threshold in range 0-127 */ + uint8_t int_duration:7; /**< time between two interrupts ODR section in CTRL_REG1, duration in range 0-127 */ + uint8_t int_type; /**< values for type of interrupts */ + gpio_cb_t cb; /**< the callback to execute */ + void *arg; /**< the callback argument */ +} lis2dh12_int_params_t; + +/** + * @brief Status of INT_SRC register + */ +#define LIS2DH12_INT_SRC_XL (0x01) /**< X low event has occurred */ +#define LIS2DH12_INT_SRC_XH (0x02) /**< X high event has occurred */ +#define LIS2DH12_INT_SRC_YL (0x04) /**< Y low event has occurred */ +#define LIS2DH12_INT_SRC_YH (0x08) /**< Y high event has occurred */ +#define LIS2DH12_INT_SRC_ZL (0x10) /**< Z low event has occurred */ +#define LIS2DH12_INT_SRC_ZH (0x20) /**< Z high event has occurred */ +#define LIS2DH12_INT_SRC_IA (0x40) /**< 1 if interrupt occurred */ +#endif /* MODULE_LIS2DH12_INT */ + +/** + * @brief Status of INT_SRC register + */ +#define LIS2DH12_STATUS_XDA (0x01) /**< X-axis new data available */ +#define LIS2DH12_STATUS_YDA (0x02) /**< Y-axis new data available */ +#define LIS2DH12_STATUS_ZDA (0x04) /**< Z-axis new data available */ +#define LIS2DH12_STATUS_ZYXDA (0x08) /**< on X-, Y-, Z-axis new data available */ +#define LIS2DH12_STATUS_XOR (0x10) /**< X-axis data overrun */ +#define LIS2DH12_STATUS_YOR (0x20) /**< Y-axis data overrun */ +#define LIS2DH12_STATUS_ZOR (0x40) /**< Y-axis data overrun */ +#define LIS2DH12_STATUS_ZYXOR (0x80) /**< on X-, Y-, Z-axis data overrun */ + /** * @brief Export the SAUL interface for this driver */ extern const saul_driver_t lis2dh12_saul_driver; +#if MODULE_LIS2DH12_INT || DOXYGEN +/** + * @brief Set the interrupt values in LIS2DH12 sensor device + * + * @param[in] dev device descriptor + * @param[in] params device interrupt configuration + * @param[in] int_line number of interrupt line (LIS2DH12_INT1 or LIS2DH12_INT2) + * + * @return LIS2DH12_OK on success + * @return LIS2DH12_NOBUS on bus errors + */ +int lis2dh12_set_int(const lis2dh12_t *dev, const lis2dh12_int_params_t *params, uint8_t int_line); + +/** + * @brief Read an interrupt event on LIS2DH12 sensor device + * + * @param[in] dev device descriptor + * @param[out] data device interrupt data + * @param[in] int_line number of interrupt line (LIS2DH12_INT1 or LIS2DH12_INT2) + * + * @return LIS2DH12_OK on success + * @return LIS2DH12_NOBUS on bus errors + */ +int lis2dh12_read_int_src(const lis2dh12_t *dev, uint8_t *data, uint8_t int_line); +#endif /* MODULE_LIS2DH12_INT */ + /** * @brief Initialize the given LIS2DH12 sensor device * diff --git a/drivers/lis2dh12/include/lis2dh12_params.h b/drivers/lis2dh12/include/lis2dh12_params.h index b8e779543c..1a2493c8af 100644 --- a/drivers/lis2dh12/include/lis2dh12_params.h +++ b/drivers/lis2dh12/include/lis2dh12_params.h @@ -53,6 +53,14 @@ extern "C" { #endif +#ifndef LIS2DH12_PARAM_INT_PIN1 +#define LIS2DH12_PARAM_INT_PIN1 GPIO_UNDEF +#endif + +#ifndef LIS2DH12_PARAM_INT_PIN2 +#define LIS2DH12_PARAM_INT_PIN2 GPIO_UNDEF +#endif + #ifndef LIS2DH12_PARAM_SCALE #define LIS2DH12_PARAM_SCALE LIS2DH12_SCALE_2G #endif @@ -61,10 +69,22 @@ extern "C" { #endif #ifndef LIS2DH12_PARAMS -#define LIS2DH12_PARAMS { LIS2DH12_PARAMS_BUSCFG, \ - .scale = LIS2DH12_PARAM_SCALE, \ - .rate = LIS2DH12_PARAM_RATE, } -#endif +#ifdef MODULE_LIS2DH12_INT +#define LIS2DH12_PARAMS { \ + LIS2DH12_PARAMS_BUSCFG, \ + .int1_pin = LIS2DH12_PARAM_INT_PIN1, \ + .int2_pin = LIS2DH12_PARAM_INT_PIN2, \ + .scale = LIS2DH12_PARAM_SCALE, \ + .rate = LIS2DH12_PARAM_RATE, \ + } +#else /* MODULE_LIS2DH12_INT */ +#define LIS2DH12_PARAMS { \ + LIS2DH12_PARAMS_BUSCFG, \ + .scale = LIS2DH12_PARAM_SCALE, \ + .rate = LIS2DH12_PARAM_RATE, \ + } +#endif /* MODULE_LIS2DH12_INT */ +#endif /* LIS2DH12_PARAMS */ #ifndef LIS2DH12_SAULINFO #define LIS2DH12_SAULINFO { .name = "lis2dh12" } diff --git a/drivers/lis2dh12/lis2dh12.c b/drivers/lis2dh12/lis2dh12.c index 97ee76acce..46506a454b 100644 --- a/drivers/lis2dh12/lis2dh12.c +++ b/drivers/lis2dh12/lis2dh12.c @@ -172,6 +172,13 @@ int lis2dh12_read(const lis2dh12_t *dev, int16_t *data) /* read sampled data from the device */ _acquire(dev); + + /* first check if valid data is available */ + if ((_read(dev, REG_STATUS_REG) & LIS2DH12_STATUS_ZYXDA) == 0) { + _release(dev); + return LIS2DH12_NODATA; + } + _read_burst(dev, REG_OUT_X_L, raw, 6); _release(dev); @@ -187,6 +194,78 @@ int lis2dh12_read(const lis2dh12_t *dev, int16_t *data) return LIS2DH12_OK; } +#ifdef MODULE_LIS2DH12_INT +int lis2dh12_set_int(const lis2dh12_t *dev, const lis2dh12_int_params_t *params, uint8_t int_line) +{ + assert (int_line == LIS2DH12_INT1 || int_line == LIS2DH12_INT2); + assert (dev && params->int_config && params->int_type); + assert (params->int_threshold >= 0); + assert (params->int_duration >= 0); + + _acquire(dev); + + gpio_t pin = GPIO_UNDEF; + + switch (int_line){ + /* first interrupt line (INT1) */ + case LIS2DH12_INT1: + pin = dev->p->int1_pin; + assert (pin != GPIO_UNDEF); + + if (gpio_init_int(pin, GPIO_IN, GPIO_RISING, params->cb, params->arg)) { + return LIS2DH12_NOINT; + } + + _write(dev, REG_CTRL_REG3, params->int_type); + _write(dev, REG_INT1_CFG, params->int_config); + _write(dev, REG_INT1_THS, params->int_threshold); + _write(dev, REG_INT1_DURATION, params->int_duration); + break; + /* second interrupt line (INT2) */ + case LIS2DH12_INT2: + pin = dev->p->int2_pin; + assert (pin != GPIO_UNDEF); + + if (gpio_init_int(pin, GPIO_IN, GPIO_RISING, params->cb, params->arg)) { + return LIS2DH12_NOINT; + } + + _write(dev, REG_CTRL_REG6, params->int_type); + _write(dev, REG_INT2_CFG, params->int_config); + _write(dev, REG_INT2_THS, params->int_threshold); + _write(dev, REG_INT2_DURATION, params->int_duration); + break; + } + + _release(dev); + + return LIS2DH12_OK; +} + +int lis2dh12_read_int_src(const lis2dh12_t *dev, uint8_t *data, uint8_t int_line) +{ + assert(dev && data); + assert(int_line == LIS2DH12_INT1 || int_line == LIS2DH12_INT2); + + _acquire(dev); + + switch (int_line) { + /* first interrupt line (INT1) */ + case LIS2DH12_INT1: + *data = _read(dev, REG_INT1_SRC); + break; + /* second interrupt line (INT2) */ + case LIS2DH12_INT2: + *data = _read(dev, REG_INT2_SRC); + break; + } + + _release(dev); + + return LIS2DH12_OK; +} +#endif /* MODULE_LIS2DH12_INT */ + int lis2dh12_poweron(const lis2dh12_t *dev) { assert(dev); diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index 2dd7267fd0..13bb31076b 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -49,6 +49,7 @@ PSEUDOMODULES += ina3221_alerts PSEUDOMODULES += l2filter_blacklist PSEUDOMODULES += l2filter_whitelist PSEUDOMODULES += lis2dh12_i2c +PSEUDOMODULES += lis2dh12_int PSEUDOMODULES += lis2dh12_spi PSEUDOMODULES += log PSEUDOMODULES += log_printfnoformat diff --git a/tests/driver_lis2dh12/Makefile b/tests/driver_lis2dh12/Makefile index 0b5d594f7d..411dece697 100644 --- a/tests/driver_lis2dh12/Makefile +++ b/tests/driver_lis2dh12/Makefile @@ -1,10 +1,13 @@ include ../Makefile.tests_common -# as default we use the SPI mode for now, as the I2C mode is not supported, yet +# use lis2dh12_spi for SPI-Mode and lis2dh12_i2c for I2C-Mode DRIVER ?= lis2dh12_spi USEMODULE += fmt USEMODULE += xtimer USEMODULE += $(DRIVER) +# for using lis2dh12 with interrupt function +USEMODULE += lis2dh12_int + include $(RIOTBASE)/Makefile.include diff --git a/tests/driver_lis2dh12/main.c b/tests/driver_lis2dh12/main.c index 9a47939a1d..10e00abcb0 100644 --- a/tests/driver_lis2dh12/main.c +++ b/tests/driver_lis2dh12/main.c @@ -22,10 +22,11 @@ #include "fmt.h" #include "xtimer.h" +#include "mutex.h" #include "lis2dh12.h" #include "lis2dh12_params.h" - + /* delay between sensor data reads */ #define DELAY (100UL * US_PER_MS) /* allocate some memory to hold one formatted string for each sensor output, so @@ -35,8 +36,64 @@ static char str_out[3][8]; /* allocate device descriptor */ static lis2dh12_t dev; +#ifdef MODULE_LIS2DH12_INT +/* control interrupt */ +typedef struct { + uint8_t line; + mutex_t *lock; + uint8_t *flags; +} lis_ctx; + +/* timer lock */ +static uint8_t isr_flags; +static mutex_t isr_mtx = MUTEX_INIT_LOCKED; +static lis_ctx ctx[2] = { + { + .line = 1, + .lock = &isr_mtx, + .flags = &isr_flags, + }, { + .line = 2, + .lock = &isr_mtx, + .flags = &isr_flags, + } +}; + +/* interrupt callback function. */ +static void lis2dh12_int_cb(void* _ctx) { + lis_ctx *control = _ctx; + + *control->flags |= control->line; + + mutex_unlock(control->lock); +} + +/* print interrupt register */ +static void lis2dh12_int_reg_content(lis2dh12_t *dev, uint8_t pin){ + + assert(pin == LIS2DH12_INT1 || pin == LIS2DH12_INT2); + + uint8_t buffer; + lis2dh12_read_int_src(dev, &buffer, pin); + + printf("content SRC_Reg_%d: 0x%02x\n", pin, buffer); + printf("\t XL %d\n", !!(buffer & LIS2DH12_INT_SRC_XL)); + printf("\t XH %d\n", !!(buffer & LIS2DH12_INT_SRC_XH)); + printf("\t YL %d\n", !!(buffer & LIS2DH12_INT_SRC_YL)); + printf("\t YH %d\n", !!(buffer & LIS2DH12_INT_SRC_YH)); + printf("\t ZL %d\n", !!(buffer & LIS2DH12_INT_SRC_ZL)); + printf("\t ZH %d\n", !!(buffer & LIS2DH12_INT_SRC_ZH)); + printf("\t IA %d\n", !!(buffer & LIS2DH12_INT_SRC_IA)); +} +#endif + int main(void) { + +#ifdef MODULE_LIS2DH12_INT + uint8_t flags = 0; +#endif + puts("LIS2DH12 accelerometer driver test application\n"); puts("Initializing LIS2DH12 sensor... "); @@ -48,13 +105,64 @@ int main(void) return 1; } - xtimer_ticks32_t last_wakeup = xtimer_now(); +#ifdef MODULE_LIS2DH12_INT + /* enable interrupt Pins */ + if (lis2dh12_params[0].int1_pin != GPIO_UNDEF) { + /* create and set the interrupt params */ + lis2dh12_int_params_t params_int1 = { + .int_type = LIS2DH12_INT_TYPE_I1_IA1, + .int_config = LIS2DH12_INT_CFG_XLIE, + .int_threshold = 31, + .int_duration = 1, + .cb = lis2dh12_int_cb, + .arg = &ctx[0], + }; + lis2dh12_set_int(&dev, ¶ms_int1, LIS2DH12_INT1); + } + + /* create and set the interrupt params */ + if (lis2dh12_params[0].int2_pin != GPIO_UNDEF) { + lis2dh12_int_params_t params_int2 = { + .int_type = LIS2DH12_INT_TYPE_I2_IA2, + .int_config = LIS2DH12_INT_CFG_YLIE, + .int_threshold = 31, + .int_duration = 1, + .cb = lis2dh12_int_cb, + .arg = &ctx[1], + }; + lis2dh12_set_int(&dev, ¶ms_int2, LIS2DH12_INT2); + } +#endif + while (1) { + +#ifdef MODULE_LIS2DH12_INT + if (xtimer_mutex_lock_timeout(&isr_mtx, DELAY) == 0) { + flags = isr_flags; + isr_flags = 0; + } + + /* check interrupt 1 and read register */ + if (flags & 0x1) { + printf("reads interrupt %d\n", LIS2DH12_INT1); + lis2dh12_int_reg_content(&dev, LIS2DH12_INT1); + flags &= ~(0x1); + } + /* check interrupt 2 and read register */ + if (flags & 0x2) { + printf("reads interrupt %d\n", LIS2DH12_INT2); + lis2dh12_int_reg_content(&dev, LIS2DH12_INT2); + flags &= ~(0x2); + } +#else + xtimer_usleep(DELAY); +#endif + /* read sensor data */ int16_t data[3]; if (lis2dh12_read(&dev, data) != LIS2DH12_OK) { - puts("error: unable to retrieve data from sensor, quitting now"); - return 1; + puts("error: unable to retrieve data from sensor"); + continue; } /* format data */ @@ -65,8 +173,6 @@ int main(void) /* print data to STDIO */ printf("X: %8s Y: %8s Z: %8s\n", str_out[0], str_out[1], str_out[2]); - - xtimer_periodic_wakeup(&last_wakeup, DELAY); } return 0;