diff --git a/drivers/include/lis2dh12.h b/drivers/include/lis2dh12.h index d88bd885c7..3d54c0013a 100644 --- a/drivers/include/lis2dh12.h +++ b/drivers/include/lis2dh12.h @@ -39,6 +39,7 @@ #include #include "saul.h" +#include "lis2dh12_registers.h" #include "periph/gpio.h" #ifdef MODULE_LIS2DH12_SPI @@ -71,19 +72,31 @@ typedef enum { /** * @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_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_VERYHIGH = 0x9, /**< sample with 1344Hz @ High resolution or \ + 5376Hz @ Low Power*/ } lis2dh12_rate_t; +/** + * @brief Available power modes + * + */ +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; + /** * @brief LIS2DH12 configuration parameters */ @@ -101,14 +114,63 @@ 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_params_t; +/** + * @brief LIS2DH12 high pass modes + */ +typedef enum { + LIS2DH12_HP_MODE_NORMAL = 0x0, /**< normal mode, reset by reading REG_REFERENCE */ + LIS2DH12_HP_MODE_REFERENCE = 0x1, /**< uses the reference signal for filtering */ + LIS2DH12_HP_MODE_AUTORESET = 0x3, /**< automatically resets on interrupt generation */ +} lis2dh12_hp_mode_t; + +/** + * @brief LIS2DH12 high pass cutoff frequency + */ +typedef enum { + LIS2DH12_HP_FREQ_DIV50 = 0, /**< cutoff freq is ODR divided by 50 */ + LIS2DH12_HP_FREQ_DIV100 = 1, /**< cutoff freq is ODR divided by 100 */ + LIS2DH12_HP_FREQ_DIV200 = 2, /**< cutoff freq is ODR divided by 200 */ + LIS2DH12_HP_FREQ_DIV400 = 3, /**< cutoff freq is ODR divided by 400 */ +} lis2dh12_hp_freq_t; + +/** + * @brief LIS2DH12 high pass config values + */ +typedef struct { + lis2dh12_hp_mode_t Highpass_mode; /**< set the High pass mode */ + lis2dh12_hp_freq_t Highpass_freq; /**< set the High pass cutoff frequency \ + related to device rate */ + bool CLICK_enable; /**< enables filter for click data */ + bool INT1_enable; /**< enables filter for AOI on interrupt 1 */ + bool INT2_enable; /**< enables filter for AOI on interrupt 2 */ + bool DATA_OUT_enable; /**< enables filter for data output */ +} lis2dh12_highpass_t; + +/** + * @brief LIS2DH12 click config values + */ +typedef struct { + bool enable_DOUBLE; /**< otherwise single click for given axis are enabled */ + bool enable_X_CLICK; /**< enable double pr single click for X axes */ + bool enable_Y_CLICK; /**< enable double pr single click for Y axes */ + bool enable_Z_CLICK; /**< enable double pr single click for Z axes */ + bool noINT_latency; /**< if "0" interrupt stays high for TIME_latency setting \ + if "1" interrupt stays high until CLICK_SRC is read */ + uint8_t CLICK_thold:7; /**< set click threshold */ + uint8_t TIME_limit:7; /**< set number of ODR cycles for time limit over threshold value */ + uint8_t TIME_latency; /**< set number of ODR cycles for latency after a click */ + uint8_t TIME_window; /**< set number of ODR cycles for window between clicks */ +} lis2dh12_click_t; + /** * @brief LIS2DH12 device descriptor */ typedef struct { const lis2dh12_params_t *p; /**< device configuration */ - uint16_t comp; /**< scale compensation factor */ + uint8_t comp; /**< scale compensation factor */ } lis2dh12_t; /** @@ -118,7 +180,8 @@ 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_NOINT = -3, /**< wrong interrupt line (has to be LIS2DH12_INT1 + or LIS2DH12_INT2) */ LIS2DH12_NODATA= -4, /**< no data available */ }; @@ -126,81 +189,53 @@ enum { /* * @brief Interrupt lines */ -enum{ +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_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 + * @brief LIS2DH12 FIFO data struct */ -#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 */ +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 */ +} lis2dh12_fifo_data_t; + +/** + * @brief LIS2DH12 FIFO modes + */ +typedef enum { + LIS2DH12_FIFO_MODE_BYPASS = 0, /**< default mode, FIFO is bypassed */ + LIS2DH12_FIFO_MODE_FIFOMODE, /**< normal FIFO mode, stops if FIFO is full */ + LIS2DH12_FIFO_MODE_STREAM, /**< Stream mode, oldest values get overwritten */ + LIS2DH12_FIFO_MODE_STREAMtoFIFO, /**< Stream mode and on interrupt jumps to FIFO mode */ +} lis2dh12_fifo_mode_t; + +/** + * @brief LIS2DH12 FIFO config values + */ +typedef struct { + lis2dh12_fifo_mode_t FIFO_mode; /**< set FIFO mode */ + uint8_t FIFO_watermark:5; /**< set the FIFO watermark level */ + bool FIFO_set_INT2; /**< sets the FIFO interrupt to INT2, otherwise INT1 */ +} lis2dh12_fifo_t; /** * @brief Export the SAUL interface for this driver @@ -233,6 +268,52 @@ int lis2dh12_set_int(const lis2dh12_t *dev, const lis2dh12_int_params_t *params, int lis2dh12_read_int_src(const lis2dh12_t *dev, uint8_t *data, uint8_t int_line); #endif /* MODULE_LIS2DH12_INT */ +/** + * @brief Set the FIFO configuration + * + * @param[in] dev device descriptor + * @param[in] config device FIFO configuration + * + * @return LIS2DH12_OK on success + */ +int lis2dh12_set_fifo(const lis2dh12_t *dev, const lis2dh12_fifo_t *config); + +/** + * @brief Restart the FIFO mode + * this sets the FIFO mode in BYPASS mode and then back to previous mode + * Note: The LIS module disables the FIFO after interrupt automatically, + * it is recommended to set the FIFO in BYPASS mode and then back to old + * FIFO mode to enable the FIFO again. + * + * @param[in] dev device descriptor + * + * @return LIS2DH12_OK on success + */ +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 + * + * @param[in] dev device descriptor + * @param[out] fifo_data FIFO data, must have space for number of data + * @param[in] number amount of FIFO data to be read + * + * @return number of valid data read from FIFO + */ +uint8_t lis2dh12_read_fifo_data(const lis2dh12_t *dev, lis2dh12_fifo_data_t *fifo_data, + uint8_t number); + /** * @brief Initialize the given LIS2DH12 sensor device * @@ -257,7 +338,100 @@ int lis2dh12_init(lis2dh12_t *dev, const lis2dh12_params_t *params); int lis2dh12_read(const lis2dh12_t *dev, int16_t *data); /** - * @brief Power on the given device + * @brief Clear the LIS2DH12 memory, clears all sampled data + * + * @param[in] dev device descriptor + * + * @return LIS2DH12_OK on success + */ +int lis2dh12_clear_data(const lis2dh12_t *dev); + +/** + * @brief Change device scale value + * + * @param[in] dev device descriptor + * @param[in] scale change to given scale value + * + * @return LIS2DH12_OK on success + */ +int lis2dh12_set_scale(lis2dh12_t *dev, lis2dh12_scale_t scale); + +/** + * @brief Change device sampling rate + * + * @param[in] dev device descriptor + * @param[in] rate change to given sampling rate + * + * @return LIS2DH12_OK on success + */ +int lis2dh12_set_datarate(const lis2dh12_t *dev, lis2dh12_rate_t rate); + +/** + * @brief Change device power mode + * + * @param[in] dev device descriptor + * @param[in] powermode change to given power mode + * + * @return LIS2DH12_OK on success + */ +int lis2dh12_set_powermode(const lis2dh12_t *dev, lis2dh12_powermode_t powermode); + +/** + * @brief Configures the high pass filter + * + * @param[in] dev device descriptor + * @param[in] config device high pass configuration + * + * @return LIS2DH12_OK on success + */ +int lis2dh12_set_highpass(const lis2dh12_t *dev, const lis2dh12_highpass_t *config); + +/** + * @brief Set the reference value to control the high-pass reference. + * In LIS2DH12_HP_MODE_REFERENCE the reference value is used to filter data + * on all axis. Subtracts reference value from acceleration. + * Note: LSB changes according to LIS2DH12_SCALE + * + * @param[in] dev device descriptor + * @param[in] reference reference value [8 Bit] + * + * @return LIS2DH12_OK on success + */ +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 + * 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 1a2493c8af..1a57f400b6 100644 --- a/drivers/lis2dh12/include/lis2dh12_params.h +++ b/drivers/lis2dh12/include/lis2dh12_params.h @@ -67,6 +67,9 @@ 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 +#endif #ifndef LIS2DH12_PARAMS #ifdef MODULE_LIS2DH12_INT @@ -76,12 +79,14 @@ extern "C" { .int2_pin = LIS2DH12_PARAM_INT_PIN2, \ .scale = LIS2DH12_PARAM_SCALE, \ .rate = LIS2DH12_PARAM_RATE, \ + .powermode = LIS2DH12_PARAM_POWERMODE, \ } #else /* MODULE_LIS2DH12_INT */ #define LIS2DH12_PARAMS { \ LIS2DH12_PARAMS_BUSCFG, \ .scale = LIS2DH12_PARAM_SCALE, \ .rate = LIS2DH12_PARAM_RATE, \ + .powermode = LIS2DH12_PARAM_POWERMODE, \ } #endif /* MODULE_LIS2DH12_INT */ #endif /* LIS2DH12_PARAMS */ diff --git a/drivers/lis2dh12/include/lis2dh12_registers.h b/drivers/lis2dh12/include/lis2dh12_registers.h new file mode 100644 index 0000000000..893714a2af --- /dev/null +++ b/drivers/lis2dh12/include/lis2dh12_registers.h @@ -0,0 +1,430 @@ +/* + * Copyright (C) 2021 ML!PA Consulting GmbH + * + */ + +/** + * @ingroup drivers_lis2dh12 + * @{ + * + * @file + * @brief LIS2DH12 register definitions + * + * @author Jan Mohr + */ + +#ifndef LIS2DH12_REGISTERS_H +#define LIS2DH12_REGISTERS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Definition of read Registers + * @{ + */ + +/** + * @brief STATUS_REG_AUX definitions + */ +enum { + LIS2DH12_STATUS_REG_AUX_TDA = 0x04, /**< Temperature new data available */ + LIS2DH12_STATUS_REG_AUX_TOR = 0x40, /**< Temperature data overrun */ +}; + +/** + * @brief STATUS_REG definitions + */ +enum { + LIS2DH12_STATUS_REG_XDA = 0x01, /**< X-axis new data available */ + LIS2DH12_STATUS_REG_YDA = 0x02, /**< Y-axis new data available */ + LIS2DH12_STATUS_REG_ZDA = 0x04, /**< Z-axis new data available */ + LIS2DH12_STATUS_REG_ZYXDA = 0x08, /**< On X-, Y-, Z-axis new data available */ + LIS2DH12_STATUS_REG_XOR = 0x10, /**< X-axis data overrun */ + LIS2DH12_STATUS_REG_YOR = 0x20, /**< Y-axis data overrun */ + LIS2DH12_STATUS_REG_ZOR = 0x40, /**< Y-axis data overrun */ + LIS2DH12_STATUS_REG_ZYXOR = 0x80, /**< On X-, Y-, Z-axis data overrun */ +}; + +/** + * @brief INT1_SRC and INT2_SRC definitions + */ +enum { + LIS2DH12_INT_SRC_XL = 0x01, /**< X low event */ + LIS2DH12_INT_SRC_XH = 0x02, /**< X high event */ + LIS2DH12_INT_SRC_YL = 0x04, /**< Y low event */ + LIS2DH12_INT_SRC_YH = 0x08, /**< Y high event */ + LIS2DH12_INT_SRC_ZL = 0x10, /**< Z low event */ + LIS2DH12_INT_SRC_ZH = 0x20, /**< Z high event */ + LIS2DH12_INT_SRC_IA = 0x40, /**< Interrupt 1 active, at least one interrupt \ + has been generated */ +}; + +/** + * @brief Interrupt config register values + */ +enum { + LIS2DH12_INT_CFG_XLIE = 0x01, /**< enable X low event */ + 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 register 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 interrupt 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 CLICK_SRC definitions + */ +typedef union { + struct { + uint8_t X_AXIS:1; /**< X click detected */ + uint8_t Y_AXIS:1; /**< Y click detected */ + uint8_t Z_AXIS:1; /**< Z click detected */ + uint8_t Sign:1; /**< Click sign, "0" positive, "1" negative */ + uint8_t SClick:1; /**< Single click detected */ + uint8_t DClick:1; /**< Double click detected */ + uint8_t IA:1; /**< Interrupt active, at least one interrupt \ + has been generated */ + uint8_t _RESERVED:1; /**< Reserved bit */ + } bit; /**< Structure used for bit access */ + uint8_t reg; /**< Type used for register access */ +} LIS2DH12_CLICK_SRC_t; + +/** + * @brief FIFO_SRC_REG definitions + */ +typedef union { + struct { + uint8_t FSS:5; /**< Number of unread samples in FIFO */ + uint8_t EMPTY:1; /**< FIFO is empty */ + uint8_t OVRN_FIFO:1; /**< Overrun in FIFO occurred */ + uint8_t WTM:1; /**< FIFO content watermark level */ + } bit; /**< Structure used for bit access */ + uint8_t reg; /**< Type used for register access */ +} LIS2DH12_FIFO_SRC_REG_t; +/** @} */ + +/** + * + * @name Definition of read/write Registers + * @{ + */ +/** + * @brief CTRL_REG_0 definitions + */ +typedef union { + struct { + uint8_t CTRL0_DEFAULT_VALUE:7; /**< Always set this to CTRL_REG0_DEFAULT */ + uint8_t SDO_PU_DISC:1; /**< disconnect pull-up on SDO/SA0 */ + } bit; /**< Structure used for bit access */ + uint8_t reg; /**< Type used for register access */ +} LIS2DH12_CTRL_REG0_t; + +/** + * @brief TEMP_CFG_REG definitions + */ +typedef union { + struct { + uint8_t _RESERVED:6; /**< Should always be zero */ + uint8_t TEMP_EN:2; /**< "00" disables Temperature sensor, "11" enables */ + } bit; /**< Structure used for bit access */ + uint8_t reg; /**< Type used for register access */ +} LIS2DH12_TEMP_CFG_REG_t; + +/** + * @brief CTRL_REG1 definitions + */ +typedef union { + struct { + uint8_t Xen:1; /**< X axis enable */ + uint8_t Yen:1; /**< Y axis enable */ + uint8_t Zen:1; /**< Z axis enable */ + uint8_t LPen:1; /**< Enable Low Power mode */ + uint8_t ODR:4; /**< Set Data rate */ + } bit; /**< Structure used for bit access */ + uint8_t reg; /**< Type used for register access */ +} LIS2DH12_CTRL_REG1_t; + +/** + * @brief CTRL_REG2 definitions + */ +typedef union { + struct { + uint8_t HP_IA1:1; /**< High pass filter enable for AOI on interrupt 1 */ + uint8_t HP_IA2:1; /**< High pass filter enable for AOI on interrupt 2 */ + uint8_t HPCLICK:1; /**< High pass filter enable for CLICK function */ + uint8_t FDS:1; /**< Enables filter output data */ + uint8_t HPCF:2; /**< High pass filter cutoff frequency */ + uint8_t HPM:2; /**< High pass filter mode selection */ + } bit; /**< Structure used for bit access */ + uint8_t reg; /**< Type used for register access */ +} LIS2DH12_CTRL_REG2_t; + +/** + * @brief CTRL_REG3 definitions + */ +typedef union { + struct { + uint8_t _RESERVED0:1; /**< Reserved bit */ + uint8_t I1_OVERRUN:1; /**< Enable FIFO overrun interrupt on INT1 */ + uint8_t I1_WTM:1; /**< Enable FIFO watermark interrupt on INT1 */ + uint8_t _RESERVED3:1; /**< Should always be "0" */ + uint8_t I1_ZYXDA:1; /**< Enable ZYXDA interrupt on INT1 */ + uint8_t I1_IA2:1; /**< Enable IA2 interrupt on INT1 */ + uint8_t I1_IA1:1; /**< Enable IA1 interrupt on INT1 */ + uint8_t I1_CLICK:1; /**< Enable CLICK interrupt on INT1 */ + } bit; /**< Structure used for bit access */ + uint8_t reg; /**< Type used for register access */ +} LIS2DH12_CTRL_REG3_t; + +/** + * @brief CTRL_REG4 definitions + */ +typedef union { + struct { + uint8_t SPIM:1; /**< SPI serial interface mode selection (SIM)*/ + uint8_t ST:2; /**< Self-test enable */ + uint8_t HR:1; /**< Operating mode */ + uint8_t FS:2; /**< Full-scale selection */ + uint8_t BLE:1; /**< Big/Little endian data selection */ + uint8_t BDU:1; /**< Block data update */ + } bit; /**< Structure used for bit access */ + uint8_t reg; /**< Type used for register access */ +} LIS2DH12_CTRL_REG4_t; + +/** + * @brief CTRL_REG5 definitions + */ +typedef union { + struct { + uint8_t D4D_INT2:1; /**< 4D detection enabled on INT2 */ + uint8_t LIR_INT2:1; /**< Latch interrupt request for INT2 */ + uint8_t D4D_INT1:1; /**< 4D detection enabled on INT1 */ + uint8_t LIR_INT1:1; /**< Latch interrupt request for INT2 */ + uint8_t _RESERVED:2; /**< Reserved bits */ + uint8_t FIFO_EN:1; /**< FIFO enable */ + uint8_t BOOT:1; /**< Clears the data content */ + } bit; /**< Structure used for bit access */ + uint8_t reg; /**< Type used for register access */ +} LIS2DH12_CTRL_REG5_t; + +/** + * @brief CTRL_REG6 definitions + */ +typedef union { + struct { + uint8_t _RESERVED0:1; /**< Reserved bit */ + uint8_t INT_POLARITY:1; /**< Set pin polarity for INT1 and INT2 */ + uint8_t _RESERVED2:1; /**< Reserved bit */ + uint8_t I2_ACT:1; /**< Enable activity interrupt on INT2 */ + uint8_t I2_BOOT:1; /**< Enable boot on INT2 */ + uint8_t I2_IA2:1; /**< Enable IA2 on INT2 */ + uint8_t I2_IA1:1; /**< Enable IA1 on INT2 */ + uint8_t I2_CLICK:1; /**< Enable CLICK interrupt on INT2 */ + } bit; /**< Structure used for bit access */ + uint8_t reg; /**< Type used for register access */ +} LIS2DH12_CTRL_REG6_t; + +/** + * @brief REFERENCE definitions + */ +typedef union { + uint8_t reg; /**< Set reference value */ +} LIS2DH12_REFERENCE_t; + +/** + * @brief FIFO_CTRL_REG definitions + */ +typedef union { + struct { + uint8_t FTH:5; /**< Set the watermark level for FIFO */ + uint8_t TR:1; /**< Trigging selection, FIFO event triggers INT1 or INT2 */ + uint8_t FM:2; /**< FIFO mode selection */ + } bit; /**< Structure used for bit access */ + uint8_t reg; /**< Type used for register access */ +} LIS2DH12_FIFO_CTRL_REG_t; + +/** + * @brief INT1_CFG definitions + */ +typedef union { + struct { + uint8_t XLIE:1; /**< Enable interrupt on X low event */ + uint8_t XHIE:1; /**< Enable interrupt on X high event */ + uint8_t YLIE:1; /**< Enable interrupt on Y low event */ + uint8_t YHIE:1; /**< Enable interrupt on Y high event */ + uint8_t ZLIE:1; /**< Enable interrupt on Z low event */ + uint8_t ZHIE:1; /**< Enable interrupt on Z high event */ + uint8_t D6D:1; /**< 6 direction detection function enable */ + uint8_t AOI:1; /**< AND/OR combination of interrupt events */ + } bit; /**< Structure used for bit access */ + uint8_t reg; /**< Type used for register access */ +} LIS2DH12_INT1_CFG_t; + +/** + * @brief INT1_THS definitions + */ +typedef union { + struct { + uint8_t THS:7; /**< Sets threshold level, the LSB changes according to + LIS2DH12_SCALE (@2G LSB=16mg; @4G LSB=32mg; @8G LSB=62mg + @16G LSB=186mg) */ + uint8_t _RESERVED:1; /**< needs to be zero */ + } bit; /**< Structure used for bit access */ + uint8_t reg; /**< Type used for register access */ +} LIS2DH12_INT1_THS_t; + +/** + * @brief INT1_DURATION definitions + */ +typedef union { + struct { + uint8_t D:7; /**< Sets the minimum duration of INT1, in ODR cycles */ + uint8_t _RESERVED:1; /**< need to be zero */ + } bit; /**< Structure used for bit access */ + uint8_t reg; /**< Type used for register access */ +} LIS2DH12_INT1_DURATION_t; + +/** + * @brief INT2_CFG definitions + */ +typedef union { + struct { + uint8_t XLIE:1; /**< Enable interrupt on X low event */ + uint8_t XHIE:1; /**< Enable interrupt on X high event */ + uint8_t YLIE:1; /**< Enable interrupt on Y low event */ + uint8_t YHIE:1; /**< Enable interrupt on Y high event */ + uint8_t ZLIE:1; /**< Enable interrupt on Z low event */ + uint8_t ZHIE:1; /**< Enable interrupt on Z high event */ + uint8_t D6D:1; /**< 6 direction detection function enable */ + uint8_t AOI:1; /**< AND/OR combination of interrupt events */ + } bit; /**< Structure used for bit access */ + uint8_t reg; /**< Type used for register access */ +} LIS2DH12_INT2_CFG_t; + +/** + * @brief INT2_THS definitions + */ +typedef union { + struct { + uint8_t THS:7; /**< Sets threshold level, LSB according to LIS2DH12_SCALE */ + uint8_t _RESERVED:1; /**< needs to be zero */ + } bit; /**< Structure used for bit access */ + uint8_t reg; /**< Type used for register access */ +} LIS2DH12_INT2_THS_t; + +/** + * @brief INT2_DURATION definitions + */ +typedef union { + struct { + uint8_t D:7; /**< Sets the minimum duration of INT2, in ODR cycles */ + uint8_t _RESERVED:1; /**< need to be zero */ + } bit; /**< Structure used for bit access */ + uint8_t reg; /**< Type used for register access */ +} LIS2DH12_INT2_DURATION_t; + +/** + * @brief CLICK_CFG definitions + */ +typedef union { + struct { + uint8_t XS:1; /**< Interrupt single-click enable on X-axis */ + uint8_t XD:1; /**< Interrupt double-click enable on X-axis */ + uint8_t YS:1; /**< Interrupt single-click enable on Y-axis */ + uint8_t YD:1; /**< Interrupt double-click enable on Y-axis */ + uint8_t ZS:1; /**< Interrupt single-click enable on Z-axis */ + uint8_t ZD:1; /**< Interrupt double-click enable on Z-axis */ + uint8_t _RESERVED:2; /**< Reserved bits */ + } bit; /**< Structure used for bit access */ + uint8_t reg; /**< Type used for register access */ +} LIS2DH12_CLICK_CFG_t; + +/** + * @brief CLICK_THS definitions + */ +typedef union { + struct { + uint8_t THS:7; /**< Sets the click threshold, LSB according to LIS2DH12_SCALE */ + uint8_t LIR_CLICK:1; /**< Enables latency on interrupt kept high, \ + "0" for duration of latency window, \ + "1" kept high until CLICK_SRC is read */ + } bit; /**< Structure used for bit access */ + uint8_t reg; /**< Type used for register access */ +} LIS2DH12_CLICK_THS_t; + +/** + * @brief TIME_LIMIT definitions + */ +typedef union { + struct { + uint8_t TLI:7; /**< Click time limit, in ODR cycles */ + uint8_t _RESERVED:1; /**< reserved bit */ + } bit; /**< Structure used for bit access */ + uint8_t reg; /**< Type used for register access */ +} LIS2DH12_TIME_LIMIT_t; + +/** + * @brief TIME_LATENCY definitions + */ +typedef union { + uint8_t reg; /**< Sets time latency, in ODR cycles */ +} LIS2DH12_TIME_LATENCY_t; + +/** + * @brief TIME_WINDOW definitions + */ +typedef union { + uint8_t reg; /**< Sets time window, in ODR cycles */ +} LIS2DH12_TIME_WINDOW_t; + +/** + * @brief ACT_THS definitions + */ +typedef union { + struct { + uint8_t ACTH:7; /**< Sets the threshold sleep-to-wake or return-to-sleep + LSB according to LIS2DH12_SCALE */ + uint8_t _RESERVED:1; /**< reserved bit */ + } bit; /**< Structure used for bit access */ + uint8_t reg; /**< Type used for register access */ +} LIS2DH12_ACT_THS_t; + +/** + * @brief ACT_DURATION definitions + */ +typedef union { + uint8_t reg; /**< Sleep-to-wake and return-to-sleep duration, in ODR cycles */ +} LIS2DH12_ACT_DURATION_t; +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* LIS2DH12_REGISTERS_H */ +/** @} */ diff --git a/drivers/lis2dh12/lis2dh12.c b/drivers/lis2dh12/lis2dh12.c index 9beb74c0ba..4126e512d1 100644 --- a/drivers/lis2dh12/lis2dh12.c +++ b/drivers/lis2dh12/lis2dh12.c @@ -21,6 +21,7 @@ #include "lis2dh12.h" #include "lis2dh12_internal.h" +#include "lis2dh12_registers.h" #define ENABLE_DEBUG 0 #include "debug.h" @@ -126,13 +127,13 @@ static void _write(const lis2dh12_t *dev, uint8_t reg, uint8_t data) #endif /* MODULE_LIS2DH12_SPI */ - 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))); + /* 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) { @@ -153,12 +154,22 @@ int lis2dh12_init(lis2dh12_t *dev, const lis2dh12_params_t *params) return LIS2DH12_NODEV; } - /* set sampling rate and scale. This also enables the device and starts - * sampling of data */ + /* enable all axes, set sampling rate and scale */ + LIS2DH12_CTRL_REG1_t reg1 = {0}; + + reg1.bit.ODR = dev->p->rate; + reg1.bit.Xen = 1; + reg1.bit.Yen = 1; + reg1.bit.Zen = 1; + _write(dev, REG_CTRL_REG4, dev->p->scale); - _write(dev, REG_CTRL_REG1, dev->p->rate); + _write(dev, REG_CTRL_REG1, reg1.reg); _release(dev); + + /* set powermode */ + lis2dh12_set_powermode(dev, dev->p->powermode); + DEBUG("[lis2dh12] initialization successful\n"); return LIS2DH12_OK; } @@ -174,7 +185,7 @@ int lis2dh12_read(const lis2dh12_t *dev, int16_t *data) _acquire(dev); /* first check if valid data is available */ - if ((_read(dev, REG_STATUS_REG) & LIS2DH12_STATUS_ZYXDA) == 0) { + if ((_read(dev, REG_STATUS_REG) & LIS2DH12_STATUS_REG_ZYXDA) == 0) { _release(dev); return LIS2DH12_NODATA; } @@ -184,11 +195,7 @@ int lis2dh12_read(const lis2dh12_t *dev, int16_t *data) /* 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); + data[i] = (int16_t)((raw[i*2 + 1] << 8) | raw[i*2]) >> dev->comp; } return LIS2DH12_OK; @@ -198,9 +205,8 @@ int lis2dh12_read(const lis2dh12_t *dev, int16_t *data) 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); + assert (dev && params); + assert (params->cb); _acquire(dev); @@ -266,13 +272,274 @@ int lis2dh12_read_int_src(const lis2dh12_t *dev, uint8_t *data, uint8_t int_line } #endif /* MODULE_LIS2DH12_INT */ +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}; + + if (config->FIFO_mode != LIS2DH12_FIFO_MODE_BYPASS) { + reg5.bit.FIFO_EN = 1; + } + fifo_reg.bit.TR = config->FIFO_set_INT2; + fifo_reg.bit.FM = config->FIFO_mode; + fifo_reg.bit.FTH = config->FIFO_watermark; + + _acquire(dev); + _write(dev, REG_CTRL_REG5, reg5.reg); + _write(dev, REG_FIFO_CTRL_REG, fifo_reg.reg); + _release(dev); + + return LIS2DH12_OK; +} + +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}; + fifo_reg.reg = _read(dev, REG_FIFO_CTRL_REG); + + uint8_t fifo_mode_old = fifo_reg.bit.FM; + fifo_reg.bit.FM = LIS2DH12_FIFO_MODE_BYPASS; + + /* switch to Bypass mode */ + _write(dev, REG_FIFO_CTRL_REG, fifo_reg.reg); + + fifo_reg.bit.FM = fifo_mode_old; + + _write(dev, REG_CTRL_REG5, reg5); + _write(dev, REG_FIFO_CTRL_REG, fifo_reg.reg); + _release(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) { + + 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}; + src_reg.reg = _read(dev, REG_FIFO_SRC_REG); + + if (src_reg.bit.FSS <= number) { + number = src_reg.bit.FSS; + } + + if (src_reg.bit.EMPTY) { + return 0; + } + + /* 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; + } + + _release(dev); + + return number; +} + +int lis2dh12_clear_data(const lis2dh12_t *dev) { + + assert(dev); + + LIS2DH12_CTRL_REG5_t ctrl_reg5 = {0}; + ctrl_reg5.bit.BOOT = 1; + + _acquire(dev); + _write(dev, REG_CTRL_REG5, ctrl_reg5.reg); + _release(dev); + + return LIS2DH12_OK; +} + +int lis2dh12_set_reference(const lis2dh12_t *dev, uint8_t reference) { + + assert(dev); + + _acquire(dev); + _write(dev, REG_REFERENCE, reference); + _release(dev); + + 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) { + + assert(dev && config); + + LIS2DH12_CTRL_REG2_t data = {0}; + + data.bit.HPM = config->Highpass_mode; + data.bit.HPCF = config->Highpass_freq; + data.bit.FDS = config->DATA_OUT_enable; + data.bit.HP_IA1 = config->INT1_enable; + data.bit.HP_IA2 = config->INT2_enable; + data.bit.HPCLICK = config->CLICK_enable; + + _acquire(dev); + _write(dev, REG_CTRL_REG2, data.reg); + _release(dev); + + return LIS2DH12_OK; +} + +int lis2dh12_set_click(const lis2dh12_t *dev, const lis2dh12_click_t *config) { + 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}; + + _acquire(dev); + reg1.reg = _read(dev, REG_CTRL_REG1); + reg4.reg = _read(dev, REG_CTRL_REG4); + + /* set power mode */ + if (powermode == LIS2DH12_POWER_LOW) { + reg1.bit.LPen = 1; + reg4.bit.HR = 0; + } + else if (powermode == LIS2DH12_POWER_HIGH) { + reg1.bit.LPen = 0; + reg4.bit.HR = 1; + } + else if (powermode == LIS2DH12_POWER_NORMAL) { + reg1.bit.LPen = 0; + reg4.bit.HR = 0; + } + else { /* power down mode */ + reg1.bit.ODR = 0; + } + + _write(dev, REG_CTRL_REG1, reg1.reg); + _write(dev, REG_CTRL_REG4, reg4.reg); + _release(dev); + + return LIS2DH12_OK; +} + +int lis2dh12_set_datarate(const lis2dh12_t *dev, lis2dh12_rate_t rate) { + + assert(dev); + assert(rate <= 0x9); + + LIS2DH12_CTRL_REG1_t reg1 = {0}; + + _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) { + + assert(dev); + assert((scale>>4) <= 0x3); + + LIS2DH12_CTRL_REG4_t reg4 = {0}; + + _acquire(dev); + reg4.reg = _read(dev, REG_CTRL_REG4); + + reg4.bit.FS = scale >> 4; + + _write(dev, REG_CTRL_REG4, reg4.reg); + _release(dev); + + dev->comp = 4 - (scale >> 4); + + return LIS2DH12_OK; +} + int lis2dh12_poweron(const lis2dh12_t *dev) { assert(dev); - _acquire(dev); - _write(dev, REG_CTRL_REG1, dev->p->rate); - _release(dev); + /* set default param values */ + lis2dh12_set_datarate(dev, dev->p->rate); + lis2dh12_set_powermode(dev, dev->p->powermode); return LIS2DH12_OK; } @@ -281,9 +548,8 @@ int lis2dh12_poweroff(const lis2dh12_t *dev) { assert(dev); - _acquire(dev); - _write(dev, REG_CTRL_REG1, 0); - _release(dev); + /* set datarate to zero */ + lis2dh12_set_datarate(dev, 0); return LIS2DH12_OK; } diff --git a/drivers/lis2dh12/lis2dh12_internal.h b/drivers/lis2dh12/lis2dh12_internal.h index 0d72b40c84..a1588af606 100644 --- a/drivers/lis2dh12/lis2dh12_internal.h +++ b/drivers/lis2dh12/lis2dh12_internal.h @@ -19,7 +19,6 @@ #ifndef LIS2DH12_INTERNAL_H #define LIS2DH12_INTERNAL_H - #ifdef __cplusplus extern "C" { #endif @@ -73,6 +72,7 @@ extern "C" { * @{ */ #define WHO_AM_I_VAL (0x33) +#define CTRL_REG0_DEFAULT (0x10) /** @} */ #ifdef __cplusplus diff --git a/tests/driver_lis2dh12/Makefile b/tests/driver_lis2dh12/Makefile index 411dece697..3cc425d3df 100644 --- a/tests/driver_lis2dh12/Makefile +++ b/tests/driver_lis2dh12/Makefile @@ -5,6 +5,7 @@ DRIVER ?= lis2dh12_spi USEMODULE += fmt USEMODULE += xtimer +USEMODULE += shell USEMODULE += $(DRIVER) # for using lis2dh12 with interrupt function diff --git a/tests/driver_lis2dh12/Makefile.ci b/tests/driver_lis2dh12/Makefile.ci new file mode 100644 index 0000000000..db547e6fd3 --- /dev/null +++ b/tests/driver_lis2dh12/Makefile.ci @@ -0,0 +1,11 @@ +BOARD_INSUFFICIENT_MEMORY := \ + arduino-duemilanove \ + arduino-leonardo \ + arduino-nano \ + arduino-uno \ + atmega328p \ + nucleo-f031k6 \ + nucleo-l011k4 \ + samd10-xmini \ + stm32f030f4-demo \ + # diff --git a/tests/driver_lis2dh12/app.config.test b/tests/driver_lis2dh12/app.config.test index 0f24ddbf00..54c15469d2 100644 --- a/tests/driver_lis2dh12/app.config.test +++ b/tests/driver_lis2dh12/app.config.test @@ -2,6 +2,7 @@ # application configuration. This is only needed during migration. CONFIG_MODULE_FMT=y CONFIG_MODULE_XTIMER=y +CONFIG_MODULE_SHELL=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 ef7b936442..b8e7b8014d 100644 --- a/tests/driver_lis2dh12/main.c +++ b/tests/driver_lis2dh12/main.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Freie Universität Berlin + * Copyright (C) 2020 ML!PA Consulting GmbH * * 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 @@ -11,170 +11,699 @@ * @{ * * @file - * @brief Test application for the LIS2DH12 accelerometer driver + * @brief Test application for LIS2DH12 accelerometer driver * - * @author Hauke Petersen + * @author Jan Mohr * * @} */ -#include -#include - -#include "fmt.h" +#include "stdio.h" +#include "string.h" +#include "stdlib.h" #include "xtimer.h" -#include "mutex.h" +#include "fmt.h" +#include "thread.h" +#include "shell.h" + #include "lis2dh12.h" #include "lis2dh12_params.h" +#include "lis2dh12_registers.h" - /* delay between sensor data reads */ -#define DELAY (100UL * US_PER_MS) +#define ENABLE_DEBUG 0 +#include "debug.h" -/* allocate some memory to hold one formatted string for each sensor output, so - * one string for the X, Y, and Z reading, respectively */ -static char str_out[3][8]; +#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 -/* control interrupt */ -typedef struct { - uint8_t line; - mutex_t *lock; - uint8_t *flags; -} lis_ctx; +/* Interrupt lines */ +static uint8_t line1 = 1; +static uint8_t line2 = 2; -/* 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 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, }; -/* interrupt callback function. */ -static void lis2dh12_int_cb(void* _ctx) { - lis_ctx *control = _ctx; +/* Memory to print current data */ +static char str_out[3][8]; - *control->flags |= control->line; +/* current lis acceleration data */ +static int16_t data_lis[3]; - mutex_unlock(control->lock); +/* 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)) { + puts("using SPI mode, for I2C mode select the lis2dh12_i2c module"); + } else { + puts("using I2C mode, for SPI mode select the lis2dh12_spi module"); + } + + /* init lis */ + if (lis2dh12_init(&dev, &lis2dh12_params[0]) == LIS2DH12_OK) { + puts("lis2dh12 [Initialized]"); + } + else { + puts("lis2dh12 [Failed]"); + } + + /* change LIS settings */ + lis2dh12_set_powermode(&dev, LIS2DH12_POWER_LOW); + lis2dh12_set_datarate(&dev, LIS2DH12_RATE_100HZ); + lis2dh12_set_scale(&dev, LIS2DH12_SCALE_4G); + +#ifdef MODULE_LIS2DH12_INT + /* set interrupt pins */ + gpio_t pin1 = dev.p->int1_pin; + gpio_t pin2 = dev.p->int2_pin; + + /* 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 */ } -/* print interrupt register */ -static void lis2dh12_int_reg_content(lis2dh12_t *dev, uint8_t pin){ +#ifdef MODULE_LIS2DH12_INT +void* lis2dh12_test_process(void* arg) { + (void) arg; + while (1) { + /* start processing */ + DEBUG("[Process]: start process\n"); - assert(pin == LIS2DH12_INT1 || pin == LIS2DH12_INT2); + /* 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); - uint8_t buffer; - lis2dh12_read_int_src(dev, &buffer, pin); + /* get fifo data */ + uint8_t number_read = lis2dh12_read_fifo_data(&dev, data_fifo, NUM_FIFO_VALUES); - 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)); + /* 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); + } + } + + /* 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); + } + } + + 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."); + } + } + /* 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."); + } + } + /* 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) { + + 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 */ + + /* MISSING command */ + if (argc < 2) { + printf("Error: Missing sub-command. %s\n", usage); + return -1; + } + + /* 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; + } + + /* 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; + } } -#endif int main(void) { #ifdef MODULE_LIS2DH12_INT - uint8_t flags = 0; -#endif + /* 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 */ - puts("LIS2DH12 accelerometer driver test application\n"); + /* init lis */ + lis2dh12_test_init(); - puts("Initializing LIS2DH12 sensor... "); - if (lis2dh12_init(&dev, &lis2dh12_params[0]) == LIS2DH12_OK) { - puts("[OK]"); - } - else { - puts("[Failed]\n"); - return 1; - } - -#ifdef MODULE_LIS2DH12_INT - /* enable interrupt Pins */ - if (gpio_is_valid(lis2dh12_params[0].int1_pin)) { - /* 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 (gpio_is_valid(lis2dh12_params[0].int2_pin)) { - 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"); - continue; - } - - /* format data */ - for (int i = 0; i < 3; i++) { - size_t len = fmt_s16_dfp(str_out[i], data[i], -3); - str_out[i][len] = '\0'; - } - - /* print data to STDIO */ - printf("X: %8s Y: %8s Z: %8s\n", str_out[0], str_out[1], str_out[2]); - } + /* running shell */ + char line_buf[SHELL_DEFAULT_BUFSIZE]; + shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE); return 0; }