From 0ab1bf42b30ee7700a2b10b1e2f5681c657be95f Mon Sep 17 00:00:00 2001 From: Benjamin Lindqvist Date: Thu, 28 Oct 2021 16:06:35 +0200 Subject: [PATCH] drivers: sensor: lis2dh: Level triggered interrupts Both DRDY and motion interrupts behaves like level signals since they remain asserted until they're cleared. Configuring them as edge interrupts is dangerous because if we ever miss an interrupt, it may never get cleared and thus will never trigger again. Treating them as edge signals seems to have no advantages, other than being marginally simpler to implement. The patch has gotten many hours of run-time on real hardware using a nRF52-based board and a LIS3DH with both interrupts connected and heavily utilized. Signed-off-by: Benjamin Lindqvist --- drivers/sensor/lis2dh/lis2dh_trigger.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/drivers/sensor/lis2dh/lis2dh_trigger.c b/drivers/sensor/lis2dh/lis2dh_trigger.c index b4b1f71cc50..d2b84dd2042 100644 --- a/drivers/sensor/lis2dh/lis2dh_trigger.c +++ b/drivers/sensor/lis2dh/lis2dh_trigger.c @@ -25,7 +25,7 @@ static inline void setup_int1(const struct device *dev, gpio_pin_interrupt_configure_dt(&cfg->gpio_drdy, enable - ? GPIO_INT_EDGE_TO_ACTIVE + ? GPIO_INT_LEVEL_ACTIVE : GPIO_INT_DISABLE); } @@ -121,7 +121,7 @@ static inline void setup_int2(const struct device *dev, gpio_pin_interrupt_configure_dt(&cfg->gpio_int, enable - ? GPIO_INT_EDGE_TO_ACTIVE + ? GPIO_INT_LEVEL_ACTIVE : GPIO_INT_DISABLE); } @@ -254,6 +254,9 @@ static void lis2dh_gpio_int1_callback(const struct device *dev, atomic_set_bit(&lis2dh->trig_flags, TRIGGED_INT1); + /* int is level trigged so disable until we clear it */ + setup_int1(lis2dh->dev, false); + #if defined(CONFIG_LIS2DH_TRIGGER_OWN_THREAD) k_sem_give(&lis2dh->gpio_sem); #elif defined(CONFIG_LIS2DH_TRIGGER_GLOBAL_THREAD) @@ -271,6 +274,9 @@ static void lis2dh_gpio_int2_callback(const struct device *dev, atomic_set_bit(&lis2dh->trig_flags, TRIGGED_INT2); + /* int is level trigged so disable until we clear it */ + setup_int2(lis2dh->dev, false); + #if defined(CONFIG_LIS2DH_TRIGGER_OWN_THREAD) k_sem_give(&lis2dh->gpio_sem); #elif defined(CONFIG_LIS2DH_TRIGGER_GLOBAL_THREAD) @@ -316,6 +322,14 @@ static void lis2dh_thread_cb(const struct device *dev) if (likely(lis2dh->handler_drdy != NULL)) { lis2dh->handler_drdy(dev, &drdy_trigger); + + } + + /* Reactivate level triggered interrupt if handler did not + * disable itself + */ + if (likely(lis2dh->handler_drdy != NULL)) { + setup_int1(dev, true); } return; @@ -342,6 +356,13 @@ static void lis2dh_thread_cb(const struct device *dev) lis2dh->handler_anymotion(dev, &anym_trigger); } + /* Reactivate level triggered interrupt if handler did not + * disable itself + */ + if (lis2dh->handler_anymotion != NULL) { + setup_int2(dev, true); + } + LOG_DBG("@tick=%u int2_src=0x%x", k_cycle_get_32(), reg_val);