]> git.earman.xyz Git - sensor-watch.git/commitdiff
power down accelerometer unless a watch face requests it
authorJoey Castillo <joeycastillo@utexas.edu>
Mon, 26 May 2025 14:51:11 +0000 (10:51 -0400)
committerJoey Castillo <joeycastillo@utexas.edu>
Mon, 26 May 2025 14:51:11 +0000 (10:51 -0400)
movement.c
movement.h
watch-faces/sensor/accelerometer_status_face.c
watch-faces/sensor/accelerometer_status_face.h
watch-faces/sensor/activity_logging_face.c

index 561925ce5fa26749b2682f9b152e8a9c5bfa7b97..a767fa35c8ae5ebc79ecb38e08b668a75c91e108 100644 (file)
@@ -40,7 +40,6 @@
 #include "shell.h"
 #include "utz.h"
 #include "zones.h"
-#include "lis2dw.h"
 #include "tc.h"
 #include "evsys.h"
 #include "delay.h"
@@ -539,7 +538,7 @@ bool movement_disable_tap_detection_if_available(void) {
     if (movement_state.has_lis2dw) {
         // Ramp data rate back down to the usual lowest rate to save power.
         lis2dw_set_low_noise_mode(false);
-        lis2dw_set_data_rate(LIS2DW_DATA_RATE_LOWEST);
+        lis2dw_set_data_rate(movement_state.accelerometer_background_rate);
         lis2dw_set_mode(LIS2DW_MODE_LOW_POWER);
         // ...disable Z axis (not sure if this is needed, does this save power?)...
         lis2dw_configure_tap_threshold(0, 0, 0, 0);
@@ -550,6 +549,24 @@ bool movement_disable_tap_detection_if_available(void) {
     return false;
 }
 
+lis2dw_data_rate_t movement_get_accelerometer_background_rate(void) {
+    if (movement_state.has_lis2dw) return movement_state.accelerometer_background_rate;
+    else return LIS2DW_DATA_RATE_POWERDOWN;
+}
+
+bool movement_set_accelerometer_background_rate(lis2dw_data_rate_t new_rate) {
+    if (movement_state.has_lis2dw) {
+        if (movement_state.accelerometer_background_rate != new_rate) {
+            lis2dw_set_data_rate(new_rate);
+            movement_state.accelerometer_background_rate = new_rate;
+
+            return true;
+        }
+    }
+
+    return false;
+}
+
 float movement_get_temperature(void) {
     float temperature_c = (float)0xFFFFFFFF;
 
@@ -702,7 +719,6 @@ void app_setup(void) {
             lis2dw_set_mode(LIS2DW_MODE_LOW_POWER);         // select low power (not high performance) mode
             lis2dw_set_low_power_mode(LIS2DW_LP_MODE_1);    // lowest power mode, 12-bit
             lis2dw_set_low_noise_mode(false);               // low noise mode raises power consumption slightly; we don't need it
-            lis2dw_set_data_rate(LIS2DW_DATA_RATE_LOWEST);  // sample at 1.6 Hz, lowest rate available
             lis2dw_enable_stationary_motion_detection();    // stationary/motion detection mode keeps the data rate at 1.6 Hz even in sleep
             lis2dw_set_range(LIS2DW_RANGE_2_G);             // Application note AN5038 recommends 2g range
             lis2dw_enable_sleep();                          // allow acceleromter to sleep and wake on activity
@@ -730,7 +746,14 @@ void app_setup(void) {
             // but it will only fire once tap recognition is enabled.
             watch_register_interrupt_callback(HAL_GPIO_A3_pin(), cb_accelerometer_event, INTERRUPT_TRIGGER_RISING);
 
+            // Enable the interrupts...
             lis2dw_enable_interrupts();
+
+            // ...and power down the accelerometer to save energy. This means the interrupts we just configured won't fire.
+            // Tap detection will ramp up sesing and make use of the A3 interrupt.
+            // If a watch face wants to check in on the A4 pin, it can call movement_set_accelerometer_background_rate
+            lis2dw_set_data_rate(LIS2DW_DATA_RATE_POWERDOWN);
+            movement_state.accelerometer_background_rate = LIS2DW_DATA_RATE_POWERDOWN;
         } else {
             watch_disable_i2c();
         }
index 5626385af0fb9e181bd3ae42a0109e0b102ce4dc..dbee3830d3c501f6bc0c3ded57afd8be98fcb7ad 100644 (file)
@@ -28,6 +28,7 @@
 #include <stdbool.h>
 #include "watch.h"
 #include "utz.h"
+#include "lis2dw.h"
 
 /// @brief A struct that allows a watch face to report its state back to Movement.
 typedef struct {
@@ -291,6 +292,8 @@ typedef struct {
 
     // boolean set if accelerometer is detected
     bool has_lis2dw;
+    // data rate for background accelerometer sensing
+    lis2dw_data_rate_t accelerometer_background_rate;
 } movement_state_t;
 
 void movement_move_to_face(uint8_t watch_face_index);
@@ -373,6 +376,10 @@ void movement_set_alarm_enabled(bool value);
 bool movement_enable_tap_detection_if_available(void);
 bool movement_disable_tap_detection_if_available(void);
 
+// gets and sets the accelerometer data rate in the background
+lis2dw_data_rate_t movement_get_accelerometer_background_rate(void);
+bool movement_set_accelerometer_background_rate(lis2dw_data_rate_t new_rate);
+
 // If the board has a temperature sensor, this function will give you the temperature in degrees celsius.
 // If the board has multiple temperature sensors, it will use the most accurate one available.
 // If the board has no temperature sensors, it will return 0xFFFFFFFF.
index a358a8b3f3a435c6a468c054c33355c599e2f255..df44330047af2500634a1820668272b6f2ac840c 100644 (file)
@@ -54,6 +54,13 @@ void accelerometer_status_face_setup(uint8_t watch_face_index, void ** context_p
 void accelerometer_status_face_activate(void *context) {
     accel_interrupt_count_state_t *state = (accel_interrupt_count_state_t *)context;
 
+    // get the current data rate from Movement
+    state->old_rate = movement_get_accelerometer_background_rate();
+    if (state->old_rate == LIS2DW_DATA_RATE_POWERDOWN) {
+        // if accelerometer was powered down, power it up at the lowest possible rate
+        movement_set_accelerometer_background_rate(LIS2DW_DATA_RATE_LOWEST);
+    }
+
     // never in settings mode at the start
     state->is_setting = false;
 
@@ -126,5 +133,9 @@ bool accelerometer_status_face_loop(movement_event_t event, void *context) {
 }
 
 void accelerometer_status_face_resign(void *context) {
-    (void) context;
+    accel_interrupt_count_state_t *state = (accel_interrupt_count_state_t *)context;
+
+    // restore old data rate. This only does something if old_rate was POWERDOWN.
+    // If the old rate was anything other than POWERDOWN, we didn't change anything and this will be a no-op.
+    movement_set_accelerometer_background_rate(state->old_rate);
 }
index 2b152d5f37cad845d704a8f7d2e8a227293f0453..2e15c510797dfe49531efbcb598cb3afe0aca805 100644 (file)
@@ -38,6 +38,7 @@
 typedef struct {
     uint8_t new_threshold;
     uint8_t threshold;
+    lis2dw_data_rate_t old_rate;
     bool is_setting;
 } accel_interrupt_count_state_t;
 
index 1fdfd9b4f1429d30bee3b638a7c95ca303f5ff94..3d5eb1cf6da19735d63c6e4c27e6650f52458d3d 100644 (file)
@@ -73,6 +73,8 @@ void activity_logging_face_setup(uint8_t watch_face_index, void ** context_ptr)
     if (*context_ptr == NULL) {
         *context_ptr = malloc(sizeof(activity_logging_state_t));
         memset(*context_ptr, 0, sizeof(activity_logging_state_t));
+        // At first run, tell Movement to run the accelerometer in the background. It will now run at this rate forever.
+        movement_set_accelerometer_background_rate(LIS2DW_DATA_RATE_LOWEST);
     }
 }