Skip to content

Commit dcb5fd2

Browse files
committed
alarm.wake_alarm works for pin and time. Pin & time can both be set at once
1 parent 752bf6e commit dcb5fd2

File tree

6 files changed

+69
-77
lines changed

6 files changed

+69
-77
lines changed

ports/atmel-samd/common-hal/alarm/__init__.c

Lines changed: 38 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ const alarm_sleep_memory_obj_t alarm_sleep_memory_obj = {
5050
// TODO: make a custom enum to avoid weird values like PM_SLEEPCFG_SLEEPMODE_BACKUP_Val?
5151
STATIC volatile uint32_t _target;
5252
STATIC bool fake_sleep;
53+
STATIC bool pin_wake;
5354

5455
void alarm_reset(void) {
5556
// Reset the alarm flag
@@ -67,9 +68,9 @@ samd_sleep_source_t alarm_get_wakeup_cause(void) {
6768
return SAMD_WAKEUP_RTC;
6869
}
6970
if (!fake_sleep && RSTC->RCAUSE.bit.BACKUP) {
70-
// not able to detect PinAlarm wake since registers are getting reset
71-
// TODO: come up with a way to detect a TAMPER
72-
if (RTC->MODE0.TAMPID.reg || RTC->MODE0.INTFLAG.bit.TAMPER) {
71+
// This is checked during rtc_init to cache TAMPID if necessary
72+
if (pin_wake ||RTC->MODE0.TAMPID.reg) {
73+
pin_wake = true;
7374
return SAMD_WAKEUP_GPIO;
7475
}
7576
return SAMD_WAKEUP_RTC;
@@ -132,12 +133,6 @@ mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj
132133
shared_alarm_save_wake_alarm(wake_alarm);
133134
break;
134135
}
135-
// TODO: the SAMD implementation of this (purportedly) disables interrupts
136-
// Presumably this doesn't impact the RTC interrupts, somehow, or it would never wake up?
137-
// Will it prevent an external interrupt from waking?
138-
// port_idle_until_interrupt();
139-
// Alternative would be `sleep(PM_SLEEPCFG_SLEEPMODE_IDLE2_Val)`, I think?
140-
141136
// ATTEMPT ------------------------------
142137
// This works but achieves same power consumption as time.sleep()
143138

@@ -161,8 +156,6 @@ mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj
161156
__WFI(); // Wait For Interrupt
162157
// Enable RTC interrupts
163158
NVIC_EnableIRQ(RTC_IRQn);
164-
165-
166159
// END ATTEMPT ------------------------------
167160
}
168161
if (mp_hal_is_interrupted()) {
@@ -183,75 +176,55 @@ void NORETURN common_hal_alarm_enter_deep_sleep(void) {
183176
_target = RTC->MODE0.COMP[1].reg;
184177
port_disable_tick(); // TODO: Required for SAMD?
185178

186-
// Set a flag in the backup registers to indicate sleep wakeup
187-
SAMD_ALARM_FLAG = 0x01;
179+
// cache alarm flag since backup registers about to be reset
180+
uint32_t _SAMD_ALARM_FLAG = SAMD_ALARM_FLAG;
188181

189182
// Clear the FPU interrupt because it can prevent us from sleeping.
190183
if (__get_FPSCR() & ~(0x9f)) {
191184
__set_FPSCR(__get_FPSCR() & ~(0x9f));
192185
(void)__get_FPSCR();
193186
}
194187

195-
// TODO: Be able to set PinAlarm and TimeAlarm together
196-
// PinAlarm (hacky way of checking if time alarm or pin alarm)
197-
if (RTC->MODE0.INTENSET.bit.TAMPER) {
198-
// Disable interrupts
199-
NVIC_DisableIRQ(RTC_IRQn);
200-
// Must disable the RTC before writing to EVCTRL and TMPCTRL
201-
RTC->MODE0.CTRLA.bit.ENABLE = 0; // Disable the RTC
202-
while (RTC->MODE0.SYNCBUSY.bit.ENABLE) { // Wait for synchronization
203-
;
204-
}
205-
RTC->MODE0.CTRLA.bit.SWRST = 1; // Software reset the RTC
206-
while (RTC->MODE0.SYNCBUSY.bit.SWRST) { // Wait for synchronization
188+
NVIC_DisableIRQ(RTC_IRQn);
189+
// Must disable the RTC before writing to EVCTRL and TMPCTRL
190+
RTC->MODE0.CTRLA.bit.ENABLE = 0; // Disable the RTC
191+
while (RTC->MODE0.SYNCBUSY.bit.ENABLE) { // Wait for synchronization
192+
;
193+
}
194+
RTC->MODE0.CTRLA.bit.SWRST = 1; // Software reset the RTC
195+
while (RTC->MODE0.SYNCBUSY.bit.SWRST) { // Wait for synchronization
196+
;
197+
}
198+
RTC->MODE0.CTRLA.reg = RTC_MODE0_CTRLA_PRESCALER_DIV1024 | // Set prescaler to 1024
199+
RTC_MODE0_CTRLA_MODE_COUNT32; // Set RTC to mode 0, 32-bit timer
200+
201+
// Check if we're setting TimeAlarm
202+
if (_SAMD_ALARM_FLAG & SAMD_ALARM_FLAG_TIME) {
203+
RTC->MODE0.COMP[1].reg = (_target / 1024) * 32;
204+
while (RTC->MODE0.SYNCBUSY.reg) {
207205
;
208206
}
209-
RTC->MODE0.CTRLA.reg = RTC_MODE0_CTRLA_PRESCALER_DIV1024 | // Set prescaler to 1024
210-
RTC_MODE0_CTRLA_MODE_COUNT32; // Set RTC to mode 0, 32-bit timer
211-
212-
// TODO: map requested pin to limited selection of TAMPER pins
207+
}
208+
// Check if we're setting PinAlarm
209+
if (_SAMD_ALARM_FLAG & SAMD_ALARM_FLAG_PIN) {
213210
RTC->MODE0.TAMPCTRL.bit.DEBNC2 = 1; // Edge triggered when INn is stable for 4 CLK_RTC_DEB periods
214211
RTC->MODE0.TAMPCTRL.bit.TAMLVL2 = 1; // rising edge
215212
// PA02 = IN2
216213
RTC->MODE0.TAMPCTRL.bit.IN2ACT = 1; // WAKE on IN2 (doesn't save timestamp)
217-
218-
// Enable interrupts
219-
NVIC_SetPriority(RTC_IRQn, 0);
220-
NVIC_EnableIRQ(RTC_IRQn);
221-
// Set interrupts for TAMPER or overflow
214+
}
215+
// Enable interrupts
216+
NVIC_SetPriority(RTC_IRQn, 0);
217+
NVIC_EnableIRQ(RTC_IRQn);
218+
if (_SAMD_ALARM_FLAG & SAMD_ALARM_FLAG_TIME) {
219+
// Set interrupts for COMPARE1
220+
RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_CMP1;
221+
}
222+
if (_SAMD_ALARM_FLAG & SAMD_ALARM_FLAG_PIN) {
223+
// Set interrupts for TAMPER pins
222224
RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_TAMPER;
223-
} else {
224-
// TimeAlarm
225-
// Retrieve COMP1 value before resetting RTC
226-
NVIC_DisableIRQ(RTC_IRQn);
227-
228-
// Must disable the RTC before writing to EVCTRL and TMPCTRL
229-
RTC->MODE0.CTRLA.bit.ENABLE = 0; // Disable the RTC
230-
while (RTC->MODE0.SYNCBUSY.bit.ENABLE) { // Wait for synchronization
231-
;
232-
}
233-
234-
RTC->MODE0.CTRLA.bit.SWRST = 1; // Software reset the RTC
235-
while (RTC->MODE0.SYNCBUSY.bit.SWRST) { // Wait for synchronization
236-
;
237-
}
238-
239-
RTC->MODE0.CTRLA.reg = RTC_MODE0_CTRLA_PRESCALER_DIV1024 | // Set prescaler to 1024
240-
RTC_MODE0_CTRLA_MODE_COUNT32; // Set RTC to mode 0, 32-bit timer
241-
242-
RTC->MODE0.COMP[1].reg = (_target / 1024) * 32;
243-
while (RTC->MODE0.SYNCBUSY.reg) {
244-
;
245-
}
246-
247-
// Enable interrupts
248-
NVIC_SetPriority(RTC_IRQn, 0);
249-
NVIC_EnableIRQ(RTC_IRQn);
250-
// Set interrupts for COMPARE1 or overflow
251-
RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_CMP1 | RTC_MODE1_INTENSET_OVF;
252225
}
253-
// Set-up Deep Sleep Mode
254-
// RAM retention
226+
227+
// Set-up Deep Sleep Mode & RAM retention
255228
PM->BKUPCFG.reg = PM_BKUPCFG_BRAMCFG(0x2); // No RAM retention 0x2 partial:0x1
256229
while (PM->BKUPCFG.bit.BRAMCFG != 0x2) { // Wait for synchronization
257230
;
@@ -260,7 +233,6 @@ void NORETURN common_hal_alarm_enter_deep_sleep(void) {
260233
while (PM->SLEEPCFG.bit.SLEEPMODE != PM_SLEEPCFG_SLEEPMODE_BACKUP_Val) {
261234
;
262235
}
263-
264236
RTC->MODE0.CTRLA.bit.ENABLE = 1; // Enable the RTC
265237
while (RTC->MODE0.SYNCBUSY.bit.ENABLE) { // Wait for synchronization
266238
;
@@ -282,10 +254,6 @@ void common_hal_alarm_pretending_deep_sleep(void) {
282254
// to generate external interrupts again. See STM32 for reference.
283255

284256
if (!fake_sleep) {
285-
SAMD_ALARM_FLAG = 1;
286-
while (RTC->MODE0.SYNCBUSY.reg) {
287-
;
288-
}
289257
fake_sleep = true;
290258
}
291259
}

ports/atmel-samd/common-hal/alarm/__init__.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,12 @@
3232
extern const alarm_sleep_memory_obj_t alarm_sleep_memory_obj;
3333

3434
// This is the first byte of the BKUP register bank.
35-
// It stores whether the last wakeup was because of an alarm.
35+
// We use it to store which alarms are set.
36+
#ifndef SAMD_ALARM_FLAG
3637
#define SAMD_ALARM_FLAG (RTC->MODE0.BKUP[0].reg)
38+
#define SAMD_ALARM_FLAG_TIME (_U_(0x1) << 0)
39+
#define SAMD_ALARM_FLAG_PIN (_U_(0x1) << 1)
40+
#endif
3741

3842
typedef enum {
3943
SAMD_WAKEUP_UNDEF,

ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
#include "hal/include/hal_gpio.h"
3232
// #include <stdio.h>
3333

34-
3534
#include "shared-bindings/alarm/pin/PinAlarm.h"
3635
#include "shared-bindings/microcontroller/__init__.h"
3736
#include "shared-bindings/microcontroller/Pin.h"
@@ -165,6 +164,7 @@ void alarm_pin_pinalarm_reset(void) {
165164
// use, reset them.
166165
pinalarm_on = false;
167166
woke_up = false;
167+
SAMD_ALARM_FLAG &= ~SAMD_ALARM_FLAG_PIN; // clear flag
168168
// Disable TAMPER interrupt
169169
RTC->MODE0.INTENCLR.bit.TAMPER = 1;
170170
// Disable TAMPER control
@@ -195,6 +195,8 @@ void alarm_pin_pinalarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_ob
195195
mp_raise_ValueError(translate("Pin cannot wake from Deep Sleep"));
196196
}
197197
pinalarm_on = true;
198+
SAMD_ALARM_FLAG |= SAMD_ALARM_FLAG_PIN;
199+
198200
// Set tamper interrupt so deep sleep knows that's the intent
199201
RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_TAMPER;
200202
common_hal_mcu_disable_interrupts();
@@ -206,7 +208,7 @@ void alarm_pin_pinalarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_ob
206208
// PA02 is n=2: IN2, LVL2, etc...
207209
RTC->MODE0.TAMPCTRL.bit.DEBNC2 = 1; // Edge triggered when INn is stable for 4 CLK_RTC_DEB periods
208210
RTC->MODE0.TAMPCTRL.bit.TAMLVL2 = alarm->value; // rising or falling edge
209-
RTC->MODE0.TAMPCTRL.bit.IN2ACT = 0x1; // WAKE on IN2 (doesn't save timestamp)
211+
RTC->MODE0.TAMPCTRL.bit.IN2ACT = 1; // WAKE on IN2 (doesn't save timestamp)
210212
common_hal_mcu_enable_interrupts();
211213
RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_TAMPER;
212214
RTC->MODE0.CTRLA.bit.ENABLE = 1; // Enable the RTC

ports/atmel-samd/common-hal/alarm/pin/PinAlarm.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@
2727
#ifndef MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ALARM_PINALARM_H
2828
#define MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ALARM_PINALARM_H
2929

30+
// This is the first byte of the BKUP register bank.
31+
// We use it to store which alarms are set.
32+
#ifndef SAMD_ALARM_FLAG
33+
#define SAMD_ALARM_FLAG (RTC->MODE0.BKUP[0].reg)
34+
#define SAMD_ALARM_FLAG_TIME (_U_(0x1) << 0)
35+
#define SAMD_ALARM_FLAG_PIN (_U_(0x1) << 1)
36+
#endif
37+
3038
#include "py/obj.h"
3139
#include "py/objtuple.h"
3240

ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,9 @@ mp_obj_t alarm_time_timealarm_create_wakeup_alarm(void) {
7272
return timer;
7373
}
7474

75-
void timer_callback(void) {
75+
void time_alarm_callback(void) {
7676
if (timealarm_on) {
77-
RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_CMP1 | RTC_MODE0_INTENCLR_CMP0 | RTC_MODE0_INTENCLR_OVF; // clear flags
77+
RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_CMP1; // clear flags
7878
woke_up = true;
7979
timealarm_on = false;
8080
}
@@ -90,6 +90,7 @@ bool alarm_time_timealarm_woke_this_cycle(void) {
9090
void alarm_time_timealarm_reset(void) {
9191
timealarm_on = false;
9292
woke_up = false;
93+
SAMD_ALARM_FLAG &= ~SAMD_ALARM_FLAG_TIME; // clear flag
9394
}
9495

9596
void alarm_time_timealarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms) {
@@ -133,13 +134,14 @@ void alarm_time_timealarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_
133134
}
134135
RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP1;
135136
RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_CMP1;
137+
SAMD_ALARM_FLAG |= SAMD_ALARM_FLAG_TIME; // set TimeAlarm flag
136138

137139
// This is set for fake sleep. Max fake sleep time is ~72 hours
138140
// True deep sleep isn't limited by this
139141
// port_interrupt_after_ticks(wakeup_in_ticks);
140142
// printf("second t %lu, cmp0 %lu, cmp1 %lu\n", (uint32_t)port_get_raw_ticks(NULL),RTC->MODE0.COMP[0].reg,RTC->MODE0.COMP[1].reg);
141143
// TODO: set up RTC->COMP[1] and create a callback pointing to
142-
// timer_callback. See atmel-samd/supervisor/port.c -> _port_interrupt_after_ticks()
144+
// time_alarm_callback. See atmel-samd/supervisor/port.c -> _port_interrupt_after_ticks()
143145
// for how to set this up. I don't know how you do the callback, though. You MUST use
144146
// COMP[1], since port.c uses COMP[0] already and needs to set that for
145147
// things like the USB enumeration delay.

ports/atmel-samd/common-hal/alarm/time/TimeAlarm.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@
2727
#ifndef MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ALARM_TIMEALARM_H
2828
#define MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ALARM_TIMEALARM_H
2929

30+
// This is the first byte of the BKUP register bank.
31+
// We use it to store which alarms are set.
32+
#ifndef SAMD_ALARM_FLAG
33+
#define SAMD_ALARM_FLAG (RTC->MODE0.BKUP[0].reg)
34+
#define SAMD_ALARM_FLAG_TIME (_U_(0x1) << 0)
35+
#define SAMD_ALARM_FLAG_PIN (_U_(0x1) << 1)
36+
#endif
37+
3038
#include "py/obj.h"
3139

3240
typedef struct {
@@ -36,7 +44,7 @@ typedef struct {
3644

3745
mp_obj_t alarm_time_timealarm_find_triggered_alarm(size_t n_alarms, const mp_obj_t *alarms);
3846
mp_obj_t alarm_time_timealarm_create_wakeup_alarm(void);
39-
void timer_callback(void);
47+
void time_alarm_callback(void);
4048
bool alarm_time_timealarm_woke_this_cycle(void);
4149
void alarm_time_timealarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms);
4250
void alarm_time_timealarm_reset(void);

0 commit comments

Comments
 (0)