|
38 | 38 | #include "modmachine.h"
|
39 | 39 | #include "uart.h"
|
40 | 40 | #include "hardware/clocks.h"
|
| 41 | +#include "hardware/pll.h" |
| 42 | +#include "hardware/structs/rosc.h" |
| 43 | +#include "hardware/structs/scb.h" |
| 44 | +#include "hardware/structs/syscfg.h" |
41 | 45 | #include "hardware/watchdog.h"
|
| 46 | +#include "hardware/xosc.h" |
42 | 47 | #include "pico/bootrom.h"
|
43 | 48 | #include "pico/stdlib.h"
|
44 | 49 | #include "pico/unique_id.h"
|
@@ -83,6 +88,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_cause_obj, machine_reset_cause);
|
83 | 88 |
|
84 | 89 | NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args) {
|
85 | 90 | MICROPY_BOARD_ENTER_BOOTLOADER(n_args, args);
|
| 91 | + rosc_hw->ctrl = ROSC_CTRL_ENABLE_VALUE_ENABLE << ROSC_CTRL_ENABLE_LSB; |
86 | 92 | reset_usb_boot(0, 0);
|
87 | 93 | for (;;) {
|
88 | 94 | }
|
@@ -113,13 +119,76 @@ STATIC mp_obj_t machine_idle(void) {
|
113 | 119 | STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_idle_obj, machine_idle);
|
114 | 120 |
|
115 | 121 | STATIC mp_obj_t machine_lightsleep(size_t n_args, const mp_obj_t *args) {
|
116 |
| - if (n_args == 0) { |
117 |
| - for (;;) { |
118 |
| - MICROPY_EVENT_POLL_HOOK |
| 122 | + mp_int_t delay_ms = 0; |
| 123 | + bool use_timer_alarm = false; |
| 124 | + |
| 125 | + if (n_args == 1) { |
| 126 | + delay_ms = mp_obj_get_int(args[0]); |
| 127 | + if (delay_ms <= 1) { |
| 128 | + // Sleep is too small, just return. |
| 129 | + return mp_const_none; |
| 130 | + } |
| 131 | + use_timer_alarm = delay_ms < (1ULL << 32) / 1000; |
| 132 | + if (use_timer_alarm) { |
| 133 | + // Use timer alarm to wake. |
| 134 | + } else { |
| 135 | + // TODO: Use RTC alarm to wake. |
| 136 | + mp_raise_ValueError(MP_ERROR_TEXT("sleep too long")); |
119 | 137 | }
|
| 138 | + } |
| 139 | + |
| 140 | + const uint32_t xosc_hz = XOSC_MHZ * 1000000; |
| 141 | + |
| 142 | + // Disable USB and ADC clocks. |
| 143 | + clock_stop(clk_usb); |
| 144 | + clock_stop(clk_adc); |
| 145 | + |
| 146 | + // CLK_REF = XOSC |
| 147 | + clock_configure(clk_ref, CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC, 0, xosc_hz, xosc_hz); |
| 148 | + |
| 149 | + // CLK_SYS = CLK_REF |
| 150 | + clock_configure(clk_sys, CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLK_REF, 0, xosc_hz, xosc_hz); |
| 151 | + |
| 152 | + // CLK_RTC = XOSC / 256 |
| 153 | + clock_configure(clk_rtc, 0, CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_XOSC_CLKSRC, xosc_hz, xosc_hz / 256); |
| 154 | + |
| 155 | + // CLK_PERI = CLK_SYS |
| 156 | + clock_configure(clk_peri, 0, CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS, xosc_hz, xosc_hz); |
| 157 | + |
| 158 | + // Disable PLLs. |
| 159 | + pll_deinit(pll_sys); |
| 160 | + pll_deinit(pll_usb); |
| 161 | + |
| 162 | + // Disable ROSC. |
| 163 | + rosc_hw->ctrl = ROSC_CTRL_ENABLE_VALUE_DISABLE << ROSC_CTRL_ENABLE_LSB; |
| 164 | + |
| 165 | + if (n_args == 0) { |
| 166 | + xosc_dormant(); |
120 | 167 | } else {
|
121 |
| - mp_hal_delay_ms(mp_obj_get_int(args[0])); |
| 168 | + uint32_t sleep_en0 = clocks_hw->sleep_en0; |
| 169 | + uint32_t sleep_en1 = clocks_hw->sleep_en1; |
| 170 | + clocks_hw->sleep_en0 = CLOCKS_SLEEP_EN0_CLK_RTC_RTC_BITS; |
| 171 | + if (use_timer_alarm) { |
| 172 | + // Use timer alarm to wake. |
| 173 | + clocks_hw->sleep_en1 = CLOCKS_SLEEP_EN1_CLK_SYS_TIMER_BITS; |
| 174 | + timer_hw->alarm[3] = timer_hw->timerawl + delay_ms * 1000; |
| 175 | + } else { |
| 176 | + // TODO: Use RTC alarm to wake. |
| 177 | + clocks_hw->sleep_en1 = 0; |
| 178 | + } |
| 179 | + scb_hw->scr |= M0PLUS_SCR_SLEEPDEEP_BITS; |
| 180 | + __wfi(); |
| 181 | + scb_hw->scr &= ~M0PLUS_SCR_SLEEPDEEP_BITS; |
| 182 | + clocks_hw->sleep_en0 = sleep_en0; |
| 183 | + clocks_hw->sleep_en1 = sleep_en1; |
122 | 184 | }
|
| 185 | + |
| 186 | + // Enable ROSC. |
| 187 | + rosc_hw->ctrl = ROSC_CTRL_ENABLE_VALUE_ENABLE << ROSC_CTRL_ENABLE_LSB; |
| 188 | + |
| 189 | + // Bring back all clocks. |
| 190 | + clocks_init(); |
| 191 | + |
123 | 192 | return mp_const_none;
|
124 | 193 | }
|
125 | 194 | MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_lightsleep_obj, 0, 1, machine_lightsleep);
|
|
0 commit comments