1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #16328 from benpicco/driver/lis2dh12-cleanup

drivers/lis2dh12: clean up API
This commit is contained in:
benpicco 2021-06-03 15:33:04 +02:00 committed by GitHub
commit 41bbafdfe4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 935 additions and 891 deletions

View File

@ -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

View File

@ -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 */

View File

@ -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
*/

View File

@ -14,10 +14,16 @@
* @brief LIS2DH12 accelerometer driver implementation
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Jan Mohr <jan.mohr@ml-pa.com>
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
* @}
*/
#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;
}

View File

@ -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,
};

View File

@ -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]);
}
}

View File

@ -6,6 +6,7 @@ DRIVER ?= lis2dh12_spi
USEMODULE += fmt
USEMODULE += xtimer
USEMODULE += shell
USEMODULE += shell_commands
USEMODULE += $(DRIVER)
# for using lis2dh12 with interrupt function

View File

@ -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

View File

@ -14,13 +14,15 @@
* @brief Test application for LIS2DH12 accelerometer driver
*
* @author Jan Mohr <jan.mohr@ml-pa.com>
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
*
* @}
*/
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#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 <subcommand> [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 <subcommand> [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, &params_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, &params_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, &params_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 <slot> <mg> [µ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 <mg> [µ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 <on|off>\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 <mode>\n", argv[0]);
puts("where <mode> 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 <rate>\n", argv[0]);
puts("where <rate> 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 <scale>\n", argv[0]);
puts("where <scale> 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);