Skip to content

Commit 51c9498

Browse files
committed
drivers/imu/lsm6dso: fix interrupt lockup preventing backlight triggers
Signed-off-by: Joshua Jun <[email protected]>
1 parent 24f1c99 commit 51c9498

File tree

1 file changed

+57
-9
lines changed

1 file changed

+57
-9
lines changed

src/fw/drivers/imu/lsm6dso/lsm6dso.c

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ uint32_t metric_firm_579_attempted_recoveries = 0;
134134
#define LSM6DSO_WATCHDOG_TIMEOUT_MS 5000 // Watchdog timeout for detecting unresponsive sensor
135135
#define LSM6DSO_MAX_CONSECUTIVE_ERRORS 5 // Maximum consecutive errors before attempting recovery
136136
#define LSM6DSO_INTERRUPT_GAP_LOG_THRESHOLD_MS 3000
137+
#define LSM6DSO_INTERRUPT_LOCKUP_THRESHOLD_MS 15000 // Max time without interrupt for motion detection
137138

138139
// LSM6DSO configuration entrypoints
139140

@@ -395,17 +396,28 @@ static void prv_lsm6dso_chase_target_state(void) {
395396
streaming_samples && (now - s_last_successful_read_ms > LSM6DSO_WATCHDOG_TIMEOUT_MS);
396397
const bool too_many_errors = (s_consecutive_errors >= LSM6DSO_MAX_CONSECUTIVE_ERRORS);
397398

398-
if (watchdog_expired || too_many_errors) {
399+
// Check for interrupt lockup - when motion detection is enabled but no interrupts occur
400+
const bool motion_detection_active = (s_lsm6dso_state.shake_detection_enabled ||
401+
s_lsm6dso_state.double_tap_detection_enabled);
402+
const bool interrupt_lockup = motion_detection_active && s_last_interrupt_ms > 0 &&
403+
(now - s_last_interrupt_ms > LSM6DSO_INTERRUPT_LOCKUP_THRESHOLD_MS);
404+
405+
if (watchdog_expired || too_many_errors || interrupt_lockup) {
399406
s_watchdog_event_count++;
400-
PBL_LOG(LOG_LEVEL_WARNING, "LSM6DSO: Sensor appears unresponsive (last_read: %lu ms ago, errors: %lu)",
401-
now - s_last_successful_read_ms, s_consecutive_errors);
402-
407+
if (interrupt_lockup) {
408+
PBL_LOG(LOG_LEVEL_WARNING, "LSM6DSO: Interrupt lockup detected (last interrupt: %lu ms ago)",
409+
(unsigned long)(now - s_last_interrupt_ms));
410+
} else {
411+
PBL_LOG(LOG_LEVEL_WARNING, "LSM6DSO: Sensor appears unresponsive (last_read: %lu ms ago, errors: %lu)",
412+
now - s_last_successful_read_ms, s_consecutive_errors);
413+
}
414+
403415
if (!prv_lsm6dso_attempt_recovery()) {
404416
PBL_LOG(LOG_LEVEL_ERROR, "LSM6DSO: Recovery failed, disabling sensor");
405417
s_lsm6dso_enabled = false;
406418
return;
407419
}
408-
420+
409421
// Reset state and continue with normal configuration
410422
s_lsm6dso_state = (lsm6dso_state_t){0};
411423
s_lsm6dso_running = false;
@@ -597,9 +609,9 @@ static void prv_lsm6dso_configure_fifo(bool enable) {
597609
uint32_t watermark = s_lsm6dso_state.num_samples;
598610
if (watermark == 0) watermark = 1; // safety
599611

600-
// Set watermark to 75% of requested samples to prevent overflow
601-
// This provides buffer for timing variations
602-
watermark = (watermark * 3) / 4;
612+
// Set watermark to 50% of requested samples to prevent overflow
613+
// This provides more buffer for timing variations and prevents lockup
614+
watermark = watermark / 2;
603615
if (watermark == 0) watermark = 1; // minimum
604616
if (watermark > LSM6DSO_FIFO_MAX_WATERMARK) watermark = LSM6DSO_FIFO_MAX_WATERMARK;
605617

@@ -798,12 +810,28 @@ static void prv_lsm6dso_process_interrupts(void) {
798810
// Wait for FIFO to actually clear
799811
psleep(1);
800812

813+
// Clear all interrupt sources after FIFO reset to ensure clean state
814+
lsm6dso_all_sources_t clear_sources;
815+
lsm6dso_all_sources_get(&lsm6dso_ctx, &clear_sources);
816+
801817
// Restore FIFO configuration if it was enabled
802818
if (s_fifo_in_use) {
803-
lsm6dso_fifo_watermark_set(&lsm6dso_ctx, current_watermark);
819+
// Reduce watermark by half to prevent future overflow
820+
uint16_t reduced_watermark = current_watermark / 2;
821+
if (reduced_watermark == 0) reduced_watermark = 1;
822+
823+
lsm6dso_fifo_watermark_set(&lsm6dso_ctx, reduced_watermark);
804824
lsm6dso_fifo_xl_batch_set(&lsm6dso_ctx, current_batch_rate);
805825
lsm6dso_fifo_mode_set(&lsm6dso_ctx, LSM6DSO_STREAM_MODE);
826+
827+
PBL_LOG(LOG_LEVEL_INFO, "LSM6DSO: Reduced FIFO watermark from %u to %u to prevent future overflow",
828+
current_watermark, reduced_watermark);
806829
}
830+
831+
// Force re-enable of external interrupt to ensure it's active
832+
exti_disable(BOARD_CONFIG_ACCEL.accel_ints[0]);
833+
psleep(1);
834+
exti_enable(BOARD_CONFIG_ACCEL.accel_ints[0]);
807835
}
808836

809837
// Collect accelerometer samples if requested
@@ -1367,6 +1395,26 @@ static bool prv_lsm6dso_attempt_recovery(void) {
13671395
#endif
13681396
return false;
13691397
}
1398+
1399+
// Reset FIFO to bypass mode to clear any stuck state
1400+
lsm6dso_fifo_mode_set(&lsm6dso_ctx, LSM6DSO_BYPASS_MODE);
1401+
1402+
// Reset interrupt configuration to ensure clean state
1403+
lsm6dso_pin_int1_route_t int1_routes = {0}; // All disabled
1404+
lsm6dso_pin_int1_route_set(&lsm6dso_ctx, int1_routes);
1405+
1406+
// Configure pulsed interrupts to prevent lockup
1407+
lsm6dso_data_ready_mode_set(&lsm6dso_ctx, LSM6DSO_DRDY_PULSED);
1408+
lsm6dso_int_notification_set(&lsm6dso_ctx, LSM6DSO_ALL_INT_PULSED);
1409+
1410+
// Clear any pending interrupt sources
1411+
lsm6dso_all_sources_t clear_sources;
1412+
lsm6dso_all_sources_get(&lsm6dso_ctx, &clear_sources);
1413+
1414+
// Reset external interrupt pin
1415+
exti_disable(BOARD_CONFIG_ACCEL.accel_ints[0]);
1416+
psleep(2);
1417+
exti_enable(BOARD_CONFIG_ACCEL.accel_ints[0]);
13701418

13711419
s_consecutive_errors = 0;
13721420
s_last_successful_read_ms = prv_get_timestamp_ms();

0 commit comments

Comments
 (0)