Power off LSM6DSO Sensor between measurements

Hello,
I want to switch off the power supply to my LSM6DSO IMU between measurements. The measurements only take place once a minute. If I operate it permanently with voltage, it would consume about 200uA. To save this, I switched off the voltage. Unfortunately this does not work, I no longer get any values back when I query the sensor. I tried it with different delays between switching on and measuring, but 0 values are always displayed. If I constantly power the IMU, everything works.
You can watch it briefly in a video. www.youtube.com/watch


nrf connect sdk 2.1.2

What do I have to change to make this work? or how can I initialize the lsm6dso manually?

Best regards, Jonas

		gpio_pin_set(gpio_dev, VDD_PIN_IMU, 1);
		k_sleep(K_MSEC(10));
		remap_pins_imu();
		pm_device_action_run(imu_dev,PM_DEVICE_ACTION_TURN_ON);		
		get_rotation(imu_dev);
		pm_device_action_run(imu_dev,PM_DEVICE_ACTION_TURN_OFF);
		k_sleep(K_MSEC(10));
		// gpio_pin_set(gpio_dev, VDD_PIN_IMU, 0);
dynamic_pinctrl_evaluation.zip

  • Oh, I accidentally closed the case. But it still doesn't work. I've now observed all relevant returns and increased the delay. The first query looks successful, the following ones don't. https://youtu.be/5-Qi-nJ3vfs
    The pin assignment works, I switch between both i2c busses and the pressure sensor brings suitable values. I could also see that when debugging

  • I am not able to build your project. What NCS version are you using? Please try to build it in an unmodified version of the SDK to see whether you can build it before uploading.

    In your main loop you call e.g. remap_pins_pressure(). This is a function that uses pm_device_action_run(). What does this function return?

    Then you have get_rotation, which uses a lot of functions. What does sensor_sample_fetch_chan() and sensor_channel_get() return when the gyro values are 0?

    BR,

    Edvin

  • Hey Edvin, 

    My Project is build with sdk 2.1.2, I have tested it now on a different Device and a fresh installation + zipped it again. If there are any problems, please add a new build configuration with the board: we_ophelia1ev_nrf52805. this should work. 

    I used the uses pm_device_action_run() function with the i2c driver. I think this was wrong. Return value was -134. But I commented it out right now.

    ensor_sample_fetch_chan() and sensor_channel_get() return both '0' regardless of correct and incorrect measured values. 

    dynamic_pinctrl_evaluation_3.zip

    Furthermore, I have now edited the driver, but it still does not work 100%. While debugging I noticed that after the function pm_device_action_run(const struct device *dev,
    enum pm_device_action action) is called, pm is 0x0 and the driver/ init function is not called. I think i have to set a pm config somewhere for the lsm6dso driver. 

    lsm6dso.c

    ...
    
    #ifdef CONFIG_PM_DEVICE
    static int lsm6dso_pm_action(const struct device *dev,
    			    enum pm_device_action action)
    {
    	int ret = 0;
    
    	switch (action) {
    	case PM_DEVICE_ACTION_RESUME:
    		/* Re-initialize the chip */
    		ret = lsm6dso_init(dev);
    		break;
    	case PM_DEVICE_ACTION_SUSPEND:
    		/* Put the chip into sleep mode */
    		// ret = bme280_reg_write(dev,
    		// 	BME280_REG_CTRL_MEAS,
    		// 	BME280_CTRL_MEAS_OFF_VAL);
    
    		// if (ret < 0) {
    		// 	LOG_DBG("CTRL_MEAS write failed: %d", ret);
    		// }
    		break;
    	default:
    		return -ENOTSUP;
    	}
    
    	return ret;
    }
    #endif /* CONFIG_PM_DEVICE */
    
    ...
    
    #define LSM6DSO_DEFINE(inst)						\
    	static struct lsm6dso_data lsm6dso_data_##inst;			\
    	static const struct lsm6dso_config lsm6dso_config_##inst =	\
    		COND_CODE_1(DT_INST_ON_BUS(inst, spi),			\
    			(LSM6DSO_CONFIG_SPI(inst)),			\
    			(LSM6DSO_CONFIG_I2C(inst)));			\
    	PM_DEVICE_DT_INST_DEFINE(inst, lsm6dso_pm_action); \
    	LSM6DSO_DEVICE_INIT(inst)
    
    DT_INST_FOREACH_STATUS_OKAY(LSM6DSO_DEFINE)
    

  • I don't have the sensor that you are using, so it is a bit difficult for me to test. If you are stuck, you can try to analyze the I2C wires using a logic analyzer, to see if the data back and forth is what you expect it to be. 

    Best regards,

    Edvin

  • Thanks, I just added the power management functionality in the lsm6dso driver and receive now measurement values. Not correct ones, but better than only zeros, 
    If someone has the same Problem here a quick guide how to add power management functionality to a sensor driver: 

    The <driver_model>.c file has to be expanded with a pm_action function. 

    #ifdef CONFIG_PM_DEVICE
    static int lsm6dso_pm_action(const struct device *dev,
    			    enum pm_device_action action)
    {
    	int ret = 0;
    
    	switch (action) {
    	case PM_DEVICE_ACTION_RESUME:
    		/* Re-initialize the chip */
    		ret = lsm6dso_init(dev);
    		break;
    	case PM_DEVICE_ACTION_SUSPEND:
    		/* Put the chip into sleep mode - 
    		I haven't done this, because I don't need it actually */
    		break;
    	default:
    		return -ENOTSUP;
    	}
    	return ret;
    }
    #endif /* CONFIG_PM_DEVICE */

    Next the DEVICE_INIT define has to be edited: 

    #define LSM6DSO_DEVICE_INIT(inst)					\
    	DEVICE_DT_INST_DEFINE(inst,					\
    			    lsm6dso_init,				\
    			    PM_DEVICE_DT_INST_GET(inst),	\  // <- instead of NULL add this
    			    &lsm6dso_data_##inst,			\
    			    &lsm6dso_config_##inst,			\
    			    POST_KERNEL,				\
    			    CONFIG_SENSOR_INIT_PRIORITY,		\
    			    &lsm6dso_driver_api);

    Lastly edit the <Device>_DEFINE :

    #define LSM6DSO_DEFINE(inst)						\
    	static struct lsm6dso_data lsm6dso_data_##inst;			\
    	static const struct lsm6dso_config lsm6dso_config_##inst =	\
    		COND_CODE_1(DT_INST_ON_BUS(inst, spi),			\
    			(LSM6DSO_CONFIG_SPI(inst)),			\
    			(LSM6DSO_CONFIG_I2C(inst)));			\
    	PM_DEVICE_DT_INST_DEFINE(inst, lsm6dso_pm_action); \     // <- add this
    	LSM6DSO_DEVICE_INIT(inst)
    
    DT_INST_FOREACH_STATUS_OKAY(LSM6DSO_DEFINE)

    when you call pm_device_action_run(dev,PM_DEVICE_ACTION_RESUME); the init function in the device driver is called.

    Thanks   Slight smile

Related