fix(imu): resynchronise the ICM-42688 before probing it

Halting the core with a debugger, or resetting it while a transaction is
in flight, leaves the sensor's SPI shift register part-way through a
word. Every later access is misaligned, WHO_AM_I reads back 0x00 and
initialisation fails, which is the `sensor=none who=0x00` case in the
field logs.

Toggle chip select around idle bytes to return the device to command
state, then soft reset so the register file starts from defaults
regardless of what the previous image was doing.

This covers the sensor-side wedge. It does not recover a wedged fabric
SPI controller, which a CPU-only debugger reset does not touch and which
was observed to need a board power cycle.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
onur cayan
2026-08-07 22:05:50 +03:00
committed by onur
parent 8349f32df1
commit 18d338fe50
@@ -30,6 +30,8 @@
#define ICM42688_WHO_AM_I 0x47u
#define ICM_PWR_LOW_NOISE 0x0fu
#define ICM_INT1_LATCHED_HIGH_PUSH_PULL 0x07u
/* DEVICE_CONFIG bit 0: self-clearing soft reset. */
#define ICM_SOFT_RESET 0x01u
#define ICM_UI_DRDY_INT1_EN 0x08u
#define TDK_GRAVITY_MPS2 9.80665
@@ -224,6 +226,33 @@ bool tdk_icm42688_init(const tdk_icm42688_config_t* config)
bsp_pmod_spi_set_clock_mode(BSP_PMOD_SPI_CLOCK_MODE0);
bsp_pmod_spi_set_timing(10u, 10u, 10u, 10u);
delay_us(1000u);
/*
* Recover a device left mid-transfer before probing it.
*
* Halting the core with a debugger, or resetting it while a transaction is
* in flight, leaves the sensor's SPI shift register part-way through a
* word. Every later access is then misaligned, WHO_AM_I reads back 0x00,
* and initialisation fails until the board is power cycled -- the
* `sensor=none who=0x00` case seen in field logs. Toggling chip select
* around idle bytes returns the device to command state, after which a
* soft reset restores the register file to defaults so this function
* starts from the same place regardless of what ran before it.
*/
for(unsigned int attempt = 0u ; attempt < 4u ; attempt++)
{
bsp_pmod_spi_select();
(void)bsp_pmod_spi_xfer8(ICM_SPI_DUMMY);
bsp_pmod_spi_deselect();
delay_us(50u);
}
write_register(ICM_DEVICE_CONFIG, ICM_SOFT_RESET);
/* Datasheet requires 1 ms before any register access after a soft reset. */
delay_ms(2u);
/* The reset asserts RESET_DONE; clear it so it cannot be mistaken for a
* data-ready later. */
(void)read_register(ICM_INT_STATUS);
diagnostics.who_am_i = read_register(ICM_WHO_AM_I);
if((diagnostics.who_am_i != ICM42688_WHO_AM_I) ||
(read_register(ICM_DEVICE_CONFIG) != 0x00u))