diff --git a/ports/alif/boards/ALIF_ENSEMBLE/board.c b/ports/alif/boards/ALIF_ENSEMBLE/board.c index 9241de60f9..ad2c47e69e 100644 --- a/ports/alif/boards/ALIF_ENSEMBLE/board.c +++ b/ports/alif/boards/ALIF_ENSEMBLE/board.c @@ -81,8 +81,8 @@ void board_early_init(void) { .vtor_address = SCB->VTOR, .vtor_address_ns = SCB->VTOR, // Configure wake-up sources. - .ewic_cfg = EWIC_VBAT_GPIO | EWIC_RTC_A, - .wakeup_events = WE_LPGPIO7 | WE_LPGPIO6 | WE_LPGPIO5 | WE_LPGPIO4 | WE_LPRTC, + .ewic_cfg = EWIC_VBAT_GPIO | EWIC_VBAT_TIMER | EWIC_RTC_A, + .wakeup_events = WE_LPGPIO7 | WE_LPGPIO6 | WE_LPGPIO5 | WE_LPGPIO4 | WE_LPTIMER0 | WE_LPRTC, }; if (se_services_set_off_profile(&off_profile)) { diff --git a/ports/alif/boards/OPENMV_AE3/board.c b/ports/alif/boards/OPENMV_AE3/board.c index a0b8378846..42a00b32d0 100644 --- a/ports/alif/boards/OPENMV_AE3/board.c +++ b/ports/alif/boards/OPENMV_AE3/board.c @@ -154,8 +154,8 @@ void board_early_init(void) { .vtor_address = SCB->VTOR, .vtor_address_ns = SCB->VTOR, // Configure wake-up sources. - .ewic_cfg = EWIC_VBAT_GPIO | EWIC_RTC_A, - .wakeup_events = WE_LPGPIO7 | WE_LPGPIO6 | WE_LPGPIO5 | WE_LPGPIO4 | WE_LPRTC, + .ewic_cfg = EWIC_VBAT_GPIO | EWIC_VBAT_TIMER | EWIC_RTC_A, + .wakeup_events = WE_LPGPIO7 | WE_LPGPIO6 | WE_LPGPIO5 | WE_LPGPIO4 | WE_LPTIMER0 | WE_LPRTC, }; if (se_services_set_off_profile(&off_profile)) { diff --git a/ports/alif/modmachine.c b/ports/alif/modmachine.c index fe84222788..93eaea8aa7 100644 --- a/ports/alif/modmachine.c +++ b/ports/alif/modmachine.c @@ -27,6 +27,7 @@ // This file is never compiled standalone, it's included directly from // extmod/modmachine.c via MICROPY_PY_MACHINE_INCLUDEFILE. +#include "modmachine.h" #include "se_services.h" #include "tusb.h" @@ -116,7 +117,37 @@ static void mp_machine_lightsleep(size_t n_args, const mp_obj_t *args) { #endif } +#include "lptimer.h" +#include "sys_ctrl_lptimer.h" + +#define LPTIMER ((LPTIMER_Type *)LPTIMER_BASE) +#define LPTIMER_CH_A (0) + +static void lptimer_set_wakeup(uint64_t timeout_us) { + lptimer_disable_counter(LPTIMER, LPTIMER_CH_A); + + ANA_REG->MISC_CTRL |= 1 << 0; // SEL_32K, select LXFO + + select_lptimer_clk(LPTIMER_CLK_SOURCE_32K, LPTIMER_CH_A); + + // Maximum 131 second timeout, to not overflow 32-bit ticks when + // LPTIMER is clocked at 32768Hz. + uint32_t timeout_ticks = (uint64_t)MIN(timeout_us, 131000000) * 32768 / 1000000; + + // Set up the LPTIMER interrupt to fire after the given timeout. + lptimer_set_mode_userdefined(LPTIMER, LPTIMER_CH_A); + lptimer_load_count(LPTIMER, LPTIMER_CH_A, &timeout_ticks); + lptimer_clear_interrupt(LPTIMER, LPTIMER_CH_A); + lptimer_unmask_interrupt(LPTIMER, LPTIMER_CH_A); + lptimer_enable_counter(LPTIMER, LPTIMER_CH_A); +} + MP_NORETURN static void mp_machine_deepsleep(size_t n_args, const mp_obj_t *args) { + mp_int_t sleep_ms = -1; + if (n_args != 0) { + sleep_ms = mp_obj_get_int(args[0]); + } + #if MICROPY_HW_ENABLE_USBDEV mp_machine_enable_usb(false); #endif @@ -127,6 +158,14 @@ MP_NORETURN static void mp_machine_deepsleep(size_t n_args, const mp_obj_t *args __disable_irq(); + if (sleep_ms >= 0) { + if (sleep_ms < 10000) { + lptimer_set_wakeup(sleep_ms * 1000); + } else { + machine_rtc_set_wakeup(sleep_ms / 1000); + } + } + // If power is removed from the subsystem, the function does // not return, and the CPU will reboot when/if the subsystem // is next powered up.