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/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());
}

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -33,14 +33,28 @@
#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++) {
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) {

View File

@ -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);

View File

@ -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);
}

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_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);

View File

@ -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;