Style changes and wakeup detection

This commit is contained in:
Lucian Copeland 2021-03-27 13:16:12 -04:00
parent d8a2d69e10
commit 529fb52309
9 changed files with 88 additions and 59 deletions

24
main.c
View File

@ -323,12 +323,12 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
rgb_status_animation_t animation; rgb_status_animation_t animation;
prep_rgb_status_animation(&result, found_main, safe_mode, &animation); prep_rgb_status_animation(&result, found_main, safe_mode, &animation);
bool asleep = false; bool fake_sleeping = false;
while (true) { while (true) {
RUN_BACKGROUND_TASKS; RUN_BACKGROUND_TASKS;
if (reload_requested) { if (reload_requested) {
#if CIRCUITPY_ALARM #if CIRCUITPY_ALARM
if (asleep) { if (fake_sleeping) {
board_init(); board_init();
} }
#endif #endif
@ -339,7 +339,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
if (serial_connected() && serial_bytes_available()) { if (serial_connected() && serial_bytes_available()) {
#if CIRCUITPY_ALARM #if CIRCUITPY_ALARM
if (asleep) { if (fake_sleeping) {
board_init(); board_init();
} }
#endif #endif
@ -355,7 +355,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
// an alarm alerts faster than our USB delay or if we pretended to deep // an alarm alerts faster than our USB delay or if we pretended to deep
// sleep. // sleep.
#if CIRCUITPY_ALARM #if CIRCUITPY_ALARM
if (asleep && common_hal_alarm_woken_from_sleep()) { if (fake_sleeping && common_hal_alarm_woken_from_sleep()) {
serial_write_compressed(translate("Woken up by alarm.\n")); serial_write_compressed(translate("Woken up by alarm.\n"));
board_init(); board_init();
supervisor_set_run_reason(RUN_REASON_STARTUP); supervisor_set_run_reason(RUN_REASON_STARTUP);
@ -394,14 +394,12 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
if (result.return_code & PYEXEC_DEEP_SLEEP) { if (result.return_code & PYEXEC_DEEP_SLEEP) {
// Make sure we have been awake long enough for USB to connect (enumeration delay). // Make sure we have been awake long enough for USB to connect (enumeration delay).
int64_t connecting_delay_ticks = CIRCUITPY_USB_CONNECTED_SLEEP_DELAY * 1024 - port_get_raw_ticks(NULL); int64_t connecting_delay_ticks = CIRCUITPY_USB_CONNECTED_SLEEP_DELAY * 1024 - port_get_raw_ticks(NULL);
if (connecting_delay_ticks > 0) { // Until it's safe to decide whether we're real/fake sleeping, just run the RGB
// Set when we've waited long enough so that we wake up from the // if (connecting_delay_ticks > 0) {
// port_idle_until_interrupt below and loop around to the real deep // port_interrupt_after_ticks(connecting_delay_ticks);
// sleep in the else clause. // // } else if (!fake_sleeping) {
port_interrupt_after_ticks(connecting_delay_ticks); if (connecting_delay_ticks < 0 && !fake_sleeping) {
// Deep sleep if we're not connected to a host. fake_sleeping = true;
} else if (!asleep) {
asleep = true;
new_status_color(BLACK); new_status_color(BLACK);
board_deinit(); board_deinit();
if (!supervisor_workflow_active()) { if (!supervisor_workflow_active()) {
@ -416,7 +414,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
} }
#endif #endif
if (!asleep) { if (!fake_sleeping) {
tick_rgb_status_animation(&animation); tick_rgb_status_animation(&animation);
} else { } else {
// This waits until a pretend deep sleep alarm occurs. They are set // This waits until a pretend deep sleep alarm occurs. They are set

View File

@ -101,7 +101,7 @@ bool alarm_pin_pinalarm_woke_us_up(void) {
} }
mp_obj_t alarm_pin_pinalarm_get_wakeup_alarm(size_t n_alarms, const mp_obj_t *alarms) { mp_obj_t alarm_pin_pinalarm_get_wakeup_alarm(size_t n_alarms, const mp_obj_t *alarms) {
// First, check to see if we match any given alarms. // For light sleep, we check if we match any existing alarms
uint64_t pin_status = ((uint64_t) pin_63_32_status) << 32 | pin_31_0_status; uint64_t pin_status = ((uint64_t) pin_63_32_status) << 32 | pin_31_0_status;
for (size_t i = 0; i < n_alarms; i++) { for (size_t i = 0; i < n_alarms; i++) {
if (!MP_OBJ_IS_TYPE(alarms[i], &alarm_pin_pinalarm_type)) { if (!MP_OBJ_IS_TYPE(alarms[i], &alarm_pin_pinalarm_type)) {
@ -112,6 +112,7 @@ mp_obj_t alarm_pin_pinalarm_get_wakeup_alarm(size_t n_alarms, const mp_obj_t *al
return alarms[i]; return alarms[i];
} }
} }
// For deep sleep, a new alarm must be created
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause(); esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
size_t pin_number = 64; size_t pin_number = 64;
if (cause == ESP_SLEEP_WAKEUP_EXT0) { if (cause == ESP_SLEEP_WAKEUP_EXT0) {
@ -151,7 +152,7 @@ static uint64_t high_alarms = 0;
static uint64_t low_alarms = 0; static uint64_t low_alarms = 0;
static uint64_t pull_pins = 0; static uint64_t pull_pins = 0;
void alarm_pin_pinalarm_reset(void) { void alarm_pin_pinalarm_reset_alarms(void) {
if (gpio_interrupt_handle != NULL) { if (gpio_interrupt_handle != NULL) {
esp_intr_free(gpio_interrupt_handle); esp_intr_free(gpio_interrupt_handle);
gpio_interrupt_handle = NULL; gpio_interrupt_handle = NULL;

View File

@ -37,6 +37,3 @@ bool board_requests_safe_mode(void) {
void reset_board(void) { void reset_board(void) {
} }
void board_deinit(void) {
}

View File

@ -39,70 +39,73 @@
#include "supervisor/port.h" #include "supervisor/port.h"
#include "supervisor/shared/workflow.h" #include "supervisor/shared/workflow.h"
#define STM_WAKEUP_UNDEF 0
#define STM_WAKEUP_GPIO 1 #define STM_WAKEUP_GPIO 1
#define STM_WAKEUP_TIMER 2 #define STM_WAKEUP_RTC 2
#define STM_ALARM_FLAG RTC->BKP0R
void common_hal_alarm_reset(void) { void common_hal_alarm_reset(void) {
// Reset the alarm flag
STM_ALARM_FLAG = 0x00;
// alarm_sleep_memory_reset(); // alarm_sleep_memory_reset();
alarm_pin_pinalarm_reset(); alarm_pin_pinalarm_reset();
alarm_time_timealarm_reset(); alarm_time_timealarm_reset();
// alarm_touch_touchalarm_reset();
// esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL); // esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL);
} }
STATIC uint8_t _get_wakeup_cause(void) { STATIC uint8_t _get_wakeup_cause(void) {
// If in light/fake sleep, check modules
if (alarm_pin_pinalarm_woke_us_up()) { if (alarm_pin_pinalarm_woke_us_up()) {
return STM_WAKEUP_GPIO; return STM_WAKEUP_GPIO;
} }
if (alarm_time_timealarm_woke_us_up()) { if (alarm_time_timealarm_woke_us_up()) {
return STM_WAKEUP_TIMER; return STM_WAKEUP_RTC;
} }
return 0; if (RTC->BKP0R & 0x01) {
// We've woken from deep sleep. Was it the WKUP pin or the RTC?
if (RTC->ISR & RTC_FLAG_ALRBF) {
// Alarm B is the deep sleep alarm
return STM_WAKEUP_RTC;
} else {
return STM_WAKEUP_GPIO;
}
}
return STM_WAKEUP_UNDEF;
} }
bool common_hal_alarm_woken_from_sleep(void) { bool common_hal_alarm_woken_from_sleep(void) {
return _get_wakeup_cause() != 0; return _get_wakeup_cause() != STM_WAKEUP_UNDEF;
} }
STATIC mp_obj_t _get_wake_alarm(size_t n_alarms, const mp_obj_t *alarms) { STATIC mp_obj_t _get_wake_alarm(size_t n_alarms, const mp_obj_t *alarms) {
if (alarm_pin_pinalarm_woke_us_up()) { if (alarm_pin_pinalarm_woke_us_up()) {
return alarm_pin_pinalarm_get_wakeup_alarm(n_alarms, alarms); return alarm_pin_pinalarm_get_wakeup_alarm(n_alarms, alarms);
} }
// esp_sleep_wakeup_cause_t cause = _get_wakeup_cause(); uint8_t cause = _get_wakeup_cause();
// switch (cause) { switch (cause) {
// case ESP_SLEEP_WAKEUP_TIMER: { case STM_WAKEUP_RTC: {
// return alarm_time_timealarm_get_wakeup_alarm(n_alarms, alarms); return alarm_time_timealarm_get_wakeup_alarm(n_alarms, alarms);
// } }
case STM_WAKEUP_GPIO: {
// case ESP_SLEEP_WAKEUP_GPIO: return alarm_pin_pinalarm_get_wakeup_alarm(n_alarms, alarms);
// case ESP_SLEEP_WAKEUP_EXT0: }
// case ESP_SLEEP_WAKEUP_EXT1: { case STM_WAKEUP_UNDEF:
// return alarm_pin_pinalarm_get_wakeup_alarm(n_alarms, alarms); default:
// } // Not a deep sleep reset.
break;
// case ESP_SLEEP_WAKEUP_TOUCHPAD: { }
// return alarm_touch_touchalarm_get_wakeup_alarm(n_alarms, alarms);
// }
// case ESP_SLEEP_WAKEUP_UNDEFINED:
// default:
// // Not a deep sleep reset.
// break;
// }
// return mp_const_none;
return mp_const_none; return mp_const_none;
} }
mp_obj_t common_hal_alarm_get_wake_alarm(void) { mp_obj_t common_hal_alarm_get_wake_alarm(void) {
//return _get_wake_alarm(0, NULL); return _get_wake_alarm(0, NULL);
return mp_const_none;
} }
// Set up light sleep or deep sleep alarms. // Set up light sleep or deep sleep alarms.
STATIC void _setup_sleep_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms) { STATIC void _setup_sleep_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms) {
alarm_pin_pinalarm_set_alarms(deep_sleep, n_alarms, alarms); alarm_pin_pinalarm_set_alarms(deep_sleep, n_alarms, alarms);
alarm_time_timealarm_set_alarms(deep_sleep, n_alarms, alarms); alarm_time_timealarm_set_alarms(deep_sleep, n_alarms, alarms);
// alarm_touch_touchalarm_set_alarm(deep_sleep, n_alarms, alarms);
} }
STATIC void _idle_until_alarm(void) { STATIC void _idle_until_alarm(void) {
@ -144,16 +147,19 @@ void NORETURN common_hal_alarm_enter_deep_sleep(void) {
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,1); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,1);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,0); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,0);
alarm_pin_pinalarm_prepare_for_deep_sleep(); alarm_pin_pinalarm_prepare_for_deep_sleep();
alarm_time_timealarm_prepare_for_deep_sleep();
port_disable_tick(); port_disable_tick();
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU); __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
// alarm_touch_touchalarm_prepare_for_deep_sleep();
// Set a flag in the backup registers to indicate sleep wakeup
STM_ALARM_FLAG = 0x01;
// HAL_PWR_EnableBkUpAccess(); // HAL_PWR_EnableBkUpAccess();
// __HAL_RCC_BACKUPRESET_FORCE(); // __HAL_RCC_BACKUPRESET_FORCE();
// __HAL_RCC_BACKUPRESET_RELEASE(); // __HAL_RCC_BACKUPRESET_RELEASE();
HAL_PWR_EnterSTANDBYMode(); HAL_PWR_EnterSTANDBYMode();
// Should never hit this // The above shuts down RAM, so we should never hit this
while(1); while(1);
} }

View File

@ -109,6 +109,7 @@ mp_obj_t alarm_pin_pinalarm_get_wakeup_alarm(size_t n_alarms, const mp_obj_t *al
} }
void alarm_pin_pinalarm_reset(void) { void alarm_pin_pinalarm_reset(void) {
HAL_PWR_DisableWakeUpPin(PWR_WAKEUP_PIN1);
alarm_pin_triggered = 0; alarm_pin_triggered = 0;
woke_up = false; woke_up = false;
} }
@ -118,20 +119,18 @@ void alarm_pin_pinalarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_ob
for (size_t i = 0; i < n_alarms; i++) { for (size_t i = 0; i < n_alarms; i++) {
if (MP_OBJ_IS_TYPE(alarms[i], &alarm_pin_pinalarm_type)) { if (MP_OBJ_IS_TYPE(alarms[i], &alarm_pin_pinalarm_type)) {
alarm_pin_pinalarm_obj_t *alarm = MP_OBJ_TO_PTR(alarms[i]); alarm_pin_pinalarm_obj_t *alarm = MP_OBJ_TO_PTR(alarms[i]);
if (deep_sleep) { if (deep_sleep) {
// Deep sleep only wakes on a rising edge from one pin, WKUP (PA00) // Deep sleep only wakes on a rising edge from one pin, WKUP (PA00)
// All pin settings are handled automatically.
if (alarm->pin != &pin_PA00) { if (alarm->pin != &pin_PA00) {
mp_raise_ValueError(translate("Only the WKUP pin can be used to wake from Deep Sleep")); mp_raise_ValueError(translate("Only the WKUP pin can be used to wake from Deep Sleep"));
} }
HAL_PWR_DisableWakeUpPin(PWR_WAKEUP_PIN1); // We can't actually turn WakeUp on here, since enabling it disables EXTI,
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU); // so we put it off until right before sleeping.
HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);
deep_wkup_enabled = true; deep_wkup_enabled = true;
} else {
stm_peripherals_exti_enable(alarm->pin->number);
} }
stm_peripherals_exti_enable(alarm->pin->number);
} }
} }
} }
@ -150,7 +149,9 @@ void alarm_pin_pinalarm_reset_alarms(bool deep_sleep, size_t n_alarms, const mp_
// If we don't have WKUP enabled, ensure it's disabled // If we don't have WKUP enabled, ensure it's disabled
// TODO; is this really required? // TODO; is this really required?
void alarm_pin_pinalarm_prepare_for_deep_sleep(void) { void alarm_pin_pinalarm_prepare_for_deep_sleep(void) {
if (!deep_wkup_enabled) { if (deep_wkup_enabled) {
HAL_PWR_DisableWakeUpPin(PWR_WAKEUP_PIN1); HAL_PWR_DisableWakeUpPin(PWR_WAKEUP_PIN1);
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);
} }
} }

View File

@ -34,6 +34,7 @@
#include STM32_HAL_H #include STM32_HAL_H
STATIC volatile bool woke_up; STATIC volatile bool woke_up;
STATIC uint32_t deep_sleep_ticks;
void common_hal_alarm_time_timealarm_construct(alarm_time_timealarm_obj_t *self, mp_float_t monotonic_time) { void common_hal_alarm_time_timealarm_construct(alarm_time_timealarm_obj_t *self, mp_float_t monotonic_time) {
self->monotonic_time = monotonic_time; self->monotonic_time = monotonic_time;
@ -95,7 +96,24 @@ void alarm_time_timealarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_
uint32_t wakeup_in_secs = MAX(0.0f, timealarm->monotonic_time - now_secs); uint32_t wakeup_in_secs = MAX(0.0f, timealarm->monotonic_time - now_secs);
uint32_t wakeup_in_ticks = wakeup_in_secs * 1024; uint32_t wakeup_in_ticks = wakeup_in_secs * 1024;
// In the deep sleep case, we can't start the timer until the USB delay has finished
if (deep_sleep) {
deep_sleep_ticks = wakeup_in_ticks;
} else {
deep_sleep_ticks = 0;
}
// Use alarm B, since port reserves A // Use alarm B, since port reserves A
// If true deep sleep is called, it will either ignore or overwrite this depending on
// whether it is shorter or longer than the USB delay
stm32_peripherals_rtc_assign_alarm_callback(PERIPHERALS_ALARM_B,timer_callback); stm32_peripherals_rtc_assign_alarm_callback(PERIPHERALS_ALARM_B,timer_callback);
stm32_peripherals_rtc_set_alarm(PERIPHERALS_ALARM_B,wakeup_in_ticks); stm32_peripherals_rtc_set_alarm(PERIPHERALS_ALARM_B,wakeup_in_ticks);
} }
void alarm_time_timealarm_prepare_for_deep_sleep(void) {
if (deep_sleep_ticks) {
// This is used for both fake and real deep sleep, so it still needs the callback
stm32_peripherals_rtc_assign_alarm_callback(PERIPHERALS_ALARM_B,timer_callback);
stm32_peripherals_rtc_set_alarm(PERIPHERALS_ALARM_B,deep_sleep_ticks);
deep_sleep_ticks = 0;
}
}

View File

@ -38,3 +38,5 @@ mp_obj_t alarm_time_timealarm_get_wakeup_alarm(size_t n_alarms, const mp_obj_t *
bool alarm_time_timealarm_woke_us_up(void); bool alarm_time_timealarm_woke_us_up(void);
void alarm_time_timealarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms); void alarm_time_timealarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms);
void alarm_time_timealarm_reset(void); void alarm_time_timealarm_reset(void);
void alarm_time_timealarm_prepare_for_deep_sleep(void);

View File

@ -369,3 +369,9 @@ void _init(void)
{ {
} }
#if CIRCUITPY_ALARM
// in case boards/xxx/board.c does not provide board_deinit()
MP_WEAK void board_deinit(void) {
}
#endif

View File

@ -92,7 +92,7 @@ void validate_objs_are_alarms(size_t n_args, const mp_obj_t *objs) {
//| This allows the user to interrupt an existing program with ctrl-C, //| This allows the user to interrupt an existing program with ctrl-C,
//| and to edit the files in CIRCUITPY, which would not be possible in true light sleep. //| and to edit the files in CIRCUITPY, which would not be possible in true light sleep.
//| Thus, to use light sleep and save significant power, //| Thus, to use light sleep and save significant power,
// it may be necessary to disconnect from the host. //| it may be necessary to disconnect from the host.
//| """ //| """
//| ... //| ...
//| //|