summaryrefslogtreecommitdiff
path: root/ports
diff options
context:
space:
mode:
authorScott Shawcroft <scott@tannewt.org>2020-12-22 16:13:02 -0800
committerScott Shawcroft <scott@tannewt.org>2020-12-22 16:13:02 -0800
commit1fca297a2d2bfefb1cdef3ecbac05f54d15e08eb (patch)
treee9273efad20b60e5a7e2864ffc3f0fd53ed531c9 /ports
parentd4e9eea397c887d9eceb5f4c6aba117a4dc3d03b (diff)
A couple sleep fixes
* Better messaging when code is stopped by an auto-reload. * Auto-reload works during sleeps on ESP32-S2. Ticks wake up the main task each time. * Made internal naming consistent. CamelCase Python names are NOT separated by an underscore.
Diffstat (limited to 'ports')
-rw-r--r--ports/esp32s2/common-hal/alarm/__init__.c31
-rw-r--r--ports/esp32s2/common-hal/alarm/pin/PinAlarm.c60
-rw-r--r--ports/esp32s2/common-hal/alarm/pin/PinAlarm.h12
-rw-r--r--ports/esp32s2/common-hal/alarm/time/TimeAlarm.c26
-rw-r--r--ports/esp32s2/common-hal/alarm/time/TimeAlarm.h2
-rw-r--r--ports/esp32s2/supervisor/port.c28
6 files changed, 75 insertions, 84 deletions
diff --git a/ports/esp32s2/common-hal/alarm/__init__.c b/ports/esp32s2/common-hal/alarm/__init__.c
index 9f19f1afc..f2686cf18 100644
--- a/ports/esp32s2/common-hal/alarm/__init__.c
+++ b/ports/esp32s2/common-hal/alarm/__init__.c
@@ -54,7 +54,7 @@ const alarm_sleep_memory_obj_t alarm_sleep_memory_obj = {
void alarm_reset(void) {
alarm_time_timealarm_reset();
- alarm_pin_pin_alarm_reset();
+ alarm_pin_pinalarm_reset();
alarm_sleep_memory_reset();
esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL);
}
@@ -63,7 +63,7 @@ STATIC esp_sleep_wakeup_cause_t _get_wakeup_cause(void) {
if (alarm_time_timealarm_woke_us_up()) {
return ESP_SLEEP_WAKEUP_TIMER;
}
- if (alarm_pin_pin_alarm_woke_us_up()) {
+ if (alarm_pin_pinalarm_woke_us_up()) {
return ESP_SLEEP_WAKEUP_GPIO;
}
@@ -84,7 +84,7 @@ STATIC mp_obj_t _get_wake_alarm(size_t n_alarms, const mp_obj_t *alarms) {
case ESP_SLEEP_WAKEUP_GPIO:
case ESP_SLEEP_WAKEUP_EXT0:
case ESP_SLEEP_WAKEUP_EXT1: {
- return alarm_pin_pin_alarm_get_wakeup_alarm(n_alarms, alarms);
+ return alarm_pin_pinalarm_get_wakeup_alarm(n_alarms, alarms);
}
case ESP_SLEEP_WAKEUP_TOUCHPAD:
@@ -106,7 +106,7 @@ mp_obj_t common_hal_alarm_get_wake_alarm(void) {
// 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_pin_alarm_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);
}
@@ -123,25 +123,14 @@ STATIC void _idle_until_alarm(void) {
}
}
-// Is it safe to do a light sleep? Check whether WiFi is on or there are
-// other ongoing tasks that should not be shut down.
-STATIC bool _light_sleep_ok(void) {
- int64_t connecting_delay_ticks = CIRCUITPY_USB_CONNECTED_SLEEP_DELAY * 1024 - port_get_raw_ticks(NULL);
- return !common_hal_wifi_radio_get_enabled(&common_hal_wifi_radio_obj) &&
- !supervisor_workflow_active() &&
- connecting_delay_ticks <= 0;
-}
-
mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj_t *alarms) {
_setup_sleep_alarms(false, n_alarms, alarms);
- // Light sleep can break some functionality so only do it when possible. Otherwise we idle.
- if (_light_sleep_ok()) {
- // Flush the UART to complete the log line.
- uart_wait_tx_idle_polling(CONFIG_ESP_CONSOLE_UART_NUM);
- esp_light_sleep_start();
- } else {
- _idle_until_alarm();
+ // We cannot esp_light_sleep_start() here because it shuts down all non-RTC peripherals.
+ _idle_until_alarm();
+
+ if (mp_hal_is_interrupted()) {
+ return mp_const_none; // Shouldn't be given to python code because exception handling should kick in.
}
mp_obj_t wake_alarm = _get_wake_alarm(n_alarms, alarms);
@@ -154,7 +143,7 @@ void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *ala
}
void NORETURN alarm_enter_deep_sleep(void) {
- alarm_pin_pin_alarm_prepare_for_deep_sleep();
+ alarm_pin_pinalarm_prepare_for_deep_sleep();
// The ESP-IDF caches the deep sleep settings and applies them before sleep.
// We don't need to worry about resetting them in the interim.
esp_deep_sleep_start();
diff --git a/ports/esp32s2/common-hal/alarm/pin/PinAlarm.c b/ports/esp32s2/common-hal/alarm/pin/PinAlarm.c
index 01e2faeb8..df8d10ef9 100644
--- a/ports/esp32s2/common-hal/alarm/pin/PinAlarm.c
+++ b/ports/esp32s2/common-hal/alarm/pin/PinAlarm.c
@@ -38,7 +38,7 @@
#include "components/soc/src/esp32s2/include/hal/gpio_ll.h"
#include "components/xtensa/include/esp_debug_helpers.h"
-void common_hal_alarm_pin_pin_alarm_construct(alarm_pin_pin_alarm_obj_t *self, mcu_pin_obj_t *pin, bool value, bool edge, bool pull) {
+void common_hal_alarm_pin_pinalarm_construct(alarm_pin_pinalarm_obj_t *self, mcu_pin_obj_t *pin, bool value, bool edge, bool pull) {
if (edge) {
mp_raise_ValueError(translate("Cannot wake on pin edge. Only level."));
}
@@ -51,41 +51,41 @@ void common_hal_alarm_pin_pin_alarm_construct(alarm_pin_pin_alarm_obj_t *self, m
self->pull = pull;
}
-mcu_pin_obj_t *common_hal_alarm_pin_pin_alarm_get_pin(alarm_pin_pin_alarm_obj_t *self) {
+mcu_pin_obj_t *common_hal_alarm_pin_pinalarm_get_pin(alarm_pin_pinalarm_obj_t *self) {
return self->pin;
}
-bool common_hal_alarm_pin_pin_alarm_get_value(alarm_pin_pin_alarm_obj_t *self) {
+bool common_hal_alarm_pin_pinalarm_get_value(alarm_pin_pinalarm_obj_t *self) {
return self->value;
}
-bool common_hal_alarm_pin_pin_alarm_get_edge(alarm_pin_pin_alarm_obj_t *self) {
+bool common_hal_alarm_pin_pinalarm_get_edge(alarm_pin_pinalarm_obj_t *self) {
return false;
}
-bool common_hal_alarm_pin_pin_alarm_get_pull(alarm_pin_pin_alarm_obj_t *self) {
+bool common_hal_alarm_pin_pinalarm_get_pull(alarm_pin_pinalarm_obj_t *self) {
return self->pull;
}
gpio_isr_handle_t gpio_interrupt_handle;
// Low and high are relative to pin number. 32+ is high. <32 is low.
-static volatile uint32_t low_pin_status = 0;
-static volatile uint32_t high_pin_status = 0;
+static volatile uint32_t pin_31_0_status = 0;
+static volatile uint32_t pin_63_32_status = 0;
void gpio_interrupt(void *arg) {
(void) arg;
- gpio_ll_get_intr_status(&GPIO, xPortGetCoreID(), (uint32_t*) &low_pin_status);
- gpio_ll_clear_intr_status(&GPIO, low_pin_status);
- gpio_ll_get_intr_status_high(&GPIO, xPortGetCoreID(), (uint32_t*) &high_pin_status);
- gpio_ll_clear_intr_status_high(&GPIO, high_pin_status);
+ gpio_ll_get_intr_status(&GPIO, xPortGetCoreID(), (uint32_t*) &pin_31_0_status);
+ gpio_ll_clear_intr_status(&GPIO, pin_31_0_status);
+ gpio_ll_get_intr_status_high(&GPIO, xPortGetCoreID(), (uint32_t*) &pin_63_32_status);
+ gpio_ll_clear_intr_status_high(&GPIO, pin_63_32_status);
// disable the interrupts that fired, maybe all of them
for (size_t i = 0; i < 32; i++) {
uint32_t mask = 1 << i;
- if ((low_pin_status & mask) != 0) {
+ if ((pin_31_0_status & mask) != 0) {
gpio_ll_intr_disable(&GPIO, i);
}
- if ((high_pin_status & mask) != 0) {
+ if ((pin_63_32_status & mask) != 0) {
gpio_ll_intr_disable(&GPIO, 32 + i);
}
}
@@ -96,18 +96,18 @@ void gpio_interrupt(void *arg) {
}
}
-bool alarm_pin_pin_alarm_woke_us_up(void) {
- return low_pin_status != 0 || high_pin_status != 0;
+bool alarm_pin_pinalarm_woke_us_up(void) {
+ return pin_31_0_status != 0 || pin_63_32_status != 0;
}
-mp_obj_t alarm_pin_pin_alarm_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.
- uint64_t pin_status = ((uint64_t) high_pin_status) << 32 | low_pin_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++) {
- if (!MP_OBJ_IS_TYPE(alarms[i], &alarm_pin_pin_alarm_type)) {
+ if (!MP_OBJ_IS_TYPE(alarms[i], &alarm_pin_pinalarm_type)) {
continue;
}
- alarm_pin_pin_alarm_obj_t *alarm = MP_OBJ_TO_PTR(alarms[i]);
+ alarm_pin_pinalarm_obj_t *alarm = MP_OBJ_TO_PTR(alarms[i]);
if ((pin_status & (1ull << alarm->pin->number)) != 0) {
return alarms[i];
}
@@ -131,8 +131,8 @@ mp_obj_t alarm_pin_pin_alarm_get_wakeup_alarm(size_t n_alarms, const mp_obj_t *a
}
}
- alarm_pin_pin_alarm_obj_t *alarm = m_new_obj(alarm_pin_pin_alarm_obj_t);
- alarm->base.type = &alarm_pin_pin_alarm_type;
+ alarm_pin_pinalarm_obj_t *alarm = m_new_obj(alarm_pin_pinalarm_obj_t);
+ alarm->base.type = &alarm_pin_pinalarm_type;
alarm->pin = NULL;
// Map the pin number back to a pin object.
for (size_t i = 0; i < mcu_pin_globals.map.used; i++) {
@@ -151,7 +151,7 @@ static uint64_t high_alarms = 0;
static uint64_t low_alarms = 0;
static uint64_t pull_pins = 0;
-void alarm_pin_pin_alarm_reset(void) {
+void alarm_pin_pinalarm_reset(void) {
if (gpio_interrupt_handle != NULL) {
esp_intr_free(gpio_interrupt_handle);
gpio_interrupt_handle = NULL;
@@ -168,21 +168,21 @@ void alarm_pin_pin_alarm_reset(void) {
high_alarms = 0;
low_alarms = 0;
pull_pins = 0;
- high_pin_status = 0;
- low_pin_status = 0;
+ pin_63_32_status = 0;
+ pin_31_0_status = 0;
}
-void alarm_pin_pin_alarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms) {
+void alarm_pin_pinalarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms) {
// Bitmask of wake up settings.
size_t high_count = 0;
size_t low_count = 0;
for (size_t i = 0; i < n_alarms; i++) {
// TODO: Check for ULP or touch alarms because they can't coexist with GPIO alarms.
- if (!MP_OBJ_IS_TYPE(alarms[i], &alarm_pin_pin_alarm_type)) {
+ if (!MP_OBJ_IS_TYPE(alarms[i], &alarm_pin_pinalarm_type)) {
continue;
}
- alarm_pin_pin_alarm_obj_t *alarm = MP_OBJ_TO_PTR(alarms[i]);
+ alarm_pin_pinalarm_obj_t *alarm = MP_OBJ_TO_PTR(alarms[i]);
gpio_num_t pin_number = alarm->pin->number;
if (alarm->value) {
@@ -239,8 +239,8 @@ void alarm_pin_pin_alarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_o
}
// Set GPIO interrupts so they wake us from light sleep or from idle via the
// interrupt handler above.
- low_pin_status = 0;
- high_pin_status = 0;
+ pin_31_0_status = 0;
+ pin_63_32_status = 0;
if (gpio_isr_register(gpio_interrupt, NULL, 0, &gpio_interrupt_handle) != ESP_OK) {
mp_raise_ValueError(translate("Can only alarm on RTC IO from deep sleep."));
}
@@ -282,7 +282,7 @@ void alarm_pin_pin_alarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_o
}
-void alarm_pin_pin_alarm_prepare_for_deep_sleep(void) {
+void alarm_pin_pinalarm_prepare_for_deep_sleep(void) {
if (pull_pins == 0) {
return;
}
diff --git a/ports/esp32s2/common-hal/alarm/pin/PinAlarm.h b/ports/esp32s2/common-hal/alarm/pin/PinAlarm.h
index 8b14931ca..93672c1f2 100644
--- a/ports/esp32s2/common-hal/alarm/pin/PinAlarm.h
+++ b/ports/esp32s2/common-hal/alarm/pin/PinAlarm.h
@@ -32,10 +32,10 @@ typedef struct {
mcu_pin_obj_t *pin;
bool value;
bool pull;
-} alarm_pin_pin_alarm_obj_t;
+} alarm_pin_pinalarm_obj_t;
-void alarm_pin_pin_alarm_reset(void);
-void alarm_pin_pin_alarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms);
-void alarm_pin_pin_alarm_prepare_for_deep_sleep(void);
-mp_obj_t alarm_pin_pin_alarm_get_wakeup_alarm(size_t n_alarms, const mp_obj_t *alarms);
-bool alarm_pin_pin_alarm_woke_us_up(void);
+void alarm_pin_pinalarm_reset(void);
+void alarm_pin_pinalarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms);
+void alarm_pin_pinalarm_prepare_for_deep_sleep(void);
+mp_obj_t alarm_pin_pinalarm_get_wakeup_alarm(size_t n_alarms, const mp_obj_t *alarms);
+bool alarm_pin_pinalarm_woke_us_up(void);
diff --git a/ports/esp32s2/common-hal/alarm/time/TimeAlarm.c b/ports/esp32s2/common-hal/alarm/time/TimeAlarm.c
index a7abde6a4..bcde0ab3c 100644
--- a/ports/esp32s2/common-hal/alarm/time/TimeAlarm.c
+++ b/ports/esp32s2/common-hal/alarm/time/TimeAlarm.c
@@ -34,23 +34,23 @@
#include "shared-bindings/alarm/time/TimeAlarm.h"
#include "shared-bindings/time/__init__.h"
-void common_hal_alarm_time_time_alarm_construct(alarm_time_time_alarm_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;
}
-mp_float_t common_hal_alarm_time_time_alarm_get_monotonic_time(alarm_time_time_alarm_obj_t *self) {
+mp_float_t common_hal_alarm_time_timealarm_get_monotonic_time(alarm_time_timealarm_obj_t *self) {
return self->monotonic_time;
}
mp_obj_t alarm_time_timealarm_get_wakeup_alarm(size_t n_alarms, const mp_obj_t *alarms) {
// First, check to see if we match
for (size_t i = 0; i < n_alarms; i++) {
- if (MP_OBJ_IS_TYPE(alarms[i], &alarm_time_time_alarm_type)) {
+ if (MP_OBJ_IS_TYPE(alarms[i], &alarm_time_timealarm_type)) {
return alarms[i];
}
}
- alarm_time_time_alarm_obj_t *timer = m_new_obj(alarm_time_time_alarm_obj_t);
- timer->base.type = &alarm_time_time_alarm_type;
+ alarm_time_timealarm_obj_t *timer = m_new_obj(alarm_time_timealarm_obj_t);
+ timer->base.type = &alarm_time_timealarm_type;
// TODO: Set monotonic_time based on the RTC state.
timer->monotonic_time = 0.0f;
return timer;
@@ -78,20 +78,20 @@ void alarm_time_timealarm_reset(void) {
}
void alarm_time_timealarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms) {
- bool time_alarm_set = false;
- alarm_time_time_alarm_obj_t *time_alarm = MP_OBJ_NULL;
+ bool timealarm_set = false;
+ alarm_time_timealarm_obj_t *timealarm = MP_OBJ_NULL;
for (size_t i = 0; i < n_alarms; i++) {
- if (!MP_OBJ_IS_TYPE(alarms[i], &alarm_time_time_alarm_type)) {
+ if (!MP_OBJ_IS_TYPE(alarms[i], &alarm_time_timealarm_type)) {
continue;
}
- if (time_alarm_set) {
+ if (timealarm_set) {
mp_raise_ValueError(translate("Only one alarm.time alarm can be set."));
}
- time_alarm = MP_OBJ_TO_PTR(alarms[i]);
- time_alarm_set = true;
+ timealarm = MP_OBJ_TO_PTR(alarms[i]);
+ timealarm_set = true;
}
- if (!time_alarm_set) {
+ if (!timealarm_set) {
return;
}
@@ -109,7 +109,7 @@ void alarm_time_timealarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_
// Compute how long to actually sleep, considering the time now.
mp_float_t now_secs = uint64_to_float(common_hal_time_monotonic_ms()) / 1000.0f;
- mp_float_t wakeup_in_secs = MAX(0.0f, time_alarm->monotonic_time - now_secs);
+ mp_float_t wakeup_in_secs = MAX(0.0f, timealarm->monotonic_time - now_secs);
const uint64_t sleep_for_us = (uint64_t) (wakeup_in_secs * 1000000);
esp_sleep_enable_timer_wakeup(sleep_for_us);
diff --git a/ports/esp32s2/common-hal/alarm/time/TimeAlarm.h b/ports/esp32s2/common-hal/alarm/time/TimeAlarm.h
index 277ababc2..dfd75524f 100644
--- a/ports/esp32s2/common-hal/alarm/time/TimeAlarm.h
+++ b/ports/esp32s2/common-hal/alarm/time/TimeAlarm.h
@@ -30,7 +30,7 @@
typedef struct {
mp_obj_base_t base;
mp_float_t monotonic_time; // values compatible with time.monotonic_time()
-} alarm_time_time_alarm_obj_t;
+} alarm_time_timealarm_obj_t;
// Find the alarm object that caused us to wake up or create an equivalent one.
mp_obj_t alarm_time_timealarm_get_wakeup_alarm(size_t n_alarms, const mp_obj_t *alarms);
diff --git a/ports/esp32s2/supervisor/port.c b/ports/esp32s2/supervisor/port.c
index 8a87180cd..17a413a2e 100644
--- a/ports/esp32s2/supervisor/port.c
+++ b/ports/esp32s2/supervisor/port.c
@@ -74,6 +74,10 @@ extern void esp_restart(void) NORETURN;
void tick_timer_cb(void* arg) {
supervisor_tick();
+
+ // CircuitPython's VM is run in a separate FreeRTOS task from timer callbacks. So, we have to
+ // notify the main task every time in case it's waiting for us.
+ xTaskNotifyGive(circuitpython_task);
}
void sleep_timer_cb(void* arg);
@@ -92,6 +96,8 @@ safe_mode_t port_init(void) {
args.name = "CircuitPython Sleep";
esp_timer_create(&args, &_sleep_timer);
+ circuitpython_task = xTaskGetCurrentTaskHandle();
+
// Send the ROM output out of the UART. This includes early logs.
#ifdef DEBUG
ets_install_uart_printf();
@@ -114,17 +120,17 @@ safe_mode_t port_init(void) {
}
esp_reset_reason_t reason = esp_reset_reason();
- if (reason == ESP_RST_BROWNOUT) {
- return BROWNOUT;
- }
- if (reason == ESP_RST_PANIC ||
- reason == ESP_RST_INT_WDT ||
- reason == ESP_RST_WDT) {
- return HARD_CRASH;
+ switch (reason) {
+ case ESP_RST_BROWNOUT:
+ return BROWNOUT;
+ case ESP_RST_PANIC:
+ case ESP_RST_INT_WDT:
+ case ESP_RST_WDT:
+ return HARD_CRASH;
+ default:
+ break;
}
- circuitpython_task = xTaskGetCurrentTaskHandle();
-
return NO_SAFE_MODE;
}
@@ -262,10 +268,6 @@ void port_enable_tick(void) {
// Disable 1/1024 second tick.
void port_disable_tick(void) {
esp_timer_stop(_tick_timer);
-
- // CircuitPython's VM is run in a separate FreeRTOS task from TinyUSB.
- // Tick disable can happen via auto-reload so poke the main task here.
- xTaskNotifyGive(circuitpython_task);
}
void sleep_timer_cb(void* arg) {