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)

Parents
  • After much confusion and life interruptions it would seem that I do have this working, via the LSM6DSL sample out of the box, or so I think.

    I was having much trouble with different things, in one case the app would crash without writing to the UART unless I stepped through the initialization with the debugger, in another case it would not flash due to some obscure overflow error.

    So, maybe this is all just a figment of my imagination.

    My setup is:
    - running within a Docker image
    - using VSCode via its remote container connected to the Docker image
    - nRFConnect VSCode extension
    - Xiao board on a Seeed Xiao expansion board
    - Uploading via Segger J-Link EDU
    - On Linux

    At the time of the above weirdness I had changed the nrfConnect tools version number, for some silly reason, from 2.5.2 to 2.6.0.
    I don't know if that's when things fell apart or not. But, I did hear on a webcast today that the presenter was having some issues with the later 2.6.0 version of the tools, so perhaps it did have some impact??

    At the same time I was trying to implement a version of LSM6DS3 as seen here: https://iwasz.pl/electronics/2021-06-18-out-of-tree-zephyr-module.md/     Got nowhere except the above debug problem.

    Then I changed the nRFConnect tool version back to 2.5.2 and went way for a few days, then things started working, don't ask why though. (Perhaps the local total eclipse fixed it)

    The versions I believe I'm currently using, and were I found the version info:

    Seeed Xiao bootloader: (double click Xiao reset button)
    ------------------------
    UF2 Bootloader 0.6.1 lib/nrfx (v2.0.0) lib/tinyusb (0.10.1-293-gaf8e5a90) lib/uf2 (remotes/origin/configupdate-9-gadbb8c7)
    Model: Seeed XIAO nRF52840
    Board-ID: Seeed_XIAO_nRF52840_Sense
    SoftDevice: S140 version 7.3.0
    Date: Nov 12 2021

    OS/SDKs
    ----------
    Zephyr
    --------
    source: github.com/.../sdk-zephyr
    3.4.99.0 (VERSION file) A Nordic downstream version I'm pretty sure
    git HEAD: 2e2523efe52a7ac89f0567b8798fd857b1e71ae3"


    nRF Connect SDK
    ----------------
    source: github.com/.../sdk-nrf
    2.5.0 (VERSION file)
    git HEAD: 1fae141fc6713dd331b797fc96c90dc84552242d

    nRFX Common Libraries (nRFxlib)
    ---------------------------------
    github.com/.../sdk-nrfxlib
    2.5.0 (.git/FETCH_HEAD)
    git HEAD: 78cc07ed7c9f168c3d6316db5af969ac5f7c977a

    nRF Tool Chain
    ---------------
    loaded via VSCode nRFConnect extension
    nRFConnect SDK ToolChain: 2.5.20231017.513615545433 (From build output)


    Versions reported from build output:
    ------------------------------------------
    -- CMake version: 3.20.5
    -- Using NCS Toolchain 2.5.20231017.513615545433 for building.
    -- Found Python3: ~/ncs/toolchains/7795df4459/usr/local/bin/python3 (found suitable version "3.8.2")
    -- Found west (found suitable version "1.1.0")
    -- Board: xiao_ble_sense
    -- Found host-tools: zephyr 0.16.1 (~/ncs/toolchains/7795df4459/opt/zephyr-sdk)
    -- Found toolchain: zephyr 0.16.1 (~/ncs/toolchains/7795df4459/opt/zephyr-sdk)
    -- Found Dtc: ~/ncs/toolchains/7795df4459/usr/local/bin/dtc (found suitable version "1.4.7", minimum required is "1.4.6")
    -- Found BOARD.dts: ~/ncs/v2.5.0/zephyr/boards/arm/xiao_ble/xiao_ble_sense.dts
    -- The C compiler identification is GNU 12.2.0
    -- The CXX compiler identification is GNU 12.2.0
    -- The ASM compiler identification is GNU
    -- Found assembler: ~/ncs/toolchains/7795df4459/opt/zephyr-sdk/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc
    -- Zephyr version: 3.4.99 (~/ncs/v2.5.0/zephyr), build: 2e2523efe52a

    I suppose when the moon comes around again it will fall apart again...

  • 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.

Reply Children
  • 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??

  • Hey   can I take you up on this?
    If this works then we can eliminate an issue with the Zephyr environment vs the XIAO Sense board.

  • Ughh, my message to you has been marked as spam by the mods, can you please help at least with un-marking the message as spam, thank you!

Related