diff --git a/drivers/include/lis2dh12.h b/drivers/include/lis2dh12.h index 3d54c0013a..b7bb106f91 100644 --- a/drivers/include/lis2dh12.h +++ b/drivers/include/lis2dh12.h @@ -63,10 +63,10 @@ extern "C" { * @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_2G = 0x0, /**< +- 2g */ + LIS2DH12_SCALE_4G = 0x1, /**< +- 4g */ + LIS2DH12_SCALE_8G = 0x2, /**< +- 8g */ + LIS2DH12_SCALE_16G = 0x3, /**< +- 16g */ } lis2dh12_scale_t; /** @@ -74,28 +74,35 @@ typedef enum { * */ typedef enum { - LIS2DH12_RATE_1HZ = 0x1, /**< sample with 1Hz @ all power modes */ - LIS2DH12_RATE_10HZ = 0x2, /**< sample with 10Hz @ all power modes */ - LIS2DH12_RATE_25HZ = 0x3, /**< sample with 25Hz @ all power modes */ - LIS2DH12_RATE_50HZ = 0x4, /**< sample with 50Hz @ all power modes */ - LIS2DH12_RATE_100HZ = 0x5, /**< sample with 100Hz @ all power modes */ - LIS2DH12_RATE_200HZ = 0x6, /**< sample with 200Hz @ all power modes */ - LIS2DH12_RATE_400HZ = 0x7, /**< sample with 400Hz @ all power modes */ - LIS2DH12_RATE_1620HZ = 0x8, /**< sample with 1620HZ @ Low Power*/ + LIS2DH12_RATE_1HZ = 0x1, /**< sample with 1Hz @ all resolutions */ + LIS2DH12_RATE_10HZ = 0x2, /**< sample with 10Hz @ all resolutions */ + LIS2DH12_RATE_25HZ = 0x3, /**< sample with 25Hz @ all resolutions */ + LIS2DH12_RATE_50HZ = 0x4, /**< sample with 50Hz @ all resolutions */ + LIS2DH12_RATE_100HZ = 0x5, /**< sample with 100Hz @ all resolutions */ + LIS2DH12_RATE_200HZ = 0x6, /**< sample with 200Hz @ all resolutions */ + LIS2DH12_RATE_400HZ = 0x7, /**< sample with 400Hz @ all resolutions */ + LIS2DH12_RATE_1620HZ = 0x8, /**< sample with 1620HZ @ 8-bit */ LIS2DH12_RATE_VERYHIGH = 0x9, /**< sample with 1344Hz @ High resolution or \ - 5376Hz @ Low Power*/ + 5376Hz @ 8-bit */ } lis2dh12_rate_t; /** - * @brief Available power modes + * @brief Available resolutions * */ typedef enum { LIS2DH12_POWER_DOWN = 0, /**< power down the device */ - LIS2DH12_POWER_LOW = 1, /**< low power mode */ - LIS2DH12_POWER_NORMAL = 2, /**< normal mode */ - LIS2DH12_POWER_HIGH = 3, /**< high resolution */ -} lis2dh12_powermode_t; + LIS2DH12_POWER_LOW = 1, /**< 8-bit mode */ + LIS2DH12_POWER_NORMAL = 2, /**< 10-bit mode */ + LIS2DH12_POWER_HIGH = 3, /**< 12-bit mode */ +} lis2dh12_resolution_t; + +#define LIS2DH12_CLICK_X_SINGLE (1 << 0) /**< single click on X axis */ +#define LIS2DH12_CLICK_X_DOUBLE (1 << 1) /**< double click on X axis */ +#define LIS2DH12_CLICK_Y_SINGLE (1 << 2) /**< single click on Y axis */ +#define LIS2DH12_CLICK_Y_DOUBLE (1 << 3) /**< double click on Y axis */ +#define LIS2DH12_CLICK_Z_SINGLE (1 << 4) /**< single click on Z axis */ +#define LIS2DH12_CLICK_Z_DOUBLE (1 << 5) /**< double click on Z axis */ /** * @brief LIS2DH12 configuration parameters @@ -114,7 +121,7 @@ typedef struct { #endif lis2dh12_scale_t scale; /**< sampling sensitivity used */ lis2dh12_rate_t rate; /**< sampling rate used */ - lis2dh12_powermode_t powermode; /**< power mode used*/ + lis2dh12_resolution_t resolution; /**< resolution used */ } lis2dh12_params_t; /** @@ -170,7 +177,6 @@ typedef struct { */ typedef struct { const lis2dh12_params_t *p; /**< device configuration */ - uint8_t comp; /**< scale compensation factor */ } lis2dh12_t; /** @@ -185,7 +191,6 @@ enum { LIS2DH12_NODATA= -4, /**< no data available */ }; -#if MODULE_LIS2DH12_INT || DOXYGEN /* * @brief Interrupt lines */ @@ -204,18 +209,18 @@ typedef struct { 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; -#endif /* MODULE_LIS2DH12_INT */ /** * @brief LIS2DH12 FIFO data struct */ -typedef struct { - int16_t X_AXIS; /**< X raw data in FIFO */ - int16_t Y_AXIS; /**< Y raw data in FIFO */ - int16_t Z_AXIS; /**< Z raw data in FIFO */ +typedef union { + struct { + int16_t x; /**< X data in mili-g */ + int16_t y; /**< Y data in mili-g */ + int16_t z; /**< Z data in mili-g */ + } axis; /**< named axis access */ + int16_t data[3]; /**< x, y, z data in mili-g */ } lis2dh12_fifo_data_t; /** @@ -239,33 +244,74 @@ typedef struct { /** * @brief Export the SAUL interface for this driver + * @{ */ extern const saul_driver_t lis2dh12_saul_driver; +extern const saul_driver_t lis2dh12_saul_temp_driver; +/** @} */ #if MODULE_LIS2DH12_INT || DOXYGEN /** - * @brief Set the interrupt values in LIS2DH12 sensor device + * @brief Configure a threshold event + * An Interrupt will be generated if acceleration exceeds the set threshold + * around the current reference value. * - * @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 + * @param[in] dev device descriptor + * @param[in] mg acceleration in mg + * @param[in] us time in µs for which the threshold must be exceeded + * @param[in] axis bitmap of axis / events to be monitored + * @param[in] event Event slot (1 or 2) + * @param[in] pin Interrupt pin to use (LIS2DH12_INT1/LIS2DH12_INT2) */ -int lis2dh12_set_int(const lis2dh12_t *dev, const lis2dh12_int_params_t *params, uint8_t int_line); +void lis2dh12_cfg_threshold_event(const lis2dh12_t *dev, + uint32_t mg, uint32_t us, + uint8_t axis, uint8_t event, uint8_t pin); /** - * @brief Read an interrupt event on LIS2DH12 sensor device + * @brief Configure a click event + * A click event is generated when the acceleration exceeds the set threshold + * for less than @p us_limit µs. + * A double click event is generated if a second click event occurs within + * @p us_window µs after the first one. + * + * @param[in] dev device descriptor + * @param[in] mg acceleration in mg + * @param[in] us_limit upper limit for click duration in µs + * @param[in] us_latency dead time after click event in µs + * @param[in] us_window time after @p us_latency in which the second click event + * must occur to register as double click + * @param[in] click bit map of click axis / types + * @param[in] pin Interrupt pin to use (LIS2DH12_INT1/LIS2DH12_INT2) + */ +void lis2dh12_cfg_click_event(const lis2dh12_t *dev, uint32_t mg, + uint32_t us_limit, uint32_t us_latency, uint32_t us_window, + uint8_t click, uint8_t pin); + +/** + * @brief Disable interrupt generation for an event + * This disables an interrupt on @p pin if a previously configured event occurs + * + * @param[in] dev device descriptor + * @param[in] event Event to disable (LIS2DH12_EVENT_1, LIS2DH12_EVENT_2 + * or LIS2DH12_EVENT_CLICK) + * @param[in] pin Interrupt pin to use (LIS2DH12_INT1/LIS2DH12_INT2) + */ +void lis2dh12_cfg_disable_event(const lis2dh12_t *dev, uint8_t event, uint8_t pin); + +/** + * @brief Wait for an interrupt event + * This function will block until an interrupt is received * * @param[in] dev device descriptor - * @param[out] data device interrupt data - * @param[in] int_line number of interrupt line (LIS2DH12_INT1 or LIS2DH12_INT2) + * @param[in] pin Interrupt pin to monitor (LIS2DH12_INT1 or LIS2DH12_INT2) + * @param[in] stale_events If true, this also reports events that were generated + * before this function was called and which are still in the + * fifo buffer. * - * @return LIS2DH12_OK on success - * @return LIS2DH12_NOBUS on bus errors + * @return negative error + * @return positive LIS2DH12_INT_SRC bit mask on success */ -int lis2dh12_read_int_src(const lis2dh12_t *dev, uint8_t *data, uint8_t int_line); +int lis2dh12_wait_event(const lis2dh12_t *dev, uint8_t pin, bool stale_events); #endif /* MODULE_LIS2DH12_INT */ /** @@ -291,16 +337,6 @@ int lis2dh12_set_fifo(const lis2dh12_t *dev, const lis2dh12_fifo_t *config); */ int lis2dh12_restart_fifo(const lis2dh12_t *dev); -/** - * @brief Read the FIFO source register - * - * @param[in] dev device descriptor - * @param[out] data LIS2DH12_FIFO_SRC_REG_t content, allocate one byte - * - * @return LIS2DH12_OK on success - */ -int lis2dh12_read_fifo_src(const lis2dh12_t *dev, LIS2DH12_FIFO_SRC_REG_t *data); - /** * @brief This function will read a given number of data from FIFO * reads amount of data that is available in FIFO @@ -330,12 +366,27 @@ 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 + * @param[out] data acceleration data in mili-g * * @return LIS2DH12_OK on success * @return LIS2DH12_NOBUS on bus error */ -int lis2dh12_read(const lis2dh12_t *dev, int16_t *data); +int lis2dh12_read(const lis2dh12_t *dev, lis2dh12_fifo_data_t *data); + +/** + * @brief Read temperature data from the given device + * + * @note The temperature sensor is not calibrated. + * Temperature values are only relative to a device specific + * reference. + * + * @param[in] dev device descriptor + * @param[out] temp temperature data in centi-°C + * + * @return LIS2DH12_OK on success + * @return LIS2DH12_NOBUS on bus error + */ +int lis2dh12_read_temperature(const lis2dh12_t *dev, int16_t *temp); /** * @brief Clear the LIS2DH12 memory, clears all sampled data @@ -347,7 +398,7 @@ int lis2dh12_read(const lis2dh12_t *dev, int16_t *data); int lis2dh12_clear_data(const lis2dh12_t *dev); /** - * @brief Change device scale value + * @brief Change device measuring range * * @param[in] dev device descriptor * @param[in] scale change to given scale value @@ -356,6 +407,15 @@ int lis2dh12_clear_data(const lis2dh12_t *dev); */ int lis2dh12_set_scale(lis2dh12_t *dev, lis2dh12_scale_t scale); +/** + * @brief Get device measuring range + * + * @param[in] dev device descriptor + * + * @return Current device range + */ +lis2dh12_scale_t lis2dh12_get_scale(lis2dh12_t *dev); + /** * @brief Change device sampling rate * @@ -367,14 +427,32 @@ int lis2dh12_set_scale(lis2dh12_t *dev, lis2dh12_scale_t scale); int lis2dh12_set_datarate(const lis2dh12_t *dev, lis2dh12_rate_t rate); /** - * @brief Change device power mode + * @brief Get device sampling rate in Hz + * + * @param[in] dev device descriptor + * + * @return current sampling rate in Hz + */ +uint16_t lis2dh12_get_datarate(const lis2dh12_t *dev); + +/** + * @brief Change device resolution * * @param[in] dev device descriptor - * @param[in] powermode change to given power mode + * @param[in] resolution change to given resolution * * @return LIS2DH12_OK on success */ -int lis2dh12_set_powermode(const lis2dh12_t *dev, lis2dh12_powermode_t powermode); +int lis2dh12_set_resolution(const lis2dh12_t *dev, lis2dh12_resolution_t resolution); + +/** + * @brief Get device resolution + * + * @param[in] dev device descriptor + * + * @return Current device resolution settings + */ +lis2dh12_resolution_t lis2dh12_get_resolution(const lis2dh12_t *dev); /** * @brief Configures the high pass filter @@ -400,37 +478,7 @@ int lis2dh12_set_highpass(const lis2dh12_t *dev, const lis2dh12_highpass_t *conf int lis2dh12_set_reference(const lis2dh12_t *dev, uint8_t reference); /** - * @brief Read the reference value - * - * @param[in] dev device descriptor - * @param[out] data reference value read from device - * - * @return LIS2DH12_OK on success - */ -int lis2dh12_read_reference(const lis2dh12_t *dev, uint8_t *data); - -/** - * @brief Set click configuration - * - * @param[in] dev device descriptor - * @param[in] config device click configuration - * - * @return LIS2DH12_OK on success - */ -int lis2dh12_set_click(const lis2dh12_t *dev, const lis2dh12_click_t *config); - -/** - * @brief Read click source register - * - * @param[in] dev device descriptor - * @param[out] data LIS2DH12_CLICK_SRC_t content, allocate one byte - * - * @return LIS2DH12_OK on success - */ -int lis2dh12_read_click_src(const lis2dh12_t *dev, LIS2DH12_CLICK_SRC_t *data); - -/** - * @brief Power on the given device and resets power mode and sampling rate + * @brief Power on the given device and resets resolution and sampling rate * to default values in the device descriptor parameters * * @param[in] dev device descriptor diff --git a/drivers/lis2dh12/include/lis2dh12_params.h b/drivers/lis2dh12/include/lis2dh12_params.h index 1a57f400b6..14f284df5e 100644 --- a/drivers/lis2dh12/include/lis2dh12_params.h +++ b/drivers/lis2dh12/include/lis2dh12_params.h @@ -67,8 +67,8 @@ extern "C" { #ifndef LIS2DH12_PARAM_RATE #define LIS2DH12_PARAM_RATE LIS2DH12_RATE_100HZ #endif -#ifndef LIS2DH12_PARAM_POWERMODE -#define LIS2DH12_PARAM_POWERMODE LIS2DH12_POWER_NORMAL +#ifndef LIS2DH12_PARAM_RESOLUTION +#define LIS2DH12_PARAM_RESOLUTION LIS2DH12_POWER_NORMAL #endif #ifndef LIS2DH12_PARAMS @@ -79,14 +79,14 @@ extern "C" { .int2_pin = LIS2DH12_PARAM_INT_PIN2, \ .scale = LIS2DH12_PARAM_SCALE, \ .rate = LIS2DH12_PARAM_RATE, \ - .powermode = LIS2DH12_PARAM_POWERMODE, \ + .resolution = LIS2DH12_PARAM_RESOLUTION, \ } #else /* MODULE_LIS2DH12_INT */ #define LIS2DH12_PARAMS { \ LIS2DH12_PARAMS_BUSCFG, \ .scale = LIS2DH12_PARAM_SCALE, \ .rate = LIS2DH12_PARAM_RATE, \ - .powermode = LIS2DH12_PARAM_POWERMODE, \ + .resolution = LIS2DH12_PARAM_RESOLUTION, \ } #endif /* MODULE_LIS2DH12_INT */ #endif /* LIS2DH12_PARAMS */ diff --git a/drivers/lis2dh12/include/lis2dh12_registers.h b/drivers/lis2dh12/include/lis2dh12_registers.h index 893714a2af..530434f285 100644 --- a/drivers/lis2dh12/include/lis2dh12_registers.h +++ b/drivers/lis2dh12/include/lis2dh12_registers.h @@ -33,6 +33,14 @@ enum { LIS2DH12_STATUS_REG_AUX_TOR = 0x40, /**< Temperature data overrun */ }; +/** + * @brief STATUS_REG_TEMP definitions + */ +enum { + LIS2DH12_TEMP_CFG_REG_DISABLE = 0x00, /**< Temperature sensor disable */ + LIS2DH12_TEMP_CFG_REG_ENABLE = 0xC0, /**< Temperature sensor enable */ +}; + /** * @brief STATUS_REG definitions */ @@ -94,8 +102,36 @@ enum { 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 */ + + LIS2DH12_INT_TYPE_IA2 = 0x20, /**< Event 2 */ + LIS2DH12_INT_TYPE_IA1 = 0x40, /**< Event 1 */ + LIS2DH12_INT_TYPE_CLICK = 0x80, /**< click interrupt */ }; +/** + * @brief Event slots + */ +enum { + LIS2DH12_EVENT_1 = 0x1, /**< first event slot */ + LIS2DH12_EVENT_2 = 0x2, /**< second event slot */ + LIS2DH12_EVENT_CLICK = 0x3, /**< click event */ +}; + +/** + * @brief Extract interrupt flags for Event Slot 1 + */ +#define LIS2DH12_INT_SRC_1(ret) (((uint32_t)(ret) >> 0) & 0x7F) + +/** + * @brief Extract interrupt flags for Event Slot 2 + */ +#define LIS2DH12_INT_SRC_2(ret) (((uint32_t)(ret) >> 8) & 0x7F) + +/** + * @brief Extract interrupt flags for Click Event + */ +#define LIS2DH12_INT_SRC_CLICK(ret) (((uint32_t)(ret) >> 16) & 0x7F) + /** * @brief CLICK_SRC definitions */ @@ -169,6 +205,13 @@ typedef union { uint8_t reg; /**< Type used for register access */ } LIS2DH12_CTRL_REG1_t; +#define LIS2DH12_CTRL_REG2_HP_IA1 (1 << 0) +#define LIS2DH12_CTRL_REG2_HP_IA2 (1 << 1) +#define LIS2DH12_CTRL_REG2_HPCLICK (1 << 2) +#define LIS2DH12_CTRL_REG2_FDS (1 << 3) + +#define LIS2DH12_CLICK_THS_LIR (0x80) + /** * @brief CTRL_REG2 definitions */ diff --git a/drivers/lis2dh12/lis2dh12.c b/drivers/lis2dh12/lis2dh12.c index 4126e512d1..963eb9be4c 100644 --- a/drivers/lis2dh12/lis2dh12.c +++ b/drivers/lis2dh12/lis2dh12.c @@ -14,10 +14,16 @@ * @brief LIS2DH12 accelerometer driver implementation * * @author Hauke Petersen + * @author Jan Mohr + * @author Benjamin Valentin * @} */ #include "assert.h" +#include "byteorder.h" +#include "mutex.h" +#include "timex.h" +#include "xtimer.h" #include "lis2dh12.h" #include "lis2dh12_internal.h" @@ -113,8 +119,7 @@ static uint8_t _read(const lis2dh12_t *dev, uint8_t reg) return tmp; } -static void _read_burst(const lis2dh12_t *dev, uint8_t reg, - void *data, size_t len) +static void _read_burst(const lis2dh12_t *dev, uint8_t reg, void *data, size_t len) { i2c_read_regs(BUS, ADDR, (FLAG_AINC | reg), data, len, 0); } @@ -127,13 +132,17 @@ static void _write(const lis2dh12_t *dev, uint8_t reg, uint8_t data) #endif /* MODULE_LIS2DH12_SPI */ +static void _write_or(const lis2dh12_t *dev, uint8_t reg, uint8_t data) +{ + data |= _read(dev, reg); + _write(dev, reg, data); +} + int lis2dh12_init(lis2dh12_t *dev, const lis2dh12_params_t *params) { assert(dev && params); dev->p = params; - /* calculate shift amount to convert raw acceleration data */ - dev->comp = 4 - (dev->p->scale >> 4); /* initialize the chip select line */ if (_init_bus(dev) != LIS2DH12_OK) { @@ -141,6 +150,15 @@ int lis2dh12_init(lis2dh12_t *dev, const lis2dh12_params_t *params) return LIS2DH12_NOBUS; } + /* set resolution */ + lis2dh12_set_resolution(dev, dev->p->resolution); + + /* clear stale data */ + lis2dh12_clear_data(dev); + + /* set data range */ + lis2dh12_set_scale(dev, dev->p->scale); + /* acquire the bus and verify that our parameters are valid */ if (_acquire(dev) != BUS_OK) { DEBUG("[lis2dh12] error: unable to acquire the bus\n"); @@ -154,6 +172,13 @@ int lis2dh12_init(lis2dh12_t *dev, const lis2dh12_params_t *params) return LIS2DH12_NODEV; } + /* clear events */ + _write(dev, REG_CTRL_REG3, 0); + _write(dev, REG_CTRL_REG6, 0); + + /* disable fifo */ + _write(dev, REG_FIFO_CTRL_REG, 0); + /* enable all axes, set sampling rate and scale */ LIS2DH12_CTRL_REG1_t reg1 = {0}; @@ -162,125 +187,317 @@ int lis2dh12_init(lis2dh12_t *dev, const lis2dh12_params_t *params) reg1.bit.Yen = 1; reg1.bit.Zen = 1; - _write(dev, REG_CTRL_REG4, dev->p->scale); _write(dev, REG_CTRL_REG1, reg1.reg); - _release(dev); + /* enable block data update */ + _write(dev, REG_CTRL_REG4, 0x80); - /* set powermode */ - lis2dh12_set_powermode(dev, dev->p->powermode); + _release(dev); DEBUG("[lis2dh12] initialization successful\n"); return LIS2DH12_OK; } -int lis2dh12_read(const lis2dh12_t *dev, int16_t *data) +static void _get_fifo_data(const lis2dh12_t *dev, lis2dh12_fifo_data_t *dst, uint8_t comp) +{ + _read_burst(dev, REG_OUT_X_L, dst, sizeof(*dst)); + + for (unsigned i = 0; i < 3; ++i) { + dst->data[i] >>= comp; + } +} + +int lis2dh12_read(const lis2dh12_t *dev, lis2dh12_fifo_data_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); + uint8_t comp = 4 - ((_read(dev, REG_CTRL_REG4) >> 4) & 0x3); + /* first check if valid data is available */ if ((_read(dev, REG_STATUS_REG) & LIS2DH12_STATUS_REG_ZYXDA) == 0) { _release(dev); return LIS2DH12_NODATA; } - _read_burst(dev, REG_OUT_X_L, raw, 6); + _get_fifo_data(dev, data, comp); _release(dev); - /* calculate the actual g-values for the x, y, and z dimension */ - for (int i = 0; i < 3; i++) { - data[i] = (int16_t)((raw[i*2 + 1] << 8) | raw[i*2]) >> dev->comp; + return LIS2DH12_OK; +} + +static const uint16_t mg_per_bit[] = { + 16, /* scale = 2g */ + 32, /* scale = 4g */ + 62, /* scale = 8g */ + 186 /* scale = 16g */ +}; + +static const uint16_t hz_per_dr[] = { + 0, /* power down */ + 1, /* Hz */ + 10, /* Hz */ + 25, /* Hz */ + 50, /* Hz */ + 100, /* Hz */ + 200, /* Hz */ + 400, /* Hz */ + 1620, /* Hz */ + 5376, /* Hz */ +}; + +void lis2dh12_cfg_threshold_event(const lis2dh12_t *dev, + uint32_t mg, uint32_t us, + uint8_t axis, uint8_t event, uint8_t line) +{ + assert(line == LIS2DH12_INT1 || line == LIS2DH12_INT2); + assert(event == LIS2DH12_EVENT_1 || event == LIS2DH12_EVENT_2); + + _acquire(dev); + + LIS2DH12_CTRL_REG2_t reg2; + reg2.reg = _read(dev, REG_CTRL_REG2); + uint8_t odr = _read(dev, REG_CTRL_REG1) >> 4; + uint8_t scale = (_read(dev, REG_CTRL_REG4) >> 4) & 0x3; + uint8_t int_reg = 0; + + /* read current interrupt configuration */ + if (line == LIS2DH12_INT1) { + int_reg = _read(dev, REG_CTRL_REG3); + } + if (line == LIS2DH12_INT2) { + int_reg = _read(dev, REG_CTRL_REG6); } - return LIS2DH12_OK; + DEBUG("[%u] threshold: %"PRIu32" mg\n", event, mg); + + /* read reference to set it to current data */ + _read(dev, REG_REFERENCE); + + /* configure interrupt */ + switch (event) { + case LIS2DH12_EVENT_1: + /* apply high-pass to interrupt */ + reg2.bit.HP_IA1 = 1; + int_reg |= LIS2DH12_INT_TYPE_IA1; + + /* clear INT flags */ + _read(dev, REG_INT1_SRC); + + _write(dev, REG_INT1_CFG, axis); + _write(dev, REG_INT1_THS, mg / mg_per_bit[scale]); + _write(dev, REG_INT1_DURATION, (us * hz_per_dr[odr]) / US_PER_SEC); + break; + case LIS2DH12_EVENT_2: + /* apply high-pass to interrupt */ + reg2.bit.HP_IA2 = 1; + int_reg |= LIS2DH12_INT_TYPE_IA2; + + /* clear INT flags */ + _read(dev, REG_INT2_SRC); + + _write(dev, REG_INT2_CFG, axis); + _write(dev, REG_INT2_THS, mg / mg_per_bit[scale]); + _write(dev, REG_INT2_DURATION, (us * hz_per_dr[odr]) / US_PER_SEC); + break; + } + + /* configure high-pass */ + _write(dev, REG_CTRL_REG2, reg2.reg); + + /* write back configuration */ + if (line == LIS2DH12_INT1) { + _write(dev, REG_CTRL_REG3, int_reg); + } + if (line == LIS2DH12_INT2) { + _write(dev, REG_CTRL_REG6, int_reg); + } + + _release(dev); +} + +void lis2dh12_cfg_click_event(const lis2dh12_t *dev, uint32_t mg, + uint32_t us_limit, uint32_t us_latency, uint32_t us_window, + uint8_t click, uint8_t line) +{ + _acquire(dev); + + uint8_t odr = _read(dev, REG_CTRL_REG1) >> 4; + uint8_t scale = (_read(dev, REG_CTRL_REG4) >> 4) & 0x3; + + DEBUG("click threshold: %"PRIu32" mg\n", mg); + + /* read reference to set it to current data */ + _read(dev, REG_REFERENCE); + + /* select click axis & mode */ + _write(dev, REG_CLICK_CFG, click); + + /* enable interrupt latching */ + _write(dev, REG_CLICK_THS, (mg / mg_per_bit[scale]) | LIS2DH12_CLICK_THS_LIR); + + /* set timing parameters */ + _write(dev, REG_TIME_LIMIT, (us_limit * hz_per_dr[odr]) / US_PER_SEC); + _write(dev, REG_TIME_LATENCY, (us_latency * hz_per_dr[odr]) / US_PER_SEC); + _write(dev, REG_TIME_WINDOW, (us_window * hz_per_dr[odr]) / US_PER_SEC); + + /* enable high-pass */ + _write_or(dev, REG_CTRL_REG2, LIS2DH12_CTRL_REG2_HPCLICK); + + /* clear INT flags */ + _read(dev, REG_CLICK_SRC); + + /* configure interrupt */ + if (line == LIS2DH12_INT1) { + _write_or(dev, REG_CTRL_REG3, LIS2DH12_INT_TYPE_CLICK); + } + if (line == LIS2DH12_INT2) { + _write_or(dev, REG_CTRL_REG6, LIS2DH12_INT_TYPE_CLICK); + } + + _release(dev); +} + +void lis2dh12_cfg_disable_event(const lis2dh12_t *dev, uint8_t event, uint8_t line) +{ + uint8_t reg = 0; + + _release(dev); + + /* read current interrupt configuration */ + if (line == LIS2DH12_INT1) { + reg = _read(dev, REG_CTRL_REG3); + } + if (line == LIS2DH12_INT2) { + reg = _read(dev, REG_CTRL_REG6); + } + + /* remove event */ + if (event == LIS2DH12_EVENT_1) { + reg &= ~LIS2DH12_INT_TYPE_IA1; + + /* clear INT flags */ + _read(dev, REG_INT1_SRC); + } + if (event == LIS2DH12_EVENT_2) { + reg &= ~LIS2DH12_INT_TYPE_IA2; + + /* clear INT flags */ + _read(dev, REG_INT2_SRC); + } + if (event == LIS2DH12_EVENT_CLICK) { + reg &= ~LIS2DH12_INT_TYPE_CLICK; + + /* clear INT flags */ + _read(dev, REG_CLICK_SRC); + } + + /* write back configuration */ + if (line == LIS2DH12_INT1) { + _write(dev, REG_CTRL_REG3, reg); + } + if (line == LIS2DH12_INT2) { + _write(dev, REG_CTRL_REG6, reg); + } + + _release(dev); } #ifdef MODULE_LIS2DH12_INT -int lis2dh12_set_int(const lis2dh12_t *dev, const lis2dh12_int_params_t *params, uint8_t int_line) +static void _cb(void *lock) { - assert (int_line == LIS2DH12_INT1 || int_line == LIS2DH12_INT2); - assert (dev && params); - assert (params->cb); - - _acquire(dev); - - gpio_t pin = GPIO_UNDEF; - - switch (int_line){ - /* first interrupt line (INT1) */ - case LIS2DH12_INT1: - pin = dev->p->int1_pin; - assert (gpio_is_valid(pin)); - - 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 (gpio_is_valid(pin)); - - 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; + mutex_unlock(lock); } -int lis2dh12_read_int_src(const lis2dh12_t *dev, uint8_t *data, uint8_t int_line) +static uint32_t _merge_int_flags(const lis2dh12_t *dev, uint8_t events) { - assert(dev && data); - assert(int_line == LIS2DH12_INT1 || int_line == LIS2DH12_INT2); + uint32_t int_src = 0; + + /* merge interrupt flags (7 bit per event) into one word */ + if (events & LIS2DH12_INT_TYPE_IA1) { + int_src |= (uint32_t)_read(dev, REG_INT1_SRC); + } + if (events & LIS2DH12_INT_TYPE_IA2) { + int_src |= (uint32_t)_read(dev, REG_INT2_SRC) << 8; + } + if (events & LIS2DH12_INT_TYPE_CLICK) { + int_src |= (uint32_t)_read(dev, REG_CLICK_SRC) << 16; + } + + DEBUG("int_src: %"PRIx32"\n", int_src); + + return int_src; +} + +#define LIS2DH12_INT_SRC_ANY (((uint32_t)LIS2DH12_INT_SRC_IA << 0) | \ + ((uint32_t)LIS2DH12_INT_SRC_IA << 8) | \ + ((uint32_t)LIS2DH12_INT_SRC_IA << 16)) + +int lis2dh12_wait_event(const lis2dh12_t *dev, uint8_t line, bool stale_events) +{ + uint32_t int_src; + uint8_t events = 0; + mutex_t lock = MUTEX_INIT_LOCKED; + gpio_t pin = line == LIS2DH12_INT2 + ? dev->p->int2_pin + : dev->p->int1_pin; _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; + /* find out which events are configured */ + if (line == LIS2DH12_INT1) { + events = _read(dev, REG_CTRL_REG3); } + if (line == LIS2DH12_INT2) { + events = _read(dev, REG_CTRL_REG6); + } + + /* check for stale interrupt */ + int_src = _merge_int_flags(dev, events); _release(dev); - return LIS2DH12_OK; + /* return early if stale interrupt is present */ + if (stale_events && (int_src & LIS2DH12_INT_SRC_ANY)) { + return int_src; + } + + /* enable interrupt pin */ + assert(gpio_is_valid(pin)); + if (gpio_init_int(pin, GPIO_IN, GPIO_RISING, _cb, &lock)) { + return LIS2DH12_NOINT; + } + + /* wait for interrupt */ + mutex_lock(&lock); + gpio_irq_disable(pin); + + /* read interrupt source */ + _acquire(dev); + int_src = _merge_int_flags(dev, events); + _release(dev); + + return int_src; } #endif /* MODULE_LIS2DH12_INT */ -int lis2dh12_set_fifo(const lis2dh12_t *dev, const lis2dh12_fifo_t *config) { +int lis2dh12_set_fifo(const lis2dh12_t *dev, const lis2dh12_fifo_t *config) +{ assert(dev && config); LIS2DH12_CTRL_REG5_t reg5 = {0}; LIS2DH12_FIFO_CTRL_REG_t fifo_reg = {0}; + reg5.bit.LIR_INT1 = 1; + reg5.bit.LIR_INT2 = 1; + if (config->FIFO_mode != LIS2DH12_FIFO_MODE_BYPASS) { reg5.bit.FIFO_EN = 1; + } else { + reg5.bit.FIFO_EN = 0; } fifo_reg.bit.TR = config->FIFO_set_INT2; fifo_reg.bit.FM = config->FIFO_mode; @@ -294,13 +511,14 @@ int lis2dh12_set_fifo(const lis2dh12_t *dev, const lis2dh12_fifo_t *config) { return LIS2DH12_OK; } -int lis2dh12_restart_fifo(const lis2dh12_t *dev) { +int lis2dh12_restart_fifo(const lis2dh12_t *dev) +{ assert(dev); _acquire(dev); uint8_t reg5 = _read(dev, REG_CTRL_REG5); - LIS2DH12_FIFO_CTRL_REG_t fifo_reg = {0}; + LIS2DH12_FIFO_CTRL_REG_t fifo_reg; fifo_reg.reg = _read(dev, REG_FIFO_CTRL_REG); uint8_t fifo_mode_old = fifo_reg.bit.FM; @@ -318,45 +536,28 @@ int lis2dh12_restart_fifo(const lis2dh12_t *dev) { return LIS2DH12_OK; } -int lis2dh12_read_fifo_src(const lis2dh12_t *dev, LIS2DH12_FIFO_SRC_REG_t *data) { - - assert(dev && data); - - _acquire(dev); - data->reg = _read(dev, REG_FIFO_SRC_REG); - _release(dev); - - return LIS2DH12_OK; -} - uint8_t lis2dh12_read_fifo_data(const lis2dh12_t *dev, lis2dh12_fifo_data_t *fifo_data, - uint8_t number) { - + uint8_t number) +{ assert(dev && fifo_data); /* check max FIFO length */ assert(number <= 32); _acquire(dev); + /* check if number is available */ - LIS2DH12_FIFO_SRC_REG_t src_reg = {0}; + LIS2DH12_FIFO_SRC_REG_t src_reg; src_reg.reg = _read(dev, REG_FIFO_SRC_REG); - if (src_reg.bit.FSS <= number) { + if (src_reg.bit.FSS < number) { number = src_reg.bit.FSS; } - if (src_reg.bit.EMPTY) { - return 0; - } + uint8_t comp = 4 - ((_read(dev, REG_CTRL_REG4) >> 4) & 0x3); /* calculate X, Y and Z values */ - for (uint8_t i = 0; i < number; i++){ - fifo_data[i].X_AXIS = (int16_t)(_read(dev, REG_OUT_X_L) | (_read(dev, REG_OUT_X_H) << 8)) - >> dev->comp; - fifo_data[i].Y_AXIS = (int16_t)(_read(dev, REG_OUT_Y_L) | (_read(dev, REG_OUT_Y_H) << 8)) - >> dev->comp; - fifo_data[i].Z_AXIS = (int16_t)(_read(dev, REG_OUT_Z_L) | (_read(dev, REG_OUT_Z_H) << 8)) - >> dev->comp; + for (uint8_t i = 0; i < number; i++) { + _get_fifo_data(dev, &fifo_data[i], comp); } _release(dev); @@ -364,12 +565,16 @@ uint8_t lis2dh12_read_fifo_data(const lis2dh12_t *dev, lis2dh12_fifo_data_t *fif return number; } -int lis2dh12_clear_data(const lis2dh12_t *dev) { +int lis2dh12_clear_data(const lis2dh12_t *dev) +{ assert(dev); - LIS2DH12_CTRL_REG5_t ctrl_reg5 = {0}; - ctrl_reg5.bit.BOOT = 1; + LIS2DH12_CTRL_REG5_t ctrl_reg5 = { + .bit.BOOT = 1, + .bit.LIR_INT1 = 1, + .bit.LIR_INT2 = 1, + }; _acquire(dev); _write(dev, REG_CTRL_REG5, ctrl_reg5.reg); @@ -378,7 +583,32 @@ int lis2dh12_clear_data(const lis2dh12_t *dev) { return LIS2DH12_OK; } -int lis2dh12_set_reference(const lis2dh12_t *dev, uint8_t reference) { +int lis2dh12_read_temperature(const lis2dh12_t *dev, int16_t *temp) +{ + uint8_t bytes[2]; + + _acquire(dev); + + /* enable temperature sensor */ + if (!_read(dev, REG_TEMP_CFG_REG)) { + uint8_t odr = _read(dev, REG_CTRL_REG1) >> 4; + _write(dev, REG_TEMP_CFG_REG, LIS2DH12_TEMP_CFG_REG_ENABLE); + if (IS_USED(MODULE_XTIMER)) { + xtimer_msleep(MS_PER_SEC / hz_per_dr[odr]); + } + } + + _read_burst(dev, REG_OUT_TEMP_L, bytes, sizeof(bytes)); + _release(dev); + + *temp = 100 * (int8_t)bytes[1]; + *temp += (100 * bytes[0]) >> 8; + + return 0; +} + +int lis2dh12_set_reference(const lis2dh12_t *dev, uint8_t reference) +{ assert(dev); @@ -389,18 +619,8 @@ int lis2dh12_set_reference(const lis2dh12_t *dev, uint8_t reference) { return LIS2DH12_OK; } -int lis2dh12_read_reference(const lis2dh12_t *dev, uint8_t *data) { - - assert(dev); - - _acquire(dev); - *data = _read(dev, REG_REFERENCE); - _release(dev); - - return LIS2DH12_OK; -} - -int lis2dh12_set_highpass(const lis2dh12_t *dev, const lis2dh12_highpass_t *config) { +int lis2dh12_set_highpass(const lis2dh12_t *dev, const lis2dh12_highpass_t *config) +{ assert(dev && config); @@ -420,67 +640,27 @@ int lis2dh12_set_highpass(const lis2dh12_t *dev, const lis2dh12_highpass_t *conf return LIS2DH12_OK; } -int lis2dh12_set_click(const lis2dh12_t *dev, const lis2dh12_click_t *config) { +int lis2dh12_set_resolution(const lis2dh12_t *dev, lis2dh12_resolution_t resolution) +{ assert(dev); - LIS2DH12_CLICK_CFG_t click_CFG = {0}; - if (config->enable_DOUBLE) { - click_CFG.bit.XD = config->enable_X_CLICK; - click_CFG.bit.YD = config->enable_Y_CLICK; - click_CFG.bit.ZD = config->enable_Z_CLICK; - } - else { - click_CFG.bit.XS = config->enable_X_CLICK; - click_CFG.bit.YS = config->enable_Y_CLICK; - click_CFG.bit.ZS = config->enable_Z_CLICK; - } - - LIS2DH12_CLICK_THS_t click_thold = {0}; - click_thold.bit.LIR_CLICK = config->noINT_latency; - click_thold.bit.THS = config->CLICK_thold; - - _acquire(dev); - _write(dev, REG_CLICK_CFG, click_CFG.reg); - _write(dev, REG_CLICK_THS, click_thold.reg); - _write(dev, REG_TIME_LIMIT, config->TIME_limit); - _write(dev, REG_TIME_LATENCY, config->TIME_latency); - _write(dev, REG_TIME_WINDOW, config->TIME_window); - _release(dev); - - return LIS2DH12_OK; -} - -int lis2dh12_read_click_src(const lis2dh12_t *dev, LIS2DH12_CLICK_SRC_t *data) { - assert(dev && data); - - _acquire(dev); - data->reg = _read(dev, REG_CLICK_SRC); - _release(dev); - - return LIS2DH12_OK; -} - -int lis2dh12_set_powermode(const lis2dh12_t *dev, lis2dh12_powermode_t powermode) { - - assert(dev); - - LIS2DH12_CTRL_REG1_t reg1 = {0}; - LIS2DH12_CTRL_REG4_t reg4 = {0}; + LIS2DH12_CTRL_REG1_t reg1; + LIS2DH12_CTRL_REG4_t reg4; _acquire(dev); reg1.reg = _read(dev, REG_CTRL_REG1); reg4.reg = _read(dev, REG_CTRL_REG4); /* set power mode */ - if (powermode == LIS2DH12_POWER_LOW) { + if (resolution == LIS2DH12_POWER_LOW) { reg1.bit.LPen = 1; reg4.bit.HR = 0; } - else if (powermode == LIS2DH12_POWER_HIGH) { + else if (resolution == LIS2DH12_POWER_HIGH) { reg1.bit.LPen = 0; reg4.bit.HR = 1; } - else if (powermode == LIS2DH12_POWER_NORMAL) { + else if (resolution == LIS2DH12_POWER_NORMAL) { reg1.bit.LPen = 0; reg4.bit.HR = 0; } @@ -495,51 +675,125 @@ int lis2dh12_set_powermode(const lis2dh12_t *dev, lis2dh12_powermode_t powermode return LIS2DH12_OK; } -int lis2dh12_set_datarate(const lis2dh12_t *dev, lis2dh12_rate_t rate) { +lis2dh12_resolution_t lis2dh12_get_resolution(const lis2dh12_t *dev) +{ + assert(dev); + + LIS2DH12_CTRL_REG1_t reg1; + LIS2DH12_CTRL_REG4_t reg4; + + _acquire(dev); + reg1.reg = _read(dev, REG_CTRL_REG1); + reg4.reg = _read(dev, REG_CTRL_REG4); + _release(dev); + + if (!reg1.bit.ODR) { + return LIS2DH12_POWER_DOWN; + } + if (reg1.bit.LPen) { + return LIS2DH12_POWER_LOW; + } + if (reg4.bit.HR) { + return LIS2DH12_POWER_HIGH; + } + return LIS2DH12_POWER_NORMAL; +} + +int lis2dh12_set_datarate(const lis2dh12_t *dev, lis2dh12_rate_t rate) +{ assert(dev); assert(rate <= 0x9); - LIS2DH12_CTRL_REG1_t reg1 = {0}; + LIS2DH12_CTRL_REG1_t reg1; _acquire(dev); reg1.reg = _read(dev, REG_CTRL_REG1); - reg1.bit.ODR = rate; - _write(dev, REG_CTRL_REG1, reg1.reg); _release(dev); return LIS2DH12_OK; } -int lis2dh12_set_scale(lis2dh12_t *dev, lis2dh12_scale_t scale) { +uint16_t lis2dh12_get_datarate(const lis2dh12_t *dev) +{ + const uint16_t rates_hz[] = { + 0, + 1, + 10, + 25, + 50, + 100, + 200, + 400, + }; assert(dev); - assert((scale>>4) <= 0x3); - LIS2DH12_CTRL_REG4_t reg4 = {0}; + LIS2DH12_CTRL_REG1_t reg1; + + _acquire(dev); + reg1.reg = _read(dev, REG_CTRL_REG1); + _release(dev); + + if (reg1.bit.ODR < ARRAY_SIZE(rates_hz)) { + return rates_hz[reg1.bit.ODR]; + } + + if (reg1.bit.LPen) { + if (reg1.bit.ODR == 8) { + return 1620; + } + if (reg1.bit.ODR == 9) { + return 5376; + } + } + + if (reg1.bit.ODR == 9) { + return 1344; + } + + return 0; +} + +int lis2dh12_set_scale(lis2dh12_t *dev, lis2dh12_scale_t scale) +{ + + assert(dev); + assert(scale <= LIS2DH12_SCALE_16G); + + LIS2DH12_CTRL_REG4_t reg4; _acquire(dev); reg4.reg = _read(dev, REG_CTRL_REG4); - - reg4.bit.FS = scale >> 4; - + reg4.bit.FS = scale; _write(dev, REG_CTRL_REG4, reg4.reg); _release(dev); - dev->comp = 4 - (scale >> 4); - return LIS2DH12_OK; } +lis2dh12_scale_t lis2dh12_get_scale(lis2dh12_t *dev) +{ + assert(dev); + + LIS2DH12_CTRL_REG4_t reg4; + + _acquire(dev); + reg4.reg = _read(dev, REG_CTRL_REG4); + _release(dev); + + return reg4.bit.FS; +} + int lis2dh12_poweron(const lis2dh12_t *dev) { assert(dev); /* set default param values */ lis2dh12_set_datarate(dev, dev->p->rate); - lis2dh12_set_powermode(dev, dev->p->powermode); + lis2dh12_set_resolution(dev, dev->p->resolution); return LIS2DH12_OK; } @@ -551,5 +805,10 @@ int lis2dh12_poweroff(const lis2dh12_t *dev) /* set datarate to zero */ lis2dh12_set_datarate(dev, 0); + /* disable temperature sensor */ + _acquire(dev); + _write(dev, REG_TEMP_CFG_REG, LIS2DH12_TEMP_CFG_REG_DISABLE); + _release(dev); + return LIS2DH12_OK; } diff --git a/drivers/lis2dh12/lis2dh12_saul.c b/drivers/lis2dh12/lis2dh12_saul.c index b3c878296b..25b87b2cf8 100644 --- a/drivers/lis2dh12/lis2dh12_saul.c +++ b/drivers/lis2dh12/lis2dh12_saul.c @@ -23,7 +23,7 @@ static int read_accelerometer(const void *dev, phydat_t *res) { - if (lis2dh12_read((const lis2dh12_t *)dev, res->val) != LIS2DH12_OK) { + if (lis2dh12_read(dev, (lis2dh12_fifo_data_t*)res->val) != LIS2DH12_OK) { return 0; } res->unit = UNIT_G; @@ -31,8 +31,25 @@ static int read_accelerometer(const void *dev, phydat_t *res) return 3; } +static int read_temperature(const void *dev, phydat_t *res) +{ + if (lis2dh12_read_temperature(dev, &res->val[0])) { + return -ECANCELED; + } + res->unit = UNIT_TEMP_C; + res->scale = -2; + + return 1; +} + const saul_driver_t lis2dh12_saul_driver = { .read = read_accelerometer, .write = saul_notsup, - .type = SAUL_SENSE_ACCEL + .type = SAUL_SENSE_ACCEL, +}; + +const saul_driver_t lis2dh12_saul_temp_driver = { + .read = read_temperature, + .write = saul_notsup, + .type = SAUL_SENSE_TEMP, }; diff --git a/drivers/saul/init_devs/auto_init_lis2dh12.c b/drivers/saul/init_devs/auto_init_lis2dh12.c index 4f89ee230c..05b9a1724e 100644 --- a/drivers/saul/init_devs/auto_init_lis2dh12.c +++ b/drivers/saul/init_devs/auto_init_lis2dh12.c @@ -30,7 +30,6 @@ */ #define LIS2DH12_NUM ARRAY_SIZE(lis2dh12_params) - /** * @brief Number of defined SAUL registry info entries */ @@ -45,7 +44,7 @@ static lis2dh12_t lis2dh12_devs[LIS2DH12_NUM]; /** * @brief Memory for the SAUL registry entries */ -static saul_reg_t saul_entries[LIS2DH12_NUM]; +static saul_reg_t saul_entries[LIS2DH12_NUM * 2]; void auto_init_lis2dh12(void) { @@ -62,9 +61,14 @@ void auto_init_lis2dh12(void) continue; } - saul_entries[i].dev = &(lis2dh12_devs[i]); - saul_entries[i].name = lis2dh12_saul_info[i].name; - saul_entries[i].driver = &lis2dh12_saul_driver; - saul_reg_add(&(saul_entries[i])); + saul_entries[2 * i].dev = &lis2dh12_devs[i]; + saul_entries[2 * i].name = lis2dh12_saul_info[i].name; + saul_entries[2 * i].driver = &lis2dh12_saul_driver; + saul_reg_add(&saul_entries[2 * i]); + + saul_entries[2 * i + 1].dev = &lis2dh12_devs[i]; + saul_entries[2 * i + 1].name = lis2dh12_saul_info[i].name; + saul_entries[2 * i + 1].driver = &lis2dh12_saul_temp_driver; + saul_reg_add(&saul_entries[2 * i + 1]); } } diff --git a/tests/driver_lis2dh12/Makefile b/tests/driver_lis2dh12/Makefile index 3cc425d3df..d47e568630 100644 --- a/tests/driver_lis2dh12/Makefile +++ b/tests/driver_lis2dh12/Makefile @@ -6,6 +6,7 @@ DRIVER ?= lis2dh12_spi USEMODULE += fmt USEMODULE += xtimer USEMODULE += shell +USEMODULE += shell_commands USEMODULE += $(DRIVER) # for using lis2dh12 with interrupt function diff --git a/tests/driver_lis2dh12/app.config.test b/tests/driver_lis2dh12/app.config.test index 54c15469d2..98d38424d2 100644 --- a/tests/driver_lis2dh12/app.config.test +++ b/tests/driver_lis2dh12/app.config.test @@ -3,6 +3,7 @@ CONFIG_MODULE_FMT=y CONFIG_MODULE_XTIMER=y CONFIG_MODULE_SHELL=y +CONFIG_MODULE_SHELL_COMMANDS=y CONFIG_MODULE_LIS2DH12=y CONFIG_MODULE_LIS2DH12_SPI=y diff --git a/tests/driver_lis2dh12/main.c b/tests/driver_lis2dh12/main.c index b8e7b8014d..2daa98a210 100644 --- a/tests/driver_lis2dh12/main.c +++ b/tests/driver_lis2dh12/main.c @@ -14,13 +14,15 @@ * @brief Test application for LIS2DH12 accelerometer driver * * @author Jan Mohr + * @author Benjamin Valentin * * @} */ -#include "stdio.h" -#include "string.h" -#include "stdlib.h" +#include +#include +#include +#include #include "xtimer.h" #include "fmt.h" #include "thread.h" @@ -33,129 +35,12 @@ #define ENABLE_DEBUG 0 #include "debug.h" -#define REFERENCE_DEFAULT 10 /* LSB according to SCALE */ - -#define THOLD_SHOCK_MILLIG_DEFAULT 1500 -#define NUM_DATA_SHOCK_DETECT 7 /* detect shock in NUM last FIFO samples */ - /* device specific */ -#define NUM_AXES 3 #define NUM_FIFO_VALUES 32 -/* axis define for click */ -#define X_CLICK 1 -#define Y_CLICK 2 -#define Z_CLICK 3 -#define DCLICK_DEFAULT 40 /* default threshold for double click */ - -#ifdef MODULE_LIS2DH12_INT -static kernel_pid_t lis2dh12_process; -#endif /* MODULE_LIS2DH12_INT */ - -int __attribute__((weak)) shell_lis2dh12_cmd(int argc, char** argv); - -static const shell_command_t shell_commands[] = { - { "lis", "Command with multiple subcommands.", shell_lis2dh12_cmd }, - { NULL, NULL, NULL }, -}; - -char lis2dh12_process_stack[THREAD_STACKSIZE_MAIN]; - -/* setting the double click order */ -static LIS2DH12_CLICK_SRC_t click_src_reg; -static lis2dh12_click_t click_cfg = { - .enable_DOUBLE = true, - .enable_X_CLICK = true, - .enable_Y_CLICK = true, - .enable_Z_CLICK = true, - .noINT_latency = true, - .CLICK_thold = DCLICK_DEFAULT, - .TIME_limit = 4, /* 4 ODR cycles -> 40ms */ - .TIME_latency = 16, /* 16 ODR cycles -> 160ms */ - .TIME_window = 10, /* 10 ODR cycles -> 100ms */ -}; - /* allocate device descriptor */ static lis2dh12_t dev; -#ifdef MODULE_LIS2DH12_INT -/* Interrupt lines */ -static uint8_t line1 = 1; -static uint8_t line2 = 2; - -/* Interrupt params */ -static lis2dh12_int_params_t params_int1 = {0}; -static lis2dh12_int_params_t params_int2 = {0}; - -/* Interrupt source register */ -static uint8_t int1_src; -#endif /* MODULE_LIS2DH12_INT */ - -/* FIFO data memory */ -static lis2dh12_fifo_data_t data_fifo[NUM_FIFO_VALUES]; -/* FIFO configuration */ -static lis2dh12_fifo_t fifo_cfg = { - .FIFO_set_INT2 = false, - .FIFO_watermark = 10, - .FIFO_mode = LIS2DH12_FIFO_MODE_STREAMtoFIFO, -}; - -/* Memory to print current data */ -static char str_out[3][8]; - -/* current lis acceleration data */ -static int16_t data_lis[3]; - -/* highpass configuration */ -lis2dh12_highpass_t highpass_cfg = { - .Highpass_mode = LIS2DH12_HP_MODE_REFERENCE, - .Highpass_freq = LIS2DH12_HP_FREQ_DIV100, - .CLICK_enable = false, - .INT1_enable = false, - .INT2_enable = false, - .DATA_OUT_enable = false, -}; - -/* reference data */ -static uint8_t reference_value; - -/* shock threshold */ -static int16_t shock_thold; - -#ifdef MODULE_LIS2DH12_INT -/* previous values */ -static int16_t old_data_lis[3]; -static uint8_t int1_src_old; - -/* lis2dh12 interrupt callback function. */ -static void lis2dh12_int_cb(void* l) { - - /* disable IRQ until lis_process is done */ - gpio_irq_disable(dev.p->int1_pin); - gpio_irq_disable(dev.p->int2_pin); - - /* reset click source */ - lis2dh12_read_click_src(&dev, &click_src_reg); - DEBUG("[INT]: CLICK_SRC 0x%x\n", click_src_reg.reg); - - uint8_t line = *(uint8_t*)l; - printf("Info: INT_line: %d\n", line); - - lis2dh12_read_reference(&dev, &reference_value); - DEBUG("[INT]: REF: 0x%x\n", reference_value); - - lis2dh12_read_int_src(&dev, &int1_src, 1); - DEBUG("[INT]: INT_SRC 0x%x\n", int1_src); - DEBUG("[INT]: INT_SRC - IA %d; ZH %d; ZL %d; YH %d; YL %d; XH %d; XL %d.\n", - int1_src & LIS2DH12_INT_SRC_IA, - int1_src & LIS2DH12_INT_SRC_ZH, int1_src & LIS2DH12_INT_SRC_ZL, - int1_src & LIS2DH12_INT_SRC_YH, int1_src & LIS2DH12_INT_SRC_YL, - int1_src & LIS2DH12_INT_SRC_XH, int1_src & LIS2DH12_INT_SRC_XL); - - thread_wakeup(lis2dh12_process); -} -#endif /* MODULE_LIS2DH12_INT */ - void lis2dh12_test_init(void) { if (IS_USED(MODULE_LIS2DH12_SPI)) { @@ -173,534 +58,320 @@ void lis2dh12_test_init(void) { } /* change LIS settings */ - lis2dh12_set_powermode(&dev, LIS2DH12_POWER_LOW); + lis2dh12_set_resolution(&dev, LIS2DH12_POWER_LOW); lis2dh12_set_datarate(&dev, LIS2DH12_RATE_100HZ); - lis2dh12_set_scale(&dev, LIS2DH12_SCALE_4G); + lis2dh12_set_scale(&dev, LIS2DH12_SCALE_16G); -#ifdef MODULE_LIS2DH12_INT - /* set interrupt pins */ - gpio_t pin1 = dev.p->int1_pin; - gpio_t pin2 = dev.p->int2_pin; + /* configure FIFO */ + lis2dh12_fifo_t fifo_cfg = { + .FIFO_mode = LIS2DH12_FIFO_MODE_STREAM, + }; - /* set Interrupt params */ - if (gpio_is_valid(pin1)) { - /* enables interrupt on all axes above the threshold value */ - params_int1.int_config = LIS2DH12_INT_CFG_XHIE - | LIS2DH12_INT_CFG_YHIE - | LIS2DH12_INT_CFG_ZHIE; - params_int1.int_duration = 1; - params_int1.cb = lis2dh12_int_cb; - params_int1.arg = &line1; - } - if (gpio_is_valid(pin2)) { - /* enables interrupt on Y-axis below the threshold value */ - params_int2.int_config = LIS2DH12_INT_CFG_YLIE; - params_int2.int_duration = 1; - params_int2.cb = lis2dh12_int_cb; - params_int2.arg = &line2; - } - - if (gpio_init_int(pin1, GPIO_IN, GPIO_RISING, lis2dh12_int_cb, &line1)) { - DEBUG("[lis_init]: INT1 failed\n"); - } - else { - DEBUG("[lis_init]: INT1 done\n"); - } - - if (gpio_init_int(pin2, GPIO_IN, GPIO_RISING, lis2dh12_int_cb, &line2)) { - DEBUG("[lis_init]: INT2 failed\n"); - } - else { - DEBUG("[lis_init]: INT2 done\n"); - } -#endif /* MODULE_LIS2DH12_INT */ - - /* enable FIFO */ lis2dh12_set_fifo(&dev, &fifo_cfg); - - /* enable click detection */ - lis2dh12_set_click(&dev, &click_cfg); - - /* set default shock value */ - shock_thold = THOLD_SHOCK_MILLIG_DEFAULT; - - /* read registers to reset device */ - lis2dh12_read_click_src(&dev, &click_src_reg); - lis2dh12_read_reference(&dev, &reference_value); -#ifdef MODULE_LIS2DH12_INT - lis2dh12_read_int_src(&dev, &int1_src, 1); -#endif /* MODULE_LIS2DH12_INT */ } #ifdef MODULE_LIS2DH12_INT void* lis2dh12_test_process(void* arg) { (void) arg; + + /* start processing */ + DEBUG("[Process]: start process\n"); + while (1) { - /* start processing */ - DEBUG("[Process]: start process\n"); - /* read FIFO_src before getting data */ - LIS2DH12_FIFO_SRC_REG_t fifo_src; - lis2dh12_read_fifo_src(&dev, &fifo_src); - DEBUG("[Process]: FIFO SRC 0x%x\n", fifo_src.reg); - DEBUG("[Process]: WTM %x, OVRN %d, EMPTY %d, FSS %d\n", fifo_src.bit.WTM, - fifo_src.bit.OVRN_FIFO, fifo_src.bit.EMPTY, fifo_src.bit.FSS); + /* wait for interrupt */ + int int1_src = lis2dh12_wait_event(&dev, LIS2DH12_INT1, false); - /* get fifo data */ - uint8_t number_read = lis2dh12_read_fifo_data(&dev, data_fifo, NUM_FIFO_VALUES); - - /* read FIFO_src after getting data */ - lis2dh12_read_fifo_src(&dev, &fifo_src); - DEBUG("[Process]: FIFO SRC 0x%x\n", fifo_src.reg); - DEBUG("[Process]: WTM %x, OVRN %d, EMPTY %d, FSS %d\n", fifo_src.bit.WTM, - fifo_src.bit.OVRN_FIFO, fifo_src.bit.EMPTY, fifo_src.bit.FSS); - - /* display FIFO data */ - if (ENABLE_DEBUG) { - for (int i = 0; i < number_read; i++){ - printf("[Process]: X[%2d] %d\n", i, data_fifo[i].X_AXIS); - printf("[Process]: Y[%2d] %d\n", i, data_fifo[i].Y_AXIS); - printf("[Process]: Z[%2d] %d\n", i, data_fifo[i].Z_AXIS); - } + if (int1_src <= 0) { + printf("error: %d\n", int1_src); + continue; } - /* After the Interrupt the FIFO needs to be enabled again. */ - lis2dh12_restart_fifo(&dev); - - /* check if shock occurred*/ - uint16_t max_data_X = 0; - uint16_t max_data_Y = 0; - uint16_t max_data_Z = 0; - - bool X_shock_pos = false; - bool Y_shock_pos = false; - bool Z_shock_pos = false; - - for (uint8_t entry = NUM_FIFO_VALUES - NUM_DATA_SHOCK_DETECT; entry < NUM_FIFO_VALUES; - entry++) { - uint16_t abs_X = data_fifo[entry].X_AXIS >= 0 ? data_fifo[entry].X_AXIS : - -1*data_fifo[entry].X_AXIS; - uint16_t abs_Y = data_fifo[entry].Y_AXIS >= 0 ? data_fifo[entry].Y_AXIS : - -1*data_fifo[entry].Y_AXIS; - uint16_t abs_Z = data_fifo[entry].Z_AXIS >= 0 ? data_fifo[entry].Z_AXIS : - -1*data_fifo[entry].Z_AXIS; - - /* check X shock direction */ - if (max_data_X <= abs_X) { - max_data_X = abs_X; - X_shock_pos = (data_fifo[entry].X_AXIS >= 0); - } - /* check Y shock direction */ - if (max_data_Y <= abs_Y) { - max_data_Y = abs_Y; - Y_shock_pos = (data_fifo[entry].Y_AXIS >= 0); - } - /* check Z shock direction */ - if (max_data_Z <= abs_Z) { - max_data_Z = abs_Z; - Z_shock_pos = (data_fifo[entry].Z_AXIS >= 0); - } + if (LIS2DH12_INT_SRC_1(int1_src) & LIS2DH12_INT_SRC_IA) { + puts("event 1"); } - - DEBUG("[Process]: oldX %d, oldY %d, oldZ %d\n", old_data_lis[0], old_data_lis[1], - old_data_lis[2]); - DEBUG("[Process]: maxX %d, maxY %d, maxZ %d\n", max_data_X, max_data_Y, max_data_Z); - - /* X shock */ - int16_t diff_value = max_data_X - old_data_lis[0]; - if (diff_value >= shock_thold) { - if (X_shock_pos) { - puts("positive X shock detected."); - } - else { - puts("negative X shock detected."); - } + if (LIS2DH12_INT_SRC_2(int1_src) & LIS2DH12_INT_SRC_IA) { + puts("event 2"); } - /* Y shock */ - diff_value = max_data_Y - old_data_lis[1]; - if (diff_value >= shock_thold) { - if (Y_shock_pos) { - puts("positive Y shock detected."); - } - else { - puts("negative Y shock detected."); - } + if (LIS2DH12_INT_SRC_CLICK(int1_src) & LIS2DH12_INT_SRC_IA) { + puts("click event"); } - /* Z shock */ - diff_value = max_data_Z - old_data_lis[2]; - if (diff_value >= shock_thold) { - if (Z_shock_pos) { - puts("positive Z shock detected."); - } - else { - puts("negative Z shock detected."); - } - } - - /* check for roll */ - /* roll conditions - * - * only 180°, changes can be detected with 6D reg in INT1_SRC - * change in ZH and ZL -> X-roll (device flipped from top to bottom) - * change in YH and YL -> Z-roll - * change in XH and XL -> Y-roll - */ - DEBUG("[Process]: OLD - IA %d; ZH %d; ZL %d; YH %d; YL %d; XH %d; XL %d.\n", - int1_src_old & LIS2DH12_INT_SRC_IA, - int1_src_old & LIS2DH12_INT_SRC_ZH, int1_src_old & LIS2DH12_INT_SRC_ZL, - int1_src_old & LIS2DH12_INT_SRC_YH, int1_src_old & LIS2DH12_INT_SRC_YL, - int1_src_old & LIS2DH12_INT_SRC_XH, int1_src_old & LIS2DH12_INT_SRC_XL); - - DEBUG("[Process]: NEW - IA %d; ZH %d; ZL %d; YH %d; YL %d; XH %d; XL %d.\n", - int1_src & LIS2DH12_INT_SRC_IA, - int1_src & LIS2DH12_INT_SRC_ZH, int1_src & LIS2DH12_INT_SRC_ZL, - int1_src & LIS2DH12_INT_SRC_YH, int1_src & LIS2DH12_INT_SRC_YL, - int1_src & LIS2DH12_INT_SRC_XH, int1_src & LIS2DH12_INT_SRC_XL); - - if (((int1_src_old & LIS2DH12_INT_SRC_ZH) != (int1_src & LIS2DH12_INT_SRC_ZH)) - && ((int1_src_old & LIS2DH12_INT_SRC_ZL) != (int1_src & LIS2DH12_INT_SRC_ZL))) { - printf("X roll detected.\n"); - } - if (((int1_src_old & LIS2DH12_INT_SRC_XH) != (int1_src & LIS2DH12_INT_SRC_XH)) - && ((int1_src_old & LIS2DH12_INT_SRC_YL) != (int1_src & LIS2DH12_INT_SRC_YL))) { - printf("Z roll detected.\n"); - } - if (((int1_src_old & LIS2DH12_INT_SRC_YH) != (int1_src & LIS2DH12_INT_SRC_YH)) - && ((int1_src_old & LIS2DH12_INT_SRC_XL) != (int1_src & LIS2DH12_INT_SRC_XL))) { - printf("Y roll detected.\n"); - } - - int1_src_old = int1_src; - - /* check click order */ - /* - * idea is to do a sequence of double clicks, to enable the device - * - */ - /* click_src read during interrupt callback */ - DEBUG("[Process]: clickSRC 0x%x\n", click_src_reg.reg); - - if (click_src_reg.bit.IA && click_src_reg.bit.DClick) { - /* X-Double */ - if (click_src_reg.bit.X_AXIS && !click_src_reg.bit.Y_AXIS - && !click_src_reg.bit.Z_AXIS) { - int8_t sign = click_src_reg.bit.Sign ? -1 : 1; - printf("got X-DCLICK, sign %d\n", sign); - } - /* Y-Double */ - if (!click_src_reg.bit.X_AXIS && click_src_reg.bit.Y_AXIS - && !click_src_reg.bit.Z_AXIS) { - int8_t sign = click_src_reg.bit.Sign ? -1 : 1; - printf("got Y-DCLICK, sign %d\n", sign); - } - /* Z-Double */ - if (!click_src_reg.bit.X_AXIS && !click_src_reg.bit.Y_AXIS - && click_src_reg.bit.Z_AXIS) { - int8_t sign = click_src_reg.bit.Sign ? -1 : 1; - printf("got Z-DCLICK, sign %d\n", sign); - } - } - - /* enable IRQ again */ - gpio_irq_enable(dev.p->int1_pin); - gpio_irq_enable(dev.p->int2_pin); - - /* thread will sleep until next wokeup_lis */ - thread_sleep(); } return NULL; } #endif /* MODULE_LIS2DH12_INT */ -int shell_lis2dh12_cmd(int argc, char **argv) { +static int shell_is2dh12_read(int argc, char **argv) +{ + (void)argc; + (void)argv; - printf("Command: lis %s %s\n", (argc > 1) ? argv[1] : "", - (argc > 2) ? argv[2] : ""); -#ifdef MODULE_LIS2DH12_INT - const char * usage = "USAGE: lis [arg], with subcommand " - "in (enable, disable, read, read_fifo, clear_data, " - "set-click, set-thold-shock, set-thold-inter, " - "set-highpass, change_rate, change_power, change_scale)."; -#else - const char * usage = "USAGE: lis [arg], with subcommand " - "in (enable, disable, read, read_fifo, clear_data, " - "change_rate, change_power, change_scale)."; -#endif /* MODULE_LIS2DH12_INT */ + lis2dh12_fifo_data_t data; - /* MISSING command */ - if (argc < 2) { - printf("Error: Missing sub-command. %s\n", usage); - return -1; + lis2dh12_read(&dev, &data); + + /* Memory to print current data */ + char str_out[3][8]; + + /* format data */ + for (unsigned j = 0; j < 3; ++j) { + size_t len = fmt_s16_dfp(str_out[j], data.data[j], -3); + str_out[j][len] = '\0'; } - /* enable disable device */ - else if (strncmp(argv[1], "enable", sizeof("enable")) == 0) { - if (lis2dh12_poweron(&dev) != LIS2DH12_OK) { - puts("unable to poweron device."); - } - return 1; - } - else if (strncmp(argv[1], "disable", sizeof("disable")) == 0) { - if (lis2dh12_poweroff(&dev) != LIS2DH12_OK) { - puts("unable to poweroff device."); - return -1; - } - return 1; - } + printf("X: %6s Y: %6s Z: %6s\n", str_out[0], str_out[1], str_out[2]); - /* read acceleration data */ - else if (strncmp(argv[1], "read", sizeof("read")) == 0) { - uint8_t amount = (argc < 3) ? 1 : atoi(argv[2]); - uint8_t amt = 0; - - /* read sensor data */ - for (amt = 0; amt < amount; amt++){ - if (lis2dh12_read(&dev, data_lis) != LIS2DH12_OK) { - puts("error: no data from sensor"); - return -1; - } - /* format data */ - for (int i = 0; i < 3; i++) { - size_t len = fmt_s16_dfp(str_out[i], data_lis[i], -3); - str_out[i][len] = '\0'; - } - - /* print data to STDIO */ - printf("X: %6s Y: %6s Z: %6s\n", str_out[0], str_out[1], str_out[2]); - - xtimer_msleep(250); - } - return 1; - } - else if (strncmp(argv[1], "read_fifo", sizeof("read_fifo")) == 0) { - uint8_t number = 0; - if ((argc < 3) || (number = atoi(argv[2])) > 32) { - puts("Error: Missing parameter."); - puts("The command should contain number of FIFO values to read (max. 32))."); - puts("USAGE: lis read_fifo [number]"); - return -1; - } - - /* read raw data from FIFO */ - uint8_t number_read = lis2dh12_read_fifo_data(&dev, data_fifo, number); - - DEBUG("[lis_command]: fifo_read %d elements.\n", number_read); - - /* print data */ - for (int entry = 0; entry < number_read; entry++){ - - /* format data */ - size_t len = fmt_s16_dfp(str_out[0], data_fifo[entry].X_AXIS, -3); - str_out[0][len] = '\0'; - len = fmt_s16_dfp(str_out[1], data_fifo[entry].Y_AXIS, -3); - str_out[1][len] = '\0'; - len = fmt_s16_dfp(str_out[2], data_fifo[entry].Z_AXIS, -3); - str_out[2][len] = '\0'; - - printf("[%2d] X: %6s Y: %6s Z: %6s\n", entry, str_out[0], str_out[1], str_out[2]); - } - return 1; - } - - /* clear memory */ - else if (strncmp(argv[1], "clear_data", sizeof("clear_data")) == 0) { - - lis2dh12_clear_data(&dev); - return 1; - } - -#ifdef MODULE_LIS2DH12_INT - /* set commands */ - else if (strncmp(argv[1], "set-click", sizeof("set-click")) == 0) { - uint8_t thold = 0; - if ((argc < 3) || (thold = atoi(argv[2])) > 127) { - puts("Error: Missing parameter."); - puts("The command should contain a threshold value below 128. " - "The LSB changes according to selected SCALE " - "(@2G LSB=16mg; @4G LSB=32mg; @8G LSB=62mg: @16G LSB=186mg)."); - puts("USAGE: lis set-click [thold]"); - return -1; - } - - click_cfg.CLICK_thold = thold; - lis2dh12_set_click(&dev, &click_cfg); - - /* enable click interrupt */ - params_int1.int_type = LIS2DH12_INT_TYPE_I1_CLICK; - lis2dh12_set_int(&dev, ¶ms_int1, LIS2DH12_INT1); - - return 1; - } - else if (strncmp(argv[1], "set-thold-shock", sizeof("set-thold-shock")) == 0) { - uint16_t thold = 0; - if ((argc < 3) || !(thold = atoi(argv[2]))) { - puts("Error: Missing parameter."); - puts("The command should contain a threshold value in [mg] below the max SCALE. " - "(@2G below 2000; @4G below 4000; and so on)"); - puts("USAGE: lis set-thold-shock [thold]"); - return -1; - } - shock_thold = thold; - return 1; - } - else if (strncmp(argv[1], "set-thold-inter", sizeof("set-thold-inter")) == 0) { - uint8_t line = 0; - if ((argc < 4) || (line = atoi(argv[3])) > 2) { - puts("Error: Missing parameter."); - puts("The command should contain threshold value and interrupt line (1 or 2). " - "The threshold LSB changes according to selected SCALE " - "(@2G LSB=16mg; @4G LSB=32mg; @8G LSB=62mg: @16G LSB=186mg)."); - puts("To disable interrupt set thold to 0."); - puts("USAGE: lis set-thold-inter [thold] [line]"); - return -1; - } - uint8_t thold = atoi(argv[2]); - if (line == 1) { - if (!thold) { - params_int1.int_config = 0; - } - else { - /* enables all axes for acceleration above threshold */ - params_int1.int_config = LIS2DH12_INT_CFG_XHIE - | LIS2DH12_INT_CFG_YHIE - | LIS2DH12_INT_CFG_ZHIE; - } - params_int1.int_type = LIS2DH12_INT_TYPE_I1_IA1; - params_int1.int_threshold = thold; - - lis2dh12_set_int(&dev, ¶ms_int1, LIS2DH12_INT1); - } - else if (line == 2){ - if (!thold) { - params_int2.int_config = 0; - } - else { - /* enables Y-axis for acceleration under the threshold */ - params_int2.int_config = LIS2DH12_INT_CFG_YLIE; - } - params_int2.int_type = LIS2DH12_INT_TYPE_I2_IA2; - params_int2.int_threshold = thold; - lis2dh12_set_int(&dev, ¶ms_int2, LIS2DH12_INT2); - } - if (thold) { - printf("Info: Interrupt thold = %d on line %d.\n", thold, line); - } - else { - printf("Info: Interrupt disabled.\n"); - } - - return 1; - } - - else if (strncmp(argv[1], "set-highpass", sizeof("set-highpass")) == 0) { - uint8_t out = 0; - uint8_t reference = atoi(argv[2]); - if ((argc < 4) || (out = atoi(argv[3])) > 3) { - puts("Error: Missing parameter."); - puts("The command should contains the number of an output which gets filtered " - "and the reference value less than 255. " - "Possible outputs are IA1 (1) or IA2 (2) or CLICK (3) " - "or (0) to disable the filter."); - puts("USAGE: lis set-highpass [reference] [out_number]"); - return -1; - } - - if (out) { - /* enable filter for output */ - highpass_cfg.DATA_OUT_enable = 0; - - /* enable HP for interrupt */ - if (out == 1) { - highpass_cfg.INT1_enable = 1; - } - else if (out == 2) { - highpass_cfg.INT2_enable = 1; - } - else { - /* enable filter for click function */ - highpass_cfg.CLICK_enable = 1; - } - printf("Info: Filter set to %d on output %d.\n", reference, out); - } - else { - printf("Info: Filter disabled.\n"); - } - - lis2dh12_set_reference(&dev, reference); - lis2dh12_set_highpass(&dev, &highpass_cfg); - return 1; - } -#endif /* MODULE_LIS2DH12_INT */ - - /* change sampling rate */ - else if (strncmp(argv[1], "change_rate", sizeof("change_rate")) == 0) { - uint8_t rate = 0; - if ((argc < 3) || (rate = atoi(argv[2])) > 9) { - puts("Error: Missing parameter."); - puts("The command should contain a number for sampling rate. " - "Possible outputs are 1Hz (1), 10Hz (2), 25Hz (3), " - "50Hz (4), 100Hz (5), 200Hz (6) or 400Hz (7)."); - puts("USAGE: lis change_rate [samplingrate]"); - return -1; - } - - lis2dh12_set_datarate(&dev, rate); - return 1; - } - - /* change power mode */ - else if (strncmp(argv[1], "change_power", sizeof("change_power")) == 0) { - uint8_t power = 0; - if ((argc < 3) || (power = atoi(argv[2])) > 9) { - puts("Error: Missing parameter."); - puts("The command should contain a number for power mode. " - "Possible outputs are POWER_DOWN (0), POWER_LOW (1), " - "POWER_NORMAL (2) or POWER_HIGH (3)."); - puts("USAGE: lis change_power [powermode]"); - return -1; - } - - lis2dh12_set_powermode(&dev, power); - return 1; - } - - /* change scale value */ - else if (strncmp(argv[1], "change_scale", sizeof("change_scale")) == 0) { - uint8_t scale = 0; - if ((argc < 3) || (scale = atoi(argv[2])) > 3) { - puts("Error: Missing parameter."); - puts("The command should contain a number for scale value. " - "Possible values are SCALE_2G (0), SCALE_4G (1), " - "SCALE_8G (2) or SCALE_16G (3)."); - puts("USAGE: lis change_scale [scale]"); - return -1; - } - - lis2dh12_set_scale(&dev, scale<<4); - return 1; - } - - /* UNKNOWN */ - else { - printf("Error: Unknown sub-command. %s\n", usage); - return -1; - } + return 0; } +static int shell_is2dh12_read_fifo(int argc, char **argv) +{ + uint8_t num = NUM_FIFO_VALUES; + lis2dh12_fifo_data_t data[NUM_FIFO_VALUES]; + + if (argc > 1) { + num = atoi(argv[1]); + } + + num = lis2dh12_read_fifo_data(&dev, data, num); + + /* print data */ + for (unsigned i = 0; i < num; ++i) { + + /* Memory to print current data */ + char str_out[3][8]; + + /* format data */ + for (unsigned j = 0; j < 3; ++j) { + size_t len = fmt_s16_dfp(str_out[j], data[i].data[j], -3); + str_out[j][len] = '\0'; + } + + printf("[%2u] X: %6s Y: %6s Z: %6s\n", i, str_out[0], str_out[1], str_out[2]); + } + + return 0; +} + +static int shell_is2dh12_threshold(int argc, char **argv) +{ + uint8_t slot; + uint32_t mg; + uint32_t us = 0; + uint8_t axis = LIS2DH12_INT_CFG_XHIE + | LIS2DH12_INT_CFG_YHIE + | LIS2DH12_INT_CFG_ZHIE; + + if (argc < 3) { + printf("usage: %s [µs]\n", argv[0]); + return -1; + } + + slot = atoi(argv[1]); + mg = atoi(argv[2]); + + if (argc > 3) { + us = atoi(argv[3]); + } + + if (slot < 1 || slot > 2) { + puts("event slot must be either 1 or 2"); + return -1; + } + + lis2dh12_cfg_threshold_event(&dev, mg, us, axis, slot, LIS2DH12_INT1); + + return 0; +} + +static int shell_is2dh12_click(int argc, char **argv) +{ + uint32_t mg; + uint32_t us = 0; + uint32_t us_delay = 0; + uint32_t us_double = 0; + uint8_t clicks = LIS2DH12_CLICK_X_SINGLE + | LIS2DH12_CLICK_Y_SINGLE + | LIS2DH12_CLICK_Z_SINGLE; + + if (argc < 2) { + printf("usage: %s [µs] [dead time µs] [double click µs]\n", argv[0]); + return -1; + } + + mg = atoi(argv[1]); + + if (argc > 2) { + us = atoi(argv[2]); + } + + if (argc > 3) { + us_delay = atoi(argv[3]); + } + + if (argc > 4) { + us_double = atoi(argv[4]); + clicks |= clicks << 1; + } + + lis2dh12_cfg_click_event(&dev, mg, us, us_delay, us_double, clicks, LIS2DH12_INT1); + + return 0; +} + +static int shell_is2dh12_power(int argc, char **argv) +{ + bool on; + + if (argc > 1 && (!strcmp(argv[1], "on") || !strcmp(argv[1], "1"))) { + on = true; + } else if (argc > 1 && (!strcmp(argv[1], "off") || !strcmp(argv[1], "0"))) { + on = false; + } else { + printf("usage: %s \n", argv[0]); + return -1; + } + + if (on) { + lis2dh12_poweron(&dev); + } else { + lis2dh12_poweroff(&dev); + } + + return 0; +} + +static int shell_is2dh12_set_resolution(int argc, char **argv) +{ + unsigned resolution = UINT_MAX; + + const char* resolutions[4] = { + "off", + "8-bit", + "10-bit", + "12-bit", + }; + + if (argc > 1) { + resolution = atoi(argv[1]); + } else { + printf("current resolution: %s\n", resolutions[lis2dh12_get_resolution(&dev)]); + } + + if (resolution > LIS2DH12_POWER_HIGH) { + printf("usage: %s \n", argv[0]); + puts("where is:"); + for (unsigned i = 0; i < ARRAY_SIZE(resolutions); ++i) { + printf("\t%u: %s\n", i, resolutions[i]); + } + return -1; + } + + lis2dh12_set_resolution(&dev, resolution); + + return 0; +} + +static int shell_is2dh12_set_rate(int argc, char **argv) +{ + unsigned rate = UINT_MAX; + + if (argc > 1) { + rate = atoi(argv[1]); + } else { + printf("Current sampling rate: %u Hz\n", lis2dh12_get_datarate(&dev)); + } + + if (rate > LIS2DH12_RATE_VERYHIGH) { + printf("usage: %s \n", argv[0]); + puts("where is:"); + puts("\t1: 1 Hz"); + puts("\t2: 10 Hz"); + puts("\t3: 25 Hz"); + puts("\t4: 50 Hz"); + puts("\t5: 100 Hz"); + puts("\t6: 200 Hz"); + puts("\t7: 400 Hz"); + puts("\t8: 1620 Hz"); + puts("\t9: 5376 Hz"); + return -1; + } + + lis2dh12_set_datarate(&dev, rate); + + return 0; +} + +static int shell_is2dh12_set_scale(int argc, char **argv) +{ + unsigned scale = UINT_MAX; + + const uint8_t scales[] = { + 2, 4, 8, 16 + }; + + if (argc > 1) { + scale = atoi(argv[1]); + } else { + printf("current range: ± %ug\n", scales[lis2dh12_get_scale(&dev)]); + } + + if (scale > LIS2DH12_SCALE_16G) { + printf("usage: %s \n", argv[0]); + puts("where is:"); + for (unsigned i = 0; i < ARRAY_SIZE(scales); ++i) { + printf("\t%u: ± %ug\n", i, scales[i]); + } + + return -1; + } + + lis2dh12_set_scale(&dev, scale); + + return 0; +} + +static int shell_is2dh12_read_temp(int argc, char **argv) +{ + (void)argc; + (void)argv; + + int16_t temp; + lis2dh12_read_temperature(&dev, &temp); + + printf("%d.%02d °C\n", temp / 100, temp % 100); + + return 0; +} + +static const shell_command_t shell_commands[] = { + { "read", "Read acceleration data", shell_is2dh12_read }, + { "read_fifo", "Read acceleration data from fifo", shell_is2dh12_read_fifo }, + { "threshold", "Configure threshold event", shell_is2dh12_threshold }, + { "click", "Configure click event", shell_is2dh12_click }, + { "power", "Enable / Disable the sensor", shell_is2dh12_power }, + { "resolution", "Get/Set resolution", shell_is2dh12_set_resolution }, + { "rate", "Get/Set sampline rate", shell_is2dh12_set_rate }, + { "scale", "Get/Set measuring range", shell_is2dh12_set_scale }, + { "temp", "Read temperature data", shell_is2dh12_read_temp }, + { NULL, NULL, NULL }, +}; + int main(void) { - -#ifdef MODULE_LIS2DH12_INT - /* processing lis2dh12 acceleration data */ - lis2dh12_process = thread_create(lis2dh12_process_stack, sizeof(lis2dh12_process_stack), - THREAD_PRIORITY_MAIN - 1, THREAD_CREATE_SLEEPING, - lis2dh12_test_process, NULL, "lis2dh12_process"); -#endif /* MODULE_LIS2DH12_INT */ - /* init lis */ lis2dh12_test_init(); +#ifdef MODULE_LIS2DH12_INT + static char lis2dh12_process_stack[THREAD_STACKSIZE_MAIN]; + + /* processing lis2dh12 acceleration data */ + thread_create(lis2dh12_process_stack, sizeof(lis2dh12_process_stack), + THREAD_PRIORITY_MAIN - 1, THREAD_CREATE_STACKTEST, + lis2dh12_test_process, NULL, "lis2dh12_process"); +#endif /* MODULE_LIS2DH12_INT */ + /* running shell */ char line_buf[SHELL_DEFAULT_BUFSIZE]; shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);