allow preserving pin state during deep sleep
This commit is contained in:
parent
5a053f9ae5
commit
60f43b1703
@ -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 ""
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -244,6 +244,7 @@ void SysTick_Handler(void) {
|
||||
|
||||
void reset_port(void) {
|
||||
reset_all_pins();
|
||||
|
||||
#if CIRCUITPY_RTC
|
||||
rtc_reset();
|
||||
#endif
|
||||
|
@ -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) },
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user