summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Shawcroft <scott@tannewt.org>2020-12-08 17:13:00 -0800
committerScott Shawcroft <scott@tannewt.org>2020-12-15 18:12:59 -0800
commit1ad49d9a18224ecc53d8f49d0675a369274556ce (patch)
tree20cc3ac4f882e18d27ce32a65ba6eb908dd4fab3
parentf2204d7d88b505155cd25b38b71ae3c35b86d438 (diff)
Add alarm.pin that wakes on pin level
Fixes #3787
-rwxr-xr-xmain.c18
-rw-r--r--ports/esp32s2/common-hal/alarm/__init__.c47
-rw-r--r--ports/esp32s2/common-hal/alarm/pin/PinAlarm.c260
-rw-r--r--ports/esp32s2/common-hal/alarm/pin/PinAlarm.h8
-rw-r--r--ports/esp32s2/common-hal/alarm/time/TimeAlarm.c25
-rw-r--r--ports/esp32s2/common-hal/alarm/time/TimeAlarm.h2
-rw-r--r--ports/esp32s2/supervisor/esp_port.h2
-rw-r--r--ports/esp32s2/supervisor/port.c47
-rw-r--r--ports/esp32s2/supervisor/usb.c7
-rw-r--r--py/obj.c6
-rw-r--r--py/vm.c2
-rw-r--r--shared-bindings/alarm/pin/PinAlarm.c6
-rw-r--r--supervisor/shared/tick.c7
13 files changed, 361 insertions, 76 deletions
diff --git a/main.c b/main.c
index 378c50657..d940f93d1 100755
--- a/main.c
+++ b/main.c
@@ -260,10 +260,10 @@ STATIC void print_code_py_status_message(safe_mode_t safe_mode) {
STATIC bool run_code_py(safe_mode_t safe_mode) {
bool serial_connected_at_start = serial_connected();
#if CIRCUITPY_AUTORELOAD_DELAY_MS > 0
- if (serial_connected_at_start) {
- serial_write("\n");
- print_code_py_status_message(safe_mode);
- }
+ serial_write("\n");
+ print_code_py_status_message(safe_mode);
+ print_safe_mode_message(safe_mode);
+ serial_write("\n");
#endif
pyexec_result_t result;
@@ -307,16 +307,14 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
if (result.return_code & PYEXEC_FORCED_EXIT) {
return reload_requested;
}
- }
-
- // Program has finished running.
- // Display a different completion message if the user has no USB attached (cannot save files)
- if (!serial_connected_at_start) {
+ // Display a different completion message if the user has no USB attached (cannot save files)
serial_write_compressed(translate("\nCode done running. Waiting for reload.\n"));
}
- bool serial_connected_before_animation = false;
+ // Program has finished running.
+
+ bool serial_connected_before_animation = serial_connected();
#if CIRCUITPY_DISPLAYIO
bool refreshed_epaper_display = false;
#endif
diff --git a/ports/esp32s2/common-hal/alarm/__init__.c b/ports/esp32s2/common-hal/alarm/__init__.c
index fae921db0..5d1f3e95d 100644
--- a/ports/esp32s2/common-hal/alarm/__init__.c
+++ b/ports/esp32s2/common-hal/alarm/__init__.c
@@ -42,6 +42,9 @@
#include "esp_sleep.h"
+#include "components/soc/soc/esp32s2/include/soc/rtc_cntl_reg.h"
+#include "components/driver/include/driver/uart.h"
+
// Singleton instance of SleepMemory.
const alarm_sleep_memory_obj_t alarm_sleep_memory_obj = {
.base = {
@@ -49,9 +52,9 @@ const alarm_sleep_memory_obj_t alarm_sleep_memory_obj = {
},
};
-
void alarm_reset(void) {
alarm_time_timealarm_reset();
+ alarm_pin_pin_alarm_reset();
alarm_sleep_memory_reset();
esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL);
}
@@ -60,6 +63,9 @@ 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()) {
+ return ESP_SLEEP_WAKEUP_GPIO;
+ }
return esp_sleep_get_wakeup_cause();
}
@@ -69,14 +75,16 @@ bool alarm_woken_from_sleep(void) {
}
STATIC mp_obj_t _get_wake_alarm(size_t n_alarms, const mp_obj_t *alarms) {
- switch (_get_wakeup_cause()) {
+ 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_EXT0: {
- // TODO: implement pin alarm wake.
- break;
+ 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);
}
case ESP_SLEEP_WAKEUP_TOUCHPAD:
@@ -98,24 +106,8 @@ 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) {
- bool time_alarm_set = false;
- alarm_time_time_alarm_obj_t *time_alarm = MP_OBJ_NULL;
-
- for (size_t i = 0; i < n_alarms; i++) {
- if (MP_OBJ_IS_TYPE(alarms[i], &alarm_pin_pin_alarm_type)) {
- mp_raise_NotImplementedError(translate("PinAlarm not yet implemented"));
- } else if (MP_OBJ_IS_TYPE(alarms[i], &alarm_time_time_alarm_type)) {
- if (time_alarm_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;
- }
- }
-
- if (time_alarm_set) {
- alarm_time_timealarm_set_alarm(time_alarm);
- }
+ alarm_pin_pin_alarm_set_alarms(deep_sleep, n_alarms, alarms);
+ alarm_time_timealarm_set_alarms(deep_sleep, n_alarms, alarms);
}
STATIC void _idle_until_alarm(void) {
@@ -134,7 +126,10 @@ 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) {
- return !common_hal_wifi_radio_get_enabled(&common_hal_wifi_radio_obj) && !supervisor_workflow_active();
+ 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) {
@@ -142,10 +137,13 @@ mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj
// 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();
}
+
mp_obj_t wake_alarm = _get_wake_alarm(n_alarms, alarms);
alarm_reset();
return wake_alarm;
@@ -156,6 +154,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();
// 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 582a66572..179f34da7 100644
--- a/ports/esp32s2/common-hal/alarm/pin/PinAlarm.c
+++ b/ports/esp32s2/common-hal/alarm/pin/PinAlarm.c
@@ -4,6 +4,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2020 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -24,15 +25,29 @@
* THE SOFTWARE.
*/
-#include "esp_sleep.h"
+#include "py/runtime.h"
#include "shared-bindings/alarm/pin/PinAlarm.h"
+#include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/microcontroller/Pin.h"
+#include "supervisor/esp_port.h"
+
+#include "components/driver/include/driver/rtc_io.h"
+#include "components/esp_system/include/esp_sleep.h"
+#include "components/freertos/include/freertos/FreeRTOS.h"
+#include "components/hal/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) {
+ if (edge) {
+ mp_raise_ValueError(translate("Cannot wake on pin edge. Only level."));
+ }
+
+ if (pull && !GPIO_IS_VALID_OUTPUT_GPIO(pin->number)) {
+ mp_raise_ValueError(translate("Cannot pull on input-only pin."));
+ }
self->pin = pin;
self->value = value;
- self->edge = edge;
self->pull = pull;
}
@@ -45,9 +60,248 @@ bool common_hal_alarm_pin_pin_alarm_get_value(alarm_pin_pin_alarm_obj_t *self) {
}
bool common_hal_alarm_pin_pin_alarm_get_edge(alarm_pin_pin_alarm_obj_t *self) {
- return self->edge;
+ return false;
}
bool common_hal_alarm_pin_pin_alarm_get_pull(alarm_pin_pin_alarm_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;
+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);
+
+ // 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) {
+ gpio_ll_intr_disable(&GPIO, i);
+ }
+ if ((high_pin_status & mask) != 0) {
+ gpio_ll_intr_disable(&GPIO, 32 + i);
+ }
+ }
+ BaseType_t high_task_wakeup;
+ vTaskNotifyGiveFromISR(circuitpython_task, &high_task_wakeup);
+ if (high_task_wakeup) {
+ portYIELD_FROM_ISR();
+ }
+}
+
+bool alarm_pin_pin_alarm_woke_us_up(void) {
+ return low_pin_status != 0 || high_pin_status != 0;
+}
+
+mp_obj_t alarm_pin_pin_alarm_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;
+ for (size_t i = 0; i < n_alarms; i++) {
+ if (!MP_OBJ_IS_TYPE(alarms[i], &alarm_pin_pin_alarm_type)) {
+ continue;
+ }
+ alarm_pin_pin_alarm_obj_t *alarm = MP_OBJ_TO_PTR(alarms[i]);
+ if ((pin_status & (1ull << alarm->pin->number)) != 0) {
+ return alarms[i];
+ }
+ }
+ esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
+ size_t pin_number = 64;
+ if (cause == ESP_SLEEP_WAKEUP_EXT0) {
+ pin_number = REG_GET_FIELD(RTC_IO_EXT_WAKEUP0_REG, RTC_IO_EXT_WAKEUP0_SEL);
+ } else {
+ if (cause == ESP_SLEEP_WAKEUP_EXT1) {
+ pin_status = esp_sleep_get_ext1_wakeup_status();
+ }
+ // If the cause is GPIO, we've already snagged pin_status in the interrupt.
+ // We'll only get here if we pretended to deep sleep. Light sleep will
+ // pass in existing objects.
+ for (size_t i = 0; i < 64; i++) {
+ if ((pin_status & (1ull << i)) != 0) {
+ pin_number = i;
+ break;
+ }
+ }
+ }
+
+ 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 = NULL;
+ // Map the pin number back to a pin object.
+ for (size_t i = 0; i < mcu_pin_globals.map.used; i++) {
+ const mcu_pin_obj_t* pin_obj = MP_OBJ_TO_PTR(mcu_pin_globals.map.table[i].value);
+ if ((size_t) pin_obj->number == pin_number) {
+ alarm->pin = mcu_pin_globals.map.table[i].value;
+ break;
+ }
+ }
+ return alarm;
+}
+
+// These must be static because we need to configure pulls later, right before
+// deep sleep.
+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) {
+ if (gpio_interrupt_handle != NULL) {
+ esp_intr_free(gpio_interrupt_handle);
+ gpio_interrupt_handle = NULL;
+ }
+ for (size_t i = 0; i < 64; i++) {
+ uint64_t mask = 1ull << i;
+ bool high = (high_alarms & mask) != 0;
+ bool low = (low_alarms & mask) != 0;
+ if (!(high || low)) {
+ continue;
+ }
+ reset_pin_number(i);
+ }
+ high_alarms = 0;
+ low_alarms = 0;
+ pull_pins = 0;
+ high_pin_status = 0;
+ low_pin_status = 0;
+}
+
+void alarm_pin_pin_alarm_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)) {
+ continue;
+ }
+ alarm_pin_pin_alarm_obj_t *alarm = MP_OBJ_TO_PTR(alarms[i]);
+
+ gpio_num_t pin_number = alarm->pin->number;
+ if (alarm->value) {
+ high_alarms |= 1ull << pin_number;
+ high_count++;
+ } else {
+ low_alarms |= 1ull << pin_number;
+ low_count++;
+ }
+ if (alarm->pull) {
+ pull_pins |= 1ull << pin_number;
+ }
+ }
+ if (high_count == 0 && low_count == 0) {
+ return;
+ }
+ if (deep_sleep && low_count > 2 && high_count == 0) {
+ mp_raise_ValueError(translate("Can only alarm on two low pins from deep sleep."));
+ }
+ if (deep_sleep && low_count > 1 && high_count > 0) {
+ mp_raise_ValueError(translate("Can only alarm on one low pin while others alarm high from deep sleep."));
+ }
+ // Only use ext0 and ext1 during deep sleep.
+ if (deep_sleep) {
+ if (high_count > 0) {
+ if (esp_sleep_enable_ext1_wakeup(high_alarms, ESP_EXT1_WAKEUP_ANY_HIGH) != ESP_OK) {
+ mp_raise_ValueError(translate("Can only alarm on RTC IO from deep sleep."));
+ }
+ }
+ size_t low_pins[2];
+ size_t j = 0;
+ for (size_t i = 0; i < 64; i++) {
+ uint64_t mask = 1ull << i;
+ if ((low_alarms & mask) != 0) {
+ low_pins[j++] = i;
+ }
+ if (j == 2) {
+ break;
+ }
+ }
+ if (low_count > 1) {
+ if (esp_sleep_enable_ext1_wakeup(1ull << low_pins[1], ESP_EXT1_WAKEUP_ALL_LOW) != ESP_OK) {
+ mp_raise_ValueError(translate("Can only alarm on RTC IO from deep sleep."));
+ }
+ }
+ if (low_count > 0) {
+ if (esp_sleep_enable_ext0_wakeup(low_pins[0], 0) != ESP_OK) {
+ mp_raise_ValueError(translate("Can only alarm on RTC IO from deep sleep."));
+ }
+ }
+ } else {
+ // Enable GPIO wake up if we're sleeping.
+ esp_sleep_enable_gpio_wakeup();
+ }
+ // 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;
+ 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."));
+ }
+ for (size_t i = 0; i < 64; i++) {
+ uint64_t mask = 1ull << i;
+ bool high = (high_alarms & mask) != 0;
+ bool low = (low_alarms & mask) != 0;
+ bool pull = (pull_pins & mask) != 0;
+ if (!(high || low)) {
+ continue;
+ }
+ if (rtc_gpio_is_valid_gpio(i)) {
+ rtc_gpio_deinit(i);
+ }
+ gpio_int_type_t interrupt_mode = GPIO_INTR_DISABLE;
+ gpio_pull_mode_t pull_mode = GPIO_FLOATING;
+ if (high) {
+ interrupt_mode = GPIO_INTR_HIGH_LEVEL;
+ pull_mode = GPIO_PULLDOWN_ONLY;
+ }
+ if (low) {
+ interrupt_mode = GPIO_INTR_LOW_LEVEL;
+ pull_mode = GPIO_PULLUP_ONLY;
+ }
+ gpio_set_direction(i, GPIO_MODE_DEF_INPUT);
+ PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[i], PIN_FUNC_GPIO);
+ if (pull) {
+ gpio_set_pull_mode(i, pull_mode);
+ size_t j = 0;
+ while (gpio_get_level(i) == false) {
+ j++;
+ }
+ }
+ never_reset_pin_number(i);
+ // Sets interrupt type and wakeup bits.
+ gpio_wakeup_enable(i, interrupt_mode);
+ gpio_intr_enable(i);
+ }
+}
+
+
+void alarm_pin_pin_alarm_prepare_for_deep_sleep(void) {
+ if (pull_pins == 0) {
+ return;
+ }
+ for (size_t i = 0; i < 64; i++) {
+ uint64_t mask = 1ull << i;
+ bool pull = (pull_pins & mask) != 0;
+ if (!pull) {
+ continue;
+ }
+ bool high = (high_alarms & mask) != 0;
+ bool low = (low_alarms & mask) != 0;
+ // The pull direction is opposite from alarm value.
+ if (high) {
+ rtc_gpio_pullup_dis(i);
+ rtc_gpio_pulldown_en(i);
+ }
+ if (low) {
+ rtc_gpio_pullup_en(i);
+ rtc_gpio_pulldown_dis(i);
+ }
+ }
+}
diff --git a/ports/esp32s2/common-hal/alarm/pin/PinAlarm.h b/ports/esp32s2/common-hal/alarm/pin/PinAlarm.h
index 0eaa7777f..8b14931ca 100644
--- a/ports/esp32s2/common-hal/alarm/pin/PinAlarm.h
+++ b/ports/esp32s2/common-hal/alarm/pin/PinAlarm.h
@@ -31,7 +31,11 @@ typedef struct {
mp_obj_base_t base;
mcu_pin_obj_t *pin;
bool value;
- bool all_same_value;
- bool edge;
bool pull;
} alarm_pin_pin_alarm_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);
diff --git a/ports/esp32s2/common-hal/alarm/time/TimeAlarm.c b/ports/esp32s2/common-hal/alarm/time/TimeAlarm.c
index 4d0bba238..a7abde6a4 100644
--- a/ports/esp32s2/common-hal/alarm/time/TimeAlarm.c
+++ b/ports/esp32s2/common-hal/alarm/time/TimeAlarm.c
@@ -63,9 +63,7 @@ STATIC bool woke_up = false;
void timer_callback(void *arg) {
(void) arg;
woke_up = true;
- if (sleeping_circuitpython_task) {
- xTaskNotifyGive(sleeping_circuitpython_task);
- }
+ xTaskNotifyGive(circuitpython_task);
}
bool alarm_time_timealarm_woke_us_up(void) {
@@ -79,7 +77,24 @@ void alarm_time_timealarm_reset(void) {
woke_up = false;
}
-void alarm_time_timealarm_set_alarm(alarm_time_time_alarm_obj_t *self) {
+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;
+
+ for (size_t i = 0; i < n_alarms; i++) {
+ if (!MP_OBJ_IS_TYPE(alarms[i], &alarm_time_time_alarm_type)) {
+ continue;
+ }
+ if (time_alarm_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;
+ }
+ if (!time_alarm_set) {
+ return;
+ }
+
if (pretend_sleep_timer != NULL) {
esp_timer_stop(pretend_sleep_timer);
} else {
@@ -94,7 +109,7 @@ void alarm_time_timealarm_set_alarm(alarm_time_time_alarm_obj_t *self) {
// 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, self->monotonic_time - now_secs);
+ mp_float_t wakeup_in_secs = MAX(0.0f, time_alarm->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 04c553009..277ababc2 100644
--- a/ports/esp32s2/common-hal/alarm/time/TimeAlarm.h
+++ b/ports/esp32s2/common-hal/alarm/time/TimeAlarm.h
@@ -36,5 +36,5 @@ typedef struct {
mp_obj_t alarm_time_timealarm_get_wakeup_alarm(size_t n_alarms, const mp_obj_t *alarms);
// Check for the wake up alarm from pretend deep sleep.
bool alarm_time_timealarm_woke_us_up(void);
-void alarm_time_timealarm_set_alarm(alarm_time_time_alarm_obj_t *self);
+void alarm_time_timealarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms);
void alarm_time_timealarm_reset(void);
diff --git a/ports/esp32s2/supervisor/esp_port.h b/ports/esp32s2/supervisor/esp_port.h
index 1164666cd..8b9e13829 100644
--- a/ports/esp32s2/supervisor/esp_port.h
+++ b/ports/esp32s2/supervisor/esp_port.h
@@ -30,6 +30,6 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
-extern TaskHandle_t sleeping_circuitpython_task;
+extern TaskHandle_t circuitpython_task;
#endif // MICROPY_INCLUDED_ESP32S2_SUPERVISOR_PORT_H
diff --git a/ports/esp32s2/supervisor/port.c b/ports/esp32s2/supervisor/port.c
index 7037b4f05..7d8aac4d5 100644
--- a/ports/esp32s2/supervisor/port.c
+++ b/ports/esp32s2/supervisor/port.c
@@ -66,6 +66,9 @@ uint32_t* heap;
uint32_t heap_size;
STATIC esp_timer_handle_t _tick_timer;
+STATIC esp_timer_handle_t _sleep_timer;
+
+TaskHandle_t circuitpython_task = NULL;
extern void esp_restart(void) NORETURN;
@@ -73,6 +76,8 @@ void tick_timer_cb(void* arg) {
supervisor_tick();
}
+void sleep_timer_cb(void* arg);
+
safe_mode_t port_init(void) {
esp_timer_create_args_t args;
args.callback = &tick_timer_cb;
@@ -81,10 +86,14 @@ safe_mode_t port_init(void) {
args.name = "CircuitPython Tick";
esp_timer_create(&args, &_tick_timer);
- #ifdef DEBUG
+ args.callback = &sleep_timer_cb;
+ args.arg = NULL;
+ args.dispatch_method = ESP_TIMER_TASK;
+ args.name = "CircuitPython Sleep";
+ esp_timer_create(&args, &_sleep_timer);
+
// Send the ROM output out of the UART. This includes early logs.
esp_rom_install_channel_putc(1, esp_rom_uart_putc);
- #endif
heap = NULL;
never_reset_module_internal_pins();
@@ -106,10 +115,14 @@ safe_mode_t port_init(void) {
if (reason == ESP_RST_BROWNOUT) {
return BROWNOUT;
}
- if (reason == ESP_RST_PANIC) {
+ if (reason == ESP_RST_PANIC ||
+ reason == ESP_RST_INT_WDT ||
+ reason == ESP_RST_WDT) {
return HARD_CRASH;
}
+ circuitpython_task = xTaskGetCurrentTaskHandle();
+
return NO_SAFE_MODE;
}
@@ -250,29 +263,25 @@ void port_disable_tick(void) {
// 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.
- if (sleeping_circuitpython_task != NULL) {
- xTaskNotifyGive(sleeping_circuitpython_task);
- }
+ xTaskNotifyGive(circuitpython_task);
}
-TickType_t sleep_time_duration;
+void sleep_timer_cb(void* arg) {
+ xTaskNotifyGive(circuitpython_task);
+}
void port_interrupt_after_ticks(uint32_t ticks) {
- sleep_time_duration = (ticks * 100)/1024;
+ uint64_t timeout_us = ticks * 1000000ull / 1024;
+ if (esp_timer_start_once(_sleep_timer, timeout_us) != ESP_OK) {
+ esp_timer_stop(_sleep_timer);
+ esp_timer_start_once(_sleep_timer, timeout_us);
+ }
}
+// On the ESP we use FreeRTOS notifications instead of interrupts so this is a
+// bit of a misnomer.
void port_idle_until_interrupt(void) {
- uint32_t notify_value = 0;
-
- if (sleep_time_duration == 0) {
- return;
- }
- sleeping_circuitpython_task = xTaskGetCurrentTaskHandle();
- xTaskNotifyWait(0x01, 0x01, &notify_value, sleep_time_duration );
- sleeping_circuitpython_task = NULL;
- if (notify_value == 1) {
- mp_handle_pending();
- }
+ xTaskNotifyWait(0x01, 0x01, NULL, portMAX_DELAY);
}
// Wrap main in app_main that the IDF expects.
diff --git a/ports/esp32s2/supervisor/usb.c b/ports/esp32s2/supervisor/usb.c
index 2bfcdfb12..6c92f7253 100644
--- a/ports/esp32s2/supervisor/usb.c
+++ b/ports/esp32s2/supervisor/usb.c
@@ -26,6 +26,7 @@
*/
#include "supervisor/usb.h"
+#include "supervisor/esp_port.h"
#include "lib/utils/interrupt_char.h"
#include "lib/mp-readline/readline.h"
@@ -52,8 +53,6 @@
StackType_t usb_device_stack[USBD_STACK_SIZE];
StaticTask_t usb_device_taskdef;
-TaskHandle_t sleeping_circuitpython_task = NULL;
-
// USB Device Driver task
// This top level thread process all usb events and invoke callbacks
void usb_device_task(void* param)
@@ -131,8 +130,6 @@ void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char)
mp_keyboard_interrupt();
// CircuitPython's VM is run in a separate FreeRTOS task from TinyUSB.
// So, we must notify the other task when a CTRL-C is received.
- if (sleeping_circuitpython_task != NULL) {
- xTaskNotifyGive(sleeping_circuitpython_task);
- }
+ xTaskNotifyGive(circuitpython_task);
}
}
diff --git a/py/obj.c b/py/obj.c
index b6462641c..218fb4321 100644
--- a/py/obj.c
+++ b/py/obj.c
@@ -29,6 +29,7 @@
#include <stdarg.h>
#include <assert.h>
+#include "lib/utils/interrupt_char.h"
#include "py/obj.h"
#include "py/objtype.h"
#include "py/objint.h"
@@ -67,7 +68,10 @@ void mp_obj_print_helper(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t
#ifdef RUN_BACKGROUND_TASKS
RUN_BACKGROUND_TASKS;
#endif
- mp_handle_pending();
+ // Stop printing if we've been interrupted.
+ if (mp_hal_is_interrupted()) {
+ return;
+ }
#ifndef NDEBUG
if (o_in == MP_OBJ_NULL) {
diff --git a/py/vm.c b/py/vm.c
index 9b3354b09..13a9980aa 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -1015,7 +1015,7 @@ unwind_jump:;
}
#endif
SET_TOP(mp_call_method_n_kw(unum & 0xff, (unum >> 8) & 0xff, sp));
- DISPATCH();
+ DISPATCH_WITH_PEND_EXC_CHECK();
}
ENTRY(MP_BC_CALL_METHOD_VAR_KW): {
diff --git a/shared-bindings/alarm/pin/PinAlarm.c b/shared-bindings/alarm/pin/PinAlarm.c
index 7a5617142..83ccc0d76 100644
--- a/shared-bindings/alarm/pin/PinAlarm.c
+++ b/shared-bindings/alarm/pin/PinAlarm.c
@@ -89,7 +89,11 @@ STATIC mp_obj_t alarm_pin_pin_alarm_make_new(const mp_obj_type_t *type, mp_uint_
//|
STATIC mp_obj_t alarm_pin_pin_alarm_obj_get_pin(mp_obj_t self_in) {
alarm_pin_pin_alarm_obj_t *self = MP_OBJ_TO_PTR(self_in);
- return common_hal_alarm_pin_pin_alarm_get_pin(self);
+ mcu_pin_obj_t* pin = common_hal_alarm_pin_pin_alarm_get_pin(self);
+ if (pin == NULL) {
+ return mp_const_none;
+ }
+ return MP_OBJ_FROM_PTR(pin);
}
MP_DEFINE_CONST_FUN_OBJ_1(alarm_pin_pin_alarm_get_pin_obj, alarm_pin_pin_alarm_obj_get_pin);
diff --git a/supervisor/shared/tick.c b/supervisor/shared/tick.c
index d37a585eb..5d75a5395 100644
--- a/supervisor/shared/tick.c
+++ b/supervisor/shared/tick.c
@@ -145,10 +145,11 @@ void mp_hal_delay_ms(mp_uint_t delay) {
delay = delay * 1024 / 1000;
uint64_t end_tick = start_tick + delay;
int64_t remaining = delay;
- while (remaining > 0) {
+
+ // Loop until we've waited long enough or we've been CTRL-Ced by autoreload
+ // or the user.
+ while (remaining > 0 && !mp_hal_is_interrupted()) {
RUN_BACKGROUND_TASKS;
- // Check to see if we've been CTRL-Ced by autoreload or the user.
- mp_handle_pending();
remaining = end_tick - port_get_raw_ticks(NULL);
// We break a bit early so we don't risk setting the alarm before the time when we call
// sleep.