more accelerometer work
This commit is contained in:
parent
57de3e77f5
commit
19376625d1
64
movement.c
64
movement.c
@ -77,6 +77,8 @@ void cb_tick(void);
|
||||
|
||||
#ifdef HAS_ACCELEROMETER
|
||||
void cb_motion_interrupt_1(void);
|
||||
void cb_motion_interrupt_2(void);
|
||||
uint32_t orientation_changes = 0;
|
||||
#endif
|
||||
|
||||
#if __EMSCRIPTEN__
|
||||
@ -638,25 +640,16 @@ void app_setup(void) {
|
||||
|
||||
// set up interrupts:
|
||||
// INT1 is on A4 which can wake from deep sleep. Wake on 6D orientation change.
|
||||
lis2dw_configure_int1(LIS2DW_CTRL4_INT1_6D);
|
||||
watch_register_interrupt_callback(HAL_GPIO_A4_pin(), cb_motion_interrupt_1, INTERRUPT_TRIGGER_FALLING);
|
||||
lis2dw_configure_int1(LIS2DW_CTRL4_INT1_6D | LIS2DW_CTRL4_INT1_WU | LIS2DW_CTRL4_INT1_TAP | LIS2DW_CTRL4_INT1_SINGLE_TAP);
|
||||
watch_register_extwake_callback(HAL_GPIO_A4_pin(), cb_motion_interrupt_1, true);
|
||||
|
||||
// configure the accelerometer to fire INT2 when its sleep state changes.
|
||||
// configure the accelerometer to output the sleep state on INT2.
|
||||
lis2dw_configure_int2(LIS2DW_CTRL5_INT2_SLEEP_STATE | LIS2DW_CTRL5_INT2_SLEEP_CHG);
|
||||
// INT2 is wired to pin A3. set it up on the external interrupt controller.
|
||||
HAL_GPIO_A3_in();
|
||||
HAL_GPIO_A3_pmuxen(HAL_GPIO_PMUX_EIC);
|
||||
eic_configure_pin(HAL_GPIO_A3_pin(), INTERRUPT_TRIGGER_FALLING);
|
||||
// but rather than firing an interrupt, we'll have it generate an event instead.
|
||||
eic_enable_event(HAL_GPIO_A3_pin());
|
||||
// we can route the EXTINT3 event generator to the TC2 event user...
|
||||
evsys_configure_channel(0, EVSYS_ID_GEN_EIC_EXTINT_3, EVSYS_ID_USER_TC2_EVU, true, true);
|
||||
// and use the TC2 event to count the number of times the sleep state changes.
|
||||
// note that this doesn't actually wake the watch — we can maintain this count even in standby.
|
||||
tc_init(2, GENERIC_CLOCK_3, TC_PRESCALER_DIV1);
|
||||
tc_set_event_action(2, TC_EVENT_ACTION_COUNT);
|
||||
tc_set_counter_mode(2, TC_COUNTER_MODE_16BIT);
|
||||
tc_enable(2);
|
||||
eic_configure_pin(HAL_GPIO_A3_pin(), INTERRUPT_TRIGGER_BOTH);
|
||||
watch_register_interrupt_callback(HAL_GPIO_A3_pin(), cb_motion_interrupt_2, INTERRUPT_TRIGGER_BOTH);
|
||||
|
||||
lis2dw_enable_interrupts();
|
||||
}
|
||||
@ -698,6 +691,17 @@ static void _sleep_mode_app_loop(void) {
|
||||
bool app_loop(void) {
|
||||
const watch_face_t *wf = &watch_faces[movement_state.current_face_idx];
|
||||
bool woke_up_for_buzzer = false;
|
||||
|
||||
// REMOVE THIS before shipping the accelerometer board: test beeps.
|
||||
if (movement_state.settings.bit.button_should_sound && event.event_type == EVENT_ACCELEROMETER_WAKE) {
|
||||
watch_buzzer_play_note_with_volume(BUZZER_NOTE_C6, 20, WATCH_BUZZER_VOLUME_SOFT);
|
||||
}
|
||||
if (movement_state.settings.bit.button_should_sound && event.event_type == EVENT_ACCELEROMETER_SLEEP) {
|
||||
watch_buzzer_play_note_with_volume(BUZZER_NOTE_C5, 15, WATCH_BUZZER_VOLUME_SOFT);
|
||||
watch_buzzer_play_note_with_volume(BUZZER_NOTE_REST, 10, WATCH_BUZZER_VOLUME_SOFT);
|
||||
watch_buzzer_play_note_with_volume(BUZZER_NOTE_C5, 15, WATCH_BUZZER_VOLUME_SOFT);
|
||||
}
|
||||
|
||||
if (movement_state.watch_face_changed) {
|
||||
if (movement_state.settings.bit.button_should_sound) {
|
||||
// low note for nonzero case, high note for return to watch_face 0
|
||||
@ -928,7 +932,35 @@ void cb_tick(void) {
|
||||
|
||||
#ifdef HAS_ACCELEROMETER
|
||||
void cb_motion_interrupt_1(void) {
|
||||
// TODO: Find out what motion event woke us up.
|
||||
printf("INT1\n");
|
||||
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++;
|
||||
}
|
||||
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;
|
||||
|
||||
// These are handled on INT2, which is not available in low energy mode.
|
||||
// If we want wakeup events on INT1, we could ask for LIS2DW_CTRL4_INT1_WU and get wake events here.
|
||||
// If we want sleep change events on INT1, we'd have to set LIS2DW_CTRL5_INT2_SLEEP_CHG and LIS2DW_CTRL7_VAL_INT2_ON_INT1
|
||||
// That would give us these two cases:
|
||||
// if (int_src & LIS2DW_REG_ALL_INT_SRC_WU_IA) printf(" Wake up");
|
||||
// if (int_src & LIS2DW_REG_ALL_INT_SRC_SLEEP_CHANGE_IA) printf(" Sleep change");
|
||||
}
|
||||
|
||||
void cb_motion_interrupt_2(void) {
|
||||
if (HAL_GPIO_A3_read()) {
|
||||
event.event_type = EVENT_ACCELEROMETER_SLEEP;
|
||||
printf("Sleep on INT2\n");
|
||||
} else {
|
||||
event.event_type = EVENT_ACCELEROMETER_WAKE;
|
||||
printf("Wake on INT2\n");
|
||||
// Not sure if it's useful to know what axis exceeded the threshold, but here's that:
|
||||
// uint8_t int_src = lis2dw_get_wakeup_source();
|
||||
// if (int_src & LIS2DW_WAKE_UP_SRC_VAL_X_WU) printf("Wake on X");
|
||||
// if (int_src & LIS2DW_WAKE_UP_SRC_VAL_Y_WU) printf("Wake on Y");
|
||||
// if (int_src & LIS2DW_WAKE_UP_SRC_VAL_Z_WU) printf("Wake on Z");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -143,6 +143,13 @@ typedef enum {
|
||||
EVENT_ALARM_BUTTON_UP, // The alarm button was pressed for less than half a second, and released.
|
||||
EVENT_ALARM_LONG_PRESS, // The alarm button was held for over half a second, but not yet released.
|
||||
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 {
|
||||
|
||||
@ -31,6 +31,10 @@
|
||||
|
||||
#ifdef HAS_ACCELEROMETER
|
||||
|
||||
// hacky: we're just tapping into Movement's orientation changes.
|
||||
// we should make better API for this.
|
||||
extern uint32_t orientation_changes;
|
||||
|
||||
static void _accel_interrupt_count_face_update_display(accel_interrupt_count_state_t *state) {
|
||||
(void) state;
|
||||
char buf[7];
|
||||
@ -38,8 +42,7 @@ static void _accel_interrupt_count_face_update_display(accel_interrupt_count_sta
|
||||
// "AC"celerometer "IN"terrupts
|
||||
watch_display_text(WATCH_POSITION_TOP_LEFT, "AC");
|
||||
watch_display_text(WATCH_POSITION_TOP_RIGHT, "1N");
|
||||
uint16_t count = tc_count16_get_count(2);
|
||||
snprintf(buf, 7, "%6d", count);
|
||||
snprintf(buf, 7, "%6lu", orientation_changes);
|
||||
watch_display_text(WATCH_POSITION_BOTTOM, buf);
|
||||
printf("%s\n", buf);
|
||||
}
|
||||
@ -90,10 +93,6 @@ bool accel_interrupt_count_face_loop(movement_event_t event, void *context) {
|
||||
}
|
||||
} else {
|
||||
switch (event.event_type) {
|
||||
case EVENT_ALARM_BUTTON_UP:
|
||||
// reset the counter
|
||||
tc_count16_set_count(2, 0);
|
||||
// fall through
|
||||
case EVENT_ACTIVATE:
|
||||
case EVENT_TICK:
|
||||
_accel_interrupt_count_face_update_display(state);
|
||||
|
||||
@ -29,20 +29,26 @@
|
||||
|
||||
#ifdef HAS_ACCELEROMETER
|
||||
|
||||
// hacky: we're just tapping into Movement's orientation changes.
|
||||
// we should make better API for this.
|
||||
extern uint32_t orientation_changes;
|
||||
|
||||
static void _activity_logging_face_log_data(activity_logging_state_t *state) {
|
||||
watch_date_time_t date_time = watch_rtc_get_date_time();
|
||||
size_t pos = state->data_points % ACTIVITY_LOGGING_NUM_DATA_POINTS;
|
||||
|
||||
state->data[pos].timestamp.reg = date_time.reg;
|
||||
state->data[pos].active_minutes = state->active_minutes;
|
||||
state->data[pos].orientation_changes = orientation_changes;
|
||||
state->active_minutes = 0;
|
||||
orientation_changes = 0;
|
||||
|
||||
state->data_points++;
|
||||
}
|
||||
|
||||
static void _activity_logging_face_update_display(activity_logging_state_t *state, bool clock_mode_24h) {
|
||||
int8_t pos = (state->data_points - 1 - state->display_index) % ACTIVITY_LOGGING_NUM_DATA_POINTS;
|
||||
char buf[7];
|
||||
char buf[16];
|
||||
|
||||
watch_clear_indicator(WATCH_INDICATOR_24H);
|
||||
watch_clear_indicator(WATCH_INDICATOR_PM);
|
||||
@ -71,11 +77,11 @@ static void _activity_logging_face_update_display(activity_logging_state_t *stat
|
||||
sprintf(buf, "%2d%02d%02d", date_time.unit.hour, date_time.unit.minute, date_time.unit.second);
|
||||
watch_display_text(WATCH_POSITION_BOTTOM, buf);
|
||||
} else {
|
||||
// we are displaying the number of accelerometer wakeups
|
||||
watch_display_text_with_fallback(WATCH_POSITION_TOP, "ACT L", "AC");
|
||||
// we are displaying the number of accelerometer wakeups and orientation changes
|
||||
watch_display_text(WATCH_POSITION_TOP, "WO");
|
||||
sprintf(buf, "%2d", state->display_index);
|
||||
watch_display_text(WATCH_POSITION_TOP_RIGHT, buf);
|
||||
sprintf(buf, "%d", state->data[pos].active_minutes);
|
||||
sprintf(buf, "%2d=%lu", state->data[pos].active_minutes, state->data[pos].orientation_changes);
|
||||
watch_display_text(WATCH_POSITION_BOTTOM, buf);
|
||||
}
|
||||
}
|
||||
@ -139,7 +145,7 @@ movement_watch_face_advisory_t activity_logging_face_advise(void *context) {
|
||||
activity_logging_state_t *state = (activity_logging_state_t *)context;
|
||||
movement_watch_face_advisory_t retval = { 0 };
|
||||
|
||||
// every minute, we want to log whether the accelerometer is alseeep or awake.
|
||||
// every minute, we want to log whether the accelerometer is asleep or awake.
|
||||
if (!HAL_GPIO_A3_read()) {
|
||||
state->active_minutes++;
|
||||
}
|
||||
|
||||
@ -44,6 +44,7 @@
|
||||
typedef struct {
|
||||
watch_date_time_t timestamp;
|
||||
uint8_t active_minutes;
|
||||
uint32_t orientation_changes;
|
||||
} activity_logging_data_point_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@ -133,6 +133,10 @@ static void _watch_disable_all_pins_except_rtc(void) {
|
||||
if (config & RTC_TAMPCTRL_IN0ACT_Msk) portb_pins_to_disable &= 0xFFFFFFFE;
|
||||
// same with RTC/IN[1] and PB02
|
||||
if (config & RTC_TAMPCTRL_IN1ACT_Msk) portb_pins_to_disable &= 0xFFFFFFFB;
|
||||
#ifdef HAS_ACCELEROMETER
|
||||
// if we're using the Motion board, keep A3 configured (it tracks the accelerometer sleep state)
|
||||
portb_pins_to_disable &= 0xFFFFFFF7;
|
||||
#endif
|
||||
|
||||
// port A: that last B is to always keep PA02 configured as-is; that's our ALARM button.
|
||||
PORT->Group[0].DIRCLR.reg = 0xFFFFFFFB;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user