diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 3b7e6227fa..fd6df1cafe 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -66,13 +66,16 @@ msgid "" "%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" msgstr "" +#: ports/atmel-samd/common-hal/alarm/__init__.c #: ports/cxd56/common-hal/analogio/AnalogOut.c ports/cxd56/common-hal/rtc/RTC.c #: ports/espressif/common-hal/rtc/RTC.c #: ports/mimxrt10xx/common-hal/analogio/AnalogOut.c -#: ports/mimxrt10xx/common-hal/rtc/RTC.c +#: ports/mimxrt10xx/common-hal/rtc/RTC.c ports/nrf/common-hal/alarm/__init__.c #: ports/nrf/common-hal/analogio/AnalogOut.c ports/nrf/common-hal/rtc/RTC.c +#: ports/raspberrypi/common-hal/alarm/__init__.c #: ports/raspberrypi/common-hal/analogio/AnalogOut.c -#: ports/raspberrypi/common-hal/rtc/RTC.c ports/stm/common-hal/rtc/RTC.c +#: ports/raspberrypi/common-hal/rtc/RTC.c ports/stm/common-hal/alarm/__init__.c +#: ports/stm/common-hal/rtc/RTC.c msgid "%q" msgstr "" @@ -902,13 +905,14 @@ msgstr "" #: ports/raspberrypi/bindings/rp2pio/StateMachine.c py/enum.c #: shared-bindings/_bleio/__init__.c shared-bindings/aesio/aes.c -#: shared-bindings/busio/SPI.c shared-bindings/microcontroller/Pin.c +#: shared-bindings/alarm/__init__.c shared-bindings/busio/SPI.c +#: shared-bindings/microcontroller/Pin.c #: shared-bindings/neopixel_write/__init__.c msgid "Expected a %q" msgstr "" #: shared-bindings/alarm/__init__.c -msgid "Expected an alarm" +msgid "Expected an %q" msgstr "" #: ports/espressif/common-hal/_bleio/Adapter.c @@ -3798,6 +3802,7 @@ msgstr "" #: ports/espressif/boards/adafruit_qtpy_esp32c3/mpconfigboard.h #: ports/espressif/boards/beetle-esp32-c3/mpconfigboard.h #: ports/espressif/boards/lolin_c3_mini/mpconfigboard.h +#: ports/espressif/boards/microdev_micro_c3/mpconfigboard.h #: supervisor/shared/safe_mode.c msgid "pressing boot button at start up.\n" msgstr "" diff --git a/ports/atmel-samd/common-hal/alarm/__init__.c b/ports/atmel-samd/common-hal/alarm/__init__.c index 405bf9d573..8f66b3a90c 100644 --- a/ports/atmel-samd/common-hal/alarm/__init__.c +++ b/ports/atmel-samd/common-hal/alarm/__init__.c @@ -142,7 +142,10 @@ mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj return wake_alarm; } -void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms) { +void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms, size_t n_dios, digitalio_digitalinout_obj_t **preserve_dios) { + if (n_dios > 0) { + mp_raise_NotImplementedError_varg(translate("%q"), MP_QSTR_preserve_dios); + } _setup_sleep_alarms(true, n_alarms, alarms); } diff --git a/ports/espressif/boards/adafruit_feather_esp32_v2/board.c b/ports/espressif/boards/adafruit_feather_esp32_v2/board.c index 22d51ef334..78341beb3b 100644 --- a/ports/espressif/boards/adafruit_feather_esp32_v2/board.c +++ b/ports/espressif/boards/adafruit_feather_esp32_v2/board.c @@ -31,17 +31,14 @@ #include "components/hal/include/hal/gpio_hal.h" #include "common-hal/microcontroller/Pin.h" -void board_init(void) { - reset_board(); -} - -void reset_board(void) { - // Turn on NeoPixel and I2C power by default. - gpio_set_direction(2, GPIO_MODE_DEF_OUTPUT); - gpio_set_level(2, true); -} - bool espressif_board_reset_pin_number(gpio_num_t pin_number) { + if (pin_number == 2) { + // Turn on NeoPixel and I2C power by default. + gpio_set_direction(pin_number, GPIO_MODE_DEF_OUTPUT); + gpio_set_level(pin_number, true); + return true; + } + return false; } diff --git a/ports/espressif/common-hal/alarm/SleepMemory.c b/ports/espressif/common-hal/alarm/SleepMemory.c index 764125ddb2..d375fdc778 100644 --- a/ports/espressif/common-hal/alarm/SleepMemory.c +++ b/ports/espressif/common-hal/alarm/SleepMemory.c @@ -31,7 +31,6 @@ #include "common-hal/alarm/SleepMemory.h" #include "shared-bindings/alarm/SleepMemory.h" -#include "esp_log.h" #include "esp_sleep.h" // Data storage for singleton instance of SleepMemory. @@ -39,7 +38,7 @@ static RTC_DATA_ATTR uint8_t _sleep_mem[SLEEP_MEMORY_LENGTH]; void alarm_sleep_memory_reset(void) { - // ESP-IDF build system takes care of doing esp_sleep_pd_config() or the equivalentwith + // ESP-IDF build system takes care of doing esp_sleep_pd_config() or the equivalent with // the correct settings, depending on which RTC mem we are using. // https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/api-reference/system/sleep_modes.html#power-down-of-rtc-peripherals-and-memories } diff --git a/ports/espressif/common-hal/alarm/__init__.c b/ports/espressif/common-hal/alarm/__init__.c index d65ab0bbb2..a47930850d 100644 --- a/ports/espressif/common-hal/alarm/__init__.c +++ b/ports/espressif/common-hal/alarm/__init__.c @@ -39,12 +39,15 @@ #include "shared-bindings/wifi/__init__.h" #include "shared-bindings/microcontroller/__init__.h" +#include "common-hal/digitalio/DigitalInOut.h" + #include "supervisor/port.h" #include "supervisor/shared/workflow.h" #include "esp_sleep.h" #include "soc/rtc_cntl_reg.h" +#include "components/driver/include/driver/gpio.h" #include "components/driver/include/driver/uart.h" // Singleton instance of SleepMemory. @@ -158,7 +161,8 @@ mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj return wake_alarm; } -void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms) { +void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms, size_t n_dios, digitalio_digitalinout_obj_t *preserve_dios[]) { + digitalio_digitalinout_preserve_for_deep_sleep(n_dios, preserve_dios); _setup_sleep_alarms(true, n_alarms, alarms); } @@ -166,6 +170,12 @@ void NORETURN common_hal_alarm_enter_deep_sleep(void) { alarm_pin_pinalarm_prepare_for_deep_sleep(); alarm_touch_touchalarm_prepare_for_deep_sleep(); + // We no longer need to remember the pin preservations, since any pin resets are all done. + clear_pin_preservations(); + + // Allow pin holds to work during deep sleep. + gpio_deep_sleep_hold_en(); + // 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/espressif/common-hal/digitalio/DigitalInOut.c b/ports/espressif/common-hal/digitalio/DigitalInOut.c index a3e8f41147..63c8ec1a41 100644 --- a/ports/espressif/common-hal/digitalio/DigitalInOut.c +++ b/ports/espressif/common-hal/digitalio/DigitalInOut.c @@ -32,6 +32,20 @@ #include "components/hal/include/hal/gpio_hal.h" +STATIC bool _pin_is_input(uint8_t pin_number) { + const uint32_t iomux = READ_PERI_REG(GPIO_PIN_MUX_REG[pin_number]); + return (iomux & FUN_IE) != 0; +} + +void digitalio_digitalinout_preserve_for_deep_sleep(size_t n_dios, digitalio_digitalinout_obj_t *preserve_dios[]) { + // Mark the pin states of the given DigitalInOuts for preservation during deep sleep + for (size_t i = 0; i < n_dios; i++) { + if (!common_hal_digitalio_digitalinout_deinited(preserve_dios[i])) { + preserve_pin_number(preserve_dios[i]->pin->number); + } + } +} + void common_hal_digitalio_digitalinout_never_reset( digitalio_digitalinout_obj_t *self) { never_reset_pin_number(self->pin->number); @@ -83,8 +97,7 @@ digitalinout_result_t common_hal_digitalio_digitalinout_switch_to_output( digitalio_direction_t common_hal_digitalio_digitalinout_get_direction( digitalio_digitalinout_obj_t *self) { - uint32_t iomux = READ_PERI_REG(GPIO_PIN_MUX_REG[self->pin->number]); - if ((iomux & FUN_IE) != 0) { + if (_pin_is_input(self->pin->number)) { return DIRECTION_INPUT; } return DIRECTION_OUTPUT; diff --git a/ports/espressif/common-hal/digitalio/DigitalInOut.h b/ports/espressif/common-hal/digitalio/DigitalInOut.h index 2d42e79809..793d2a0986 100644 --- a/ports/espressif/common-hal/digitalio/DigitalInOut.h +++ b/ports/espressif/common-hal/digitalio/DigitalInOut.h @@ -36,4 +36,6 @@ typedef struct { bool output_value; } digitalio_digitalinout_obj_t; +extern void digitalio_digitalinout_preserve_for_deep_sleep(size_t n_dios, digitalio_digitalinout_obj_t *preserve_dios[]); + #endif // MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_DIGITALIO_DIGITALINOUT_H diff --git a/ports/espressif/common-hal/esp32_camera/Camera.c b/ports/espressif/common-hal/esp32_camera/Camera.c index 97300a639c..5ee112a911 100644 --- a/ports/espressif/common-hal/esp32_camera/Camera.c +++ b/ports/espressif/common-hal/esp32_camera/Camera.c @@ -191,8 +191,6 @@ framesize_t common_hal_esp32_camera_camera_get_frame_size(esp32_camera_camera_ob return self->camera_config.frame_size; } -#include "esp_log.h" - void common_hal_esp32_camera_camera_reconfigure(esp32_camera_camera_obj_t *self, framesize_t frame_size, pixformat_t pixel_format, camera_grab_mode_t grab_mode, mp_int_t framebuffer_count) { sensor_t *sensor = esp_camera_sensor_get(); camera_sensor_info_t *sensor_info = esp_camera_sensor_get_info(&sensor->id); diff --git a/ports/espressif/common-hal/microcontroller/Pin.c b/ports/espressif/common-hal/microcontroller/Pin.c index 127505f0e9..adc1e8b918 100644 --- a/ports/espressif/common-hal/microcontroller/Pin.c +++ b/ports/espressif/common-hal/microcontroller/Pin.c @@ -33,14 +33,13 @@ #include "components/driver/include/driver/gpio.h" #include "components/hal/include/hal/gpio_hal.h" -STATIC uint64_t never_reset_pins; -STATIC uint64_t in_use; +STATIC uint64_t _never_reset_pin_mask; +STATIC uint64_t _preserved_pin_mask; +STATIC uint64_t _in_use_pin_mask; -// 64-bit pin mask for a single bit -#define PIN_BIT(pin_number) (((uint64_t)1) << pin_number) - -// Bit mask of all pins that should never ever be reset. +// Bit mask of all pins that should never EVER be reset. // Typically these are SPI flash and PSRAM control pins, and communication pins. +// "Reset forbidden" is stronger than "never reset" below, which may only be temporary. static const uint64_t pin_mask_reset_forbidden = #if defined(CONFIG_IDF_TARGET_ESP32) // Never ever reset serial pins for bootloader and possibly USB-serial converter. @@ -105,7 +104,7 @@ void never_reset_pin_number(gpio_num_t pin_number) { if (pin_number == NO_PIN || pin_number == (uint8_t)NO_PIN) { return; } - never_reset_pins |= PIN_BIT(pin_number); + _never_reset_pin_mask |= PIN_BIT(pin_number); } void common_hal_never_reset_pin(const mcu_pin_obj_t *pin) { @@ -119,12 +118,29 @@ MP_WEAK bool espressif_board_reset_pin_number(gpio_num_t pin_number) { return false; } +STATIC bool _reset_forbidden(gpio_num_t pin_number) { + return pin_mask_reset_forbidden & PIN_BIT(pin_number); +} + +STATIC bool _never_reset(gpio_num_t pin_number) { + return _never_reset_pin_mask & PIN_BIT(pin_number); +} + +STATIC bool _preserved_pin(gpio_num_t pin_number) { + return _preserved_pin_mask & PIN_BIT(pin_number); +} + STATIC void _reset_pin(gpio_num_t pin_number) { // Never ever reset pins used for flash, RAM, and basic communication. - if (pin_mask_reset_forbidden & PIN_BIT(pin_number)) { + if (_reset_forbidden(pin_number)) { return; } + // Disable any existing hold on this pin, + if (GPIO_IS_VALID_OUTPUT_GPIO(pin_number)) { + gpio_hold_dis(pin_number); + } + // Give the board a chance to reset the pin in a particular way. if (espressif_board_reset_pin_number(pin_number)) { return; @@ -152,6 +168,18 @@ STATIC void _reset_pin(gpio_num_t pin_number) { } } +void preserve_pin_number(gpio_num_t pin_number) { + if (GPIO_IS_VALID_OUTPUT_GPIO(pin_number)) { + gpio_hold_en(pin_number); + _preserved_pin_mask |= PIN_BIT(pin_number); + } +} + +void clear_pin_preservations(void) { + _preserved_pin_mask = 0; +} + + // Mark pin as free and return it to a quiescent state. void reset_pin_number(gpio_num_t pin_number) { // Some CircuitPython APIs deal in uint8_t pin numbers, but NO_PIN is -1. @@ -159,8 +187,8 @@ void reset_pin_number(gpio_num_t pin_number) { if (pin_number == NO_PIN || pin_number == (uint8_t)NO_PIN) { return; } - never_reset_pins &= ~PIN_BIT(pin_number); - in_use &= ~PIN_BIT(pin_number); + _never_reset_pin_mask &= ~PIN_BIT(pin_number); + _in_use_pin_mask &= ~PIN_BIT(pin_number); _reset_pin(pin_number); } @@ -177,15 +205,20 @@ void common_hal_reset_pin(const mcu_pin_obj_t *pin) { } void reset_all_pins(void) { + // Undo deep sleep holds in case we woke up from deep sleep. + // We still need to unhold individual pins, which is done by _reset_pin. + gpio_deep_sleep_hold_dis(); + for (uint8_t i = 0; i < GPIO_PIN_COUNT; i++) { uint32_t iomux_address = GPIO_PIN_MUX_REG[i]; if (iomux_address == 0 || - (never_reset_pins & PIN_BIT(i))) { + _never_reset(i) || + _preserved_pin(i)) { continue; } _reset_pin(i); } - in_use = never_reset_pins; + _in_use_pin_mask = _never_reset_pin_mask; } void claim_pin_number(gpio_num_t pin_number) { @@ -194,7 +227,7 @@ void claim_pin_number(gpio_num_t pin_number) { if (pin_number == NO_PIN || pin_number == (uint8_t)NO_PIN) { return; } - in_use |= PIN_BIT(pin_number); + _in_use_pin_mask |= PIN_BIT(pin_number); } void claim_pin(const mcu_pin_obj_t *pin) { @@ -206,7 +239,7 @@ void common_hal_mcu_pin_claim(const mcu_pin_obj_t *pin) { } bool pin_number_is_free(gpio_num_t pin_number) { - return !(in_use & PIN_BIT(pin_number)); + return !(_in_use_pin_mask & PIN_BIT(pin_number)); } bool common_hal_mcu_pin_is_free(const mcu_pin_obj_t *pin) { diff --git a/ports/espressif/common-hal/microcontroller/Pin.h b/ports/espressif/common-hal/microcontroller/Pin.h index e74346ef65..55927fe068 100644 --- a/ports/espressif/common-hal/microcontroller/Pin.h +++ b/ports/espressif/common-hal/microcontroller/Pin.h @@ -31,21 +31,28 @@ #include "peripherals/pins.h" -void reset_all_pins(void); +// 64-bit pin mask for a single bit +#define PIN_BIT(pin_number) (((uint64_t)1) << pin_number) + +extern void common_hal_reset_pin(const mcu_pin_obj_t *pin); +extern void common_hal_never_reset_pin(const mcu_pin_obj_t *pin); + +extern void reset_all_pins(void); // reset_pin_number takes the pin number instead of the pointer so that objects don't // need to store a full pointer. -void reset_pin_number(gpio_num_t pin_number); -void common_hal_reset_pin(const mcu_pin_obj_t *pin); -void common_hal_never_reset_pin(const mcu_pin_obj_t *pin); -void claim_pin(const mcu_pin_obj_t *pin); -void claim_pin_number(gpio_num_t pin_number); -bool pin_number_is_free(gpio_num_t pin_number); -void never_reset_pin_number(gpio_num_t pin_number); +extern void reset_pin_number(gpio_num_t pin_number); +extern void claim_pin(const mcu_pin_obj_t *pin); +extern void claim_pin_number(gpio_num_t pin_number); +extern bool pin_number_is_free(gpio_num_t pin_number); +extern void never_reset_pin_number(gpio_num_t pin_number); + +extern void preserve_pin_number(gpio_num_t pin_number); +extern void clear_pin_preservations(void); // Allow the board to reset a pin in a board-specific way. This can be used // for LEDs or enable pins to put them in a state beside the default pull-up. // Return true to indicate that the pin was reset. Returning false will lead to // the port-default reset behavior. -bool espressif_board_reset_pin_number(gpio_num_t pin_number); +extern bool espressif_board_reset_pin_number(gpio_num_t pin_number); #endif // MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_MICROCONTROLLER_PIN_H diff --git a/ports/nrf/common-hal/alarm/__init__.c b/ports/nrf/common-hal/alarm/__init__.c index 043be0b319..75f616c805 100644 --- a/ports/nrf/common-hal/alarm/__init__.c +++ b/ports/nrf/common-hal/alarm/__init__.c @@ -247,7 +247,10 @@ mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj return wake_alarm; } -void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms) { +void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms, size_t n_dios, digitalio_digitalinout_obj_t **preserve_dios) { + if (n_dios > 0) { + mp_raise_NotImplementedError_varg(translate("%q"), MP_QSTR_preserve_dios); + } _setup_sleep_alarms(true, n_alarms, alarms); } diff --git a/ports/raspberrypi/common-hal/alarm/__init__.c b/ports/raspberrypi/common-hal/alarm/__init__.c index 0d6734568b..31fa58aab3 100644 --- a/ports/raspberrypi/common-hal/alarm/__init__.c +++ b/ports/raspberrypi/common-hal/alarm/__init__.c @@ -194,7 +194,10 @@ mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj return wake_alarm; } -void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms) { +void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms, size_t n_dios, digitalio_digitalinout_obj_t **preserve_dios) { + if (n_dios > 0) { + mp_raise_NotImplementedError_varg(translate("%q"), MP_QSTR_preserve_dios); + } _setup_sleep_alarms(true, n_alarms, alarms); } diff --git a/ports/stm/common-hal/alarm/__init__.c b/ports/stm/common-hal/alarm/__init__.c index 466c2d5199..26099b0503 100644 --- a/ports/stm/common-hal/alarm/__init__.c +++ b/ports/stm/common-hal/alarm/__init__.c @@ -144,7 +144,10 @@ mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj return wake_alarm; } -void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms) { +void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms, size_t n_dios, digitalio_digitalinout_obj_t **preserve_dios) { + if (n_dios > 0) { + mp_raise_NotImplementedError_varg(translate("%q"), MP_QSTR_preserve_dios); + } _setup_sleep_alarms(true, n_alarms, alarms); } diff --git a/ports/stm/supervisor/port.c b/ports/stm/supervisor/port.c index b15d81611e..c3f1fee190 100644 --- a/ports/stm/supervisor/port.c +++ b/ports/stm/supervisor/port.c @@ -244,6 +244,7 @@ void SysTick_Handler(void) { void reset_port(void) { reset_all_pins(); + #if CIRCUITPY_RTC rtc_reset(); #endif diff --git a/shared-bindings/alarm/__init__.c b/shared-bindings/alarm/__init__.c index 7fd14b7641..3b81dd479f 100644 --- a/shared-bindings/alarm/__init__.c +++ b/shared-bindings/alarm/__init__.c @@ -32,6 +32,7 @@ #include "shared-bindings/alarm/pin/PinAlarm.h" #include "shared-bindings/alarm/time/TimeAlarm.h" #include "shared-bindings/alarm/touch/TouchAlarm.h" +#include "shared-bindings/digitalio/DigitalInOut.h" #include "shared-bindings/supervisor/Runtime.h" #include "shared-bindings/time/__init__.h" #include "supervisor/shared/workflow.h" @@ -80,7 +81,7 @@ STATIC void validate_objs_are_alarms(size_t n_args, const mp_obj_t *objs) { mp_obj_is_type(objs[i], &alarm_touch_touchalarm_type)) { continue; } - mp_raise_TypeError_varg(translate("Expected an alarm")); + mp_raise_TypeError_varg(translate("Expected an %q"), MP_QSTR_Alarm); } } @@ -112,7 +113,7 @@ STATIC mp_obj_t alarm_light_sleep_until_alarms(size_t n_args, const mp_obj_t *ar } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(alarm_light_sleep_until_alarms_obj, 1, MP_OBJ_FUN_ARGS_MAX, alarm_light_sleep_until_alarms); -//| def exit_and_deep_sleep_until_alarms(*alarms: circuitpython_typing.Alarm) -> None: +//| def exit_and_deep_sleep_until_alarms(*alarms: circuitpython_typing.Alarm, preserve_dios: Sequence[digitalio.DigitalInOut] = ()) -> None: //| """Exit the program and go into a deep sleep, until awakened by one of the alarms. //| This function does not return. //| @@ -126,6 +127,22 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(alarm_light_sleep_until_alarms_obj, 1, MP_OB //| //| If no alarms are specified, the microcontroller will deep sleep until reset. //| +//| :param circuitpython_typing.Alarm alarms: the alarms that can wake the microcontroller. +//| :param Sequence[digitalio.DigitalInOut] preserve_dios: A sequence of `DigitalInOut` objects +//| whose state should be preserved during deep sleep. +//| If a `DigitalInOut` in the sequence is set to be an output, +//| its current `DigitalInOut.value` (``True`` or ``False``) +//| will be preserved during the deep sleep. +//| If a `DigitalInOut` in the sequence is set to be an input, +//| its current `DigitalInOut.pull` value (``DOWN``, ``UP``, or ``None``) +//| will be preserved during deep sleep. +//| +//| Preserving `DigitalInOut` states during deep sleep can be used to ensure that +//| external or on-board devices are powered or unpowered during sleep, among other purposes. +//| +//| On some microcontrollers, some pins cannot remain in their original state for hardware reasons. +//| +//| //| **If CircuitPython is connected to a host computer via USB or BLE //| the first time a deep sleep is requested, //| the connection will be maintained and the system will not go into deep sleep.** @@ -136,28 +153,50 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(alarm_light_sleep_until_alarms_obj, 1, MP_OB //| the next deep sleep will still be a true deep sleep. You must do a hard reset //| or power-cycle to exit a true deep sleep loop. //| -//| Here is skeletal example that deep-sleeps and restarts every 60 seconds: +//| Here is a skeletal example: //| //| .. code-block:: python //| //| import alarm //| import time +//| import board //| //| print("Waking up") //| -//| # Set an alarm for 60 seconds from now. +//| # Create an alarm for 60 seconds from now, and also a pin alarm. //| time_alarm = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + 60) +//| pin_alarm = alarm.pin.PinAlarm(board.D7, False) //| -//| # Deep sleep until the alarm goes off. Then restart the program. -//| alarm.exit_and_deep_sleep_until_alarms(time_alarm) +//| # Deep sleep until one of the alarm goes off. Then restart the program. +//| alarm.exit_and_deep_sleep_until_alarms(time_alarm, pin_alarm) //| """ //| ... //| -STATIC mp_obj_t alarm_exit_and_deep_sleep_until_alarms(size_t n_args, const mp_obj_t *args) { - validate_objs_are_alarms(n_args, args); +STATIC mp_obj_t alarm_exit_and_deep_sleep_until_alarms(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_preserve_dios }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_preserve_dios, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_tuple} }, + }; - // Validate the alarms and set them. - common_hal_alarm_set_deep_sleep_alarms(n_args, args); + // args will contain only the value for preserve_dios. The *alarms args are in pos_args. + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(0, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + validate_objs_are_alarms(n_args, pos_args); + + mp_obj_t preserve_dios = args[ARG_preserve_dios].u_obj; + const size_t num_dios = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(preserve_dios)); + digitalio_digitalinout_obj_t *dios_array[num_dios]; + + for (mp_uint_t i = 0; i < num_dios; i++) { + mp_obj_t dio = mp_obj_subscr(preserve_dios, MP_OBJ_NEW_SMALL_INT(i), MP_OBJ_SENTINEL); + if (!mp_obj_is_type(dio, &digitalio_digitalinout_type)) { + mp_raise_TypeError_varg(translate("Expected a %q"), MP_QSTR_DigitalInOut); + } + dios_array[i] = MP_OBJ_TO_PTR(dio); + } + + common_hal_alarm_set_deep_sleep_alarms(n_args, pos_args, num_dios, dios_array); // Raise an exception, which will be processed in main.c. mp_raise_type_arg(&mp_type_DeepSleepRequest, NULL); @@ -165,7 +204,7 @@ STATIC mp_obj_t alarm_exit_and_deep_sleep_until_alarms(size_t n_args, const mp_o // Doesn't get here. return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(alarm_exit_and_deep_sleep_until_alarms_obj, 1, MP_OBJ_FUN_ARGS_MAX, alarm_exit_and_deep_sleep_until_alarms); +MP_DEFINE_CONST_FUN_OBJ_KW(alarm_exit_and_deep_sleep_until_alarms_obj, 0, alarm_exit_and_deep_sleep_until_alarms); STATIC const mp_map_elem_t alarm_pin_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_pin) }, diff --git a/shared-bindings/alarm/__init__.h b/shared-bindings/alarm/__init__.h index eb67917dce..ea86e44f2f 100644 --- a/shared-bindings/alarm/__init__.h +++ b/shared-bindings/alarm/__init__.h @@ -30,6 +30,7 @@ #include "py/obj.h" #include "common-hal/alarm/__init__.h" +#include "common-hal/digitalio/DigitalInOut.h" // Light sleep fully self-contained and does not exit user code. It will return // the same alarm object that was orignally passed in, unlike deep sleep, which @@ -42,7 +43,7 @@ extern mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const // supervisor will idle using `port_wait_for_interrupt`. After each call, it will // call alarm_woken_from_sleep to see if we've been woken by an alarm and if so, // it will exit idle as if deep sleep was exited -extern void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms); +extern void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms, size_t n_dios, digitalio_digitalinout_obj_t **preserve_dios); extern NORETURN void common_hal_alarm_enter_deep_sleep(void); diff --git a/shared-bindings/dualbank/__init__.c b/shared-bindings/dualbank/__init__.c index f907c91e0e..fa4c2af691 100644 --- a/shared-bindings/dualbank/__init__.c +++ b/shared-bindings/dualbank/__init__.c @@ -56,7 +56,7 @@ //| ... //| -//| def flash(*buffer: ReadableBuffer, offset: int=0) -> None: +//| def flash(buffer: ReadableBuffer, offset: int=0) -> None: //| """Writes one of two app partitions at the given offset. //| //| This can be called multiple times when flashing the firmware diff --git a/shared/runtime/pyexec.c b/shared/runtime/pyexec.c index 72714b9a2b..87219d18f5 100644 --- a/shared/runtime/pyexec.c +++ b/shared/runtime/pyexec.c @@ -168,17 +168,21 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input } // check for SystemExit - if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type((mp_obj_t)nlr.ret_val)), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) { + + // nlr.ret_val is an exception object. + mp_obj_t exception_obj = (mp_obj_t)nlr.ret_val; + + if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(exception_obj)), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) { // at the moment, the value of SystemExit is unused ret = pyexec_system_exit; #if CIRCUITPY_ALARM - } else if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type((mp_obj_t)nlr.ret_val)), &mp_type_DeepSleepRequest)) { + } else if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(exception_obj)), MP_OBJ_FROM_PTR(&mp_type_DeepSleepRequest))) { ret = PYEXEC_DEEP_SLEEP; #endif - } else if ((mp_obj_t)nlr.ret_val == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_reload_exception))) { + } else if (exception_obj == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_reload_exception))) { ret = PYEXEC_RELOAD; } else { - mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); + mp_obj_print_exception(&mp_plat_print, exception_obj); ret = PYEXEC_EXCEPTION; }