drivers/sensor: lis2dw12: add threshold interrupt support
Add optional threshold interrupt support. Implemented using SENSOR_TRIG_THRESHOLD sensor trigger type. The features can be optionally enabled through Kconfig, or disabled for smaller code size. Signed-off-by: Maxime Vincent <maxime@veemax.be>
This commit is contained in:
parent
652ab7f2d4
commit
bf1334bafb
4 changed files with 154 additions and 0 deletions
|
@ -59,4 +59,16 @@ config LIS2DW12_TAP
|
||||||
|
|
||||||
endif # LIS2DW12_TRIGGER
|
endif # LIS2DW12_TRIGGER
|
||||||
|
|
||||||
|
config LIS2DW12_THRESHOLD
|
||||||
|
bool "Wakeup threshold trigger (via interrupt)"
|
||||||
|
help
|
||||||
|
Enable the wakeup threshold trigger feature.
|
||||||
|
The wake-up interrupt signal is generated if a certain number of
|
||||||
|
consecutive data exceed the configured threshold (config in DT).
|
||||||
|
The threshold is applied to both positive and negative data: for
|
||||||
|
a wake-up interrupt generation at least one of the three axes must
|
||||||
|
be bigger than the threshold. See ST AN5038 for more details about
|
||||||
|
the feature.
|
||||||
|
|
||||||
|
|
||||||
endif # LIS2DW12
|
endif # LIS2DW12
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#define DT_DRV_COMPAT st_lis2dw12
|
#define DT_DRV_COMPAT st_lis2dw12
|
||||||
|
|
||||||
#include <init.h>
|
#include <init.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <sys/__assert.h>
|
#include <sys/__assert.h>
|
||||||
#include <sys/byteorder.h>
|
#include <sys/byteorder.h>
|
||||||
#include <logging/log.h>
|
#include <logging/log.h>
|
||||||
|
@ -157,11 +158,102 @@ static int lis2dw12_config(const struct device *dev, enum sensor_channel chan,
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline int32_t sensor_ms2_to_mg(const struct sensor_value *ms2)
|
||||||
|
{
|
||||||
|
int64_t nano_ms2 = (ms2->val1 * 1000000LL + ms2->val2) * 1000LL;
|
||||||
|
|
||||||
|
if (nano_ms2 > 0) {
|
||||||
|
return (nano_ms2 + SENSOR_G / 2) / SENSOR_G;
|
||||||
|
} else {
|
||||||
|
return (nano_ms2 - SENSOR_G / 2) / SENSOR_G;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CONFIG_LIS2DW12_THRESHOLD
|
||||||
|
|
||||||
|
/* Converts a lis2dw12_fs_t range to its value in milli-g
|
||||||
|
* Range can be 2/4/8/16G
|
||||||
|
*/
|
||||||
|
#define FS_RANGE_TO_MG(fs_range) ((2U << fs_range) * 1000U)
|
||||||
|
|
||||||
|
/* Converts a range in mg to the lsb value for the WK_THS register
|
||||||
|
* For the reg value: 1 LSB = 1/64 of FS
|
||||||
|
* Range can be 2/4/8/16G
|
||||||
|
*/
|
||||||
|
#define MG_TO_WK_THS_LSB(range_mg) (range_mg / 64)
|
||||||
|
|
||||||
|
/* Calculates the WK_THS reg value
|
||||||
|
* from the threshold in mg and the lsb value in mg
|
||||||
|
* with correct integer rounding
|
||||||
|
*/
|
||||||
|
#define THRESHOLD_MG_TO_WK_THS_REG(thr_mg, lsb_mg) \
|
||||||
|
((thr_mg + (lsb_mg / 2)) / lsb_mg)
|
||||||
|
|
||||||
|
static int lis2dw12_attr_set_thresh(const struct device *dev,
|
||||||
|
enum sensor_channel chan,
|
||||||
|
enum sensor_attribute attr,
|
||||||
|
const struct sensor_value *val)
|
||||||
|
{
|
||||||
|
uint8_t reg;
|
||||||
|
size_t ret;
|
||||||
|
int lsb_mg;
|
||||||
|
const struct lis2dw12_device_config *cfg = dev->config;
|
||||||
|
stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
|
||||||
|
|
||||||
|
LOG_DBG("%s on channel %d", __func__, chan);
|
||||||
|
|
||||||
|
/* can only be set for all directions at once */
|
||||||
|
if (chan != SENSOR_CHAN_ACCEL_XYZ) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Configure wakeup threshold threshold. */
|
||||||
|
lis2dw12_fs_t range;
|
||||||
|
int err = lis2dw12_full_scale_get(ctx, &range);
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t thr_mg = abs(sensor_ms2_to_mg(val));
|
||||||
|
|
||||||
|
/* Check maximum value: depends on current FS value */
|
||||||
|
if (thr_mg >= FS_RANGE_TO_MG(range)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The threshold is applied to both positive and negative data:
|
||||||
|
* for a wake-up interrupt generation at least one of the three axes must be
|
||||||
|
* bigger than the threshold.
|
||||||
|
*/
|
||||||
|
lsb_mg = MG_TO_WK_THS_LSB(FS_RANGE_TO_MG(range));
|
||||||
|
reg = THRESHOLD_MG_TO_WK_THS_REG(thr_mg, lsb_mg);
|
||||||
|
|
||||||
|
LOG_DBG("Threshold %d mg -> fs: %u mg -> reg = %d LSBs",
|
||||||
|
thr_mg, FS_RANGE_TO_MG(range), reg);
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
return lis2dw12_wkup_threshold_set(ctx, reg);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int lis2dw12_attr_set(const struct device *dev,
|
static int lis2dw12_attr_set(const struct device *dev,
|
||||||
enum sensor_channel chan,
|
enum sensor_channel chan,
|
||||||
enum sensor_attribute attr,
|
enum sensor_attribute attr,
|
||||||
const struct sensor_value *val)
|
const struct sensor_value *val)
|
||||||
{
|
{
|
||||||
|
#if CONFIG_LIS2DW12_THRESHOLD
|
||||||
|
switch (attr) {
|
||||||
|
case SENSOR_ATTR_UPPER_THRESH:
|
||||||
|
case SENSOR_ATTR_LOWER_THRESH:
|
||||||
|
return lis2dw12_attr_set_thresh(dev, chan, attr, val);
|
||||||
|
default:
|
||||||
|
/* Do nothing */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
switch (chan) {
|
switch (chan) {
|
||||||
case SENSOR_CHAN_ACCEL_X:
|
case SENSOR_CHAN_ACCEL_X:
|
||||||
case SENSOR_CHAN_ACCEL_Y:
|
case SENSOR_CHAN_ACCEL_Y:
|
||||||
|
|
|
@ -101,6 +101,9 @@ struct lis2dw12_data {
|
||||||
sensor_trigger_handler_t tap_handler;
|
sensor_trigger_handler_t tap_handler;
|
||||||
sensor_trigger_handler_t double_tap_handler;
|
sensor_trigger_handler_t double_tap_handler;
|
||||||
#endif /* CONFIG_LIS2DW12_TAP */
|
#endif /* CONFIG_LIS2DW12_TAP */
|
||||||
|
#ifdef CONFIG_LIS2DW12_THRESHOLD
|
||||||
|
sensor_trigger_handler_t threshold_handler;
|
||||||
|
#endif /* CONFIG_LIS2DW12_THRESHOLD */
|
||||||
#if defined(CONFIG_LIS2DW12_TRIGGER_OWN_THREAD)
|
#if defined(CONFIG_LIS2DW12_TRIGGER_OWN_THREAD)
|
||||||
K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_LIS2DW12_THREAD_STACK_SIZE);
|
K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_LIS2DW12_THREAD_STACK_SIZE);
|
||||||
struct k_thread thread;
|
struct k_thread thread;
|
||||||
|
|
|
@ -67,6 +67,21 @@ static int lis2dw12_enable_int(const struct device *dev,
|
||||||
return lis2dw12_pin_int1_route_set(ctx,
|
return lis2dw12_pin_int1_route_set(ctx,
|
||||||
&int_route.ctrl4_int1_pad_ctrl);
|
&int_route.ctrl4_int1_pad_ctrl);
|
||||||
#endif /* CONFIG_LIS2DW12_TAP */
|
#endif /* CONFIG_LIS2DW12_TAP */
|
||||||
|
#ifdef CONFIG_LIS2DW12_THRESHOLD
|
||||||
|
/**
|
||||||
|
* Trigger fires when channel reading transitions configured
|
||||||
|
* thresholds. The thresholds are configured via the @ref
|
||||||
|
* SENSOR_ATTR_LOWER_THRESH and @ref SENSOR_ATTR_UPPER_THRESH
|
||||||
|
* attributes.
|
||||||
|
*/
|
||||||
|
case SENSOR_TRIG_THRESHOLD:
|
||||||
|
LOG_DBG("Setting int1_wu: %d\n", enable);
|
||||||
|
lis2dw12_pin_int1_route_get(ctx,
|
||||||
|
&int_route.ctrl4_int1_pad_ctrl);
|
||||||
|
int_route.ctrl4_int1_pad_ctrl.int1_wu = enable;
|
||||||
|
return lis2dw12_pin_int1_route_set(ctx,
|
||||||
|
&int_route.ctrl4_int1_pad_ctrl);
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
LOG_ERR("Unsupported trigger interrupt route %d", type);
|
LOG_ERR("Unsupported trigger interrupt route %d", type);
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
|
@ -121,6 +136,14 @@ int lis2dw12_trigger_set(const struct device *dev,
|
||||||
lis2dw12->double_tap_handler = handler;
|
lis2dw12->double_tap_handler = handler;
|
||||||
return lis2dw12_enable_int(dev, SENSOR_TRIG_DOUBLE_TAP, state);
|
return lis2dw12_enable_int(dev, SENSOR_TRIG_DOUBLE_TAP, state);
|
||||||
#endif /* CONFIG_LIS2DW12_TAP */
|
#endif /* CONFIG_LIS2DW12_TAP */
|
||||||
|
#ifdef CONFIG_LIS2DW12_THRESHOLD
|
||||||
|
case SENSOR_TRIG_THRESHOLD:
|
||||||
|
{
|
||||||
|
LOG_DBG("Set trigger %d (handler: %p)\n", trig->type, handler);
|
||||||
|
lis2dw12->threshold_handler = handler;
|
||||||
|
return lis2dw12_enable_int(dev, SENSOR_TRIG_THRESHOLD, state);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
LOG_ERR("Unsupported sensor trigger");
|
LOG_ERR("Unsupported sensor trigger");
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
|
@ -179,6 +202,25 @@ static int lis2dw12_handle_double_tap_int(const struct device *dev)
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_LIS2DW12_TAP */
|
#endif /* CONFIG_LIS2DW12_TAP */
|
||||||
|
|
||||||
|
#ifdef CONFIG_LIS2DW12_THRESHOLD
|
||||||
|
static int lis2dw12_handle_wu_ia_int(const struct device *dev)
|
||||||
|
{
|
||||||
|
struct lis2dw12_data *lis2dw12 = dev->data;
|
||||||
|
sensor_trigger_handler_t handler = lis2dw12->threshold_handler;
|
||||||
|
|
||||||
|
struct sensor_trigger thresh_trig = {
|
||||||
|
.type = SENSOR_TRIG_THRESHOLD,
|
||||||
|
.chan = SENSOR_CHAN_ALL,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (handler) {
|
||||||
|
handler(dev, &thresh_trig);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* lis2dw12_handle_interrupt - handle the drdy event
|
* lis2dw12_handle_interrupt - handle the drdy event
|
||||||
* read data and call handler if registered any
|
* read data and call handler if registered any
|
||||||
|
@ -202,6 +244,11 @@ static void lis2dw12_handle_interrupt(const struct device *dev)
|
||||||
lis2dw12_handle_double_tap_int(dev);
|
lis2dw12_handle_double_tap_int(dev);
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_LIS2DW12_TAP */
|
#endif /* CONFIG_LIS2DW12_TAP */
|
||||||
|
#ifdef CONFIG_LIS2DW12_THRESHOLD
|
||||||
|
if (sources.all_int_src.wu_ia) {
|
||||||
|
lis2dw12_handle_wu_ia_int(dev);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
gpio_pin_interrupt_configure_dt(&cfg->gpio_int,
|
gpio_pin_interrupt_configure_dt(&cfg->gpio_int,
|
||||||
GPIO_INT_EDGE_TO_ACTIVE);
|
GPIO_INT_EDGE_TO_ACTIVE);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue