Running the LSM6DLS (IMU) zephyr example with nrf52840 based Xiao BLE Sense

Hi all,

I've been trying to get the samples/sensor/lsm6dsl example working with the nrf52840-based Xiao BLE Sense and have had no luck.

I guess that it's due to the power line for the sensor being connected to the P1.08

I dug into the xiao_ble_sense.dts and I can indeed see:

	lsm6ds3tr-c-en {
		compatible = "regulator-fixed-sync", "regulator-fixed";
		enable-gpios = <&gpio1 8 (NRF_GPIO_DRIVE_S0H1 | GPIO_ACTIVE_HIGH)>;
		regulator-name = "LSM6DS3TR_C_EN";
		regulator-boot-on;
		startup-delay-us = <3000>;
	};

However no matter how I try and drive it from the code the sensor refuses to initialize with the console output:

[00:00:00.794,647] <dbg> LSM6DSL: lsm6dsl_init_chip: failed to reboot device
[00:00:00.794,677] <err> LSM6DSL: Failed to initialize chip
*** Booting nRF Connect SDK d96769faceca ***
Begin init of lsm6ds3tr and regulator 
sensor: device not ready.

My code to run is based of the sample code for the sensor with the lsm6ds3tr_c_en modifications:

/*
 * Copyright (c) 2018 STMicroelectronics
 *
 * SPDX-License-Identifier: Apache-2.0
 */

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

static const struct device *lsm6ds3tr_c_en;

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

static int print_samples;
static int lsm6dsl_trig_cnt;

static struct sensor_value accel_x_out, accel_y_out, accel_z_out;
static struct sensor_value gyro_x_out, gyro_y_out, gyro_z_out;
#if defined(CONFIG_LSM6DSL_EXT0_LIS2MDL)
static struct sensor_value magn_x_out, magn_y_out, magn_z_out;
#endif
#if defined(CONFIG_LSM6DSL_EXT0_LPS22HB)
static struct sensor_value press_out, temp_out;
#endif

#ifdef CONFIG_LSM6DSL_TRIGGER
static void lsm6dsl_trigger_handler(const struct device *dev,
				    const struct sensor_trigger *trig)
{
	static struct sensor_value accel_x, accel_y, accel_z;
	static struct sensor_value gyro_x, gyro_y, gyro_z;
#if defined(CONFIG_LSM6DSL_EXT0_LIS2MDL)
	static struct sensor_value magn_x, magn_y, magn_z;
#endif
#if defined(CONFIG_LSM6DSL_EXT0_LPS22HB)
	static struct sensor_value press, temp;
#endif
	lsm6dsl_trig_cnt++;

	sensor_sample_fetch_chan(dev, SENSOR_CHAN_ACCEL_XYZ);
	sensor_channel_get(dev, SENSOR_CHAN_ACCEL_X, &accel_x);
	sensor_channel_get(dev, SENSOR_CHAN_ACCEL_Y, &accel_y);
	sensor_channel_get(dev, SENSOR_CHAN_ACCEL_Z, &accel_z);

	/* lsm6dsl gyro */
	sensor_sample_fetch_chan(dev, SENSOR_CHAN_GYRO_XYZ);
	sensor_channel_get(dev, SENSOR_CHAN_GYRO_X, &gyro_x);
	sensor_channel_get(dev, SENSOR_CHAN_GYRO_Y, &gyro_y);
	sensor_channel_get(dev, SENSOR_CHAN_GYRO_Z, &gyro_z);

#if defined(CONFIG_LSM6DSL_EXT0_LIS2MDL)
	/* lsm6dsl external magn */
	sensor_sample_fetch_chan(dev, SENSOR_CHAN_MAGN_XYZ);
	sensor_channel_get(dev, SENSOR_CHAN_MAGN_X, &magn_x);
	sensor_channel_get(dev, SENSOR_CHAN_MAGN_Y, &magn_y);
	sensor_channel_get(dev, SENSOR_CHAN_MAGN_Z, &magn_z);
#endif

#if defined(CONFIG_LSM6DSL_EXT0_LPS22HB)
	/* lsm6dsl external press/temp */
	sensor_sample_fetch_chan(dev, SENSOR_CHAN_PRESS);
	sensor_channel_get(dev, SENSOR_CHAN_PRESS, &press);

	sensor_sample_fetch_chan(dev, SENSOR_CHAN_AMBIENT_TEMP);
	sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, &temp);
#endif

	if (print_samples) {
		print_samples = 0;

		accel_x_out = accel_x;
		accel_y_out = accel_y;
		accel_z_out = accel_z;

		gyro_x_out = gyro_x;
		gyro_y_out = gyro_y;
		gyro_z_out = gyro_z;

#if defined(CONFIG_LSM6DSL_EXT0_LIS2MDL)
		magn_x_out = magn_x;
		magn_y_out = magn_y;
		magn_z_out = magn_z;
#endif

#if defined(CONFIG_LSM6DSL_EXT0_LPS22HB)
		press_out = press;
		temp_out = temp;
#endif
	}

}
#endif

int main(void)
{
	int cnt = 0;
	char out_str[64];
	struct sensor_value odr_attr;
    const struct device *const lsm6dsl_dev = DEVICE_DT_GET_ONE(st_lsm6dsl);

	printk("Begin init of lsm6ds3tr and regulator \n");
    /* Initialize the regulator device */
	lsm6ds3tr_c_en = DEVICE_DT_GET(DT_PATH(lsm6ds3tr_c_en));
    if (!device_is_ready(lsm6ds3tr_c_en)) {
        printk("Regulator device not ready\n");
        return 0;
    }

    /* Enable the regulator */
    if (regulator_enable(lsm6ds3tr_c_en) < 0) {
        printk("Failed to enable regulator\n");
        return 0;
    }

	 k_sleep(K_MSEC(10000));

	
	if (!device_is_ready(lsm6dsl_dev)) {
		printk("sensor: device not ready.\n");
		return 0;
	}

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

	if (sensor_attr_set(lsm6dsl_dev, SENSOR_CHAN_ACCEL_XYZ,
			    SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) {
		printk("Cannot set sampling frequency for accelerometer.\n");
		return 0;
	}

	if (sensor_attr_set(lsm6dsl_dev, SENSOR_CHAN_GYRO_XYZ,
			    SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) {
		printk("Cannot set sampling frequency for gyro.\n");
		return 0;
	}

#ifdef CONFIG_LSM6DSL_TRIGGER
	struct sensor_trigger trig;

	trig.type = SENSOR_TRIG_DATA_READY;
	trig.chan = SENSOR_CHAN_ACCEL_XYZ;

	if (sensor_trigger_set(lsm6dsl_dev, &trig, lsm6dsl_trigger_handler) != 0) {
		printk("Could not set sensor type and channel\n");
		return 0;
	}
#endif

	if (sensor_sample_fetch(lsm6dsl_dev) < 0) {
		printk("Sensor sample update error\n");
		return 0;
	}

	while (1) {
		/* Erase previous */
		printk("\0033\014");
		printf("LSM6DSL sensor samples:\n\n");

		/* lsm6dsl accel */
		sprintf(out_str, "accel x:%f ms/2 y:%f ms/2 z:%f ms/2",
							  out_ev(&accel_x_out),
							  out_ev(&accel_y_out),
							  out_ev(&accel_z_out));
		printk("%s\n", out_str);

		/* lsm6dsl gyro */
		sprintf(out_str, "gyro x:%f dps y:%f dps z:%f dps",
							   out_ev(&gyro_x_out),
							   out_ev(&gyro_y_out),
							   out_ev(&gyro_z_out));
		printk("%s\n", out_str);

#if defined(CONFIG_LSM6DSL_EXT0_LIS2MDL)
		/* lsm6dsl external magn */
		sprintf(out_str, "magn x:%f gauss y:%f gauss z:%f gauss",
							   out_ev(&magn_x_out),
							   out_ev(&magn_y_out),
							   out_ev(&magn_z_out));
		printk("%s\n", out_str);
#endif

#if defined(CONFIG_LSM6DSL_EXT0_LPS22HB)
		/* lsm6dsl external press/temp */
		sprintf(out_str, "press: %f kPa - temp: %f deg",
			out_ev(&press_out), out_ev(&temp_out));
		printk("%s\n", out_str);
#endif

		printk("loop:%d trig_cnt:%d\n\n", ++cnt, lsm6dsl_trig_cnt);

		print_samples = 1;
		k_sleep(K_MSEC(2000));
	}
}


And my prj.conf:
CONFIG_STDOUT_CONSOLE=y
CONFIG_I2C=y
CONFIG_SPI=n
CONFIG_SENSOR=y
CONFIG_LSM6DSL_TRIGGER_GLOBAL_THREAD=y
CONFIG_CBPRINTF_FP_SUPPORT=y

CONFIG_LOG=y
CONFIG_LOG_DEFAULT_LEVEL=3
CONFIG_SENSOR_LOG_LEVEL_DBG=y

CONFIG_UART_CONSOLE=y
CONFIG_UART_INTERRUPT_DRIVEN=y
CONFIG_UART_LINE_CTRL=y

I am trying to drive this the proper way but am I missing something obvious?

Should I just ignore the config and drive P1.08 manually?

Thanks for taking a look!
I'm using nRF Connect SDK v2.6.0 (latest available at the time of posting)

  • Thank you for your input !

    This is wild, what do you think is causing this shaky operation?

    Oh and I also followed the out of tree zephyr module repo but then I realized that all that changes is the I2C address and that is defined in the configuration in the recent versions of Zephyr.

  • no clue as to why the issues were happening. I could not narrow it down via the debugger.  Just starting under the debugger did not help, I needed to step through the init code, stepping over most of the secondary function calls before I could let it run.

    I did try changing the tools version back to the 2.6.0, it still works. 

    I did setup to  run west build/flash within a terminal outside of VSCode/nRFConnect by setting appropriate env variables. So I suppose I could have had something wonky there, part built with 2.6 tools, part with 2.5 tools. 

    I suppose it could be a non initialized variable somewhere, or a strange timing issue.

      I think I prefer the eclipse clearing thing out as the resolution. :o)

  • I have the exact same error and my device is not ready during init. I followed this sample for reference but unable to fix the issue. Would be great if you can share the working code and config.

    The lsm6ds3tr_c_en is ready but lsm6dsl_dev is not ready.

    I am on the inverted side of earth so the eclipse may take a while to clear out :)

    main.c:

    #include <stdio.h>
    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <zephyr/drivers/sensor.h>
    #include <zephyr/drivers/gpio.h>
    #include <zephyr/sys/util.h>
    
    #define SLEEP_MS 1000
    #define LEDR_NODE DT_ALIAS(led0)
    #define LEDG_NODE DT_ALIAS(led1)
    #define LEDB_NODE DT_ALIAS(led2)
    
    static const struct gpio_dt_spec statLeds[3] = {
    	GPIO_DT_SPEC_GET(LEDR_NODE, gpios),
    	GPIO_DT_SPEC_GET(LEDG_NODE, gpios),
    	GPIO_DT_SPEC_GET(LEDB_NODE, gpios)
    };
    static const struct device *lsm6dsl_dev = DEVICE_DT_GET_ONE(st_lsm6dsl);
    static const struct device *lsm6ds3tr_c_en = DEVICE_DT_GET(DT_PATH(lsm6ds3tr_c_en));
    
    static int print_samples;
    static int lsm6dsl_trig_cnt;
    static struct sensor_value accel_x_out, accel_y_out, accel_z_out;
    static struct sensor_value gyro_x_out, gyro_y_out, gyro_z_out;
    
    #ifdef CONFIG_LSM6DSL_TRIGGER
    static void lsm6dsl_trigger_handler(const struct device *dev, const struct sensor_trigger *trig)
    {
    	static struct sensor_value accel_x, accel_y, accel_z;
    	static struct sensor_value gyro_x, gyro_y, gyro_z;
    	lsm6dsl_trig_cnt++;
    
    	sensor_sample_fetch_chan(dev, SENSOR_CHAN_ACCEL_XYZ);
    	sensor_channel_get(dev, SENSOR_CHAN_ACCEL_X, &accel_x);
    	sensor_channel_get(dev, SENSOR_CHAN_ACCEL_Y, &accel_y);
    	sensor_channel_get(dev, SENSOR_CHAN_ACCEL_Z, &accel_z);
    
    	/* lsm6dsl gyro */
    	sensor_sample_fetch_chan(dev, SENSOR_CHAN_GYRO_XYZ);
    	sensor_channel_get(dev, SENSOR_CHAN_GYRO_X, &gyro_x);
    	sensor_channel_get(dev, SENSOR_CHAN_GYRO_Y, &gyro_y);
    	sensor_channel_get(dev, SENSOR_CHAN_GYRO_Z, &gyro_z);
    
    	if (print_samples) {
    		print_samples = 0;
    		accel_x_out = accel_x;
    		accel_y_out = accel_y;
    		accel_z_out = accel_z;
    		gyro_x_out = gyro_x;
    		gyro_y_out = gyro_y;
    		gyro_z_out = gyro_z;
    	}
    }
    #endif
    
    
    static int setStatLed(int red, int green, int blue) {
    	return gpio_pin_set_dt(&statLeds[0], red)
    			&& gpio_pin_set_dt(&statLeds[1], green)
    			&& gpio_pin_set_dt(&statLeds[2], blue);
    }
    
    
    int main(void) 
    {
    	char out_str[64];
    	struct sensor_value odr_attr;
    
    	for (unsigned int i = 0; i < 3; i++) {
    		if (!gpio_is_ready_dt(&statLeds[0])) {
    			printk("led %d: not ready\n", i);
    			return 0;
    		}
    		if (gpio_pin_configure_dt(&statLeds[0], GPIO_OUTPUT_ACTIVE) < 0) {
    			printk("led %d: config fail\n", i);
    			return 0;
    		}
    	}
    	setStatLed(1, 0, 0);
    
    	if (!device_is_ready(lsm6ds3tr_c_en)) {
            printk("lsm6ds3tr_c_en: not ready\n");
            return 0;
        }
        /* Enable the regulator */
        if (regulator_enable(lsm6ds3tr_c_en) < 0) {
            printk("lsm6ds3tr_c_en: regulator fail\n");
            return 0;
        }
    	if (!device_is_ready(lsm6dsl_dev)) {
    		printk("st_lsm6dsl: not ready\n");
    		return 0;
    	}
    	printk("devices ready\n");
    	setStatLed(0, 1, 0);
    
    	/* set accel/gyro sampling frequency to 104 Hz */
    	odr_attr.val1 = 104;
    	odr_attr.val2 = 0;
    	if (sensor_attr_set(lsm6dsl_dev, SENSOR_CHAN_ACCEL_XYZ, SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) {
    		printk("Cannot set sampling frequency for accelerometer.\n");
    		return 0;
    	}
    	if (sensor_attr_set(lsm6dsl_dev, SENSOR_CHAN_GYRO_XYZ, SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) {
    		printk("Cannot set sampling frequency for gyro.\n");
    		return 0;
    	}
    
    	#ifdef CONFIG_LSM6DSL_TRIGGER
    	struct sensor_trigger trig;
    	trig.type = SENSOR_TRIG_DATA_READY;
    	trig.chan = SENSOR_CHAN_ACCEL_XYZ;
    	if (sensor_trigger_set(lsm6dsl_dev, &trig, lsm6dsl_trigger_handler) != 0) {
    		printk("Could not set sensor type and channel\n");
    		return 0;
    	}
    	#endif
    
    	if (sensor_sample_fetch(lsm6dsl_dev) < 0) {
    		printk("st_lsm6dsl: sample update err\n");
    		return 0;
    	}
    
    	while (true) {
    		printk("\0033\014");
    
    		sprintf(out_str, "accel x:%f ms/2 y:%f ms/2 z:%f ms/2",
    			sensor_value_to_double(&accel_x_out),
    			sensor_value_to_double(&accel_y_out),
    			sensor_value_to_double(&accel_z_out)
    		);
    		printk("%s\n", out_str);
    
    		/* lsm6dsl gyro */
    		sprintf(out_str, "gyro x:%f dps y:%f dps z:%f dps",
    			sensor_value_to_double(&gyro_x_out),
    			sensor_value_to_double(&gyro_y_out),
    			sensor_value_to_double(&gyro_z_out)
    		);
    
    		printk("%s\n", out_str);
    
    		print_samples = 1;
    		k_msleep(SLEEP_MS);
    	}
    
    	return 0;
    }

    prf.conf:

    CONFIG_STDOUT_CONSOLE=y
    CONFIG_PRINTK=y
    CONFIG_CBPRINTF_FP_SUPPORT=y
    CONFIG_UART_CONSOLE=y
    CONFIG_SENSOR=y
    CONFIG_I2C=y
    CONFIG_SPI=n
    
    CONFIG_LSM6DSL=y
    CONFIG_LSM6DSL_ENABLE_TEMP=n
    CONFIG_LSM6DSL_TRIGGER_GLOBAL_THREAD=y

  •   I've built the code you posted, the main.c and prj.conf in my environment with both the 2.5.2 and 2.6.0 toolchains (at least I'm pretty sure). In both cases the code seems to run just fine on "my machine" ( yeah, I know, what else hidden is different).

    Have you checked your tool/SDK/cmake/Zephyr etc versions against what I posted? 

    Again, I'm running Linux/VSCode/NCS extension/ in a Docker container.

    Also I have the Xiao installed in an expansion board if that matters, which I suppose it might if there are pullups and such on the expansion board that may come into play. (I have no clue on that)

    I also have the Xiao 3.3 volt pin disconnected from the expansion board due to issues I ran into with other expansion boards, I suppose a voltage fluctuation/difference could in theory come into play.

    And for more completeness am using a Segger JLink EDU to upload/run the app.

    I you want to drop your built .elf and .hex files out on a Google drive or some such, I can upload it to my board to see if it works there??

  • I have exacly the same problem. ncs v2.6.1, nrf52840_xxAA_rev2, example lsm6dsl. The device_is_ready statement fails, state 5. I tried to enable pullup in pnctrl for i2c, adjusted delay. Would be really nice to get this running, especially because it does with Arduino.

Related