3434#include "hardware/structs/watchdog.h"
3535
3636// XOSC shutdown
37- #include "hardware/rtc.h"
3837#include "hardware/pll.h"
3938#include "hardware/regs/io_bank0.h"
4039
40+ #if PICO_RP2350
41+ #include "hardware/powman.h"
42+ #include "pico/low_power.h"
43+ #endif
44+
4145// Watchdog scratch register
4246// Not used elsewhere in the SDK for now, keep an eye on it
4347#define RP_WKUP_SCRATCH_REG 0
4448
4549// Light sleep turns off nonvolatile Busio and other wake-only peripherals
4650// TODO: this only saves about 2mA right now, expand with other non-essentials
51+ #if PICO_RP2040
4752const uint32_t RP_LIGHTSLEEP_EN0_MASK = ~(
4853 CLOCKS_SLEEP_EN0_CLK_SYS_SPI1_BITS |
4954 CLOCKS_SLEEP_EN0_CLK_PERI_SPI1_BITS |
@@ -59,7 +64,28 @@ const uint32_t RP_LIGHTSLEEP_EN0_MASK = ~(
5964 );
6065// This bank has the USB clocks in it, leave it for now
6166const uint32_t RP_LIGHTSLEEP_EN1_MASK = CLOCKS_SLEEP_EN1_RESET ;
67+ #else
68+ // Same peripherals as RP2040. RP2350 adds PIO2 and moves SPI to the second bank.
69+ const uint32_t RP_LIGHTSLEEP_EN0_MASK = ~(
70+ CLOCKS_SLEEP_EN0_CLK_SYS_PWM_BITS |
71+ CLOCKS_SLEEP_EN0_CLK_SYS_PIO2_BITS |
72+ CLOCKS_SLEEP_EN0_CLK_SYS_PIO1_BITS |
73+ CLOCKS_SLEEP_EN0_CLK_SYS_PIO0_BITS |
74+ CLOCKS_SLEEP_EN0_CLK_SYS_I2C1_BITS |
75+ CLOCKS_SLEEP_EN0_CLK_SYS_I2C0_BITS |
76+ CLOCKS_SLEEP_EN0_CLK_SYS_ADC_BITS |
77+ CLOCKS_SLEEP_EN0_CLK_ADC_BITS
78+ );
79+ // This bank has the USB clocks in it, only turn off SPI
80+ const uint32_t RP_LIGHTSLEEP_EN1_MASK = CLOCKS_SLEEP_EN1_RESET & ~(
81+ CLOCKS_SLEEP_EN1_CLK_SYS_SPI1_BITS |
82+ CLOCKS_SLEEP_EN1_CLK_PERI_SPI1_BITS |
83+ CLOCKS_SLEEP_EN1_CLK_SYS_SPI0_BITS |
84+ CLOCKS_SLEEP_EN1_CLK_PERI_SPI0_BITS
85+ );
86+ #endif
6287
88+ #if PICO_RP2040
6389// Light sleeps used for TimeAlarm deep sleep turn off almost everything
6490const uint32_t RP_LIGHTSLEEP_EN0_MASK_HARSH = (
6591 CLOCKS_SLEEP_EN0_CLK_RTC_RTC_BITS |
@@ -68,6 +94,7 @@ const uint32_t RP_LIGHTSLEEP_EN0_MASK_HARSH = (
6894const uint32_t RP_LIGHTSLEEP_EN1_MASK_HARSH = 0x0 ;
6995
7096static void prepare_for_dormant_xosc (void );
97+ #endif
7198
7299// Singleton instance of SleepMemory.
73100const alarm_sleep_memory_obj_t alarm_sleep_memory_obj = {
@@ -80,13 +107,29 @@ const alarm_sleep_memory_obj_t alarm_sleep_memory_obj = {
80107// This object lives across VM instantiations, so none of these objects can contain references to the heap.
81108alarm_wake_alarm_union_t alarm_wake_alarm ;
82109
110+ #if PICO_RP2350
111+ // powman remembers what caused the last power up until the next one. Only report
112+ // it until the first alarm_reset() after boot.
113+ static bool powman_wakeup_reported ;
114+
115+ bool alarm_woke_from_powman (void ) {
116+ // powman is not reset by a watchdog reboot, so its registers would be stale.
117+ return (powman_hw -> chip_reset & POWMAN_CHIP_RESET_HAD_SWCORE_PD_BITS ) &&
118+ !watchdog_caused_reboot () &&
119+ (powman_hw -> last_swcore_pwrup & (RP_POWMAN_PWRUP_GPIO_BITS | RP_POWMAN_PWRUP_ALARM_BITS ));
120+ }
121+ #endif
122+
83123void alarm_reset (void ) {
84124 alarm_sleep_memory_reset ();
85125 alarm_pin_pinalarm_reset ();
86126 alarm_time_timealarm_reset ();
87127
88128 // Reset the scratch source
89129 watchdog_hw -> scratch [RP_WKUP_SCRATCH_REG ] = RP_SLEEP_WAKEUP_UNDEF ;
130+ #if PICO_RP2350
131+ powman_wakeup_reported = true;
132+ #endif
90133}
91134
92135static uint8_t _get_wakeup_cause (void ) {
@@ -102,6 +145,14 @@ static uint8_t _get_wakeup_cause(void) {
102145 if (watchdog_hw -> scratch [RP_WKUP_SCRATCH_REG ] != RP_SLEEP_WAKEUP_UNDEF ) {
103146 return watchdog_hw -> scratch [RP_WKUP_SCRATCH_REG ];
104147 }
148+ #if PICO_RP2350
149+ if (!powman_wakeup_reported && alarm_woke_from_powman ()) {
150+ if (powman_hw -> last_swcore_pwrup & RP_POWMAN_PWRUP_ALARM_BITS ) {
151+ return RP_SLEEP_WAKEUP_RTC ;
152+ }
153+ return RP_SLEEP_WAKEUP_GPIO ;
154+ }
155+ #endif
105156 return RP_SLEEP_WAKEUP_UNDEF ;
106157}
107158
@@ -172,7 +223,7 @@ mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj
172223 clocks_hw -> sleep_en1 = RP_LIGHTSLEEP_EN1_MASK ;
173224
174225 // Enable System Control Block (SCB) deep sleep
175- scb_hw -> scr |= M0PLUS_SCR_SLEEPDEEP_BITS ;
226+ scb_hw -> scr |= ARM_CPU_PREFIXED ( SCR_SLEEPDEEP_BITS ) ;
176227
177228 __wfi ();
178229 }
@@ -194,7 +245,41 @@ void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *ala
194245 _setup_sleep_alarms (true, n_alarms , alarms );
195246}
196247
248+ #if PICO_RP2350
249+ // Power down with powman. Waking up reboots into main(), so this does not return.
250+ static void MP_NORETURN rp2350_enter_deep_sleep (void ) {
251+ #if CIRCUITPY_CYW43
252+ cyw43_enter_deep_sleep ();
253+ #endif
254+
255+ // pico_low_power arms one wakeup per call and leaves the others alone, so
256+ // arm every pin alarm first.
257+ alarm_pin_pinalarm_enable_powman_wakeups ();
258+
259+ // A NULL power state keeps only the SRAM that holds .persistent_data powered.
260+ // That is where alarm.sleep_memory lives.
261+ uint pin_number ;
262+ bool edge ;
263+ bool value ;
264+ if (!alarm_time_timealarm_is_set () &&
265+ alarm_pin_pinalarm_first_powman_wakeup (& pin_number , & edge , & value )) {
266+ low_power_pstate_until_gpio_pin_state (pin_number , edge , value , NULL , NULL );
267+ } else {
268+ // With no alarm at all, sleep until a time that never comes.
269+ uint64_t wakeup_ms = alarm_time_timealarm_is_set () ? alarm_time_timealarm_get_wakeup_ms () : INT64_MAX / 1000 ;
270+ low_power_pstate_until_aon_timer (from_us_since_boot (wakeup_ms * 1000 ), NULL , NULL );
271+ }
272+
273+ // Could not power down, most likely because an alarm already fired.
274+ watchdog_hw -> scratch [RP_WKUP_SCRATCH_REG ] = _get_wakeup_cause ();
275+ reset_cpu ();
276+ }
277+ #endif
278+
197279void MP_NORETURN common_hal_alarm_enter_deep_sleep (void ) {
280+ #if PICO_RP2350
281+ rp2350_enter_deep_sleep ();
282+ #else
198283 bool timealarm_set = alarm_time_timealarm_is_set ();
199284
200285 #if CIRCUITPY_CYW43
@@ -223,12 +308,14 @@ void MP_NORETURN common_hal_alarm_enter_deep_sleep(void) {
223308 // Just before reset, enable the pinalarm interrupt.
224309 alarm_pin_pinalarm_entering_deep_sleep ();
225310 reset_cpu ();
311+ #endif
226312}
227313
228314void common_hal_alarm_gc_collect (void ) {
229315 gc_collect_ptr (shared_alarm_get_wake_alarm ());
230316}
231317
318+ #if PICO_RP2040
232319static void prepare_for_dormant_xosc (void ) {
233320 // TODO: add ROSC support with sleep_run_from_dormant_source when it's added to SDK
234321 uint src_hz = XOSC_MHZ * MHZ ;
@@ -259,3 +346,4 @@ static void prepare_for_dormant_xosc(void) {
259346 pll_deinit (pll_sys );
260347 pll_deinit (pll_usb );
261348}
349+ #endif
0 commit comments