Fix a couple fake sleep bugs on nrf and esp

On ESP ctrl-c during fake sleep will now stop the sleep. A crash
on real deep sleep is now fixed as well. (Exception string saving
was crashing on reading the deep sleep exception.) Fixes #4010

This also fixes nRF fake sleep after the first time. The internal
variable wasn't being reset early enough. Fixes #4869
This commit is contained in:
Scott Shawcroft 2021-07-28 08:50:11 -07:00
parent e9369d50e1
commit cdf978f3af
No known key found for this signature in database
GPG Key ID: 0DFD512649C052DA
6 changed files with 27 additions and 55 deletions

View File

@ -165,7 +165,12 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
}
if (result != NULL) {
result->return_code = ret;
#if CIRCUITPY_ALARM
// Don't set the exception object if we exited for deep sleep.
if (ret != 0 && ret != PYEXEC_DEEP_SLEEP) {
#else
if (ret != 0) {
#endif
mp_obj_t return_value = (mp_obj_t)nlr.ret_val;
result->exception = return_value;
result->exception_line = -1;

View File

@ -62,6 +62,11 @@ void alarm_reset(void) {
esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL);
}
// This will be reset to false by full resets when bss is cleared. Otherwise, the
// reload is due to CircuitPython and the ESP wakeup cause will be stale. This
// can happen if USB is connected after a deep sleep.
STATIC bool soft_wakeup = false;
STATIC esp_sleep_wakeup_cause_t _get_wakeup_cause(void) {
// First check if the modules remember what last woke up
if (alarm_pin_pinalarm_woke_this_cycle()) {
@ -75,7 +80,11 @@ STATIC esp_sleep_wakeup_cause_t _get_wakeup_cause(void) {
}
// If waking from true deep sleep, modules will have lost their state,
// so check the deep wakeup cause manually
return esp_sleep_get_wakeup_cause();
if (!soft_wakeup) {
soft_wakeup = true;
return esp_sleep_get_wakeup_cause();
}
return ESP_SLEEP_WAKEUP_UNDEFINED;
}
bool common_hal_alarm_woken_from_sleep(void) {

View File

@ -28,6 +28,7 @@
#include "py/runtime.h"
#include "supervisor/usb.h"
#include "supervisor/esp_port.h"
#include "supervisor/port.h"
#include "lib/utils/interrupt_char.h"
#include "lib/mp-readline/readline.h"
@ -109,6 +110,7 @@ void init_usb_hardware(void) {
usb_device_stack,
&usb_device_taskdef);
}
/**
* Callback invoked when received an "wanted" char.
* @param itf Interface index (for multiple cdc interfaces)
@ -116,13 +118,13 @@ void init_usb_hardware(void) {
*/
void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char) {
(void)itf; // not used
// 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.
port_wake_main_task();
// Workaround for using lib/utils/interrupt_char.c
// Compare mp_interrupt_char with wanted_char and ignore if not matched
if (mp_interrupt_char == wanted_char) {
tud_cdc_read_flush(); // flush read fifo
mp_sched_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.
xTaskNotifyGive(circuitpython_task);
}
}

View File

@ -952,8 +952,11 @@ bool common_hal_bleio_adapter_is_bonded_to_central(bleio_adapter_obj_t *self) {
}
void bleio_adapter_gc_collect(bleio_adapter_obj_t *adapter) {
gc_collect_root((void **)adapter, sizeof(bleio_adapter_obj_t) / sizeof(size_t));
gc_collect_root((void **)bleio_connections, sizeof(bleio_connections) / sizeof(size_t));
// We divide by size_t so that we can scan each 32-bit aligned value to see
// if it is a pointer. This allows us to change the structs without worrying
// about collecting new pointers.
gc_collect_root((void **)adapter, sizeof(bleio_adapter_obj_t) / (sizeof(size_t)));
gc_collect_root((void **)bleio_connections, sizeof(bleio_connections) / (sizeof(size_t)));
}
void bleio_adapter_reset(bleio_adapter_obj_t *adapter) {

View File

@ -137,6 +137,8 @@ mp_obj_t common_hal_alarm_create_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) {
sleepmem_wakeup_event = SLEEPMEM_WAKEUP_BY_NONE;
sleepmem_wakeup_pin = WAKEUP_PIN_UNDEF;
alarm_pin_pinalarm_set_alarms(deep_sleep, n_alarms, alarms);
alarm_time_timealarm_set_alarms(deep_sleep, n_alarms, alarms);
alarm_touch_touchalarm_set_alarm(deep_sleep, n_alarms, alarms);
@ -156,10 +158,6 @@ void system_on_idle_until_alarm(int64_t timediff_ms, uint32_t prescaler) {
if (timediff_ms != -1) {
have_timeout = true;
#if 0
int64_t now = common_hal_time_monotonic_ms();
dbg_printf("now_ms=%ld timediff_ms=%ld\r\n", (long)now, (long)timediff_ms);
#endif
if (timediff_ms < 0) {
timediff_ms = 0;
}
@ -175,34 +173,17 @@ void system_on_idle_until_alarm(int64_t timediff_ms, uint32_t prescaler) {
start_tick = port_get_raw_ticks(NULL);
end_tick = start_tick + tickdiff;
}
#if 0
dbg_printf("start_tick=%ld end_tick=%ld have_timeout=%c\r\n", (long)start_tick, (long)end_tick, have_timeout ? 'T' : 'F');
#endif
int64_t remaining;
sleepmem_wakeup_event = SLEEPMEM_WAKEUP_BY_NONE;
sleepmem_wakeup_pin = WAKEUP_PIN_UNDEF;
#ifdef NRF_DEBUG_PRINT
int ct = 40;
char reason = '?';
#define WAKEUP_REASON(x) reason = (x)
#else
#define WAKEUP_REASON(x)
#endif
while (1) {
if (mp_hal_is_interrupted()) {
WAKEUP_REASON('I');
break;
}
if (serial_connected() && serial_bytes_available()) {
WAKEUP_REASON('S');
break;
}
RUN_BACKGROUND_TASKS;
if (common_hal_alarm_woken_from_sleep()) {
WAKEUP_REASON('W');
break;
}
if (have_timeout) {
@ -210,51 +191,28 @@ void system_on_idle_until_alarm(int64_t timediff_ms, uint32_t prescaler) {
// We break a bit early so we don't risk setting the alarm before the time when we call
// sleep.
if (remaining < 1) {
WAKEUP_REASON('t');
break;
}
port_interrupt_after_ticks(remaining);
}
// Idle until an interrupt happens.
port_idle_until_interrupt();
#ifdef NRF_DEBUG_PRINT
if (ct > 0) {
mp_printf(&mp_plat_print, "_");
--ct;
}
#endif
if (have_timeout) {
remaining = end_tick - port_get_raw_ticks(NULL);
if (remaining <= 0) {
sleepmem_wakeup_event = SLEEPMEM_WAKEUP_BY_TIMER;
WAKEUP_REASON('T');
break;
}
}
}
#ifdef NRF_DEBUG_PRINT
mp_printf(&mp_plat_print, "%c\r\n", reason);
#endif
#if defined(MICROPY_QSPI_CS)
qspi_flash_exit_sleep();
#endif
#ifdef NRF_DEBUG_PRINT
tickdiff = port_get_raw_ticks(NULL) - start_tick;
double sec;
if (prescaler == 0) {
sec = (double)tickdiff / 1024;
} else {
sec = (double)(tickdiff * prescaler) / 1024;
}
mp_printf(&mp_plat_print, "lapse %6.1f sec\r\n", sec);
#endif
}
mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj_t *alarms) {
mp_obj_t wake_alarm = mp_const_none;
alarm_time_timealarm_clear_wakeup_time();
_setup_sleep_alarms(false, n_alarms, alarms);
#ifdef NRF_DEBUG_PRINT
@ -290,7 +248,6 @@ mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj
}
void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms) {
alarm_time_timealarm_clear_wakeup_time();
_setup_sleep_alarms(true, n_alarms, alarms);
}

View File

@ -70,10 +70,6 @@ int64_t alarm_time_timealarm_get_wakeup_timediff_ms(void) {
return wakeup_time_saved - common_hal_time_monotonic_ms();
}
void alarm_time_timealarm_clear_wakeup_time(void) {
wakeup_time_saved = 0;
}
void alarm_time_timealarm_reset(void) {
port_disable_interrupt_after_ticks_ch(1);
wakeup_time_saved = 0;