diff --git a/docs/library/machine.Pin.rst b/docs/library/machine.Pin.rst index 49fb66beb3..edba11d5f3 100644 --- a/docs/library/machine.Pin.rst +++ b/docs/library/machine.Pin.rst @@ -42,7 +42,7 @@ Usage Model:: Constructors ------------ -.. class:: Pin(id, mode=-1, pull=-1, *, value=None, drive=0, alt=-1) +.. class:: Pin(id, mode=-1, pull=-1, *, value=None, drive=0, alt=-1, sense=-1) Access the pin peripheral (GPIO pin) associated with the given ``id``. If additional arguments are given in the constructor then they are used to initialise @@ -97,6 +97,15 @@ Constructors one pin alternate function is supported the this argument is not required. Not all ports implement this argument. + - ``sense`` specifies whether and on what input value the pin contributes to the + *DETECT* signal, which wakes an nRF51/52 system from deep sleep. It can be one of: + + - ``Pin.SENSE_DISABLED`` - Do not wake from this pin. + - ``Pin.SENSE_LOW`` - Wake when pin is low. + - ``Pin.SENSE_HIGH`` - Wake when pin is high. + + Availability: nrf port. + As specified above, the Pin class allows to set an alternate function for a particular pin, but it does not specify any further operations on such a pin. Pins configured in alternate-function mode are usually not used as GPIO but are instead driven by other @@ -108,7 +117,7 @@ Constructors Methods ------- -.. method:: Pin.init(mode=-1, pull=-1, *, value=None, drive=0, alt=-1) +.. method:: Pin.init(mode=-1, pull=-1, *, value=None, drive=0, alt=-1, sense=-1) Re-initialise the pin using the given parameters. Only those arguments that are specified will be set. The rest of the pin peripheral state will remain @@ -274,3 +283,13 @@ not all constants are available on all ports. Pin.IRQ_HIGH_LEVEL Selects the IRQ trigger type. + +.. data:: Pin.SENSE_DISABLED + Pin.SENSE_LOW + Pin.SENSE_HIGH + + Selects the *SENSE* configuration of the pin, which determines + whether and on what input value it contributes to the *DETECT* + signal, which wakes the system from deep sleep. + + Availability: nrf port. diff --git a/docs/library/machine.rst b/docs/library/machine.rst index 532266d1d9..95dd4ada1e 100644 --- a/docs/library/machine.rst +++ b/docs/library/machine.rst @@ -160,6 +160,15 @@ Power related functions return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake from other resets. + *nrf port:* + + * The *time_ms* argument to `deepsleep` is ignored, the sleep is always indefinite. + nRF microcontrollers are incapable of waking on a timer as all clocks are off in + the deep sleep state. + + * Pins are configured as wake sources using the ``sense`` argument to the + `Pin` constructor. + .. function:: wake_reason() Get the wake reason. See :ref:`constants ` for the possible return values. diff --git a/ports/nrf/modules/machine/modmachine.c b/ports/nrf/modules/machine/modmachine.c index de1d0e3124..d5767e4ff4 100644 --- a/ports/nrf/modules/machine/modmachine.c +++ b/ports/nrf/modules/machine/modmachine.c @@ -49,12 +49,20 @@ #if MICROPY_PY_MACHINE_RTCOUNTER #include "rtcounter.h" #endif +#if defined(POWER_SYSTEMOFF_SYSTEMOFF_Enter) +// nRF51/52 +#include "nrf_power.h" +#elif defined(REGULATORS_SYSTEMOFF_SYSTEMOFF_Enable) +// nRF91 +#include "nrf_regulators.h" +#endif +#define PYB_RESET_POWER_ON (32) #define PYB_RESET_HARD (0) #define PYB_RESET_WDT (1) #define PYB_RESET_SOFT (2) #define PYB_RESET_LOCKUP (3) -#define PYB_RESET_POWER_ON (16) +#define PYB_RESET_DEEPSLEEP (16) #define PYB_RESET_LPCOMP (17) #define PYB_RESET_DIF (18) #define PYB_RESET_NFC (19) @@ -93,11 +101,12 @@ MICROPY_PY_MACHINE_RTCOUNTER_ENTRY \ MICROPY_PY_MACHINE_TIMER_ENTRY \ MICROPY_PY_MACHINE_TEMP_ENTRY \ + { MP_ROM_QSTR(MP_QSTR_PWRON_RESET), MP_ROM_INT(PYB_RESET_POWER_ON) }, \ { MP_ROM_QSTR(MP_QSTR_HARD_RESET), MP_ROM_INT(PYB_RESET_HARD) }, \ { MP_ROM_QSTR(MP_QSTR_WDT_RESET), MP_ROM_INT(PYB_RESET_WDT) }, \ { MP_ROM_QSTR(MP_QSTR_SOFT_RESET), MP_ROM_INT(PYB_RESET_SOFT) }, \ { MP_ROM_QSTR(MP_QSTR_LOCKUP_RESET), MP_ROM_INT(PYB_RESET_LOCKUP) }, \ - { MP_ROM_QSTR(MP_QSTR_PWRON_RESET), MP_ROM_INT(PYB_RESET_POWER_ON) }, \ + { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP_RESET), MP_ROM_INT(PYB_RESET_DEEPSLEEP) }, \ { MP_ROM_QSTR(MP_QSTR_LPCOMP_RESET), MP_ROM_INT(PYB_RESET_LPCOMP) }, \ { MP_ROM_QSTR(MP_QSTR_DEBUG_IF_RESET), MP_ROM_INT(PYB_RESET_DIF) }, \ MICROPY_PY_MACHINE_NFC_RESET_ENTRY \ @@ -115,7 +124,7 @@ void machine_init(void) { } else if (state & POWER_RESETREAS_LOCKUP_Msk) { reset_cause = PYB_RESET_LOCKUP; } else if (state & POWER_RESETREAS_OFF_Msk) { - reset_cause = PYB_RESET_POWER_ON; + reset_cause = PYB_RESET_DEEPSLEEP; #if !defined(NRF9160_XXAA) } else if (state & POWER_RESETREAS_LPCOMP_Msk) { reset_cause = PYB_RESET_LPCOMP; @@ -126,10 +135,12 @@ void machine_init(void) { } else if (state & POWER_RESETREAS_NFC_Msk) { reset_cause = PYB_RESET_NFC; #endif + } else { + reset_cause = PYB_RESET_POWER_ON; } // clear reset reason - NRF_POWER->RESETREAS = (1 << reset_cause); + NRF_POWER->RESETREAS = 0xFFFFFFFF; } // machine.info([dump_alloc_table]) @@ -200,7 +211,18 @@ static void mp_machine_lightsleep(size_t n_args, const mp_obj_t *args) { } NORETURN static void mp_machine_deepsleep(size_t n_args, const mp_obj_t *args) { - mp_machine_reset(); + #if defined(POWER_SYSTEMOFF_SYSTEMOFF_Enter) + // nRF51/52 + nrf_power_system_off(NRF_POWER); + #elif defined(REGULATORS_SYSTEMOFF_SYSTEMOFF_Enable) + // nRF91 + nrf_regulators_system_off(NRF_REGULATORS); + #else + #error figure out how to enter System OFF mode on this chip + #endif + // never reached, just to convince the compiler of NORETURN + for (;;) { + } } static mp_int_t mp_machine_reset_cause(void) { diff --git a/ports/nrf/modules/machine/pin.c b/ports/nrf/modules/machine/pin.c index 2191cc9521..7bd2f53626 100644 --- a/ports/nrf/modules/machine/pin.c +++ b/ports/nrf/modules/machine/pin.c @@ -349,6 +349,7 @@ static mp_obj_t pin_obj_init_helper(const pin_obj_t *self, mp_uint_t n_args, con { MP_QSTR_af, MP_ARG_INT, {.u_int = -1}}, // legacy { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, { MP_QSTR_alt, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1}}, + { MP_QSTR_sense, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1}}, }; // parse args @@ -374,13 +375,21 @@ static mp_obj_t pin_obj_init_helper(const pin_obj_t *self, mp_uint_t n_args, con nrf_gpio_pin_input_t input = (mode == NRF_GPIO_PIN_DIR_INPUT) ? NRF_GPIO_PIN_INPUT_CONNECT : NRF_GPIO_PIN_INPUT_DISCONNECT; + // sense mode (default unmodified) + nrf_gpio_pin_sense_t sense = (nrf_gpio_pin_sense_t)args[5].u_int; + if (sense == (nrf_gpio_pin_sense_t)-1) { + sense = nrf_gpio_pin_sense_get(self->pin); + } else if (sense != NRF_GPIO_PIN_NOSENSE && sense != NRF_GPIO_PIN_SENSE_LOW && sense != NRF_GPIO_PIN_SENSE_HIGH) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("invalid pin sense: %d"), sense); + } + if (mode == NRF_GPIO_PIN_DIR_OUTPUT || mode == NRF_GPIO_PIN_DIR_INPUT) { nrf_gpio_cfg(self->pin, mode, input, pull, NRF_GPIO_PIN_S0S1, - NRF_GPIO_PIN_NOSENSE); + sense); } else { mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("invalid pin mode: %d"), mode); } @@ -614,6 +623,10 @@ static const mp_rom_map_elem_t pin_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_AF_OD), MP_ROM_INT(GPIO_MODE_AF_OD) }, { MP_ROM_QSTR(MP_QSTR_PULL_NONE), MP_ROM_INT(GPIO_NOPULL) }, */ + { MP_ROM_QSTR(MP_QSTR_SENSE_DISABLED), MP_ROM_INT(NRF_GPIO_PIN_NOSENSE) }, + { MP_ROM_QSTR(MP_QSTR_SENSE_LOW), MP_ROM_INT(NRF_GPIO_PIN_SENSE_LOW) }, + { MP_ROM_QSTR(MP_QSTR_SENSE_HIGH), MP_ROM_INT(NRF_GPIO_PIN_SENSE_HIGH) }, + #include "genhdr/pins_af_const.h" };