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

drivers/lis2dh12: fix event handling

Don't push event handling to the user.
This commit is contained in:
Benjamin Valentin 2021-04-23 17:18:54 +02:00 committed by Benjamin Valentin
parent db0edd3ec1
commit e8264d3ea9
2 changed files with 295 additions and 65 deletions

View File

@ -97,6 +97,13 @@ typedef enum {
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
*/
@ -185,7 +192,6 @@ enum {
LIS2DH12_NODATA= -4, /**< no data available */
};
#if MODULE_LIS2DH12_INT || DOXYGEN
/*
* @brief Interrupt lines
*/
@ -204,10 +210,7 @@ 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
@ -244,28 +247,66 @@ extern const saul_driver_t lis2dh12_saul_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 */
/**

View File

@ -14,10 +14,15 @@
* @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 "lis2dh12.h"
#include "lis2dh12_internal.h"
@ -198,74 +203,258 @@ int lis2dh12_read(const lis2dh12_t *dev, int16_t *data)
return LIS2DH12_OK;
}
#ifdef MODULE_LIS2DH12_INT
int lis2dh12_set_int(const lis2dh12_t *dev, const lis2dh12_int_params_t *params, uint8_t int_line)
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 (int_line == LIS2DH12_INT1 || int_line == LIS2DH12_INT2);
assert (dev && params);
assert (params->cb);
assert(line == LIS2DH12_INT1 || line == LIS2DH12_INT2);
assert(event == LIS2DH12_EVENT_1 || event == LIS2DH12_EVENT_2);
_acquire(dev);
gpio_t pin = GPIO_UNDEF;
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;
switch (int_line){
/* first interrupt line (INT1) */
case LIS2DH12_INT1:
pin = dev->p->int1_pin;
assert (gpio_is_valid(pin));
/* 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);
}
if (gpio_init_int(pin, GPIO_IN, GPIO_RISING, params->cb, params->arg)) {
return LIS2DH12_NOINT;
}
DEBUG("[%u] threshold: %lu mg\n", event, mg);
_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));
/* read reference to set it to current data */
_read(dev, REG_REFERENCE);
if (gpio_init_int(pin, GPIO_IN, GPIO_RISING, params->cb, params->arg)) {
return LIS2DH12_NOINT;
}
/* configure interrupt */
switch (event) {
case LIS2DH12_EVENT_1:
/* apply high-pass to interrupt */
reg2.bit.HP_IA1 = 1;
int_reg |= LIS2DH12_INT_TYPE_IA1;
_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;
/* 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);
return LIS2DH12_OK;
}
int lis2dh12_read_int_src(const lis2dh12_t *dev, uint8_t *data, uint8_t int_line)
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)
{
assert(dev && data);
assert(int_line == LIS2DH12_INT1 || int_line == LIS2DH12_INT2);
_acquire(dev);
switch (int_line) {
/* first interrupt line (INT1) */
case LIS2DH12_INT1:
*data = _read(dev, REG_INT1_SRC);
break;
/* second interrupt line (INT2) */
case LIS2DH12_INT2:
*data = _read(dev, REG_INT2_SRC);
break;
uint8_t odr = _read(dev, REG_CTRL_REG1) >> 4;
uint8_t scale = (_read(dev, REG_CTRL_REG4) >> 4) & 0x3;
DEBUG("click threshold: %lu 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);
}
return LIS2DH12_OK;
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
static void _cb(void *lock)
{
mutex_unlock(lock);
}
static uint32_t _merge_int_flags(const lis2dh12_t *dev, uint8_t events)
{
uint32_t int_src = 0;
/* merge interrupt flags (7 bit per event) into one word */
if (events & LIS2DH12_INT_TYPE_IA1) {
int_src |= _read(dev, REG_INT1_SRC);
}
if (events & LIS2DH12_INT_TYPE_IA2) {
int_src |= _read(dev, REG_INT2_SRC) << 8;
}
if (events & LIS2DH12_INT_TYPE_CLICK) {
int_src |= _read(dev, REG_CLICK_SRC) << 16;
}
DEBUG("int_src: %lx\n", int_src);
return int_src;
}
#define LIS2DH12_INT_SRC_ANY ((LIS2DH12_INT_SRC_IA << 0) | \
(LIS2DH12_INT_SRC_IA << 8) | \
(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);
/* 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 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 */