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

  • Has anyone else tried to move back to nRF Connect SDK V2.5.0? You all seem to be using 2.6.1?

    As mentioned above, it seems to work for me using SDK 2.5.0. I did finally install SDK V2.6.1 and do indeed see the reported  "not ready" message when building with 2.6.1.

    2.5.0 works,  2.6.1 does not.

    I do see a difference in one of the board files, xiao_ble_defconfig.  "CONFIG_PINCTRL=y" was removed in the 2.6.1 version.

    At this point my build environment workspace is giving me trouble ( lost ability to switch SDK versions within VSCode nRFConnect extension) so I cannot see if adding it back into the 2.6.1 version will solve the issue. I'm sure there are other changes between the two versions as well, I only compared the sample and the board files.

    Again, I would give SDK V2.5.0 a shot, see what happens.

  • Thank  for the hint!

    I just tried the following code on these ncs versions:

    SDK Toolchain LSM6DSL Works?
    2.5.0 2.5.0 YES
    2.5.3 2.5.3 YES
    2.5.3 2.6.1 YES
    2.6.0 2.6.0 NO
    2.6.1 2.6.1 NO

     main.c:

    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <zephyr/drivers/sensor.h>
    #include <zephyr/drivers/gpio.h>
    #include <zephyr/sys/util.h>
    #include <stdio.h>
    
    #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 int print_samples;
    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;
    
    
    static inline float out_ev(struct sensor_value *val)
    {
    	return (val->val1 + (float)val->val2 / 1000000);
    }
    
    static void setStatLed(int red, int green, int blue) {
    	gpio_pin_set_dt(&statLeds[0], red);
    	gpio_pin_set_dt(&statLeds[1], green);
    	gpio_pin_set_dt(&statLeds[2], blue);
    	return;
    }
    
    #ifdef CONFIG_LSM6DSL_TRIGGER
    static void lsm6dsl_trigger_handler(const struct device *dev, struct sensor_trigger *trig)
    {
    	static struct sensor_value accel_x, accel_y, accel_z;
    	static struct sensor_value gyro_x, gyro_y, gyro_z;
    
    	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
    
    int main(void)
    {
    	char out_str[64];
    	struct sensor_value odr_attr;
    	const struct device *lsm6dsl_dev = DEVICE_DT_GET_ONE(st_lsm6dsl);
    
    	for (unsigned int i = 0; i < 3; i++) {
    		if (!gpio_is_ready_dt(&statLeds[i])) {
    			printk("led %d: not ready\n", i);
    			return 0;
    		}
    		if (gpio_pin_configure_dt(&statLeds[i], GPIO_OUTPUT_ACTIVE) < 0) {
    			printk("led %d: config fail\n", i);
    			return 0;
    		}
    	}
    	setStatLed(1, 0, 0);
    	k_msleep(100);
    
    	if (lsm6dsl_dev == NULL) {
    		printk("Could not get LSM6DSL device\n");
    		return 0;
    	}
    	if (!device_is_ready(lsm6dsl_dev)) {
    		printk("LSM6DSL: 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;
    	}
    	setStatLed(0, 1, 0);
    	k_msleep(100);
    
    	while (1) {
    		setStatLed(0, 0, 1);
    		/* 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\n", out_str);
    
    		print_samples = 1;
    		setStatLed(0, 0, 0);
    		k_msleep(50);
    	}
    
    	return 0;
    }
    

    Note: the k_msleep(100) is not required, its just to show the status on builtin-led.

    prj.conf:

    CONFIG_PRINTK=y
    CONFIG_CBPRINTF_FP_SUPPORT=y
    CONFIG_UART_CONSOLE=y
    CONFIG_SENSOR=y
    
    CONFIG_LSM6DSL=y
    CONFIG_LSM6DSL_ENABLE_TEMP=n
    CONFIG_LSM6DSL_TRIGGER_GLOBAL_THREAD=y
    

    I also tried adding CONFIG_PINCTRL=y to ncs/v2.6.1/zephyr/boards/arm/xiao_ble/xiao_ble_defconfig in SDK 2.6.1 but still does not work, and has the same issue.

    This clearly means something has changed and unset in 2.6.x which is not directly related to xiao_ble as per quick diff.

    Time to investigate the ncs SDK now!

        This should be somewhat helpful.

  • Thank you for putting time in it. Bugs like this in the framework are really frustrating and time consuming. Hopefully Nordic will fix this soon. And indeed switching back to a previous framework is a headache too, for instance, when I set the SDK to 2.5.3 and make a new build configuration, the debugger does not do anything.

    (debug with SDK 2.5.3)

    JLinkGDBServerCLExe: SEGGER J-Link GDB Server V7.96h Command Line Version
    JLinkGDBServerCLExe: 
    JLinkGDBServerCLExe: JLinkARM.dll V7.96h (DLL compiled May 15 2024 15:39:51)
    JLinkGDBServerCLExe: 
    JLinkGDBServerCLExe: -----GDB Server start settings-----
    JLinkGDBServerCLExe: GDBInit file:                  none
    JLinkGDBServerCLExe: GDB Server Listening port:     43081
    JLinkGDBServerCLExe: SWO raw output listening port: 2332
    JLinkGDBServerCLExe: Terminal I/O port:             2333
    JLinkGDBServerCLExe: Accept remote connection:      yes
    JLinkGDBServerCLExe: Generate logfile:              off
    JLinkGDBServerCLExe: Verify download:               off
    JLinkGDBServerCLExe: Init regs on start:            off
    JLinkGDBServerCLExe: Silent mode:                   on
    JLinkGDBServerCLExe: Single run mode:               on
    JLinkGDBServerCLExe: Target connection timeout:     0 ms
    JLinkGDBServerCLExe: ------J-Link related settings------
    JLinkGDBServerCLExe: J-Link Host interface:         USB
    JLinkGDBServerCLExe: J-Link script:                 none
    JLinkGDBServerCLExe: J-Link settings file:          none
    JLinkGDBServerCLExe: ------Target related settings------
    JLinkGDBServerCLExe: Target device:                 nRF52840_xxAA
    JLinkGDBServerCLExe: Target device parameters:      none
    JLinkGDBServerCLExe: Target interface:              SWD
    JLinkGDBServerCLExe: Target interface speed:        12000kHz
    JLinkGDBServerCLExe: Target endian:                 little
    JLinkGDBServerCLExe: 
    =thread-group-added,id="i1"
    =cmd-param-changed,param="pagination",value="off"
    0x00003958 in ?? ()

    (debug with SDK 2.6.1)

    JLinkGDBServerCLExe: SEGGER J-Link GDB Server V7.96h Command Line Version
    JLinkGDBServerCLExe: 
    JLinkGDBServerCLExe: JLinkARM.dll V7.96h (DLL compiled May 15 2024 15:39:51)
    JLinkGDBServerCLExe: 
    JLinkGDBServerCLExe: -----GDB Server start settings-----
    JLinkGDBServerCLExe: GDBInit file:                  none
    JLinkGDBServerCLExe: GDB Server Listening port:     33091
    JLinkGDBServerCLExe: SWO raw output listening port: 2332
    JLinkGDBServerCLExe: Terminal I/O port:             2333
    JLinkGDBServerCLExe: Accept remote connection:      yes
    JLinkGDBServerCLExe: Generate logfile:              off
    JLinkGDBServerCLExe: Verify download:               off
    JLinkGDBServerCLExe: Init regs on start:            off
    JLinkGDBServerCLExe: Silent mode:                   on
    JLinkGDBServerCLExe: Single run mode:               on
    JLinkGDBServerCLExe: Target connection timeout:     0 ms
    JLinkGDBServerCLExe: ------J-Link related settings------
    JLinkGDBServerCLExe: J-Link Host interface:         USB
    JLinkGDBServerCLExe: J-Link script:                 none
    JLinkGDBServerCLExe: J-Link settings file:          none
    JLinkGDBServerCLExe: ------Target related settings------
    JLinkGDBServerCLExe: Target device:                 nRF52840_xxAA
    JLinkGDBServerCLExe: Target device parameters:      none
    JLinkGDBServerCLExe: Target interface:              SWD
    JLinkGDBServerCLExe: Target interface speed:        12000kHz
    JLinkGDBServerCLExe: Target endian:                 little
    JLinkGDBServerCLExe: 
    =thread-group-added,id="i1"
    =cmd-param-changed,param="pagination",value="off"
    z_arm_reset () at /home/bergm006/ncs/v2.6.1/zephyr/arch/arm/core/cortex_m/reset.S:73
    73	    movs.n r0, #0
    [New Remote target]
    [New Thread 536872392]
    [New Thread 536871944]
    [New Thread 536872776]
    [New Thread 536872152]
    [New Thread 536872568]
    [Switching to Thread 536872568]
    
    Thread 7 hit Breakpoint 1, main () at /home/bergm006/nrf-projects/lsm6dsl/src/main.c:99
    99	{

  • Might verify the Toolchain version required for v2.6.1??

    I was having some trouble debugging v2.6.1 with Segger Ozone. I noticed when I switched SDK versions from 2.5.0 to 2.6.1 there were a number of "outdated" messages for various tools reported in the VSCode output view.

    So I updated the nrf toolchain version to 2.6.0. The issue with Ozone seemed to clear up, though it could be for unrelated reasons.

Reply
  • Might verify the Toolchain version required for v2.6.1??

    I was having some trouble debugging v2.6.1 with Segger Ozone. I noticed when I switched SDK versions from 2.5.0 to 2.6.1 there were a number of "outdated" messages for various tools reported in the VSCode output view.

    So I updated the nrf toolchain version to 2.6.0. The issue with Ozone seemed to clear up, though it could be for unrelated reasons.

Children
  • So with the debugger behaving properly I may have a work around. 

    It seems if I put a small k_sleep() at the entrance to   lsm6dsl_init() it would start behaving. 

     $InstallDir/v2.6.1/zephyr/drivers/sensor/lsm6dsl/lsm6dsl.c

    <

    static int lsm6dsl_init(const struct device *dev)
    {
    	int ret;
    	k_sleep(K_MSEC(1));
    	const struct lsm6dsl_config * const config = dev->config;
    
    	ret = config->bus_init(dev);
    	
    	...

    You might give it a shot. I don't know why at this point.

    SDK: 2.6.1
    ToolChain: 2.6.0
    Then again, not always work. Some sort of timing issue I guess.
  • In trying to debug this  (V2.6.1) the only thing I've found is that when setting breakpoints at various points through the sensor init processing, it will then work from then on. Nothing consistent enough to run down. Could be timing with the i2c xfers, new thread interactions seen with 2.6.1, debugger changing timing, etc...

    It's beyond my ability to look at it further.

Related