mirror of
https://github.com/apache/nuttx.git
synced 2026-10-04 04:38:10 +00:00
sensors/lsm6ds3trc: reset the sensor before arming its interrupt
lsm6ds3trc_register() attached the INT1 handler without ever putting the sensor into a known state, which made every reboot a coin toss. The LSM6DS3TR-C has its own supply and its own reset. An MCU reset -- watchdog, RTS pin, esptool, a plain "reboot" -- does not reset it, so it comes back still holding whatever the previous session configured: for this driver, INT1_CTRL.INT1_FTH still set and a FIFO still over its watermark, i.e. INT1 already asserted at registration time. With the (correct) ONHIGH level trigger, arming an already-active line storms immediately. The board then wedges during bring-up with no console output and no crash dump -- it looked like a boot that stopped right after Wi-Fi init and never reached NSH. That symptom cost a long detour: it was blamed in turn on a stuck I2C bus, on corrupted NVS/Wi-Fi calibration, and finally on a failing USB-serial adapter, because the one thing that reliably cleared it was unplugging the board -- which is simply the only way to power-cycle the *sensor*. SW_RESET (CTRL3_C bit 0) clears INT1_CTRL and FIFO_CTRL back to 0, which deasserts INT1. It self-clears in ~50 us; poll for it rather than assume, and retry the write a few times, since the bus has been seen to return -EIO on the very first transaction after a cold boot. Carry on if the reset never takes. An unreset sensor risks the storm this exists to prevent, but refusing to register leaves the application with no /dev/uorb/sensor_accel0 at all, which is fatal to it -- a single -EIO here took the whole collar down once. Losing the sensor to guard against a maybe-storm is the wrong trade. Assisted-by: Claude:claude-opus-5 Signed-off-by: Felipe Moura <moura.fmo@gmail.com>
This commit is contained in:
parent
3d267aab2a
commit
159ef8105b
1 changed files with 82 additions and 0 deletions
|
|
@ -1630,6 +1630,88 @@ int lsm6ds3trc_register(FAR struct i2c_master_s *i2c, uint8_t addr,
|
|||
goto unreg_gyro;
|
||||
}
|
||||
|
||||
/* Put the sensor into its power-on register state before anything else
|
||||
* touches it, and in particular before the interrupt is attached.
|
||||
*
|
||||
* The LSM6DS3TR-C has its own supply and its own reset: an MCU reset
|
||||
* (watchdog, RTS pin, esptool, `reboot`) does not reset the sensor, so
|
||||
* it comes up still holding whatever the previous session configured.
|
||||
* For this driver that means INT1_CTRL.INT1_FTH still set and a FIFO
|
||||
* still over its watermark -- i.e. INT1 asserted high, immediately, at
|
||||
* registration time.
|
||||
*
|
||||
* INT1 is level-triggered (ONHIGH; see the comment in
|
||||
* boards/xtensa/esp32s3/common/src/esp32s3_board_lsm6ds3trc.c for why
|
||||
* edge triggering is wrong here). A level-triggered line that is
|
||||
* already active when esp_gpioirqenable() runs re-fires forever, and
|
||||
* the board then wedges during bring-up with no console output and no
|
||||
* crash dump -- observed as a boot that stops right after Wi-Fi init
|
||||
* and never reaches NSH, recoverable only by physically removing power
|
||||
* from the sensor.
|
||||
*
|
||||
* SW_RESET (CTRL3_C bit 0) clears INT1_CTRL and FIFO_CTRL back to 0,
|
||||
* which deasserts INT1. It self-clears in ~50us; poll rather than
|
||||
* assume, and carry on if the sensor does not answer -- a sensor that
|
||||
* cannot be reset is a problem for the caller to report, not a reason
|
||||
* to arm an interrupt line we know may be stuck high.
|
||||
*/
|
||||
|
||||
{
|
||||
uint8_t ctrl3_c;
|
||||
int attempt;
|
||||
int tries;
|
||||
bool reset_done = false;
|
||||
|
||||
/* The I2C bus is not always ready the instant we get here -- a write
|
||||
* at this point has been seen to fail with -EIO on a cold boot. Give
|
||||
* it a few attempts with a short pause between them.
|
||||
*/
|
||||
|
||||
for (attempt = 0; attempt < 3 && !reset_done; attempt++)
|
||||
{
|
||||
ctrl3_c = 0x01; /* SW_RESET */
|
||||
|
||||
err = lsm6ds3trc_write_bytes(priv, CTRL3_C, &ctrl3_c, 1);
|
||||
if (err < 0)
|
||||
{
|
||||
snwarn("Software reset write failed (attempt %d): %d\n",
|
||||
attempt + 1, err);
|
||||
nxsig_usleep(10000);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (tries = 0; tries < 20; tries++)
|
||||
{
|
||||
nxsig_usleep(1000);
|
||||
|
||||
if (lsm6ds3trc_read_bytes(priv, CTRL3_C, &ctrl3_c, 1) >= 0 &&
|
||||
(ctrl3_c & 0x01) == 0)
|
||||
{
|
||||
reset_done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Carry on even if it never took. Not resetting the sensor risks the
|
||||
* interrupt storm this reset exists to prevent (see the comment
|
||||
* above), but that is a far better failure than refusing to register
|
||||
* the device at all: an unregistered sensor leaves the application
|
||||
* with no /dev/uorb/sensor_accel0 to open, which is fatal to it.
|
||||
* Losing the whole sensor to protect against a maybe-storm is the
|
||||
* wrong trade -- and it is exactly what happened on 2026-09-19, when
|
||||
* a single -EIO here took the collar down completely.
|
||||
*/
|
||||
|
||||
if (!reset_done)
|
||||
{
|
||||
snerr("Software reset did not complete; continuing unreset. "
|
||||
"INT1 may already be asserted -- watch for an IRQ storm.\n");
|
||||
}
|
||||
|
||||
err = OK;
|
||||
}
|
||||
|
||||
/* Write CTRL1_XL's FS_XL bits to match the software default above --
|
||||
* ODR is set later by activate(), but FSR needs to be right from the
|
||||
* first sample instead of only after an explicit SNIOC_SETFULLSCALE.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue