Trigger mode on LSM6DSO

Hello,

I've been working on a project involving an IMU and bluetooth for a while, and had been using the IMU (LSM6DSO) on polling mode. Unfortunately, I found out that I will need to use trigger mode for this application, so I've been trying to figure out how to do that. I've made what feels like a hundred changes to my config and devicetree overlay files to try and get this working and have had no success so far. It seems like many of the trigger mode config options don't work, or say that they weren't able to set the value to y. I did find one combination that at least let me successfully build my code, and I will share both of those files here. I've been starting with the lsm6dso sample and trying to add code that sends an interrupt when the IMU records >2g acceleration and turns an LED on the nrf52 dk, but currently nothing occurs after the line 'Failed to set acceleration threshold' is printed in the terminal. Lastly, I have verified that my physical wiring and connections are as they should be, and uploaded the working code (using polling mode) to confirm. I would really appreciate any help or information that you can share regarding this. Thank you!

/*
 * Copyright (c) 2020 Yestin Sun
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <stdio.h>
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/drivers/gpio.h>


static inline float out_ev(struct sensor_value *val)
{
	return (val->val1 + (float)val->val2 / 1000000);
}
#define LED0_NODE DT_ALIAS(led0)

static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);

static void fetch_and_display(const struct device *dev)
{
	struct sensor_value x, y, z;
	static int trig_cnt;

	trig_cnt++;

	/* lsm6dso accel */
	sensor_sample_fetch_chan(dev, SENSOR_CHAN_ACCEL_XYZ);
	sensor_channel_get(dev, SENSOR_CHAN_ACCEL_X, &x);
	sensor_channel_get(dev, SENSOR_CHAN_ACCEL_Y, &y);
	sensor_channel_get(dev, SENSOR_CHAN_ACCEL_Z, &z);

	printf("accel x:%f ms/2 y:%f ms/2 z:%f ms/2\n",
			(double)out_ev(&x), (double)out_ev(&y), (double)out_ev(&z));

	/* lsm6dso gyro */
	sensor_sample_fetch_chan(dev, SENSOR_CHAN_GYRO_XYZ);
	sensor_channel_get(dev, SENSOR_CHAN_GYRO_X, &x);
	sensor_channel_get(dev, SENSOR_CHAN_GYRO_Y, &y);
	sensor_channel_get(dev, SENSOR_CHAN_GYRO_Z, &z);

	printf("gyro x:%f rad/s y:%f rad/s z:%f rad/s\n",
			(double)out_ev(&x), (double)out_ev(&y), (double)out_ev(&z));

	printf("trig_cnt:%d\n\n", trig_cnt);
}

static int set_sampling_freq(const struct device *dev)
{
	int ret = 0;
	struct sensor_value odr_attr;

	/* set accel/gyro sampling frequency to 12.5 Hz */
	odr_attr.val1 = 12.5;
	odr_attr.val2 = 0;

	ret = sensor_attr_set(dev, SENSOR_CHAN_ACCEL_XYZ,
			SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr);
	if (ret != 0) {
		printf("Cannot set sampling frequency for accelerometer.\n");
		return ret;
	}

	ret = sensor_attr_set(dev, SENSOR_CHAN_GYRO_XYZ,
			SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr);
	if (ret != 0) {
		printf("Cannot set sampling frequency for gyro.\n");
		return ret;
	}

	return 0;
}

#ifdef CONFIG_LSM6DSO_TRIGGER
static void trigger_handler(const struct device *dev,
	const struct sensor_trigger *trig)
{
static bool led_on = false;
printf("Triggered.\n");
// Toggle LED
led_on = !led_on;
gpio_pin_set_dt(&led, led_on);

// Optional: also display sensor data
fetch_and_display(dev);
}



static void test_trigger_mode(const struct device *dev)
{
	struct sensor_trigger trig;
	struct sensor_value threshold;

	if (set_sampling_freq(dev) != 0)
		return;

	// Set 2g threshold (approx. 19.6 m/s²)
	threshold.val1 = 19;
	threshold.val2 = 600000;

	if (sensor_attr_set(dev, SENSOR_CHAN_ACCEL_XYZ, SENSOR_ATTR_SLOPE_TH, &threshold) != 0) {

		printf("Failed to set acceleration threshold\n");
		return;
	}

	// Set trigger type to threshold
	trig.type = SENSOR_TRIG_THRESHOLD;
	trig.chan = SENSOR_CHAN_ACCEL_XYZ;

	if (sensor_trigger_set(dev, &trig, trigger_handler) != 0) {
		printf("Could not set threshold trigger\n");
		return;
	}
}


#else
static void test_polling_mode(const struct device *dev)
{
	if (set_sampling_freq(dev) != 0) {
		return;
	}

	while (1) {
		fetch_and_display(dev);
		k_sleep(K_MSEC(1000));
	}
}
#endif

int main(void)
{
	const struct device *const dev = DEVICE_DT_GET_ONE(st_lsm6dso);

	if (!device_is_ready(dev)) {
		printk("%s: device not ready.\n", dev->name);
		return 0;
	}

#ifdef CONFIG_LSM6DSO_TRIGGER
	printf("Testing LSM6DSO sensor in trigger mode.\n\n");
	if (!gpio_is_ready_dt(&led)) {
		printk("LED device not ready\n");
		return 0;
	}

	if (gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE) != 0) {
		printk("Failed to configure LED\n");
		return 0;
	}

	test_trigger_mode(dev);
#else
	printf("Testing LSM6DSO sensor in polling mode.\n\n");
	test_polling_mode(dev);
#endif
	return 0;
}
 

Config file: 

CONFIG_STDOUT_CONSOLE=y
CONFIG_I2C=y
CONFIG_GPIO=y
CONFIG_SENSOR=y
CONFIG_LSM6DSO=y

CONFIG_LSM6DSO_TRIGGER_GLOBAL_THREAD=y  # or OWN_THREAD if you prefer
CONFIG_CBPRINTF_FP_SUPPORT=y


Devicetree overlay: 
&i2c0 {
    lsm6dso@6b {
        compatible = "st,lsm6dso";
        reg = <0x6b>;
        label = "LSM6DSO";
        irq-gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>;
        int-pin = <1>;
        status = "okay";
    };
};
Parents
  • Hi I will look into it. 

    From a first glance it looks like you are missing the second interrupt pin from the sensor. 

    From the last update I can't see that you put any threshold on the trigger at all. 

    When you used 

    // Set 2g threshold (approx. 19.6 m/s²)
    threshold.val1 = 19;
    threshold.val2 = 600000;

    if (sensor_attr_set(dev, SENSOR_CHAN_ACCEL_XYZ, SENSOR_ATTR_SLOPE_TH, &threshold) != 0) {

    printf("Failed to set acceleration threshold\n");
    return;
    }

    What did it return?  Did you try to read the config back?

    Regurn

  • I kept getting issues with setting the trigger type to threshold and read somewhere that it might not be supported on the version I'm working with. I also cannot find documentation as to what units the threshold.val1 and threshold.val2 are, so I'm not sure what values I actually set in the code you referenced. I've tried manually updating registers with code like this:

        // CTRL1_XL: Set accelerometer to 12.5 Hz, ±4g
        lsm6dso_write_reg(0x10, 0x50);  
       
        // WAKE_UP_THS: Set threshold ~2g (32 * 4g / 64 = 2g)
        lsm6dso_write_reg(0x5B, 0x20);
       
        // WAKE_UP_DUR: No delay
        lsm6dso_write_reg(0x5C, 0x00);
       
        // MD1_CFG: Route wake-up to INT1
        lsm6dso_write_reg(0x5E, 0x20);
       
        // CTRL3_C: Enable auto-increment
        lsm6dso_write_reg(0x12, 0x44);
    and no matter what I try, it still continuously triggers when it shouldn't be. The code you shared was from an older version of what I was trying, but if you think that might be the right way to go about doing what I need to do, I can go back and check. I recall that for a while I was getting the output 'failed to set acceleration threshold' and then nothing else.
Reply
  • I kept getting issues with setting the trigger type to threshold and read somewhere that it might not be supported on the version I'm working with. I also cannot find documentation as to what units the threshold.val1 and threshold.val2 are, so I'm not sure what values I actually set in the code you referenced. I've tried manually updating registers with code like this:

        // CTRL1_XL: Set accelerometer to 12.5 Hz, ±4g
        lsm6dso_write_reg(0x10, 0x50);  
       
        // WAKE_UP_THS: Set threshold ~2g (32 * 4g / 64 = 2g)
        lsm6dso_write_reg(0x5B, 0x20);
       
        // WAKE_UP_DUR: No delay
        lsm6dso_write_reg(0x5C, 0x00);
       
        // MD1_CFG: Route wake-up to INT1
        lsm6dso_write_reg(0x5E, 0x20);
       
        // CTRL3_C: Enable auto-increment
        lsm6dso_write_reg(0x12, 0x44);
    and no matter what I try, it still continuously triggers when it shouldn't be. The code you shared was from an older version of what I was trying, but if you think that might be the right way to go about doing what I need to do, I can go back and check. I recall that for a while I was getting the output 'failed to set acceleration threshold' and then nothing else.
Children
  • It seems like there are two ways of handling triggering with this device: Manually configuring registers, or using the lsm6dso driver to enable it. Based on what I can find, threshold mode isn't supported by the driver, so I will need to change the registers manually. The issue is that my trigger handler function no longer gets called if I don't enable triggering mode via the drivers, so I would need to make a new function that gets called when the interrupt pin is triggered, but I have no clue how to do that.

Related