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
  • Hello, just spent another few hours on this and made some progress but am still struggling. The device gets trigger mode to work, but my current issue is that it is CONSTANTLY triggering no matter what I try to do to fix it. Overall, I've just been really struggling to find documentation regarding how this all works. I understand that another approach to this is to manually change the register values in the lsm6dso, and I tried that too but it didn't work. All I really need is to setup the device so that it sends an interrupt/trigger when acceleration exceeds 2g. I'll share my current code with the changes that I made so that it reads data from the sensor constantly. I don't believe I made any changes to the devicetree overlay or config file.

     

    /*
     * 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>
    #include <zephyr/drivers/i2c.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;
    
    
    	
        threshold.val1 = 10;
        threshold.val2 = 0;
    
    	// Set trigger type to threshold
    	trig.type = SENSOR_TRIG_DELTA;  
    	//trig.type = SENSOR_TRIG_THRESHOLD; 
    	trig.chan = SENSOR_CHAN_ACCEL_XYZ;
    	//trig.chan = SENSOR_CHAN_GYRO_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;
    }
    
     

Reply
  • Hello, just spent another few hours on this and made some progress but am still struggling. The device gets trigger mode to work, but my current issue is that it is CONSTANTLY triggering no matter what I try to do to fix it. Overall, I've just been really struggling to find documentation regarding how this all works. I understand that another approach to this is to manually change the register values in the lsm6dso, and I tried that too but it didn't work. All I really need is to setup the device so that it sends an interrupt/trigger when acceleration exceeds 2g. I'll share my current code with the changes that I made so that it reads data from the sensor constantly. I don't believe I made any changes to the devicetree overlay or config file.

     

    /*
     * 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>
    #include <zephyr/drivers/i2c.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;
    
    
    	
        threshold.val1 = 10;
        threshold.val2 = 0;
    
    	// Set trigger type to threshold
    	trig.type = SENSOR_TRIG_DELTA;  
    	//trig.type = SENSOR_TRIG_THRESHOLD; 
    	trig.chan = SENSOR_CHAN_ACCEL_XYZ;
    	//trig.chan = SENSOR_CHAN_GYRO_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;
    }
    
     

Children
No Data
Related