diff --git a/CMakeLists.txt b/CMakeLists.txt index a76866c0d..202a09fcd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,6 +77,7 @@ add_subdirectory(gpio) add_subdirectory(hstx) add_subdirectory(i2c) add_subdirectory(interp) +add_subdirectory(low_power) add_subdirectory(multicore) add_subdirectory(otp) add_subdirectory(picoboard) diff --git a/low_power/CMakeLists.txt b/low_power/CMakeLists.txt new file mode 100644 index 000000000..e53891a6c --- /dev/null +++ b/low_power/CMakeLists.txt @@ -0,0 +1,5 @@ +add_subdirectory(low_power_sleep) +add_subdirectory(low_power_dormant) +if (NOT PICO_RP2040) + add_subdirectory(low_power_pstate) +endif() diff --git a/low_power/low_power_dormant/CMakeLists.txt b/low_power/low_power_dormant/CMakeLists.txt new file mode 100644 index 000000000..8932b5ac2 --- /dev/null +++ b/low_power/low_power_dormant/CMakeLists.txt @@ -0,0 +1,38 @@ +add_executable(low_power_dormant_timer + low_power_dormant_timer.c +) +target_link_libraries(low_power_dormant_timer PRIVATE + pico_stdlib + pico_low_power + pico_status_led +) +pico_add_extra_outputs(low_power_dormant_timer) +example_auto_set_url(low_power_dormant_timer) +pico_enable_stdio_usb(low_power_dormant_timer 0) +pico_enable_stdio_uart(low_power_dormant_timer 1) + +add_executable(low_power_dormant_gpio + low_power_dormant_gpio.c +) +target_link_libraries(low_power_dormant_gpio PRIVATE + pico_stdlib + pico_low_power + pico_status_led +) +pico_add_extra_outputs(low_power_dormant_gpio) +example_auto_set_url(low_power_dormant_gpio) +pico_enable_stdio_usb(low_power_dormant_gpio 0) +pico_enable_stdio_uart(low_power_dormant_gpio 1) + +# firmware for generating a clock on gp21 for running the dormant test on rp2040 +# connect the clock out from gp21 to gp20 (or gp22) on the rp2040 running the dormant test +add_executable(low_power_clksrc + low_power_clksrc.c +) +target_link_libraries(low_power_clksrc PRIVATE + pico_stdlib + pico_status_led +) +pico_add_extra_outputs(low_power_clksrc) +pico_enable_stdio_usb(low_power_clksrc 0) +pico_enable_stdio_uart(low_power_clksrc 1) diff --git a/low_power/low_power_dormant/low_power_clksrc.c b/low_power/low_power_dormant/low_power_clksrc.c new file mode 100644 index 000000000..c76c248d8 --- /dev/null +++ b/low_power/low_power_dormant/low_power_clksrc.c @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2026 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" + +#ifndef RTC_CLOCK_SRC_GPIO_OUT +#define RTC_CLOCK_SRC_GPIO_OUT 21 +#endif + +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_CLOCK_SRC_GPIO_OUT, CLOCKS_CLK_GPOUT3_CTRL_AUXSRC_VALUE_CLK_USB, 1024); // 48kHz + + repeating_timer_t repeat; + add_repeating_timer_ms(500, repeater, NULL, &repeat); + + while (true) __wfi(); + + return 0; +} \ No newline at end of file diff --git a/low_power/low_power_dormant/low_power_dormant_gpio.c b/low_power/low_power_dormant/low_power_dormant_gpio.c new file mode 100644 index 000000000..f006847f0 --- /dev/null +++ b/low_power/low_power_dormant/low_power_dormant_gpio.c @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2024 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include "pico/stdlib.h" +#include "pico/low_power.h" +#include "pico/status_led.h" + +// GPIO to wait to go high, connect the other end to 3V3 OUT +#ifndef LOW_POWER_WAKE_GPIO +#define LOW_POWER_WAKE_GPIO 15 +#endif + +#ifndef CLOCK_SOURCE +#if PICO_RP2040 +#define CLOCK_SOURCE DORMANT_CLOCK_SOURCE_XOSC +#else +#define CLOCK_SOURCE DORMANT_CLOCK_SOURCE_LPOSC +#endif +#endif + +// Got to sleep and wakeup when gpio goes high +int main() { + + stdio_init_all(); + hard_assert(status_led_init()); + gpio_init(LOW_POWER_WAKE_GPIO); + + uint32_t count = 1; + while(true) { + status_led_set_state(true); + + printf("Wake up, test run: %u\n", count++); + + // Wait for gpio to go low + if (gpio_get(LOW_POWER_WAKE_GPIO)) { + printf("Awake until gpio %u goes low\n", LOW_POWER_WAKE_GPIO); + while(gpio_get(LOW_POWER_WAKE_GPIO)) { + tight_loop_contents(); + } + } + + // go dormant + printf("Dormant until gpio %u goes high\n", LOW_POWER_WAKE_GPIO); + status_led_set_state(false); + + int rc = low_power_dormant_until_gpio_pin_state(LOW_POWER_WAKE_GPIO, true, true, CLOCK_SOURCE, NULL); + status_led_set_state(true); + if (rc != PICO_OK) { + printf("low_power_dormant_until_aon_timer returned error %d\n", rc); + hard_assert(false); + } + } + return 0; +} diff --git a/low_power/low_power_dormant/low_power_dormant_timer.c b/low_power/low_power_dormant/low_power_dormant_timer.c new file mode 100644 index 000000000..823e2d162 --- /dev/null +++ b/low_power/low_power_dormant/low_power_dormant_timer.c @@ -0,0 +1,77 @@ +/** + * Copyright (c) 2024 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include "pico/stdlib.h" +#include "pico/low_power.h" +#include "pico/aon_timer.h" +#include "pico/status_led.h" + +#ifdef PICO_RP2350 +#include "hardware/powman.h" +#endif + +// How long to wait +#ifndef AWAKE_TIME_MS +#define AWAKE_TIME_MS 10000 +#endif +#ifndef SLEEP_TIME_MS +#define SLEEP_TIME_MS 10000 +#endif + +#if PICO_RP2040 +#ifndef RTC_CLOCK_SRC_GPIO_IN +#define RTC_CLOCK_SRC_GPIO_IN 20 +#endif +#endif + +#ifndef CLOCK_SOURCE +#if PICO_RP2040 +#define CLOCK_SOURCE DORMANT_CLOCK_SOURCE_XOSC +#else +#define CLOCK_SOURCE DORMANT_CLOCK_SOURCE_LPOSC +#endif +#endif + +// Got to sleep and wakeup after 5 seconds +// The example will repeatedly wait 10 seconds then switch off for 10 seconds +// The debugger will appear to be unresponsive while the device is off +int main() { + stdio_init_all(); + // Must start aon timer + low_power_start_aon_timer_at_time_ms(1776858754000); +#if AWAKE_TIME_MS < 10000 + // pause for at least 10s to allow the debugger to attach on power up to allow the device to be re-programmed + printf("Waiting a bit to allow debugger to attach\n"); + sleep_ms(10000 - AWAKE_TIME_MS); +#endif + hard_assert(status_led_init()); + uint32_t count = 1; + while(true) { + status_led_set_state(true); + + printf("Wake up, test run: %u\n", count++); + + // Stay awake for a few seconds + printf("Awake for %dms\n", AWAKE_TIME_MS); + sleep_ms(AWAKE_TIME_MS); + + // go dormant + printf("Dormant for %dms\n", SLEEP_TIME_MS); + status_led_set_state(false); + +#if PICO_RP2040 + low_power_set_external_clock_source(RTC_CLOCK_FREQ_HZ, RTC_CLOCK_SRC_GPIO_IN); +#endif + int rc = low_power_dormant_for_ms(SLEEP_TIME_MS, CLOCK_SOURCE, NULL); + status_led_set_state(true); + if (rc != PICO_OK) { + printf("low_power_dormant_for_ms returned error %d\n", rc); + hard_assert(false); + } + } + return 0; +} diff --git a/low_power/low_power_pstate/CMakeLists.txt b/low_power/low_power_pstate/CMakeLists.txt new file mode 100644 index 000000000..5889d7b6a --- /dev/null +++ b/low_power/low_power_pstate/CMakeLists.txt @@ -0,0 +1,27 @@ +add_executable(low_power_pstate_timer + low_power_pstate_timer.c + ) +target_link_libraries(low_power_pstate_timer PRIVATE + pico_stdlib + pico_low_power + pico_status_led +) +pico_set_persistent_data_loc(low_power_pstate_timer 0x20040000) # SRAM1 power domain +pico_add_extra_outputs(low_power_pstate_timer) +example_auto_set_url(low_power_pstate_timer) +pico_enable_stdio_usb(low_power_pstate_timer 0) +pico_enable_stdio_uart(low_power_pstate_timer 1) + +add_executable(low_power_pstate_gpio + low_power_pstate_gpio.c + ) +target_link_libraries(low_power_pstate_gpio PRIVATE + pico_stdlib + pico_low_power + pico_status_led +) +pico_set_persistent_data_loc(low_power_pstate_gpio 0x20040000) # SRAM1 power domain +pico_add_extra_outputs(low_power_pstate_gpio) +example_auto_set_url(low_power_pstate_gpio) +pico_enable_stdio_usb(low_power_pstate_gpio 0) +pico_enable_stdio_uart(low_power_pstate_gpio 1) diff --git a/low_power/low_power_pstate/low_power_pstate_gpio.c b/low_power/low_power_pstate/low_power_pstate_gpio.c new file mode 100644 index 000000000..9981f5813 --- /dev/null +++ b/low_power/low_power_pstate/low_power_pstate_gpio.c @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2024 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include "pico/stdlib.h" +#include "pico/low_power.h" +#include "pico/aon_timer.h" +#include "pico/status_led.h" + +// GPIO to wait to go high, connect the other end to 3V3 OUT +#ifndef LOW_POWER_WAKE_GPIO +#define LOW_POWER_WAKE_GPIO 15 +#endif + +uint32_t __persistent_data(run_count); + +// The example will repeatedly wait 10 seconds then switch off for 10 seconds +// The debugger will appear to be unresponsive while the device is off +int main() { + stdio_init_all(); + + hard_assert(status_led_init()); + status_led_set_state(true); + + // Scratch register survives power down + printf("Wake up, test run: %u\n", run_count++); + + // Wait for gpio to go low + if (gpio_get(LOW_POWER_WAKE_GPIO)) { + printf("Awake until gpio %u goes low\n", LOW_POWER_WAKE_GPIO); + while(gpio_get(LOW_POWER_WAKE_GPIO)) { + tight_loop_contents(); + } + } + + // power off + printf("Low power until gpio %u goes high\n", LOW_POWER_WAKE_GPIO); + status_led_set_state(false); + int rc = low_power_pstate_until_gpio_pin_state(LOW_POWER_WAKE_GPIO, true, true, NULL, NULL); + status_led_set_state(true); + printf("low_power_pstate_until_aon_timer returned error %d\n", rc); + hard_assert(false); // should never get here! + return 0; +} diff --git a/low_power/low_power_pstate/low_power_pstate_timer.c b/low_power/low_power_pstate/low_power_pstate_timer.c new file mode 100644 index 000000000..05cc905d3 --- /dev/null +++ b/low_power/low_power_pstate/low_power_pstate_timer.c @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2024 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include "pico/stdlib.h" +#include "pico/low_power.h" +#include "pico/aon_timer.h" +#include "pico/status_led.h" + +// How long to wait +#ifndef AWAKE_TIME_MS +#define AWAKE_TIME_MS 10000 +#endif +#ifndef SLEEP_TIME_MS +#define SLEEP_TIME_MS 10000 +#endif + +uint32_t __persistent_data(run_count); + +// The example will repeatedly wait 10 seconds then switch off for 10 seconds +// The debugger will appear to be unresponsive while the device is off +int main() { + stdio_init_all(); + // Must start the aon timer if needed + printf("Current time: %llu\n", aon_timer_get_absolute_time()); + if (!aon_timer_is_running()) { + low_power_start_aon_timer_at_time_ms(1776858754000); + } +#if AWAKE_TIME_MS < 10000 + // pause for at least 10s to allow the debugger to attach on power up to allow the device to be re-programmed + printf("Waiting a bit to allow debugger to attach\n"); + sleep_ms(10000 - AWAKE_TIME_MS); +#endif + hard_assert(status_led_init()); + status_led_set_state(true); + + // Scratch register survives power down + printf("Wake up, test run: %u\n", run_count++); + + // Stay awake for a few seconds + printf("Awake for %dms\n", AWAKE_TIME_MS); + sleep_ms(AWAKE_TIME_MS); + + // power off + printf("Low power for %dms\n", SLEEP_TIME_MS); + status_led_set_state(false); + int rc = low_power_pstate_for_ms(SLEEP_TIME_MS, NULL, NULL); + status_led_set_state(true); + printf("low_power_pstate_for_ms returned error %d\n", rc); + hard_assert(false); // should never get here! + return 0; +} diff --git a/low_power/low_power_sleep/CMakeLists.txt b/low_power/low_power_sleep/CMakeLists.txt new file mode 100644 index 000000000..b143d5364 --- /dev/null +++ b/low_power/low_power_sleep/CMakeLists.txt @@ -0,0 +1,25 @@ +add_executable(low_power_sleep_timer + low_power_sleep_timer.c + ) +target_link_libraries(low_power_sleep_timer PRIVATE + pico_stdlib + pico_low_power + pico_status_led +) +pico_add_extra_outputs(low_power_sleep_timer) +example_auto_set_url(low_power_sleep_timer) +pico_enable_stdio_usb(low_power_sleep_timer 0) +pico_enable_stdio_uart(low_power_sleep_timer 1) + +add_executable(low_power_sleep_gpio + low_power_sleep_gpio.c + ) +target_link_libraries(low_power_sleep_gpio PRIVATE + pico_stdlib + pico_low_power + pico_status_led +) +pico_add_extra_outputs(low_power_sleep_gpio) +example_auto_set_url(low_power_sleep_gpio) +pico_enable_stdio_usb(low_power_sleep_gpio 0) +pico_enable_stdio_uart(low_power_sleep_gpio 1) diff --git a/low_power/low_power_sleep/low_power_sleep_gpio.c b/low_power/low_power_sleep/low_power_sleep_gpio.c new file mode 100644 index 000000000..450c0cf79 --- /dev/null +++ b/low_power/low_power_sleep/low_power_sleep_gpio.c @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2024 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include "pico/stdlib.h" +#include "pico/low_power.h" +#include "pico/status_led.h" + +// GPIO to wait to go high, connect the other end to 3V3 OUT +#ifndef LOW_POWER_WAKE_GPIO +#define LOW_POWER_WAKE_GPIO 15 +#endif + +// Got to sleep and wakeup after 10 seconds +int main() { + + stdio_init_all(); + hard_assert(status_led_init()); + gpio_init(LOW_POWER_WAKE_GPIO); + + uint32_t count = 1; + while(true) { + status_led_set_state(true); + + printf("Wake up, test run: %u\n", count++); + + // Wait for gpio to go low + if (gpio_get(LOW_POWER_WAKE_GPIO)) { + printf("Awake until gpio %u goes low\n", LOW_POWER_WAKE_GPIO); + while(gpio_get(LOW_POWER_WAKE_GPIO)) { + tight_loop_contents(); + } + } + + // go to sleep + printf("Sleeping until gpio %u goes high\n", LOW_POWER_WAKE_GPIO); + status_led_set_state(false); + + int rc = low_power_sleep_until_gpio_pin_state(LOW_POWER_WAKE_GPIO, true, true, NULL, true); + status_led_set_state(true); + if (rc != PICO_OK) { + printf("low_power_sleep_until_gpio_pin_state returned error %d\n", rc); + hard_assert(false); + } + } + return 0; +} diff --git a/low_power/low_power_sleep/low_power_sleep_timer.c b/low_power/low_power_sleep/low_power_sleep_timer.c new file mode 100644 index 000000000..1b55aa2eb --- /dev/null +++ b/low_power/low_power_sleep/low_power_sleep_timer.c @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2024 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include "pico/stdlib.h" +#include "pico/low_power.h" +#include "pico/status_led.h" + +// How long to wait +#ifndef AWAKE_TIME_MS +#define AWAKE_TIME_MS 10000 +#endif +#ifndef SLEEP_TIME_MS +#define SLEEP_TIME_MS 10000 +#endif + +// Got to sleep and wakeup after 10 seconds +int main() { + + stdio_init_all(); + hard_assert(status_led_init()); + + uint32_t count = 1; + while(true) { + status_led_set_state(true); + + printf("Wake up, test run: %u\n", count++); + + // Stay awake for a few seconds + printf("Awake for %dms\n", AWAKE_TIME_MS); + sleep_ms(AWAKE_TIME_MS); + + // go to sleep + printf("Sleeping for %dms\n", SLEEP_TIME_MS); + status_led_set_state(false); + int rc = low_power_sleep_for_ms(SLEEP_TIME_MS, NULL, true); + status_led_set_state(true); + if (rc != PICO_OK) { + printf("low_power_sleep_for_ms returned error %d\n", rc); + hard_assert(false); + } + } + return 0; +}