Issue getting interrupts to work for LSM6DSV16X on a NRF52840

Hey everyone, 

I am having trouble setting up the lsm6dsv16x as a interrupt. I was able to successfully poll the data meaning I can talk and read imu data, but no interrupt mode. 
I tried most of the configuration setup, but not sure what I am missing

Here is part of the code


I did port over the st driver code from here
github.com/.../5cbd8301660f10beee129327326beb92e8af17e9

&i2c0 {
    compatible = "nordic,nrf-twim";
    clock-frequency = <I2C_BITRATE_FAST>;
    status = "okay";
    pinctrl-0 = <&i2c0_default>;
    pinctrl-1 = <&i2c0_sleep>;
    pinctrl-names = "default", "sleep";        
	zephyr,concat-buf-size = <1024>;
    lsm6dsv16x: lsm6dsv16x@6b {
		status = "okay";
        compatible =  "zephyr,custom-lsm6dsv16x";
        int0-gpios = <&gpio0 8 (GPIO_PULL_DOWN | GPIO_ACTIVE_LOW )>;
		label="lsm6dsv16x";
        reg = <0x6b>;  
    };

	bmm350: bmm350@14 {
		status = "okay";
		compatible = "bosch,bmm350";
		reg = <0x14>;
	};

};

const struct gpio_dt_spec interrupt1 = GPIO_DT_SPEC_GET(DT_NODELABEL(lsm6dsv16x), int0_gpios);
static struct gpio_callback gpio_cb;
static lsm6dsv16x_interrupt_mode_t irq;

void IMU::lsm6dsv16x_read_data_irq(void)
{
    uint8_t whoamI;
    int16_t data_raw_acceleration[3];
    double_t acceleration_mg[3];
    lsm6dsv16x_filt_settling_mask_t filt_settling_mask;
    uint8_t tx_buffer[100];

    // Check device ID
    lsm6dsv16x_device_id_get(&dev_ctx, &whoamI);
    if (whoamI != LSM6DSV16X_ID) {
        LOG_ERR("Wrong device ID");
        return;
    }

    // Restore default configuration
    lsm6dsv16x_reset_set(&dev_ctx, LSM6DSV16X_RESTORE_CTRL_REGS);
    lsm6dsv16x_reset_t rst;
    do {
        lsm6dsv16x_reset_get(&dev_ctx, &rst);
    } while (rst != LSM6DSV16X_READY);

    lsm6dsv16x_block_data_update_set(&dev_ctx, PROPERTY_ENABLE);

    // Enable interrupt on data ready
    lsm6dsv16x_pin_int_route_t pin_int = {0};
    pin_int.drdy_xl = PROPERTY_ENABLE;
    lsm6dsv16x_pin_int1_route_set(&dev_ctx, &pin_int);


    /* Configure GPIO interrupt */
    if (!device_is_ready(interrupt1.port)) {
        LOG_ERR("IMU interrupt pin not ready");
        return;
    }

    int ret = gpio_pin_configure_dt(&interrupt1, GPIO_INPUT);
    if (ret != 0) {
        LOG_ERR("Failed to configure IMU interrupt pin: %d", ret);
        return;
    }


    gpio_init_callback(&gpio_cb, imu_irq_callback, BIT(interrupt1.pin));
    gpio_add_callback(interrupt1.port, &gpio_cb);
    
    ret = gpio_pin_interrupt_configure_dt(&interrupt1, GPIO_INT_EDGE_TO_ACTIVE);
    if (ret != 0) {
        LOG_ERR("Failed to configure IMU interrupt: %d", ret);
        return;
    }
    // Set ODR and FS
    lsm6dsv16x_xl_data_rate_set(&dev_ctx, LSM6DSV16X_ODR_AT_120Hz);
    lsm6dsv16x_xl_full_scale_set(&dev_ctx, LSM6DSV16X_2g);

    filt_settling_mask.drdy = PROPERTY_ENABLE;
    filt_settling_mask.irq_xl = PROPERTY_ENABLE;
    filt_settling_mask.irq_g = PROPERTY_ENABLE;
    lsm6dsv16x_filt_settling_mask_set(&dev_ctx, filt_settling_mask);
    lsm6dsv16x_filt_xl_lp2_set(&dev_ctx, PROPERTY_ENABLE);
    lsm6dsv16x_filt_xl_lp2_bandwidth_set(&dev_ctx, LSM6DSV16X_XL_STRONG);
}

  • I'm pretty sure you actually don't need to port ST's generic C drivers because they're already baked into Zephyr. I'm not sure what the exact issue is in your code, but my best guess is it's either your pin configuration -- it may need to be active high with no pulldown and int1/2 rather than int0-- or the way you're setting the DRDY pin. I recommend taking a look at the sensors-on-board sample instead, stripping the main file of everything not related to the LSM6DSV16X (and optionally, removing the runtime code that re-configures the trigger mode parameters), enabling trigger mode in your prj.conf with CONFIG_LSM6DSV16X_TRIGGER_GLOBAL_THREAD=y, and re-testing. This configuration worked for me using the modified sample code on a 52840 DK, protocol-agnostic stuff should be more or less the same:

    &spi1 {
    	lsm6dsv16x@0 {
    		status="okay";
    		compatible = "st,lsm6dsv16x";
    		reg = <0x0>;
    		spi-max-frequency = <1000000>;
    		int1-gpios = <&gpio0 7 0>;
    		int2-gpios = <&gpio0 8 0>;
    		accel-range = <3>;
    		gyro-range = <12>;
    		accel-odr = <10>;
    		gyro-odr = <10>;
    		drdy-pin = <1>;
    		drdy-pulsed;
    	};
    
    	cs-gpios = <&gpio0 29 GPIO_ACTIVE_LOW>;
    };

  • Hey there, 

    I do see there is zephyr drivers, but one thing it is missing is qvar. Which is a feature I need to develop with and st drivers have them already. 

  • You're not choosing one or the other when you use the Zephyr driver, the Zephyr driver calls the stmemsc functions directly. You can always expand the driver to add qvar functionality, or use custom SPI calls alongside the driver.

  • Thanks for that, for sure I will look into the zephyr drivers, I was just used to the stm32 drivers since I did a small project using the same imu with stm32 drivers. But turns out the solution was not as difficult. Through Trial and error, I had to flush/read the flag of the interrupt to reset it right after I set the settings. The issue was, as soon as I configured it, the interrupt pin stayed high. I read through different methods, whether keep it open drain, push pull, latch, not latch. .

    But what worked for me was reading the data ready or use the get data function and boom, my interrupts started firing.  I know why this solution works, but not sure why it is not stated in the stm32 examples. But yes, if qvar does not go our way, then I will use the zephyr drivers . 

Related