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:
@@ -30,6 +30,8 @@
|
|||||||
#define ICM42688_WHO_AM_I 0x47u
|
#define ICM42688_WHO_AM_I 0x47u
|
||||||
#define ICM_PWR_LOW_NOISE 0x0fu
|
#define ICM_PWR_LOW_NOISE 0x0fu
|
||||||
#define ICM_INT1_LATCHED_HIGH_PUSH_PULL 0x07u
|
#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 ICM_UI_DRDY_INT1_EN 0x08u
|
||||||
|
|
||||||
#define TDK_GRAVITY_MPS2 9.80665
|
#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_clock_mode(BSP_PMOD_SPI_CLOCK_MODE0);
|
||||||
bsp_pmod_spi_set_timing(10u, 10u, 10u, 10u);
|
bsp_pmod_spi_set_timing(10u, 10u, 10u, 10u);
|
||||||
delay_us(1000u);
|
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);
|
diagnostics.who_am_i = read_register(ICM_WHO_AM_I);
|
||||||
if((diagnostics.who_am_i != ICM42688_WHO_AM_I) ||
|
if((diagnostics.who_am_i != ICM42688_WHO_AM_I) ||
|
||||||
(read_register(ICM_DEVICE_CONFIG) != 0x00u))
|
(read_register(ICM_DEVICE_CONFIG) != 0x00u))
|
||||||
|
|||||||
Reference in New Issue
Block a user