From 9bf9fffd7c07eb815ff040e635c33c323c8fd844 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Fri, 22 Aug 2025 14:59:27 +0100 Subject: [PATCH] Add support for RP2040 dormant (using external RTC clock) --- src/rp2_common/pico_low_power/low_power.c | 9 +++---- test/hello_sleep/CMakeLists.txt | 11 ++++++++ test/hello_sleep/hello_sleep.c | 14 +++++++--- test/hello_sleep/rtc_clksrc.c | 33 +++++++++++++++++++++++ 4 files changed, 57 insertions(+), 10 deletions(-) create mode 100644 test/hello_sleep/rtc_clksrc.c diff --git a/src/rp2_common/pico_low_power/low_power.c b/src/rp2_common/pico_low_power/low_power.c index 27aa3da4..54895004 100644 --- a/src/rp2_common/pico_low_power/low_power.c +++ b/src/rp2_common/pico_low_power/low_power.c @@ -215,11 +215,7 @@ void low_power_sleep_until_pin_state(uint gpio_pin, bool edge, bool high, // Clear the irq so we can go back to dormant mode again if we want gpio_acknowledge_irq(gpio_pin, event); - - // todo fix race in gpio_set_irq_enabled_with_callback - // gpio_set_irq_enabled_with_callback(gpio_pin, event, false, NULL); - gpio_set_irq_enabled(gpio_pin, event, false); - gpio_set_irq_callback(NULL); + gpio_set_irq_enabled_with_callback(gpio_pin, event, false, NULL); post_clock_gating(); } @@ -374,7 +370,7 @@ void low_power_go_dormant(dormant_clock_source_t dormant_clock_source) { int low_power_dormant_until_aon_timer(absolute_time_t until, dormant_clock_source_t dormant_clock_source, - __unused uint src_hz, uint gpio_pin, + uint src_hz, uint gpio_pin, const clock_dest_set_t *keep_enabled) { low_power_setup_clocks_for_dormant(dormant_clock_source); @@ -388,6 +384,7 @@ int low_power_dormant_until_aon_timer(absolute_time_t until, clock_dest_set_add(&local_keep_enabled, CLK_DEST_RTC_RTC); #elif PICO_RP2350 // todo + ((void)src_hz); ((void)gpio_pin); if (dormant_clock_source == DORMANT_CLOCK_SOURCE_LPOSC) powman_timer_set_1khz_tick_source_lposc(); diff --git a/test/hello_sleep/CMakeLists.txt b/test/hello_sleep/CMakeLists.txt index d565e10d..92174173 100644 --- a/test/hello_sleep/CMakeLists.txt +++ b/test/hello_sleep/CMakeLists.txt @@ -7,6 +7,17 @@ target_link_libraries(hello_sleep pico_stdlib pico_low_power pico_status_led) # create map/bin/hex file etc. pico_add_extra_outputs(hello_sleep) +if (PICO_RP2040) + add_executable(rtc_clksrc + rtc_clksrc.c + ) + + target_link_libraries(rtc_clksrc pico_stdlib pico_status_led) + + # create map/bin/hex file etc. + pico_add_extra_outputs(rtc_clksrc) +endif() + add_executable(hello_sleep_gpio hello_sleep_gpio.c ) diff --git a/test/hello_sleep/hello_sleep.c b/test/hello_sleep/hello_sleep.c index 3c9d9a72..895e5365 100644 --- a/test/hello_sleep/hello_sleep.c +++ b/test/hello_sleep/hello_sleep.c @@ -14,6 +14,8 @@ #define SLEEP_TIME_S 2 #define SLEEP_TIME_MS SLEEP_TIME_S * 1000 +#define RTC_GPIO 22 // must support clock input, see the GPIO function table in the datasheet. + bool repeater(repeating_timer_t *timer) { if (aon_timer_is_running()) { printf(" Repeating timer at %dms (aon: %dms)\n", to_ms_since_boot(get_absolute_time()), to_ms_since_boot(aon_timer_get_absolute_time())); @@ -86,7 +88,6 @@ int main() { printf("Doing %d second pause to prove timer running\n", SLEEP_TIME_S); busy_wait_ms(SLEEP_TIME_MS); -#if !PICO_RP2040 printf("Going DORMANT for %d seconds via AON TIMER\n", SLEEP_TIME_S); // todo, ah; we should start the aon timer; still have to decide what to do about keeping them in sync @@ -95,9 +96,13 @@ int main() { aon_timer_start(&ts); wakeup_time = delayed_by_ms(start_time, SLEEP_TIME_MS); - low_power_dormant_until_aon_timer(wakeup_time, DORMANT_CLOCK_SOURCE_LPOSC, XOSC_KHZ * 1000, - 0, // gpio pin (unused with powman) - NULL); + low_power_dormant_until_aon_timer(wakeup_time, + #if PICO_RP2040 + DORMANT_CLOCK_SOURCE_XOSC, 46875, + #else + DORMANT_CLOCK_SOURCE_LPOSC, XOSC_HZ, + #endif + RTC_GPIO, NULL); diff = absolute_time_diff_us(get_absolute_time(), wakeup_time); // need to use the AON timer for checking time, since the other timer is unclocked diff = absolute_time_diff_us(wakeup_time, get_absolute_time()); @@ -113,6 +118,7 @@ int main() { printf("Doing %d second pause to prove timer running\n", SLEEP_TIME_S); busy_wait_ms(SLEEP_TIME_MS); +#if !PICO_RP2040 printf("Going to PSTATE for %d seconds\n", SLEEP_TIME_S); start_time = aon_timer_get_absolute_time(); diff --git a/test/hello_sleep/rtc_clksrc.c b/test/hello_sleep/rtc_clksrc.c new file mode 100644 index 00000000..287903b6 --- /dev/null +++ b/test/hello_sleep/rtc_clksrc.c @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include "pico/stdlib.h" +#include "pico/status_led.h" +#include "pico/sync.h" +#include "hardware/clocks.h" + +#define RTC_GPIO 21 + +bool repeater(repeating_timer_t *timer) { + printf(" Repeating timer at %dms\n", to_ms_since_boot(get_absolute_time())); + status_led_set_state(!status_led_get_state()); + return true; +} + +int main() { + stdio_init_all(); + status_led_init(); + + clock_gpio_init(RTC_GPIO, CLOCKS_CLK_GPOUT3_CTRL_AUXSRC_VALUE_CLK_RTC, 1); + + repeating_timer_t repeat; + add_repeating_timer_ms(500, repeater, NULL, &repeat); + + while (true) __wfi(); + + return 0; +} \ No newline at end of file