diff --git a/zephcore/boards/common/nrf52_wakeup.dtsi b/zephcore/boards/common/nrf52_wakeup.dtsi index 1d9455a..8729f53 100644 --- a/zephcore/boards/common/nrf52_wakeup.dtsi +++ b/zephcore/boards/common/nrf52_wakeup.dtsi @@ -1,11 +1,18 @@ /* - * Common: configure the 'buttons' gpio-keys node as a wakeup source. + * Common: mark the 'buttons' gpio-keys node as a wakeup source. * - * On nRF52840, sys_poweroff() enters System OFF (~1µA). Waking via the user - * button requires GPIO SENSE bits to be set before poweroff. Zephyr's gpio-keys - * driver adds GPIO_INT_WAKEUP to the interrupt flags when wakeup-source is set, - * which causes the nRF52 GPIO driver to call nrf_gpio_cfg_sense_set(). Those - * SENSE bits persist through System OFF and trigger a reset on button press. + * NOTE: On nRF52, this property is currently inert — the nRF GPIO driver + * does not implement GPIO_INT_WAKEUP, so wakeup-source alone does not set + * the GPIO SENSE bits required for System OFF wakeup. Actual SENSE + * configuration is done explicitly in action_deep_sleep() (ui_task.c) + * via nrf_gpio_cfg_sense_input() right before sys_poweroff(). + * + * Kept here so that: + * 1. If a future Zephyr nRF GPIO driver gains GPIO_INT_WAKEUP support, + * this will work automatically alongside the HAL call (harmless + * double-set). + * 2. It documents wakeup intent in devicetree for boards that may run + * on other platforms where the driver does honour GPIO_INT_WAKEUP. * * Include this in any nRF52 board DTS that defines a 'buttons' gpio-keys node. * Boards without buttons (e.g. ikoka_nano, rak4631) should NOT include this. diff --git a/zephcore/helpers/ui/ui_task.c b/zephcore/helpers/ui/ui_task.c index 0e1afb9..dbe675f 100644 --- a/zephcore/helpers/ui/ui_task.c +++ b/zephcore/helpers/ui/ui_task.c @@ -48,6 +48,10 @@ #include #endif +#if defined(CONFIG_SOC_FAMILY_NORDIC_NRF) +#include +#endif + #include /* GPS control (extern "C" in ZephyrSensorManager.h) */ @@ -577,8 +581,47 @@ static void action_deep_sleep(void) gps_power_off_for_shutdown(); mesh_disable_power_regulators(); - /* 5. Enter System OFF. - * Wake via reset button → full chip reset → clean boot. */ + /* 5. Configure GPIO SENSE for button wakeup, then enter System OFF. + * + * The nRF GPIO driver does not implement GPIO_INT_WAKEUP, so the + * wakeup-source DTS property has no effect on nRF52. We must set + * SENSE bits directly via the nRF HAL. sys_poweroff() goes straight + * to nrf_power_system_off() with no device PM suspend, so these bits + * persist into System OFF and trigger a reset on next button press. + * + * Wait for button release first: if we enter System OFF while the + * button is still held (long-press shutdown), DETECT is already + * asserted and the chip cannot enter System OFF cleanly. */ +#if defined(CONFIG_SOC_FAMILY_NORDIC_NRF) && DT_NODE_EXISTS(DT_ALIAS(sw0)) + { +#define _SW0_NODE DT_ALIAS(sw0) +#define _SW0_PORT DT_PROP(DT_GPIO_CTLR(_SW0_NODE, gpios), port) +#define _SW0_PIN DT_GPIO_PIN(_SW0_NODE, gpios) +#define _SW0_FLAGS DT_GPIO_FLAGS(_SW0_NODE, gpios) + + static const struct gpio_dt_spec sw0 = + GPIO_DT_SPEC_GET(DT_ALIAS(sw0), gpios); + gpio_pin_configure_dt(&sw0, GPIO_INPUT); + + int64_t deadline = k_uptime_get() + 5000; + while (gpio_pin_get_dt(&sw0) && k_uptime_get() < deadline) { + k_sleep(K_MSEC(10)); + } + + nrf_gpio_cfg_sense_input( + NRF_GPIO_PIN_MAP(_SW0_PORT, _SW0_PIN), + (_SW0_FLAGS & GPIO_PULL_UP) ? NRF_GPIO_PIN_PULLUP : + (_SW0_FLAGS & GPIO_PULL_DOWN) ? NRF_GPIO_PIN_PULLDOWN : + NRF_GPIO_PIN_NOPULL, + (_SW0_FLAGS & GPIO_ACTIVE_LOW) ? NRF_GPIO_PIN_SENSE_LOW + : NRF_GPIO_PIN_SENSE_HIGH); +#undef _SW0_NODE +#undef _SW0_PORT +#undef _SW0_PIN +#undef _SW0_FLAGS + } +#endif /* CONFIG_SOC_FAMILY_NORDIC_NRF && sw0 */ + LOG_INF("deep sleep: entering System OFF"); sys_poweroff(); CODE_UNREACHABLE;