Skip to content

nrf/modules/machine: Implement deepsleep() #13367

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions docs/library/machine.Pin.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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.
9 changes: 9 additions & 0 deletions docs/library/machine.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 <machine_constants>` for the possible return values.
Expand Down
32 changes: 27 additions & 5 deletions ports/nrf/modules/machine/modmachine.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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 \
Expand All @@ -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;
Expand All @@ -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])
Expand Down Expand Up @@ -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) {
Expand Down
15 changes: 14 additions & 1 deletion ports/nrf/modules/machine/pin.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
}
Expand Down Expand Up @@ -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"
};

Expand Down
Loading