From bbdb141e198d74b0dcfa85545ba54e9080fa9d7a Mon Sep 17 00:00:00 2001 From: Toby Date: Sun, 20 Sep 2026 22:52:10 +0200 Subject: [PATCH] docs: document LSM6DS status register bug investigation --- docs/lsm6ds-status-register-bug.md | 436 +++++++++++++++++++++++++++++ 1 file changed, 436 insertions(+) create mode 100644 docs/lsm6ds-status-register-bug.md diff --git a/docs/lsm6ds-status-register-bug.md b/docs/lsm6ds-status-register-bug.md new file mode 100644 index 000000000..dbc3c5740 --- /dev/null +++ b/docs/lsm6ds-status-register-bug.md @@ -0,0 +1,436 @@ +# 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: + +``` yaml +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: + +``` text +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: + +``` cpp +LSM6DS_ODR_OFF = 0x00 +``` + +but the ESPHome configuration schema did not expose `OFF`. + +This was corrected so YAML could use: + +``` yaml +gyro_odr: "OFF" +``` + +`OFF` is quoted because an unquoted YAML value may be interpreted as +boolean false. + +Commit: + +``` text +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: + +``` cpp +if (this->gyro_odr_ != LSM6DS_ODR_OFF && ...) { + // gyro read +} + +if (this->accel_odr_ != LSM6DS_ODR_OFF && ...) { + // accelerometer read +} +``` + +Commit: + +``` text +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`: + +``` cpp +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(this->accel_odr_), + static_cast(this->gyro_odr_)); +``` + +Diagnostic commits: + +``` text +e2d4b947e lsm6ds: add temporary status diagnostics +53218bd4d lsm6ds: raise temporary status diagnostic to warning +``` + +With: + +``` text +accel_odr = 0x04 (104 Hz) +gyro_odr = 0x00 (OFF) +``` + +the device repeatedly reported: + +``` text +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: + +``` cpp +if (status & 0x01) { // GDA - incorrect + // read gyroscope +} + +if (status & 0x02) { // XLDA - incorrect + // read accelerometer +} +``` + +Corrected implementation: + +``` cpp +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: + +``` cpp +if (status & 0x04) { // TDA + // read temperature +} +``` + +The temporary diagnostic logging was removed in the final correction. + +Commit: + +``` text +7adb22de2 lsm6ds: fix swapped accel and gyro status bits +``` + +------------------------------------------------------------------------ + +## 7. Validation + +The firmware containing commit `7adb22de2` was deployed with: + +``` text +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 + +``` text +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: + +``` text +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: + +``` text +/srv/docker/esphome/firmware-archive/rv-level/2026-09-20_2148/firmware.elf +``` + +SHA-256: + +``` text +dca98d924fb09c63646d59a1ed7a10e48790692ae67c51bf260bd0275b2d5171 +``` + +Corresponding OTA image: + +``` text +/srv/docker/esphome/firmware-archive/rv-level/2026-09-20_2148/firmware.ota.bin +``` + +SHA-256: + +``` text +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: + +``` cpp +status & 0x01 // GDA +status & 0x02 // XLDA +``` + +Correct mapping: + +``` text +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: + +``` text +accel_odr=0x04 +gyro_odr=0x00 +``` + +repeatedly produced: + +``` text +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 + +``` cpp +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: + +``` text +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.