Commit 0e05686d authored by Erdem Efe's avatar Erdem Efe Committed by Maureen Helm
Browse files

sensor: freefall added to lis2dw12 sensor driver.



lis2dw12 supports freefall detection and set related parameters

Signed-off-by: default avatarErdem Efe <erdemefe1@gmail.com>
parent a61ca790
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -73,5 +73,8 @@ config LIS2DW12_THRESHOLD
	  be bigger than the threshold. See ST AN5038 for more details about
	  the feature.


config LIS2DW12_FREEFALL
	bool "Free Fall detection (via interrupt)"
	help
	  Enable freefall detection via interrupt.
endif # LIS2DW12
+61 −5
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ static int lis2dw12_set_odr(const struct device *dev, uint16_t odr)
{
	const struct lis2dw12_device_config *cfg = dev->config;
	stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
	struct lis2dw12_data *lis2dw12 = dev->data;
	uint8_t val;

	/* check if power off */
@@ -76,7 +77,7 @@ static int lis2dw12_set_odr(const struct device *dev, uint16_t odr)
		LOG_ERR("ODR too high");
		return -ENOTSUP;
	}

	lis2dw12->odr = odr;
	return lis2dw12_data_rate_set(ctx, val);
}

@@ -238,6 +239,41 @@ static int lis2dw12_attr_set_thresh(const struct device *dev,
}
#endif

#ifdef CONFIG_LIS2DW12_FREEFALL
static int lis2dw12_attr_set_ff_dur(const struct device *dev,
					enum sensor_channel chan,
					enum sensor_attribute attr,
					const struct sensor_value *val)
{
	int rc;
	uint16_t duration;
	const struct lis2dw12_device_config *cfg = dev->config;
	struct lis2dw12_data *lis2dw12 = dev->data;
	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;
	}

	/**
	 * The given duration in milliseconds with the val
	 * parameter is converted into register specific value.
	 */
	duration = (lis2dw12->odr * (uint16_t)sensor_value_to_double(val)) / 1000;

	LOG_DBG("Freefall: duration is %d ms", (uint16_t)sensor_value_to_double(val));
	rc = lis2dw12_ff_dur_set(ctx, duration);
	if (rc != 0) {
		LOG_ERR("Failed to set freefall duration");
		return -EIO;
	}
	return rc;
}
#endif

static int lis2dw12_attr_set(const struct device *dev,
			      enum sensor_channel chan,
			      enum sensor_attribute attr,
@@ -254,6 +290,12 @@ static int lis2dw12_attr_set(const struct device *dev,
	}
#endif

#ifdef CONFIG_LIS2DW12_FREEFALL
	if (attr == SENSOR_ATTR_FF_DUR) {
		return lis2dw12_attr_set_ff_dur(dev, chan, attr, val);
	}
#endif

	switch (chan) {
	case SENSOR_CHAN_ACCEL_X:
	case SENSOR_CHAN_ACCEL_Y:
@@ -347,6 +389,7 @@ static int lis2dw12_set_low_noise(const struct device *dev,
static int lis2dw12_init(const struct device *dev)
{
	const struct lis2dw12_device_config *cfg = dev->config;
	struct lis2dw12_data *lis2dw12 = dev->data;
	stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
	uint8_t wai;
	int ret;
@@ -390,14 +433,15 @@ static int lis2dw12_init(const struct device *dev)
		LOG_ERR("Failed to configure low_noise");
		return ret;
	}

	/* set default odr to 12.5Hz acc */
	ret = lis2dw12_set_odr(dev, 12);
	/* set the output data rate */
	ret = lis2dw12_set_odr(dev, cfg->odr);
	if (ret < 0) {
		LOG_ERR("odr init error (12.5 Hz)");
		LOG_ERR("odr init error %d", cfg->odr);
		return ret;
	}

	lis2dw12->odr = cfg->odr;

	LOG_DBG("range is %d", cfg->range);
	ret = lis2dw12_set_range(dev, LIS2DW12_FS_TO_REG(cfg->range));
	if (ret < 0) {
@@ -469,6 +513,14 @@ static int lis2dw12_init(const struct device *dev)
#define LIS2DW12_CONFIG_TAP(inst)
#endif /* CONFIG_LIS2DW12_TAP */

#ifdef CONFIG_LIS2DW12_FREEFALL
#define LIS2DW12_CONFIG_FREEFALL(inst)					\
	.freefall_duration = DT_INST_PROP(inst, ff_duration),	\
	.freefall_threshold = DT_INST_PROP(inst, ff_threshold),
#else
#define LIS2DW12_CONFIG_FREEFALL(inst)
#endif /* CONFIG_LIS2DW12_FREEFALL */

#ifdef CONFIG_LIS2DW12_TRIGGER
#define LIS2DW12_CFG_IRQ(inst) \
	.gpio_int = GPIO_DT_SPEC_INST_GET(inst, irq_gpios),		\
@@ -498,6 +550,7 @@ static int lis2dw12_init(const struct device *dev)
					   0),				\
		},							\
		.pm = DT_INST_PROP(inst, power_mode),			\
		.odr = DT_INST_PROP_OR(inst, odr, 12),			\
		.range = DT_INST_PROP(inst, range),			\
		.bw_filt = DT_INST_PROP(inst, bw_filt),      \
		.low_noise = DT_INST_PROP(inst, low_noise),      \
@@ -505,6 +558,7 @@ static int lis2dw12_init(const struct device *dev)
		.hp_ref_mode = DT_INST_PROP(inst, hp_ref_mode), \
		.drdy_pulsed = DT_INST_PROP(inst, drdy_pulsed),      \
		LIS2DW12_CONFIG_TAP(inst)				\
		LIS2DW12_CONFIG_FREEFALL(inst)		\
		COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, irq_gpios),	\
			(LIS2DW12_CFG_IRQ(inst)), ())			\
	}
@@ -527,6 +581,7 @@ static int lis2dw12_init(const struct device *dev)
			.i2c = I2C_DT_SPEC_INST_GET(inst),		\
		},							\
		.pm = DT_INST_PROP(inst, power_mode),			\
		.odr = DT_INST_PROP_OR(inst, odr, 12),			\
		.range = DT_INST_PROP(inst, range),			\
		.bw_filt = DT_INST_PROP(inst, bw_filt),      \
		.low_noise = DT_INST_PROP(inst, low_noise),      \
@@ -534,6 +589,7 @@ static int lis2dw12_init(const struct device *dev)
		.hp_ref_mode = DT_INST_PROP(inst, hp_ref_mode), \
		.drdy_pulsed = DT_INST_PROP(inst, drdy_pulsed),      \
		LIS2DW12_CONFIG_TAP(inst)				\
		LIS2DW12_CONFIG_FREEFALL(inst)		\
		COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, irq_gpios),	\
			(LIS2DW12_CFG_IRQ(inst)), ())			\
	}
+18 −0
Original line number Diff line number Diff line
@@ -32,6 +32,14 @@
	 (_odr <= 12) ? LIS2DW12_XL_ODR_12Hz5 : \
	 ((31 - __builtin_clz(_odr / 25))) + 3)

/* Return data rate in Hz for given register value */
#define LIS2DW12_REG_TO_ODR(_reg) \
	((_reg == 0) ? 0 : \
	(_reg == 1) ? 1 : \
	(_reg == 2) ? 12 : \
	(_reg > 9) ? 1600 : \
	(1 << (_reg - 3)) * 25)

/* FS reg value from Full Scale */
#define LIS2DW12_FS_TO_REG(_fs)	(30 - __builtin_clz(_fs))

@@ -67,6 +75,7 @@ struct lis2dw12_device_config {
#endif
	} stmemsc_cfg;
	lis2dw12_mode_t pm;
	uint16_t odr;
	uint8_t range;
	uint8_t bw_filt;
	bool low_noise;
@@ -83,6 +92,10 @@ struct lis2dw12_device_config {
	uint8_t tap_latency;
	uint8_t tap_quiet;
#endif /* CONFIG_LIS2DW12_TAP */
#ifdef CONFIG_LIS2DW12_FREEFALL
	uint8_t freefall_duration;
	uint8_t freefall_threshold;
#endif /* CONFIG_LIS2DW12_FREEFALL */
#endif /* CONFIG_LIS2DW12_TRIGGER */
};

@@ -92,6 +105,8 @@ struct lis2dw12_data {

	 /* save sensitivity */
	uint16_t gain;
	 /* output data rate */
	uint16_t odr;

#ifdef CONFIG_LIS2DW12_TRIGGER
	const struct device *dev;
@@ -105,6 +120,9 @@ struct lis2dw12_data {
#ifdef CONFIG_LIS2DW12_THRESHOLD
	sensor_trigger_handler_t threshold_handler;
#endif /* CONFIG_LIS2DW12_THRESHOLD */
#ifdef CONFIG_LIS2DW12_FREEFALL
	sensor_trigger_handler_t freefall_handler;
#endif /* CONFIG_LIS2DW12_FREEFALL */
#if defined(CONFIG_LIS2DW12_TRIGGER_OWN_THREAD)
	K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_LIS2DW12_THREAD_STACK_SIZE);
	struct k_thread thread;
+81 −0
Original line number Diff line number Diff line
@@ -82,6 +82,21 @@ static int lis2dw12_enable_int(const struct device *dev,
		return lis2dw12_pin_int1_route_set(ctx,
						   &int_route.ctrl4_int1_pad_ctrl);
#endif
#ifdef CONFIG_LIS2DW12_FREEFALL
	/**
	 * Trigger fires when the readings does not include Earth's
	 * gravitional force for configured duration and threshold.
	 * The duration and the threshold can be configured in the
	 * devicetree source of the accelerometer node.
	 */
	case SENSOR_TRIG_FREEFALL:
		LOG_DBG("Setting int1_ff: %d\n", enable);
		lis2dw12_pin_int1_route_get(ctx,
				&int_route.ctrl4_int1_pad_ctrl);
		int_route.ctrl4_int1_pad_ctrl.int1_ff = enable;
		return lis2dw12_pin_int1_route_set(ctx,
				&int_route.ctrl4_int1_pad_ctrl);
#endif /* CONFIG_LIS2DW12_FREEFALL */
	default:
		LOG_ERR("Unsupported trigger interrupt route %d", type);
		return -ENOTSUP;
@@ -144,6 +159,13 @@ int lis2dw12_trigger_set(const struct device *dev,
		return lis2dw12_enable_int(dev, SENSOR_TRIG_THRESHOLD, state);
	}
#endif
#ifdef CONFIG_LIS2DW12_FREEFALL
	case SENSOR_TRIG_FREEFALL:
	LOG_DBG("Set freefall %d (handler: %p)\n", trig->type, handler);
		lis2dw12->freefall_handler = handler;
		return lis2dw12_enable_int(dev, SENSOR_TRIG_FREEFALL, state);
	break;
#endif /* CONFIG_LIS2DW12_FREEFALL */
	default:
		LOG_ERR("Unsupported sensor trigger");
		return -ENOTSUP;
@@ -221,6 +243,25 @@ static int lis2dw12_handle_wu_ia_int(const struct device *dev)
}
#endif

#ifdef CONFIG_LIS2DW12_FREEFALL
static int lis2dw12_handle_ff_ia_int(const struct device *dev)
{
	struct lis2dw12_data *lis2dw12 = dev->data;
	sensor_trigger_handler_t handler = lis2dw12->freefall_handler;

	struct sensor_trigger freefall_trig = {
		.type = SENSOR_TRIG_FREEFALL,
		.chan = SENSOR_CHAN_ALL,
	};

	if (handler) {
		handler(dev, &freefall_trig);
	}

	return 0;
}
#endif /* CONFIG_LIS2DW12_FREEFALL */

/**
 * lis2dw12_handle_interrupt - handle the drdy event
 * read data and call handler if registered any
@@ -249,6 +290,11 @@ static void lis2dw12_handle_interrupt(const struct device *dev)
		lis2dw12_handle_wu_ia_int(dev);
	}
#endif
#ifdef CONFIG_LIS2DW12_FREEFALL
	if (sources.all_int_src.ff_ia) {
		lis2dw12_handle_ff_ia_int(dev);
	}
#endif /* CONFIG_LIS2DW12_FREEFALL */

	gpio_pin_interrupt_configure_dt(&cfg->gpio_int,
					GPIO_INT_EDGE_TO_ACTIVE);
@@ -370,6 +416,34 @@ static int lis2dw12_tap_init(const struct device *dev)
}
#endif /* CONFIG_LIS2DW12_TAP */

#ifdef CONFIG_LIS2DW12_FREEFALL
static int lis2dw12_ff_init(const struct device *dev)
{
	int rc;
	const struct lis2dw12_device_config *cfg = dev->config;
	struct lis2dw12_data *lis2dw12 = dev->data;
	stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
	uint16_t duration;

	duration = (lis2dw12->odr * cfg->freefall_duration) / 1000;

	LOG_DBG("FREEFALL: duration is %d ms", cfg->freefall_duration);
	rc = lis2dw12_ff_dur_set(ctx, duration);
	if (rc != 0) {
		LOG_ERR("Failed to set freefall duration");
		return -EIO;
	}

	LOG_DBG("FREEFALL: threshold is %02x", cfg->freefall_threshold);
	rc = lis2dw12_ff_threshold_set(ctx, cfg->freefall_threshold);
	if (rc != 0) {
		LOG_ERR("Failed to set freefall thrshold");
		return -EIO;
	}
	return 0;
}
#endif /* CONFIG_LIS2DW12_FREEFALL */

int lis2dw12_init_interrupt(const struct device *dev)
{
	struct lis2dw12_data *lis2dw12 = dev->data;
@@ -439,6 +513,13 @@ int lis2dw12_init_interrupt(const struct device *dev)
	}
#endif /* CONFIG_LIS2DW12_TAP */

#ifdef CONFIG_LIS2DW12_FREEFALL
	ret = lis2dw12_ff_init(dev);
		if (ret < 0) {
			return ret;
		}
#endif /* CONFIG_LIS2DW12_FREEFALL */

	return gpio_pin_interrupt_configure_dt(&cfg->gpio_int,
					       GPIO_INT_EDGE_TO_ACTIVE);
}
+66 −0
Original line number Diff line number Diff line
@@ -50,6 +50,28 @@ properties:
        -  4
        -  2

    odr:
      type: int
      required: false
      description: |
        Output data rate in Hz. Default value is 12.5Hz if this is not set.
        The output data rates which are represented with fractional
        numbers are converted into their integer parts (1.65Hz -> 1, 12.5Hz -> 12).
        If 0 selected as the odr, the accelerometer initializes into
        power off state.

      enum:
        -  0
        -  1
        -  12
        -  25
        -  50
        -  100
        -  200
        -  400
        -  800
        -  1600

    bw-filt:
      type: int
      required: false
@@ -193,3 +215,47 @@ properties:
        Selects the pulsed mode for data-ready interrupt when enabled,
        and the latched mode when disabled.
        Sets the corresponding DRDY_PULSED bit in the CTRL7 register.

    ff-duration:
      type: int
      default: 30
      required: false
      description: |
        The freefall duration value represented in milliseconds.
        If the accelerometer readings of the all axes are lower
        than the freefall threshold value for the freefall duration long,
        then a freefall trigger occurs. This value is 5 bits long in the
        register and 1 LSB = 1 * 1/ODR. This value depends on the ODR.
        if the data rate change in code with SENSOR ATTR SAMPLING FREQUENCY,
        It must be set again with SENSOR_ATT_FF_DUR attribute. ST propose
        100Hz ODR and 30ms ff-duration for recognize freefall detection
        refer to ST DT0100 design tip document.

    ff-threshold:
      type: int
      default: 3
      required: false
      description: |
        The freefall threshold value represented in mg.
        If the accelerometer readings of the all axes are lower
        than the freefall threshold value for the freefall duration long,
        then a freefall trigger occurs. This value is 3 bits long.
        Default value chosen 3 (312 mg) refer to ST DT0100 design tip document.
        0 # ~156mg
        1 # ~219mg
        2 # ~250mg
        3 # ~312mg
        4 # ~344mg
        5 # ~406mg
        6 # ~469mg
        7 # ~500mg

      enum:
        - 0
        - 1
        - 2
        - 3
        - 4
        - 5
        - 6
        - 7
Loading