Files
esphome-lsm6ds/docs/lsm6ds-status-register-bug.md
T

10 KiB

LSM6DS External Component Bug Investigation

Purpose

This document records the investigation and correction of an LSM6DS external-component bug found while diagnosing recurring ESP32-C6 interrupt-watchdog resets in the RV level sensor.

It separates confirmed driver bugs, supporting diagnostic evidence, fixes made in the rv-lsm6ds branch, validation results, and the still-unproven relationship between these bugs and the interrupt-watchdog resets.

A concise upstream bug report is included at the end.


1. Test environment

Hardware

  • Seeed Studio XIAO ESP32-C6
  • Modulino Movement / LSM6DSOXTR IMU
  • I2C address: 0x6A
  • I2C SDA: GPIO22
  • I2C SCL: GPIO23

Software

  • ESPHome 2026.8.2
  • ESP-IDF framework
  • External component fork: https://git.mr2web.net/mr2web/esphome-lsm6ds.git
  • Working branch: rv-lsm6ds

Relevant configuration:

lsm6ds_i2c:
  id: imu
  i2c_id: i2c_bus
  address: 0x6A
  accel_range: 2G
  gyro_range: 250DPS
  accel_odr: 104HZ
  gyro_odr: "OFF"
  update_interval: 10ms

The accelerometer intentionally remains at 104 Hz. High-rate sampling is required by the RV leveling application because lower sampling previously produced vibration/aliasing-related drift.


2. Original investigation context

The RV level sensor experienced recurring hangs followed by ESP32-C6 interrupt-watchdog resets:

Reason: Interrupt wdt
Crashed core: 0

During a live failure, ESPHome API/entity updates stopped while the device continued responding to ping. It later rebooted and reported the watchdog reset.

The leveling calculation uses accelerometer data only. Gyroscope and temperature data are not required for leveling.

Inspection of the external component showed that its polling update() function reads STATUS_REG and conditionally reads/publishes gyroscope, accelerometer and temperature data. At a 10 ms polling interval this is a high-frequency I2C path.


3. Adding support for ODR OFF

The C++ component already defined:

LSM6DS_ODR_OFF = 0x00

but the ESPHome configuration schema did not expose OFF.

This was corrected so YAML could use:

gyro_odr: "OFF"

OFF is quoted because an unquoted YAML value may be interpreted as boolean false.

Commit:

41cb715d6 lsm6ds: expose OFF output data rate

4. Disabled-sensor read guards

After configuring gyro_odr: "OFF", the driver continued publishing repeated frozen gyroscope values.

A guard was added so a disabled sensor would not be read even if the status test appeared true:

if (this->gyro_odr_ != LSM6DS_ODR_OFF && ...) {
    // gyro read
}

if (this->accel_odr_ != LSM6DS_ODR_OFF && ...) {
    // accelerometer read
}

Commit:

3b86faa44 lsm6ds: skip reads for disabled sensors

After this change:

  • gyroscope publications stopped;
  • temperature continued to update;
  • accelerometer publications unexpectedly disappeared;
  • the application reported IMU DATA INVALID.

Because temperature was still read successfully, the IMU and I2C communication were still functioning. This pointed to the interpretation of STATUS_REG.


5. STATUS_REG diagnostic

Temporary instrumentation was added after reading register 0x1E:

uint8_t status;
if (!this->read_register(0x1E, &status, 1))
  return;

ESP_LOGW(TAG, "STATUS=0x%02X accel_odr=0x%02X gyro_odr=0x%02X",
         status,
         static_cast<uint8_t>(this->accel_odr_),
         static_cast<uint8_t>(this->gyro_odr_));

Diagnostic commits:

e2d4b947e lsm6ds: add temporary status diagnostics
53218bd4d lsm6ds: raise temporary status diagnostic to warning

With:

accel_odr = 0x04  (104 Hz)
gyro_odr  = 0x00  (OFF)

the device repeatedly reported:

STATUS=0x01 accel_odr=0x04 gyro_odr=0x00
STATUS=0x05 accel_odr=0x04 gyro_odr=0x00

0x02 was not observed.

0x05 is 0x01 | 0x04 and appeared when temperature data was also available. This demonstrated that 0x01 was the accelerometer-ready flag, not the gyroscope-ready flag.


6. Confirmed STATUS_REG bug

Correct mapping:

Bit Mask Meaning


0 0x01 XLDA --- accelerometer data available 1 0x02 GDA --- gyroscope data available 2 0x04 TDA --- temperature data available

The external component had XLDA and GDA reversed.

Previous logic was effectively:

if (status & 0x01) {  // GDA - incorrect
    // read gyroscope
}

if (status & 0x02) {  // XLDA - incorrect
    // read accelerometer
}

Corrected implementation:

if (this->gyro_odr_ != LSM6DS_ODR_OFF && (status & 0x02)) {  // GDA
    // read gyroscope
}

if (this->accel_odr_ != LSM6DS_ODR_OFF && (status & 0x01)) {  // XLDA
    // read accelerometer
}

Temperature remains:

if (status & 0x04) {  // TDA
    // read temperature
}

The temporary diagnostic logging was removed in the final correction.

Commit:

7adb22de2 lsm6ds: fix swapped accel and gyro status bits

7. Validation

The firmware containing commit 7adb22de2 was deployed with:

Accelerometer ODR: 104 Hz
Gyroscope ODR:     OFF
Polling interval:  10 ms

After correction:

  • accelerometer X/Y/Z publishes normally;
  • gyroscope values no longer publish;
  • temperature continues to update;
  • raw and calibrated pitch/roll publish normally;
  • orientation calibration reports READY;
  • RV Level diagnostic reports OK;
  • activation from INACTIVE to ACTIVE works normally.

This confirms the XLDA/GDA mask error independently of the watchdog investigation.


8. Relevant commit history

7adb22de2 lsm6ds: fix swapped accel and gyro status bits
53218bd4d lsm6ds: raise temporary status diagnostic to warning
e2d4b947e lsm6ds: add temporary status diagnostics
3b86faa44 lsm6ds: skip reads for disabled sensors
41cb715d6 lsm6ds: expose OFF output data rate

Branch: rv-lsm6ds

Repository: https://git.mr2web.net/mr2web/esphome-lsm6ds.git


9. Interrupt-watchdog relationship

The STATUS_REG bug was discovered while investigating recurring ESP32-C6 resets reporting:

Reason: Interrupt wdt
Crashed core: 0

Earlier firmware polled the LSM6DS every 10 ms with both accelerometer and gyroscope configured at high rate. The leveling application requires accelerometer data but not gyroscope data.

The corrected firmware removes unnecessary gyroscope activity and fixes incorrect status-bit handling.

Confirmed

  1. XLDA and GDA status masks were reversed.
  2. 0x01 is XLDA and 0x02 is GDA.
  3. The configuration schema did not expose the already-supported C++ LSM6DS_ODR_OFF value.
  4. A sensor configured with ODR OFF should not be read by the polling path.
  5. With corrected masks, accelerometer at 104 Hz and gyroscope OFF operate as expected.

Not yet proven

It has not been established that the reversed status bits, unnecessary gyroscope path, or their combined workload caused the ESP32-C6 interrupt-watchdog resets.

The corrected firmware is being left unchanged for an endurance test.


10. Exact endurance-test firmware artifacts

Exact ELF preserved on the RockPi:

/srv/docker/esphome/firmware-archive/rv-level/2026-09-20_2148/firmware.elf

SHA-256:

dca98d924fb09c63646d59a1ed7a10e48790692ae67c51bf260bd0275b2d5171

Corresponding OTA image:

/srv/docker/esphome/firmware-archive/rv-level/2026-09-20_2148/firmware.ota.bin

SHA-256:

1e7dc78e4b40fe7b1f7f31294c70968b5cf6736840e4fd37926a64afd1477d67

These came from the ESPHome remote build generated at approximately 21:48 on 2026-09-20.

If another watchdog reset occurs, its PC and BT addresses should be decoded against this exact firmware.elf, not a rebuilt ELF.


Upstream Bug Report

LSM6DS STATUS_REG XLDA/GDA masks are reversed

The LSM6DS base component has the XLDA and GDA bits of STATUS_REG (0x1E) reversed.

Affected logic treated:

status & 0x01  // GDA
status & 0x02  // XLDA

Correct mapping:

bit 0 / 0x01 = XLDA — accelerometer data available
bit 1 / 0x02 = GDA  — gyroscope data available
bit 2 / 0x04 = TDA  — temperature data available

Reproduction

Test environment:

  • LSM6DSOXTR
  • ESP32-C6
  • ESPHome 2026.8.2
  • I2C
  • accelerometer ODR: 104 Hz
  • gyroscope ODR: OFF
  • polling interval: 10 ms

Temporary logging with:

accel_odr=0x04
gyro_odr=0x00

repeatedly produced:

STATUS=0x01 accel_odr=0x04 gyro_odr=0x00
STATUS=0x05 accel_odr=0x04 gyro_odr=0x00

0x02 was not observed.

This is consistent with bit 0 being XLDA and bit 2 being TDA.

Fix

if (this->gyro_odr_ != LSM6DS_ODR_OFF && (status & 0x02)) {  // GDA
    ...
}

if (this->accel_odr_ != LSM6DS_ODR_OFF && (status & 0x01)) {  // XLDA
    ...
}

After correction with accelerometer at 104 Hz and gyroscope OFF:

  • accelerometer values update normally;
  • no gyroscope values are read/published;
  • temperature continues to update normally.

Fix commit:

7adb22de2 lsm6ds: fix swapped accel and gyro status bits

Related work also exposes OFF as an ODR configuration option and prevents reads for an output whose ODR is OFF. Those changes are separable from the XLDA/GDA correction.

No claim is currently made that the status-bit bug caused the separately observed ESP32-C6 interrupt-watchdog resets.