Implement fake and true deep sleep alarm differentiation

This commit is contained in:
Lucian Copeland 2021-04-02 15:13:10 -04:00
parent 17585e1e07
commit 66a1583183
8 changed files with 89 additions and 27 deletions

View File

@ -39,11 +39,7 @@
#include "supervisor/port.h" #include "supervisor/port.h"
#include "supervisor/shared/workflow.h" #include "supervisor/shared/workflow.h"
#define STM_WAKEUP_UNDEF 0 STATIC uint8_t true_deep_wake_reason;
#define STM_WAKEUP_GPIO 1
#define STM_WAKEUP_RTC 2
#define STM_ALARM_FLAG RTC->BKP0R
void alarm_reset(void) { void alarm_reset(void) {
// Reset the alarm flag // Reset the alarm flag
@ -54,6 +50,12 @@ void alarm_reset(void) {
// esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL); // 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) { STATIC uint8_t _get_wakeup_cause(void) {
// If in light/fake sleep, check modules // If in light/fake sleep, check modules
if (alarm_pin_pinalarm_woke_us_up()) { 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()) { if (alarm_time_timealarm_woke_us_up()) {
return STM_WAKEUP_RTC; return STM_WAKEUP_RTC;
} }
if (RTC->BKP0R & 0x01) { // Check to see if we woke from deep sleep (reason set in port_init)
// We've woken from deep sleep. Was it the WKUP pin or the RTC? if (true_deep_wake_reason) {
if (RTC->ISR & RTC_FLAG_ALRBF) { return true_deep_wake_reason;
// Alarm B is the deep sleep alarm
return STM_WAKEUP_RTC;
} else {
return STM_WAKEUP_GPIO;
}
} }
return STM_WAKEUP_UNDEF; return STM_WAKEUP_UNDEF;
} }
@ -160,6 +157,19 @@ void NORETURN common_hal_alarm_enter_deep_sleep(void) {
while(1); 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) { void common_hal_alarm_gc_collect(void) {
gc_collect_ptr(shared_alarm_get_wake_alarm()); gc_collect_ptr(shared_alarm_get_wake_alarm());
} }

View File

@ -31,6 +31,13 @@
const alarm_sleep_memory_obj_t alarm_sleep_memory_obj; 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); extern void alarm_reset(void);
#endif // MICROPY_INCLUDED_STM32_COMMON_HAL_ALARM__INIT__H #endif // MICROPY_INCLUDED_STM32_COMMON_HAL_ALARM__INIT__H

View File

@ -36,6 +36,7 @@ STATIC bool woke_up;
STATIC uint16_t alarm_pin_triggered; STATIC uint16_t alarm_pin_triggered;
STATIC bool deep_wkup_enabled; STATIC bool deep_wkup_enabled;
STATIC bool reserved_alarms[STM32_GPIO_PORT_SIZE];
STATIC void pin_alarm_callback(uint8_t num) { STATIC void pin_alarm_callback(uint8_t num) {
alarm_pin_triggered |= (1 << 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)) { if (!stm_peripherals_exti_is_free(pin->number)) {
mp_raise_RuntimeError(translate("Pin interrupt already in use")); mp_raise_RuntimeError(translate("Pin interrupt already in use"));
} }
stm_peripherals_exti_reserve(pin->number);
GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = pin_mask(pin->number); GPIO_InitStruct.Pin = pin_mask(pin->number);
GPIO_InitStruct.Mode = value ? GPIO_MODE_IT_RISING : GPIO_MODE_IT_FALLING; 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); 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->pin = pin;
self->value = value; self->value = value;
self->pull = pull; 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_pin_pinalarm_obj_t *alarm = m_new_obj(alarm_pin_pinalarm_obj_t);
alarm->base.type = &alarm_pin_pinalarm_type; 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; return alarm;
} }
@ -113,6 +113,12 @@ void alarm_pin_pinalarm_reset(void) {
alarm_pin_triggered = 0; alarm_pin_triggered = 0;
woke_up = false; woke_up = false;
deep_wkup_enabled = 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. // 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) // Deep sleep only wakes on a rising edge from one pin, WKUP (PA00)
// All pin settings are handled automatically. // 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("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, // We can't actually turn WakeUp on here, since enabling it disables EXTI,
// so we put it off until right before sleeping. // so we put it off until right before sleeping.
deep_wkup_enabled = true; 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); stm_peripherals_exti_enable(alarm->pin->number);
reserved_alarms[alarm->pin->number] = true;
} }
} }
} }

View File

@ -33,16 +33,30 @@
#include "peripherals/exti.h" #include "peripherals/exti.h"
STATIC bool stm_exti_reserved[STM32_GPIO_PORT_SIZE]; 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); STATIC void (*stm_exti_callback[STM32_GPIO_PORT_SIZE])(uint8_t num);
void exti_reset(void) { void exti_reset(void) {
for (size_t i = 0;i < STM32_GPIO_PORT_SIZE; i++) { for (size_t i = 0;i < STM32_GPIO_PORT_SIZE; i++) {
stm_exti_reserved[i] = false; if (!stm_exti_never_reset[i]) {
stm_exti_callback[i] = NULL; stm_exti_reserved[i] = false;
stm_peripherals_exti_disable(i); 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) { bool stm_peripherals_exti_is_free(uint8_t num) {
return !stm_exti_reserved[num]; return !stm_exti_reserved[num];
} }

View File

@ -32,6 +32,8 @@
#define STM32_GPIO_PORT_SIZE 16 #define STM32_GPIO_PORT_SIZE 16
void exti_reset(void); 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_is_free(uint8_t num);
bool stm_peripherals_exti_reserve(uint8_t num); bool stm_peripherals_exti_reserve(uint8_t num);
void stm_peripherals_exti_enable(uint8_t num); void stm_peripherals_exti_enable(uint8_t num);

View File

@ -154,7 +154,7 @@ void stm32_peripherals_rtc_disable_wakeup_timer(void) {
HAL_RTCEx_DeactivateWakeUpTimer(&hrtc); 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_A);
HAL_RTC_DeactivateAlarm(&hrtc, RTC_ALARM_B); HAL_RTC_DeactivateAlarm(&hrtc, RTC_ALARM_B);
} }

View File

@ -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_enable_wakeup_timer(void);
void stm32_peripherals_rtc_disable_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_assign_alarm_callback(uint8_t alarm_idx, void(*callback)(void)) ;
void stm32_peripherals_rtc_set_alarm(uint8_t alarm_idx, uint32_t ticks); void stm32_peripherals_rtc_set_alarm(uint8_t alarm_idx, uint32_t ticks);
bool stm32_peripherals_rtc_alarm_triggered(uint8_t alarm_idx); bool stm32_peripherals_rtc_alarm_triggered(uint8_t alarm_idx);

View File

@ -53,6 +53,9 @@
#if CIRCUITPY_PULSEIO || CIRCUITPY_ALARM #if CIRCUITPY_PULSEIO || CIRCUITPY_ALARM
#include "peripherals/exti.h" #include "peripherals/exti.h"
#endif #endif
#if CIRCUITPY_ALARM
#include "common-hal/alarm/__init__.h"
#endif
#include "peripherals/clocks.h" #include "peripherals/clocks.h"
#include "peripherals/gpio.h" #include "peripherals/gpio.h"
@ -170,8 +173,18 @@ safe_mode_t port_init(void) {
__HAL_RCC_SYSCFG_CLK_ENABLE(); __HAL_RCC_SYSCFG_CLK_ENABLE();
__HAL_RCC_PWR_CLK_ENABLE(); __HAL_RCC_PWR_CLK_ENABLE();
HAL_PWR_EnableBkUpAccess(); 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_FORCE();
__HAL_RCC_BACKUPRESET_RELEASE(); __HAL_RCC_BACKUPRESET_RELEASE();
@ -180,7 +193,7 @@ safe_mode_t port_init(void) {
stm32_peripherals_rtc_init(); stm32_peripherals_rtc_init();
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU); __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
stm32_peripherals_reset_alarms(); stm32_peripherals_rtc_reset_alarms();
// Turn off SysTick // Turn off SysTick
SysTick->CTRL = 0; SysTick->CTRL = 0;