Bug in driver for the LIS2DU12 accelerometer sensor at init step

Hi,

I found a bug in the init part of the LIS2DU12 driver. The driver tries to reboot the LIS2DU12 sensor using the SW_RESET bit in CTRL1 register even if it is not in power-down mode with ODR bits with value 0x000 in the CTRL5 register. It is written in the LIS2DU12 datasheet to reset the device it has to be in power down mode (see page 30 in LIS2DU12 datasheet).
If the nRF is reseted and the LIS2DU12 was previously configured to an ODR not powerdown, you are expecting a reset timeout error in the LIS2DUdriver

Here is how to reproduce :

  1. Have a nRF52832 (or other) dev kit with a LIS2DU12 connected to it using SPI
  2. Have it properly configured and starting well, and set the accel-odr with a value different from OFF
  3. Flash the nRF and things are going wel
  4. Reset the nRF without powering off the board and LIS2DU12
  5. You got the LIS2DU12 reset error 

Having a look at the code brings this explaination : checkout this file https://github.com/nrfconnect/sdk-zephyr/blob/main/drivers/sensor/st/lis2du12/lis2du12.c#L65

static inline int lis2du12_reboot(const struct device *dev)
{
	const struct lis2du12_config *cfg = dev->config;
	stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
	lis2du12_status_t status;
	uint8_t tries = 10;

	if (lis2du12_init_set(ctx, LIS2DU12_RESET) < 0) {
		return -EIO;
	}

	do {
		if (!--tries) {
			LOG_ERR("sw reset timed out");
			return -ETIMEDOUT;
		}
		k_usleep(50);

		if (lis2du12_status_get(ctx, &status) < 0) {
			return -EIO;
		}
	} while (status.sw_reset != 0);

	if (lis2du12_init_set(ctx, LIS2DU12_DRV_RDY) < 0) {
		return -EIO;
	}

	return 0;
}

As we can see, before sending the reset command, nothing is done to be sure the ODR value is set to 000.


A suggested fix it to set ODR to 000 before reboot :

static inline int lis2du12_reboot(const struct device *dev)
{
	const struct lis2du12_config *cfg = dev->config;
	stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
	lis2du12_status_t status;
	uint8_t tries = 10;

    // set ODR to 000 before reset
	if (lis2du12_accel_set_odr_raw(dev, LIS2DU12_OFF) < 0) {
		return -EIO;
	}
	
	if (lis2du12_init_set(ctx, LIS2DU12_RESET) < 0) {
		return -EIO;
	}

	do {
		if (!--tries) {
			LOG_ERR("sw reset timed out");
			return -ETIMEDOUT;
		}
		k_usleep(50);

		if (lis2du12_status_get(ctx, &status) < 0) {
			return -EIO;
		}
	} while (status.sw_reset != 0);

	if (lis2du12_init_set(ctx, LIS2DU12_DRV_RDY) < 0) {
		return -EIO;
	}

	return 0;
}

Related