Skip to content

Commit

Permalink
accel: count orientation changes with TC2 instead of waking up
Browse files Browse the repository at this point in the history
  • Loading branch information
joeycastillo committed Nov 19, 2024
1 parent 548260b commit c6af677
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 36 deletions.
69 changes: 41 additions & 28 deletions movement.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,7 @@ void cb_tick(void);

#ifdef HAS_ACCELEROMETER
void cb_accelerometer_event(void);
void cb_accelerometer_sleep_change(void);
uint32_t orientation_changes = 0;
void cb_accelerometer_wake(void);
uint8_t stationary_minutes = 0;
#endif

Expand Down Expand Up @@ -657,14 +656,36 @@ void app_setup(void) {
// set up interrupts:
// INT1 is wired to pin A3. We'll configure the accelerometer to output an interrupt on INT1 when it detects an orientation change.
lis2dw_configure_int1(LIS2DW_CTRL4_INT1_6D);
watch_register_interrupt_callback(HAL_GPIO_A3_pin(), cb_accelerometer_event, INTERRUPT_TRIGGER_RISING);

// INT2 is wired to pin A4. We'll configure the accelerometer to output the sleep state on INT2.
lis2dw_configure_int2(LIS2DW_CTRL5_INT2_SLEEP_STATE | LIS2DW_CTRL5_INT2_SLEEP_CHG);
HAL_GPIO_A3_in();
HAL_GPIO_A3_pmuxen(HAL_GPIO_PMUX_EIC);
eic_configure_pin(HAL_GPIO_A3_pin(), INTERRUPT_TRIGGER_RISING);
// but rather than hooking it up to an interrupt callback, we'll have it trigger an event.
eic_enable_event(HAL_GPIO_A3_pin());

// that event will increment a counter on TC2. So let's set that up:
if (!tc_is_enabled(2)) {
// TC2 clocked from GCLK3, the 1024 Hz clock. No further division.
tc_init(2, GENERIC_CLOCK_3, TC_PRESCALER_DIV1);
}
// COUNT16 mode, count up to 65535 orientation changes (we will reset before it overflows)
tc_set_counter_mode(2, TC_COUNTER_MODE_16BIT);
// run in standby (we spend most of our time in standby)
tc_set_run_in_standby(2, true);
// finally set the event action to count up when an event is received.
tc_set_event_action(2, TC_EVENT_ACTION_COUNT);
// enable TC2!
tc_enable(2);

// now configure the event system:
// on channel 0, route the INT3 event generator to the TC2 event user. Run in standby, on the asynchronous path.
evsys_configure_channel(0, EVSYS_ID_GEN_EIC_EXTINT_3, EVSYS_ID_USER_TC2_EVU, true, true);
// this concludes the setup for orientation tracking.

// next: INT2 is wired to pin A4. We'll configure the accelerometer to output the sleep state on INT2.
// a falling edge on INT2 indicates the accelerometer has woken up.
// when configured via the extwake callback, we can only detect rising or falling edges, not both (as we could using the EIC).
// this line configures an extwake calling `cb_accelerometer_sleep_change` when the accelerometer wakes up.
watch_register_extwake_callback(HAL_GPIO_A4_pin(), cb_accelerometer_sleep_change, false);
lis2dw_configure_int2(LIS2DW_CTRL5_INT2_SLEEP_STATE | LIS2DW_CTRL5_INT2_SLEEP_CHG);
HAL_GPIO_A4_in();
watch_register_extwake_callback(HAL_GPIO_A4_pin(), cb_accelerometer_wake, false);

lis2dw_enable_interrupts();
}
Expand Down Expand Up @@ -937,31 +958,23 @@ void cb_tick(void) {

#ifdef HAS_ACCELEROMETER
void cb_accelerometer_event(void) {
// This callback is not currently in use! Tap tracking will require using an interrupt on A3 instead of an event.
// I imagine watch faces will request tap tracking in a specific context, and we'll expose a Movement function
// that swaps out the mode for as long as the watch face needs taps. (the sampling rate required for tap tracking
// will to consume a lot more power, so we can't leave it on all the time.)
uint8_t int_src = lis2dw_get_interrupt_source();
if (int_src & LIS2DW_REG_ALL_INT_SRC_6D_IA) {
event.event_type = EVENT_ORIENTATION_CHANGE;
orientation_changes++;
printf("Orientation change\n");
}

// not currently listening for these:
if (int_src & LIS2DW_REG_ALL_INT_SRC_DOUBLE_TAP) event.event_type = EVENT_DOUBLE_TAP;
if (int_src & LIS2DW_REG_ALL_INT_SRC_SINGLE_TAP) event.event_type = EVENT_SINGLE_TAP;
if (int_src & LIS2DW_REG_ALL_INT_SRC_FF_IA) event.event_type = EVENT_FREE_FALL;
}

void cb_accelerometer_sleep_change(void) {
if (HAL_GPIO_A4_read()) {
event.event_type = EVENT_ACCELEROMETER_SLEEP;
printf("Sleep on INT2\n");
} else {
event.event_type = EVENT_ACCELEROMETER_WAKE;
// reset the stationary minutes counter; we're counting consecutive stationary minutes.
stationary_minutes = 0;
// also: wake up!
_movement_reset_inactivity_countdown();
printf("Wake on INT2\n");
}
void cb_accelerometer_wake(void) {
printf("Woke up from accelerometer!\n");
event.event_type = EVENT_ACCELEROMETER_WAKE;
// reset the stationary minutes counter; we're counting consecutive stationary minutes.
stationary_minutes = 0;
// also: wake up!
_movement_reset_inactivity_countdown();
}

#endif
3 changes: 0 additions & 3 deletions movement.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,8 @@ typedef enum {
EVENT_ALARM_LONG_UP, // The alarm button was held for over half a second, and released.

EVENT_ACCELEROMETER_WAKE, // The accelerometer has detected motion and woken up.
EVENT_ACCELEROMETER_SLEEP, // The accelerometer has returned to sleep.
EVENT_ORIENTATION_CHANGE, // The orientation of the watch has changed. Available in low energy mode.
EVENT_SINGLE_TAP, // Accelerometer detected a single tap. This event is not yet implemented.
EVENT_DOUBLE_TAP, // Accelerometer detected a double tap. This event is not yet implemented.
EVENT_FREE_FALL, // Accelerometer detected the watch in free fall. This event is not yet implemented.
} movement_event_type_t;

typedef struct {
Expand Down
4 changes: 2 additions & 2 deletions watch-faces/demo/accel_interrupt_count_face.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@

// hacky: we're just tapping into Movement's global state.
// we should make better API for this.
extern uint32_t orientation_changes;
extern uint8_t stationary_minutes;

static void _accel_interrupt_count_face_update_display(accel_interrupt_count_state_t *state) {
Expand All @@ -48,7 +47,8 @@ static void _accel_interrupt_count_face_update_display(accel_interrupt_count_sta
else watch_display_text(WATCH_POSITION_TOP_RIGHT, " A");

// Orientation changes / active minutes
sprintf(buf, "%-3lu/%2d", orientation_changes > 999 ? 999 : orientation_changes, stationary_minutes);
uint16_t orientation_changes = tc_count16_get_count(2);
sprintf(buf, "%-3u/%2d", orientation_changes > 999 ? 999 : orientation_changes, stationary_minutes);
watch_display_text(WATCH_POSITION_BOTTOM, buf);
}

Expand Down
7 changes: 4 additions & 3 deletions watch-faces/sensor/activity_logging_face.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@
#include "activity_logging_face.h"
#include "filesystem.h"
#include "watch.h"
#include "tc.h"

#ifdef HAS_ACCELEROMETER

// hacky: we're just tapping into Movement's global state.
// we should make better API for this.
extern uint32_t orientation_changes;
extern uint8_t stationary_minutes;

static void _activity_logging_face_log_data(activity_logging_state_t *state) {
Expand All @@ -45,7 +45,7 @@ static void _activity_logging_face_log_data(activity_logging_state_t *state) {
data_point.bit.hour = date_time.unit.hour;
data_point.bit.minute = date_time.unit.minute;
data_point.bit.stationary_minutes = stationary_minutes;
data_point.bit.orientation_changes = orientation_changes;
data_point.bit.orientation_changes = tc_count16_get_count(2); // orientation changes are counted in TC2
// print size of thing
printf("Size of data point: %d\n", sizeof(activity_logging_data_point_t));
if (filesystem_append_file("activity.dat", (char *)&data_point, sizeof(activity_logging_data_point_t))) {
Expand All @@ -57,7 +57,8 @@ static void _activity_logging_face_log_data(activity_logging_state_t *state) {
state->data[pos].reg = data_point.reg;
state->data_points++;

orientation_changes = 0;
// reset the number of orientation changes.
tc_count16_set_count(2, 0);
}

static void _activity_logging_face_update_display(activity_logging_state_t *state, bool clock_mode_24h) {
Expand Down

0 comments on commit c6af677

Please sign in to comment.