@@ -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