From c78e8cbd275ebff7cfe40eeb89575f86ac27b8a6 Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser <kaspar@schleiser.de> Date: Fri, 9 Jun 2017 17:40:44 +0200 Subject: [PATCH] drivers: mma8x5x: add motion detection interrupt support --- drivers/include/mma8x5x.h | 26 +++++++++++ drivers/mma8x5x/mma8x5x.c | 93 ++++++++++++++++++++++++++++++++------- 2 files changed, 102 insertions(+), 17 deletions(-) diff --git a/drivers/include/mma8x5x.h b/drivers/include/mma8x5x.h index e8ae2c97d0..7b91b3c048 100644 --- a/drivers/include/mma8x5x.h +++ b/drivers/include/mma8x5x.h @@ -178,6 +178,32 @@ int mma8x5x_is_ready(mma8x5x_t *dev); */ void mma8x5x_read(mma8x5x_t *dev, mma8x5x_data_t *data); +/** + * @brief Configure motion detection interrupt + * + * User needs to configure MCU side of the selected int pin. mma8x5x will set + * the pin to low on interrupt. Before another interrupt can occur, the + * current interrupt must be acknowledged using @p mma8x5x_ack_int(). + * + * @param[in] dev device descriptor of accelerometer + * @param[in] int_pin select mma8x5x int pin (1 or 2) + * @param[in] threshold motion detection threshold (see datasheet) + */ +void mma8x5x_set_motiondetect(mma8x5x_t *dev, uint8_t int_pin, uint8_t threshold); + +/** + * @brief Acknowledge motion detection interrupt + * + * Acknowledges (clears) a motion detection interrupt. + * See @ref mma8x5x_set_motiondetect(). + * + * @warning: this does incur an I2C write, thus should not be done from within + * the ISR. + * + * @param[in] dev device descriptor of accelerometer + */ +void mma8x5x_ack_int(mma8x5x_t *dev); + #ifdef __cplusplus } #endif diff --git a/drivers/mma8x5x/mma8x5x.c b/drivers/mma8x5x/mma8x5x.c index 2ea16c78c7..193353727d 100644 --- a/drivers/mma8x5x/mma8x5x.c +++ b/drivers/mma8x5x/mma8x5x.c @@ -105,47 +105,106 @@ void mma8x5x_set_user_offset(mma8x5x_t *dev, int8_t x, int8_t y, int8_t z) i2c_release(BUS); } -void mma8x5x_set_active(mma8x5x_t *dev) +static int _get_reg(mma8x5x_t *dev, uint8_t addr) { uint8_t reg; assert(dev); - DEBUG("[mma8x5x] put device to active mode\n"); + DEBUG("[mma8x5x] getting reg 0x%02x\n", (unsigned)addr); i2c_acquire(BUS); - i2c_read_reg(BUS, ADDR, MMA8X5X_CTRL_REG1, ®); - reg |= MMA8X5X_CTRL_REG1_ACTIVE; - i2c_write_reg(BUS, ADDR, MMA8X5X_CTRL_REG1, reg); + i2c_read_reg(BUS, ADDR, addr, ®); i2c_release(BUS); + + DEBUG("[mma8x5x] reg 0x%02x=0x%02x\n", (unsigned)addr, (unsigned)reg); + return reg; } -void mma8x5x_set_standby(mma8x5x_t *dev) +static void _reg_setbits(mma8x5x_t *dev, uint8_t reg, uint8_t val) { - uint8_t reg; + uint8_t tmp; assert(dev); - DEBUG("[mma8x5x] put device to standby mode\n"); - i2c_acquire(BUS); - i2c_read_reg(BUS, ADDR, MMA8X5X_CTRL_REG1, ®); - reg &= ~MMA8X5X_CTRL_REG1_ACTIVE; - i2c_write_reg(BUS, ADDR, MMA8X5X_CTRL_REG1, reg); + i2c_read_reg(BUS, ADDR, reg, &tmp); + DEBUG("[mma8x5x] 0x%02x: 0x%02x | 0x%02x = 0x%02x\n", + (unsigned)reg, (unsigned)tmp, (unsigned)val, (unsigned) tmp | val); + tmp |= val; + i2c_write_reg(BUS, ADDR, reg, tmp); i2c_release(BUS); } -int mma8x5x_is_ready(mma8x5x_t *dev) +static void _reg_clearbits(mma8x5x_t *dev, uint8_t reg, uint8_t val) { - uint8_t reg; + uint8_t tmp; assert(dev); - DEBUG("[mma8x5x] checking for new available data\n"); - i2c_acquire(BUS); - i2c_read_reg(BUS, ADDR, MMA8X5X_STATUS, ®); + i2c_read_reg(BUS, ADDR, reg, &tmp); + DEBUG("[mma8x5x] 0x%02x: 0x%02x &= ~0x%02x = 0x%02x\n", + (unsigned)reg, (unsigned)tmp, (unsigned)val, (unsigned) tmp & ~val); + tmp &= ~val; + i2c_write_reg(BUS, ADDR, reg, tmp); i2c_release(BUS); +} + +void mma8x5x_set_active(mma8x5x_t *dev) +{ + DEBUG("[mma8x5x] put device to active mode\n"); + _reg_setbits(dev, MMA8X5X_CTRL_REG1, MMA8X5X_CTRL_REG1_ACTIVE); +} + +void mma8x5x_set_standby(mma8x5x_t *dev) +{ + DEBUG("[mma8x5x] put device to standby mode\n"); + _reg_clearbits(dev, MMA8X5X_CTRL_REG1, MMA8X5X_CTRL_REG1_ACTIVE); +} + +void mma8x5x_set_motiondetect(mma8x5x_t *dev, uint8_t int_pin, uint8_t threshold) +{ + DEBUG("[mma8x5x] put device to motion detect mode (ELE=1, OAE=1)\n"); + assert(int_pin < 3); + + mma8x5x_set_standby(dev); + + _reg_setbits(dev, MMA8X5X_FF_MT_CFG, \ + MMA8X5X_FF_MT_CFG_XEFE | \ + MMA8X5X_FF_MT_CFG_YEFE | \ + MMA8X5X_FF_MT_CFG_ZEFE | \ + MMA8X5X_FF_MT_CFG_OAE | MMA8X5X_FF_MT_CFG_ELE); + + switch(int_pin) { + case 0: + _reg_clearbits(dev, MMA8X5X_CTRL_REG4, MMA8X5X_CTRL_REG4_INT_EN_FF_MT); + goto out; + case 1: + _reg_setbits(dev, MMA8X5X_CTRL_REG5, MMA8X5X_CTRL_REG5_INT_CFG_FF_MT); + break; + case 2: + _reg_clearbits(dev, MMA8X5X_CTRL_REG5, MMA8X5X_CTRL_REG5_INT_CFG_FF_MT); + break; + } + + _reg_setbits(dev, MMA8X5X_FF_MT_THS, threshold & 0x7f); + _reg_setbits(dev, MMA8X5X_CTRL_REG4, MMA8X5X_CTRL_REG4_INT_EN_FF_MT); + +out: + mma8x5x_set_active(dev); +} + +void mma8x5x_ack_int(mma8x5x_t *dev) +{ + _get_reg(dev, MMA8X5X_FF_MT_SRC); +} + +int mma8x5x_is_ready(mma8x5x_t *dev) +{ + DEBUG("[mma8x5x] checking for new available data\n"); + + uint8_t reg = _get_reg(dev, MMA8X5X_STATUS); if (reg & MMA8X5X_STATUS_ZYXDR) { return MMA8X5X_DATA_READY; -- GitLab