From 529fb52309a356593025915fef3da8a66f4da313 Mon Sep 17 00:00:00 2001 From: Lucian Copeland Date: Sat, 27 Mar 2021 13:16:12 -0400 Subject: [PATCH] Style changes and wakeup detection --- main.c | 24 +++---- ports/esp32s2/common-hal/alarm/pin/PinAlarm.c | 5 +- .../boards/feather_stm32f405_express/board.c | 3 - ports/stm/common-hal/alarm/__init__.c | 70 ++++++++++--------- ports/stm/common-hal/alarm/pin/PinAlarm.c | 17 ++--- ports/stm/common-hal/alarm/time/TimeAlarm.c | 18 +++++ ports/stm/common-hal/alarm/time/TimeAlarm.h | 2 + ports/stm/supervisor/port.c | 6 ++ shared-bindings/alarm/__init__.c | 2 +- 9 files changed, 88 insertions(+), 59 deletions(-) diff --git a/main.c b/main.c index c7a5afabcb..68c0e025e1 100755 --- a/main.c +++ b/main.c @@ -323,12 +323,12 @@ STATIC bool run_code_py(safe_mode_t safe_mode) { rgb_status_animation_t animation; prep_rgb_status_animation(&result, found_main, safe_mode, &animation); - bool asleep = false; + bool fake_sleeping = false; while (true) { RUN_BACKGROUND_TASKS; if (reload_requested) { #if CIRCUITPY_ALARM - if (asleep) { + if (fake_sleeping) { board_init(); } #endif @@ -339,7 +339,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode) { if (serial_connected() && serial_bytes_available()) { #if CIRCUITPY_ALARM - if (asleep) { + if (fake_sleeping) { board_init(); } #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 // sleep. #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")); board_init(); 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) { // 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); - if (connecting_delay_ticks > 0) { - // Set when we've waited long enough so that we wake up from the - // port_idle_until_interrupt below and loop around to the real deep - // sleep in the else clause. - port_interrupt_after_ticks(connecting_delay_ticks); - // Deep sleep if we're not connected to a host. - } else if (!asleep) { - asleep = true; + // Until it's safe to decide whether we're real/fake sleeping, just run the RGB + // if (connecting_delay_ticks > 0) { + // port_interrupt_after_ticks(connecting_delay_ticks); + // // } else if (!fake_sleeping) { + if (connecting_delay_ticks < 0 && !fake_sleeping) { + fake_sleeping = true; new_status_color(BLACK); board_deinit(); if (!supervisor_workflow_active()) { @@ -416,7 +414,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode) { } #endif - if (!asleep) { + if (!fake_sleeping) { tick_rgb_status_animation(&animation); } else { // This waits until a pretend deep sleep alarm occurs. They are set diff --git a/ports/esp32s2/common-hal/alarm/pin/PinAlarm.c b/ports/esp32s2/common-hal/alarm/pin/PinAlarm.c index df8d10ef9e..237136c3d8 100644 --- a/ports/esp32s2/common-hal/alarm/pin/PinAlarm.c +++ b/ports/esp32s2/common-hal/alarm/pin/PinAlarm.c @@ -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) { - // 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; for (size_t i = 0; i < n_alarms; i++) { 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]; } } + // For deep sleep, a new alarm must be created esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause(); size_t pin_number = 64; 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 pull_pins = 0; -void alarm_pin_pinalarm_reset(void) { +void alarm_pin_pinalarm_reset_alarms(void) { if (gpio_interrupt_handle != NULL) { esp_intr_free(gpio_interrupt_handle); gpio_interrupt_handle = NULL; diff --git a/ports/stm/boards/feather_stm32f405_express/board.c b/ports/stm/boards/feather_stm32f405_express/board.c index 6652c840c6..f8e462f938 100644 --- a/ports/stm/boards/feather_stm32f405_express/board.c +++ b/ports/stm/boards/feather_stm32f405_express/board.c @@ -37,6 +37,3 @@ bool board_requests_safe_mode(void) { void reset_board(void) { } - -void board_deinit(void) { -} \ No newline at end of file diff --git a/ports/stm/common-hal/alarm/__init__.c b/ports/stm/common-hal/alarm/__init__.c index 1ee43a99cc..0cefc58834 100644 --- a/ports/stm/common-hal/alarm/__init__.c +++ b/ports/stm/common-hal/alarm/__init__.c @@ -39,70 +39,73 @@ #include "supervisor/port.h" #include "supervisor/shared/workflow.h" +#define STM_WAKEUP_UNDEF 0 #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) { + // Reset the alarm flag + STM_ALARM_FLAG = 0x00; // alarm_sleep_memory_reset(); alarm_pin_pinalarm_reset(); alarm_time_timealarm_reset(); - // alarm_touch_touchalarm_reset(); // esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL); } STATIC uint8_t _get_wakeup_cause(void) { + // If in light/fake sleep, check modules if (alarm_pin_pinalarm_woke_us_up()) { return STM_WAKEUP_GPIO; } 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) { - 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) { if (alarm_pin_pinalarm_woke_us_up()) { return alarm_pin_pinalarm_get_wakeup_alarm(n_alarms, alarms); } - // esp_sleep_wakeup_cause_t cause = _get_wakeup_cause(); - // switch (cause) { - // case ESP_SLEEP_WAKEUP_TIMER: { - // return alarm_time_timealarm_get_wakeup_alarm(n_alarms, alarms); - // } - - // case ESP_SLEEP_WAKEUP_GPIO: - // case ESP_SLEEP_WAKEUP_EXT0: - // case ESP_SLEEP_WAKEUP_EXT1: { - // return alarm_pin_pinalarm_get_wakeup_alarm(n_alarms, alarms); - // } - - // 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; + uint8_t cause = _get_wakeup_cause(); + switch (cause) { + case STM_WAKEUP_RTC: { + return alarm_time_timealarm_get_wakeup_alarm(n_alarms, alarms); + } + case STM_WAKEUP_GPIO: { + return alarm_pin_pinalarm_get_wakeup_alarm(n_alarms, alarms); + } + case STM_WAKEUP_UNDEF: + default: + // Not a deep sleep reset. + break; + } return mp_const_none; } mp_obj_t common_hal_alarm_get_wake_alarm(void) { - //return _get_wake_alarm(0, NULL); - return mp_const_none; + return _get_wake_alarm(0, NULL); } // 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) { alarm_pin_pinalarm_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) { @@ -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,0); alarm_pin_pinalarm_prepare_for_deep_sleep(); + alarm_time_timealarm_prepare_for_deep_sleep(); port_disable_tick(); __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_RCC_BACKUPRESET_FORCE(); // __HAL_RCC_BACKUPRESET_RELEASE(); HAL_PWR_EnterSTANDBYMode(); - // Should never hit this + // The above shuts down RAM, so we should never hit this while(1); } diff --git a/ports/stm/common-hal/alarm/pin/PinAlarm.c b/ports/stm/common-hal/alarm/pin/PinAlarm.c index 9d6423d859..3bff19b76c 100644 --- a/ports/stm/common-hal/alarm/pin/PinAlarm.c +++ b/ports/stm/common-hal/alarm/pin/PinAlarm.c @@ -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) { + HAL_PWR_DisableWakeUpPin(PWR_WAKEUP_PIN1); alarm_pin_triggered = 0; 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++) { if (MP_OBJ_IS_TYPE(alarms[i], &alarm_pin_pinalarm_type)) { alarm_pin_pinalarm_obj_t *alarm = MP_OBJ_TO_PTR(alarms[i]); - if (deep_sleep) { // Deep sleep only wakes on a rising edge from one pin, WKUP (PA00) + // All pin settings are handled automatically. if (alarm->pin != &pin_PA00) { mp_raise_ValueError(translate("Only the WKUP pin can be used to wake from Deep Sleep")); } - HAL_PWR_DisableWakeUpPin(PWR_WAKEUP_PIN1); - __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU); - HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1); - + // We can't actually turn WakeUp on here, since enabling it disables EXTI, + // so we put it off until right before sleeping. 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 // TODO; is this really required? 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_CLEAR_FLAG(PWR_FLAG_WU); + HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1); } } diff --git a/ports/stm/common-hal/alarm/time/TimeAlarm.c b/ports/stm/common-hal/alarm/time/TimeAlarm.c index 5817feb585..5ca08fa994 100644 --- a/ports/stm/common-hal/alarm/time/TimeAlarm.c +++ b/ports/stm/common-hal/alarm/time/TimeAlarm.c @@ -34,6 +34,7 @@ #include STM32_HAL_H 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) { 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_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 + // 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_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; + } +} diff --git a/ports/stm/common-hal/alarm/time/TimeAlarm.h b/ports/stm/common-hal/alarm/time/TimeAlarm.h index d4041dc0ae..11c7a634c5 100644 --- a/ports/stm/common-hal/alarm/time/TimeAlarm.h +++ b/ports/stm/common-hal/alarm/time/TimeAlarm.h @@ -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); 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_prepare_for_deep_sleep(void); diff --git a/ports/stm/supervisor/port.c b/ports/stm/supervisor/port.c index d040cee184..49cc92ca5b 100644 --- a/ports/stm/supervisor/port.c +++ b/ports/stm/supervisor/port.c @@ -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 diff --git a/shared-bindings/alarm/__init__.c b/shared-bindings/alarm/__init__.c index 46aa88dff4..b04e821bbb 100644 --- a/shared-bindings/alarm/__init__.c +++ b/shared-bindings/alarm/__init__.c @@ -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, //| 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, -// it may be necessary to disconnect from the host. +//| it may be necessary to disconnect from the host. //| """ //| ... //|