39
39
#include "supervisor/port.h"
40
40
#include "supervisor/workflow.h"
41
41
42
+ STATIC uint32_t TAMPID = 0 ;
43
+
42
44
// Singleton instance of SleepMemory.
43
45
const alarm_sleep_memory_obj_t alarm_sleep_memory_obj = {
44
46
.base = {
45
47
.type = & alarm_sleep_memory_type ,
46
48
},
47
49
};
48
- // TODO: make a custom enum to avoid weird values like PM_SLEEPCFG_SLEEPMODE_BACKUP_Val?
49
- STATIC volatile uint32_t _target ;
50
- STATIC bool fake_sleep ;
51
- STATIC bool pin_wake ;
52
50
53
51
void alarm_reset (void ) {
54
52
// Reset the alarm flag
55
- SAMD_ALARM_FLAG = 0x00 ;
56
53
alarm_pin_pinalarm_reset ();
57
54
alarm_time_timealarm_reset ();
58
55
}
59
56
60
- samd_sleep_source_t alarm_get_wakeup_cause (void ) {
61
- // If in light/fake sleep, check modules
62
- if (alarm_pin_pinalarm_woke_this_cycle ()) {
63
- return SAMD_WAKEUP_GPIO ;
64
- }
65
- if (alarm_time_timealarm_woke_this_cycle ()) {
66
- return SAMD_WAKEUP_RTC ;
67
- }
68
- if (!fake_sleep && RSTC -> RCAUSE .bit .BACKUP ) {
69
- // This is checked during rtc_init to cache TAMPID if necessary
70
- if (pin_wake || RTC -> MODE0 .TAMPID .reg ) {
71
- pin_wake = true;
72
- return SAMD_WAKEUP_GPIO ;
73
- }
74
- return SAMD_WAKEUP_RTC ;
75
- }
76
- return SAMD_WAKEUP_UNDEF ;
57
+ void alarm_get_wakeup_cause (void ) {
58
+ // Called from rtc_init, just before SWRST of RTC. It is called
59
+ // at an early stage of main(), to save TAMPID from SWRST. Later,
60
+ // common_hal_alarm_create_wake_alarm is called to make a wakeup
61
+ // alarm from the deep sleep.
62
+
63
+ TAMPID = RTC -> MODE0 .TAMPID .reg ;
77
64
}
78
65
79
66
bool common_hal_alarm_woken_from_sleep (void ) {
80
- return alarm_get_wakeup_cause () != SAMD_WAKEUP_UNDEF ;
67
+ return alarm_pin_pinalarm_woke_this_cycle () || alarm_time_timealarm_woke_this_cycle () ;
81
68
}
82
69
83
70
mp_obj_t common_hal_alarm_create_wake_alarm (void ) {
84
- // If woken from deep sleep, create a copy alarm similar to what would have
85
- // been passed in originally. Otherwise, just return none
86
- samd_sleep_source_t cause = alarm_get_wakeup_cause ();
87
- switch (cause ) {
88
- case SAMD_WAKEUP_RTC : {
89
- return alarm_time_timealarm_create_wakeup_alarm ();
90
- }
91
- case SAMD_WAKEUP_GPIO : {
92
- return alarm_pin_pinalarm_create_wakeup_alarm ();
93
- }
94
- case SAMD_WAKEUP_UNDEF :
95
- default :
96
- // Not a deep sleep reset.
97
- break ;
71
+ // Called from main.c on the first start up, just before alarm_reset.
72
+ // Return a copy of wakeup alarm from deep sleep / fake deep sleep.
73
+ // In case of fake sleep, status should be left in TimeAlarm/PinAlarm.
74
+ bool true_deep = RSTC -> RCAUSE .bit .BACKUP ;
75
+
76
+ if (alarm_pin_pinalarm_woke_this_cycle ()) {
77
+ TAMPID = RTC -> MODE0 .TAMPID .reg ;
78
+ RTC -> MODE0 .TAMPID .reg = TAMPID ; // clear register
79
+ return alarm_pin_pinalarm_create_wakeup_alarm (TAMPID );
80
+ }
81
+ if (alarm_time_timealarm_woke_this_cycle () || (true_deep && TAMPID == 0 )) {
82
+ return alarm_time_timealarm_create_wakeup_alarm ();
83
+ }
84
+ if (true_deep ) {
85
+ return alarm_pin_pinalarm_create_wakeup_alarm (TAMPID );
98
86
}
99
87
return mp_const_none ;
100
88
}
@@ -103,64 +91,54 @@ mp_obj_t common_hal_alarm_create_wake_alarm(void) {
103
91
STATIC void _setup_sleep_alarms (bool deep_sleep , size_t n_alarms , const mp_obj_t * alarms ) {
104
92
alarm_pin_pinalarm_set_alarms (deep_sleep , n_alarms , alarms );
105
93
alarm_time_timealarm_set_alarms (deep_sleep , n_alarms , alarms );
106
- fake_sleep = false;
107
94
}
108
95
109
96
mp_obj_t common_hal_alarm_light_sleep_until_alarms (size_t n_alarms , const mp_obj_t * alarms ) {
110
97
_setup_sleep_alarms (false, n_alarms , alarms );
111
98
mp_obj_t wake_alarm = mp_const_none ;
112
99
100
+ // This works but achieves same power consumption as time.sleep()
101
+ PM -> SLEEPCFG .reg = PM_SLEEPCFG_SLEEPMODE_STANDBY ;
102
+ while (PM -> SLEEPCFG .bit .SLEEPMODE != PM_SLEEPCFG_SLEEPMODE_STANDBY_Val ) {
103
+ }
104
+ // STDBYCFG is left to be 0 to retain SYSRAM. Note that, even if
105
+ // RAMCFG_OFF is set here, SYSRAM seems to be retained, probably
106
+ // because RTC and/or USB keeps sleepwalking.
107
+
113
108
while (!mp_hal_is_interrupted ()) {
114
109
RUN_BACKGROUND_TASKS ;
115
110
// Detect if interrupt was alarm or ctrl-C interrupt.
116
- if (common_hal_alarm_woken_from_sleep ()) {
117
- samd_sleep_source_t cause = alarm_get_wakeup_cause ();
118
- switch (cause ) {
119
- case SAMD_WAKEUP_RTC : {
120
- wake_alarm = alarm_time_timealarm_find_triggered_alarm (n_alarms ,alarms );
121
- break ;
122
- }
123
- case SAMD_WAKEUP_GPIO : {
124
- wake_alarm = alarm_pin_pinalarm_find_triggered_alarm (n_alarms ,alarms );
125
- break ;
126
- }
127
- default :
128
- // Should not reach this, if all light sleep types are covered correctly
129
- break ;
130
- }
131
- shared_alarm_save_wake_alarm (wake_alarm );
111
+ if (alarm_time_timealarm_woke_this_cycle ()) {
112
+ wake_alarm = alarm_time_timealarm_find_triggered_alarm (n_alarms ,alarms );
113
+ break ;
114
+ }
115
+ if (alarm_pin_pinalarm_woke_this_cycle ()) {
116
+ wake_alarm = alarm_pin_pinalarm_find_triggered_alarm (n_alarms ,alarms );
132
117
break ;
133
118
}
134
- // ATTEMPT ------------------------------
135
- // This works but achieves same power consumption as time.sleep()
136
119
137
120
// Clear the FPU interrupt because it can prevent us from sleeping.
138
121
if (__get_FPSCR () & ~(0x9f )) {
139
122
__set_FPSCR (__get_FPSCR () & ~(0x9f ));
140
123
(void )__get_FPSCR ();
141
124
}
142
125
143
- // Disable RTC interrupts
144
- NVIC_DisableIRQ (RTC_IRQn );
145
- // Set standby power domain stuff
146
- PM -> STDBYCFG .reg = PM_STDBYCFG_RAMCFG_OFF ;
147
- // Set-up Sleep Mode
148
- PM -> SLEEPCFG .reg = PM_SLEEPCFG_SLEEPMODE_STANDBY ;
149
- while (PM -> SLEEPCFG .bit .SLEEPMODE != PM_SLEEPCFG_SLEEPMODE_STANDBY_Val ) {
150
- ;
151
- }
152
-
126
+ common_hal_mcu_disable_interrupts ();
153
127
__DSB (); // Data Synchronization Barrier
154
128
__WFI (); // Wait For Interrupt
155
- // Enable RTC interrupts
156
- NVIC_EnableIRQ (RTC_IRQn );
157
- // END ATTEMPT ------------------------------
129
+ common_hal_mcu_enable_interrupts ();
158
130
}
131
+ // Restore SLEEPCFG or port_idle_until_interrupt sleeps in STANDBY mode.
132
+ PM -> SLEEPCFG .reg = PM_SLEEPCFG_SLEEPMODE_IDLE2 ;
133
+ while (PM -> SLEEPCFG .bit .SLEEPMODE != PM_SLEEPCFG_SLEEPMODE_IDLE2_Val ) {
134
+ }
135
+ alarm_pin_pinalarm_deinit_alarms (n_alarms , alarms ); // after care for alarm_pin_pinalarm_set_alarms
136
+ alarm_reset ();
137
+
159
138
if (mp_hal_is_interrupted ()) {
160
139
return mp_const_none ; // Shouldn't be given to python code because exception handling should kick in.
161
140
}
162
141
163
- alarm_reset ();
164
142
return wake_alarm ;
165
143
}
166
144
@@ -171,69 +149,49 @@ void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *ala
171
149
void NORETURN common_hal_alarm_enter_deep_sleep (void ) {
172
150
alarm_pin_pinalarm_prepare_for_deep_sleep ();
173
151
alarm_time_timealarm_prepare_for_deep_sleep ();
174
- _target = RTC -> MODE0 .COMP [1 ].reg ;
175
- port_disable_tick (); // TODO: Required for SAMD?
152
+ // port_disable_tick(); // TODO: Required for SAMD?
176
153
177
- // cache alarm flag since backup registers about to be reset
178
- uint32_t _SAMD_ALARM_FLAG = SAMD_ALARM_FLAG ;
154
+ // cache alarm flag and etc since RTC about to be reset
155
+ uint32_t _flag = SAMD_ALARM_FLAG ; // RTC->MODE0.BKUP[0].reg
156
+ uint32_t _target = RTC -> MODE0 .COMP [1 ].reg ;
157
+ uint32_t _tampctrl = RTC -> MODE0 .TAMPCTRL .reg ;
179
158
180
159
// Clear the FPU interrupt because it can prevent us from sleeping.
181
160
if (__get_FPSCR () & ~(0x9f )) {
182
161
__set_FPSCR (__get_FPSCR () & ~(0x9f ));
183
162
(void )__get_FPSCR ();
184
163
}
185
164
186
- NVIC_DisableIRQ ( RTC_IRQn );
165
+ common_hal_mcu_disable_interrupts ( );
187
166
// Must disable the RTC before writing to EVCTRL and TMPCTRL
188
- RTC -> MODE0 .CTRLA .bit .ENABLE = 0 ; // Disable the RTC
189
- while (RTC -> MODE0 .SYNCBUSY .bit .ENABLE ) { // Wait for synchronization
190
- ;
191
- }
192
167
RTC -> MODE0 .CTRLA .bit .SWRST = 1 ; // Software reset the RTC
193
168
while (RTC -> MODE0 .SYNCBUSY .bit .SWRST ) { // Wait for synchronization
194
- ;
195
169
}
196
170
RTC -> MODE0 .CTRLA .reg = RTC_MODE0_CTRLA_PRESCALER_DIV1024 | // Set prescaler to 1024
197
171
RTC_MODE0_CTRLA_MODE_COUNT32 ; // Set RTC to mode 0, 32-bit timer
198
172
173
+ SAMD_ALARM_FLAG = _flag ;
199
174
// Check if we're setting TimeAlarm
200
- if (_SAMD_ALARM_FLAG & SAMD_ALARM_FLAG_TIME ) {
201
- RTC -> MODE0 .COMP [1 ].reg = ( _target / 1024 ) * 32 ;
175
+ if (SAMD_ALARM_FLAG_TIME_CHK ) {
176
+ RTC -> MODE0 .COMP [1 ].reg = _target ;
202
177
while (RTC -> MODE0 .SYNCBUSY .reg ) {
203
- ;
204
178
}
205
- }
206
- // Check if we're setting PinAlarm
207
- if (_SAMD_ALARM_FLAG & SAMD_ALARM_FLAG_PIN ) {
208
- RTC -> MODE0 .TAMPCTRL .bit .DEBNC2 = 1 ; // Edge triggered when INn is stable for 4 CLK_RTC_DEB periods
209
- RTC -> MODE0 .TAMPCTRL .bit .TAMLVL2 = 1 ; // rising edge
210
- // PA02 = IN2
211
- RTC -> MODE0 .TAMPCTRL .bit .IN2ACT = 1 ; // WAKE on IN2 (doesn't save timestamp)
212
- }
213
- // Enable interrupts
214
- NVIC_SetPriority (RTC_IRQn , 0 );
215
- NVIC_EnableIRQ (RTC_IRQn );
216
- if (_SAMD_ALARM_FLAG & SAMD_ALARM_FLAG_TIME ) {
217
- // Set interrupts for COMPARE1
218
179
RTC -> MODE0 .INTENSET .reg = RTC_MODE0_INTENSET_CMP1 ;
219
180
}
220
- if (_SAMD_ALARM_FLAG & SAMD_ALARM_FLAG_PIN ) {
221
- // Set interrupts for TAMPER pins
181
+ // Check if we're setting PinAlarm
182
+ if (SAMD_ALARM_FLAG_PIN_CHK ) {
183
+ RTC -> MODE0 .TAMPCTRL .reg = _tampctrl ;
222
184
RTC -> MODE0 .INTENSET .reg = RTC_MODE0_INTENSET_TAMPER ;
223
185
}
186
+ // Enable interrupts
187
+ common_hal_mcu_enable_interrupts ();
224
188
225
- // Set-up Deep Sleep Mode & RAM retention
226
- PM -> BKUPCFG .reg = PM_BKUPCFG_BRAMCFG (0x2 ); // No RAM retention 0x2 partial:0x1
227
- while (PM -> BKUPCFG .bit .BRAMCFG != 0x2 ) { // Wait for synchronization
228
- ;
229
- }
189
+ // Set-up Deep Sleep Mode with backup RAM retention
230
190
PM -> SLEEPCFG .reg = PM_SLEEPCFG_SLEEPMODE_BACKUP ;
231
191
while (PM -> SLEEPCFG .bit .SLEEPMODE != PM_SLEEPCFG_SLEEPMODE_BACKUP_Val ) {
232
- ;
233
192
}
234
193
RTC -> MODE0 .CTRLA .bit .ENABLE = 1 ; // Enable the RTC
235
194
while (RTC -> MODE0 .SYNCBUSY .bit .ENABLE ) { // Wait for synchronization
236
- ;
237
195
}
238
196
239
197
__DSB (); // Data Synchronization Barrier
@@ -245,16 +203,9 @@ void NORETURN common_hal_alarm_enter_deep_sleep(void) {
245
203
}
246
204
}
247
205
248
- void common_hal_alarm_pretending_deep_sleep (void ) {
249
- // TODO:
250
- // If tamper detect interrupts cannot be used to wake from the Idle tier of sleep,
251
- // This section will need to re-initialize the pins to allow the PORT peripheral
252
- // to generate external interrupts again. See STM32 for reference.
253
-
254
- if (!fake_sleep ) {
255
- fake_sleep = true;
256
- }
257
- }
206
+ // Default common_hal_alarm_pretending_deep_sleep is defined in
207
+ // shared-bindings, which is used here. Note that "pretending" does
208
+ // not work on REPL; it only works for main.py (or code.py, ...).
258
209
259
210
void common_hal_alarm_gc_collect (void ) {
260
211
gc_collect_ptr (shared_alarm_get_wake_alarm ());
0 commit comments