diff --git a/ports/stm/common-hal/alarm/__init__.c b/ports/stm/common-hal/alarm/__init__.c index 14c484f1b0..0f19f7922e 100644 --- a/ports/stm/common-hal/alarm/__init__.c +++ b/ports/stm/common-hal/alarm/__init__.c @@ -39,11 +39,7 @@ #include "supervisor/port.h" #include "supervisor/shared/workflow.h" -#define STM_WAKEUP_UNDEF 0 -#define STM_WAKEUP_GPIO 1 -#define STM_WAKEUP_RTC 2 - -#define STM_ALARM_FLAG RTC->BKP0R +STATIC uint8_t true_deep_wake_reason; void alarm_reset(void) { // Reset the alarm flag @@ -54,6 +50,12 @@ void alarm_reset(void) { // esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL); } +// Kind of a hack, required as RTC is reset in port.c +// TODO: in the future, don't reset it at all, just override critical flags +void alarm_set_wakeup_reason(uint8_t reason) { + true_deep_wake_reason = reason; +} + STATIC uint8_t _get_wakeup_cause(void) { // If in light/fake sleep, check modules if (alarm_pin_pinalarm_woke_us_up()) { @@ -62,14 +64,9 @@ STATIC uint8_t _get_wakeup_cause(void) { if (alarm_time_timealarm_woke_us_up()) { return STM_WAKEUP_RTC; } - 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; - } + // Check to see if we woke from deep sleep (reason set in port_init) + if (true_deep_wake_reason) { + return true_deep_wake_reason; } return STM_WAKEUP_UNDEF; } @@ -160,6 +157,19 @@ void NORETURN common_hal_alarm_enter_deep_sleep(void) { while(1); } +void common_hal_alarm_pretending_deep_sleep(void) { + // Re-enable the WKUP pin (PA00) since VM cleanup resets it + // If there are no PinAlarms, EXTI won't be turned on, and this won't do anything + // TODO: replace with `prepare_for_fake_deep_sleep` if other WKUP are added. + GPIO_InitTypeDef GPIO_InitStruct = {0}; + GPIO_InitStruct.Pin = pin_mask(0); + GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; + GPIO_InitStruct.Pull = GPIO_PULLDOWN; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + port_idle_until_interrupt(); +} + void common_hal_alarm_gc_collect(void) { gc_collect_ptr(shared_alarm_get_wake_alarm()); } diff --git a/ports/stm/common-hal/alarm/__init__.h b/ports/stm/common-hal/alarm/__init__.h index cb90dccb28..0bfafbcee2 100644 --- a/ports/stm/common-hal/alarm/__init__.h +++ b/ports/stm/common-hal/alarm/__init__.h @@ -31,6 +31,13 @@ const alarm_sleep_memory_obj_t alarm_sleep_memory_obj; +#define STM_WAKEUP_UNDEF 0 +#define STM_WAKEUP_GPIO 1 +#define STM_WAKEUP_RTC 2 + +#define STM_ALARM_FLAG RTC->BKP0R + +extern void alarm_set_wakeup_reason(uint8_t reason); extern void alarm_reset(void); #endif // MICROPY_INCLUDED_STM32_COMMON_HAL_ALARM__INIT__H diff --git a/ports/stm/common-hal/alarm/pin/PinAlarm.c b/ports/stm/common-hal/alarm/pin/PinAlarm.c index d7f1c30398..d2594c10d9 100644 --- a/ports/stm/common-hal/alarm/pin/PinAlarm.c +++ b/ports/stm/common-hal/alarm/pin/PinAlarm.c @@ -36,6 +36,7 @@ STATIC bool woke_up; STATIC uint16_t alarm_pin_triggered; STATIC bool deep_wkup_enabled; +STATIC bool reserved_alarms[STM32_GPIO_PORT_SIZE]; STATIC void pin_alarm_callback(uint8_t num) { alarm_pin_triggered |= (1 << num); @@ -50,7 +51,6 @@ void common_hal_alarm_pin_pinalarm_construct(alarm_pin_pinalarm_obj_t *self, con if (!stm_peripherals_exti_is_free(pin->number)) { mp_raise_RuntimeError(translate("Pin interrupt already in use")); } - stm_peripherals_exti_reserve(pin->number); GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = pin_mask(pin->number); GPIO_InitStruct.Mode = value ? GPIO_MODE_IT_RISING : GPIO_MODE_IT_FALLING; @@ -63,8 +63,7 @@ void common_hal_alarm_pin_pinalarm_construct(alarm_pin_pinalarm_obj_t *self, con } HAL_GPIO_Init(pin_port(pin->port), &GPIO_InitStruct); - stm_peripherals_exti_set_callback(pin_alarm_callback,pin->number); - + // EXTI is set up and enabled in set_alarm self->pin = pin; self->value = value; self->pull = pull; @@ -101,10 +100,11 @@ mp_obj_t alarm_pin_pinalarm_get_wakeup_alarm(size_t n_alarms, const mp_obj_t *al } } - // Placeholder for deep sleep + // If the above isn't true, we woke from deep sleep, so create a new alarm alarm_pin_pinalarm_obj_t *alarm = m_new_obj(alarm_pin_pinalarm_obj_t); alarm->base.type = &alarm_pin_pinalarm_type; - alarm->pin = NULL; + // TODO: replace this if/when other WKUP pins are supported + alarm->pin = &pin_PA00; return alarm; } @@ -113,6 +113,12 @@ void alarm_pin_pinalarm_reset(void) { alarm_pin_triggered = 0; woke_up = false; deep_wkup_enabled = false; + for (uint8_t i = 0; i < STM32_GPIO_PORT_SIZE; i++) { + if (reserved_alarms[i]) { + stm_peripherals_exti_reset_exti(i); + reserved_alarms[i] = false; + } + } } // Deep sleep alarms don't actually make use of EXTI, but we pretend they're the same. @@ -124,14 +130,24 @@ void alarm_pin_pinalarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_ob // 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")); + mp_raise_ValueError(translate("Pin cannot wake from Deep Sleep")); + } + if (alarm->value == false || alarm->pull == false) { + // Enabling WakeUp automatically sets this, but warn anyway to set expectations + mp_raise_ValueError(translate("Deep sleep pins must use a rising edge with pulldown")); } // 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; + // EXTI needs to persist past the VM cleanup for fake deep sleep + stm_peripherals_exti_never_reset(alarm->pin->number); } - + if (!stm_peripherals_exti_reserve(alarm->pin->number)) { + mp_raise_RuntimeError(translate("Pin interrupt already in use")); + } + stm_peripherals_exti_set_callback(pin_alarm_callback,alarm->pin->number); stm_peripherals_exti_enable(alarm->pin->number); + reserved_alarms[alarm->pin->number] = true; } } } diff --git a/ports/stm/peripherals/exti.c b/ports/stm/peripherals/exti.c index 26e7195671..fe17309f06 100644 --- a/ports/stm/peripherals/exti.c +++ b/ports/stm/peripherals/exti.c @@ -33,16 +33,30 @@ #include "peripherals/exti.h" STATIC bool stm_exti_reserved[STM32_GPIO_PORT_SIZE]; +STATIC bool stm_exti_never_reset[STM32_GPIO_PORT_SIZE]; STATIC void (*stm_exti_callback[STM32_GPIO_PORT_SIZE])(uint8_t num); void exti_reset(void) { for (size_t i = 0;i < STM32_GPIO_PORT_SIZE; i++) { - stm_exti_reserved[i] = false; - stm_exti_callback[i] = NULL; - stm_peripherals_exti_disable(i); + if (!stm_exti_never_reset[i]) { + stm_exti_reserved[i] = false; + stm_exti_callback[i] = NULL; + stm_peripherals_exti_disable(i); + } } } +void stm_peripherals_exti_never_reset(uint8_t num) { + stm_exti_never_reset[num] = true; +} + +void stm_peripherals_exti_reset_exti(uint8_t num) { + stm_peripherals_exti_disable(num); + stm_exti_never_reset[num] = false; + stm_exti_reserved[num] = false; + stm_exti_callback[num] = NULL; +} + bool stm_peripherals_exti_is_free(uint8_t num) { return !stm_exti_reserved[num]; } diff --git a/ports/stm/peripherals/exti.h b/ports/stm/peripherals/exti.h index 15e2207c9c..4a3358ec2e 100644 --- a/ports/stm/peripherals/exti.h +++ b/ports/stm/peripherals/exti.h @@ -32,6 +32,8 @@ #define STM32_GPIO_PORT_SIZE 16 void exti_reset(void); +void stm_peripherals_exti_never_reset(uint8_t num); +void stm_peripherals_exti_reset_exti(uint8_t num); bool stm_peripherals_exti_is_free(uint8_t num); bool stm_peripherals_exti_reserve(uint8_t num); void stm_peripherals_exti_enable(uint8_t num); diff --git a/ports/stm/peripherals/rtc.c b/ports/stm/peripherals/rtc.c index 70753d3b8e..427dcf4e9a 100644 --- a/ports/stm/peripherals/rtc.c +++ b/ports/stm/peripherals/rtc.c @@ -154,7 +154,7 @@ void stm32_peripherals_rtc_disable_wakeup_timer(void) { HAL_RTCEx_DeactivateWakeUpTimer(&hrtc); } -void stm32_peripherals_reset_alarms(void) { +void stm32_peripherals_rtc_reset_alarms(void) { HAL_RTC_DeactivateAlarm(&hrtc, RTC_ALARM_A); HAL_RTC_DeactivateAlarm(&hrtc, RTC_ALARM_B); } diff --git a/ports/stm/peripherals/rtc.h b/ports/stm/peripherals/rtc.h index d010a2a0c8..2dea6920a4 100644 --- a/ports/stm/peripherals/rtc.h +++ b/ports/stm/peripherals/rtc.h @@ -43,7 +43,7 @@ void stm32_peripherals_rtc_set_wakeup_mode_tick(void); void stm32_peripherals_rtc_enable_wakeup_timer(void); void stm32_peripherals_rtc_disable_wakeup_timer(void); -void stm32_peripherals_reset_alarms(void); +void stm32_peripherals_rtc_reset_alarms(void); void stm32_peripherals_rtc_assign_alarm_callback(uint8_t alarm_idx, void(*callback)(void)) ; void stm32_peripherals_rtc_set_alarm(uint8_t alarm_idx, uint32_t ticks); bool stm32_peripherals_rtc_alarm_triggered(uint8_t alarm_idx); diff --git a/ports/stm/supervisor/port.c b/ports/stm/supervisor/port.c index 78c05fc98e..22061257d5 100644 --- a/ports/stm/supervisor/port.c +++ b/ports/stm/supervisor/port.c @@ -53,6 +53,9 @@ #if CIRCUITPY_PULSEIO || CIRCUITPY_ALARM #include "peripherals/exti.h" #endif +#if CIRCUITPY_ALARM +#include "common-hal/alarm/__init__.h" +#endif #include "peripherals/clocks.h" #include "peripherals/gpio.h" @@ -170,8 +173,18 @@ safe_mode_t port_init(void) { __HAL_RCC_SYSCFG_CLK_ENABLE(); __HAL_RCC_PWR_CLK_ENABLE(); - HAL_PWR_EnableBkUpAccess(); + + // TODO: don't reset RTC entirely and move this back to alarm + if (STM_ALARM_FLAG & 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 + alarm_set_wakeup_reason(STM_WAKEUP_RTC); + } else { + alarm_set_wakeup_reason(STM_WAKEUP_GPIO); + } + } __HAL_RCC_BACKUPRESET_FORCE(); __HAL_RCC_BACKUPRESET_RELEASE(); @@ -180,7 +193,7 @@ safe_mode_t port_init(void) { stm32_peripherals_rtc_init(); __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU); - stm32_peripherals_reset_alarms(); + stm32_peripherals_rtc_reset_alarms(); // Turn off SysTick SysTick->CTRL = 0;