cleaning up TimeAlarm and PinAlarm

This commit is contained in:
Max Holliday 2021-10-01 17:36:04 -06:00
parent cd28d50e7a
commit 79cd10ac85
4 changed files with 55 additions and 66 deletions

View File

@ -29,7 +29,7 @@
#include "py/objtuple.h"
#include "py/runtime.h"
#include "lib/utils/interrupt_char.h"
#include <stdio.h>
// #include <stdio.h>
#include "shared-bindings/alarm/__init__.h"
#include "shared-bindings/alarm/SleepMemory.h"
@ -47,8 +47,10 @@ const alarm_sleep_memory_obj_t alarm_sleep_memory_obj = {
.type = &alarm_sleep_memory_type,
},
};
uint32_t target2 = 0;
// TODO: make a custom enum to avoid weird values like PM_SLEEPCFG_SLEEPMODE_BACKUP_Val?
STATIC volatile uint32_t _target;
STATIC bool fake_sleep;
STATIC bool pin_alarm = false;
void alarm_reset(void) {
// Reset the alarm flag
@ -58,15 +60,6 @@ void alarm_reset(void) {
}
samd_sleep_source_t alarm_get_wakeup_cause(void) {
// uint8_t reset_cause = RSTC->RCAUSE.reg;
// printf("reset cause: %u\n",reset_cause);
// printf("POR %u, BKUP %u, EXT %u, SYST %u\n",
// reset_cause & RSTC_RCAUSE_POR,
// reset_cause & RSTC_RCAUSE_BACKUP,
// reset_cause & RSTC_RCAUSE_EXT,
// reset_cause & RSTC_RCAUSE_SYST);
// printf("RTC INTFLAG: %u\n",RTC->MODE0.INTFLAG.reg);
// If in light/fake sleep, check modules
if (alarm_pin_pinalarm_woke_this_cycle()) {
return SAMD_WAKEUP_GPIO;
@ -74,8 +67,12 @@ samd_sleep_source_t alarm_get_wakeup_cause(void) {
if (alarm_time_timealarm_woke_this_cycle()) {
return SAMD_WAKEUP_RTC;
}
// TODO: for deep sleep, manually determine how the chip woke up
// TODO: try checking the interrupt flag tables for RTC TAMPER vs COMPARE
if (RSTC->RCAUSE.bit.BACKUP) {
if (RTC->MODE0.INTFLAG.bit.TAMPER) {
return SAMD_WAKEUP_GPIO;
}
return SAMD_WAKEUP_RTC;
}
return SAMD_WAKEUP_UNDEF;
}
@ -105,7 +102,8 @@ mp_obj_t common_hal_alarm_create_wake_alarm(void) {
// Set up light sleep or deep sleep alarms.
STATIC void _setup_sleep_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms) {
alarm_pin_pinalarm_set_alarms(deep_sleep, n_alarms, alarms);
target2 = alarm_time_timealarm_set_alarms(deep_sleep, n_alarms, alarms);
alarm_time_timealarm_set_alarms(deep_sleep, n_alarms, alarms);
fake_sleep = false;
}
mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj_t *alarms) {
@ -178,7 +176,8 @@ void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *ala
void NORETURN common_hal_alarm_enter_deep_sleep(void) {
alarm_pin_pinalarm_prepare_for_deep_sleep();
target2 = alarm_time_timealarm_prepare_for_deep_sleep();
alarm_time_timealarm_prepare_for_deep_sleep();
_target = RTC->MODE0.COMP[1].reg;
port_disable_tick(); // TODO: Required for SAMD?
// Set a flag in the backup registers to indicate sleep wakeup
@ -192,7 +191,7 @@ void NORETURN common_hal_alarm_enter_deep_sleep(void) {
// hacky way of checking if time alarm or pin alarm
// TODO: find better way of determining pin vs time
if (target2 == 0) {
if (RTC->MODE0.INTENSET.bit.TAMPER) {
// Disable interrupts
NVIC_DisableIRQ(RTC_IRQn);
@ -206,6 +205,7 @@ void NORETURN common_hal_alarm_enter_deep_sleep(void) {
RTC->MODE0.CTRLA.reg = RTC_MODE0_CTRLA_PRESCALER_DIV1024 | // Set prescaler to 1024
RTC_MODE0_CTRLA_MODE_COUNT32; // Set RTC to mode 0, 32-bit timer
// TODO: map requested pin to limited selection of TAMPER pins
//PA02 = IN2
RTC->MODE0.TAMPCTRL.bit.DEBNC2 = 1; // Edge triggered when INn is stable for 4 CLK_RTC_DEB periods
RTC->MODE0.TAMPCTRL.bit.TAMLVL2 = 1; // rising edge
@ -216,8 +216,8 @@ void NORETURN common_hal_alarm_enter_deep_sleep(void) {
NVIC_EnableIRQ(RTC_IRQn);
// Set interrupts for TAMPER or overflow
RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_TAMPER;
}
else {
} else {
// Retrieve COMP1 value before resetting RTC
// Disable interrupts
NVIC_DisableIRQ(RTC_IRQn);
@ -231,7 +231,7 @@ void NORETURN common_hal_alarm_enter_deep_sleep(void) {
RTC->MODE0.CTRLA.reg = RTC_MODE0_CTRLA_PRESCALER_DIV1024 | // Set prescaler to 1024
RTC_MODE0_CTRLA_MODE_COUNT32; // Set RTC to mode 0, 32-bit timer
RTC->MODE0.COMP[1].reg = (target2/1024) * 32;
RTC->MODE0.COMP[1].reg = (_target/1024) * 32;
while(RTC->MODE0.SYNCBUSY.reg);
// Enable interrupts
@ -239,8 +239,7 @@ void NORETURN common_hal_alarm_enter_deep_sleep(void) {
NVIC_EnableIRQ(RTC_IRQn);
// Set interrupts for COMPARE1 or overflow
RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_CMP1 | RTC_MODE1_INTENSET_OVF;
}
}
// Set-up Deep Sleep Mode
// RAM retention
PM->BKUPCFG.reg = PM_BKUPCFG_BRAMCFG(0x2); // No RAM retention 0x2 partial:0x1
@ -260,36 +259,21 @@ void NORETURN common_hal_alarm_enter_deep_sleep(void) {
}
}
void common_hal_alarm_pretending_deep_sleep(void) {
MP_NOINLINE void common_hal_alarm_pretending_deep_sleep(void) {
// TODO:
// If tamper detect interrupts cannot be used to wake from the Idle tier of sleep,
// This section will need to re-initialize the pins to allow the PORT peripheral
// to generate external interrupts again. See STM32 for reference.
// COMP never fires... I don't know why
if (RTC->MODE0.INTFLAG.bit.CMP1 || RTC->MODE0.INTFLAG.bit.CMP0){
printf("fake sleep finished (proper way)\n");
timer_callback();
RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_CMP1; // clear flag
}
else {
// this works, but is a terrible way of checking
if (port_get_raw_ticks(NULL) > (RTC->MODE0.COMP[1].reg)) {
timer_callback();
// printf("COUNT %lu\n",(uint32_t)port_get_raw_ticks(NULL));
// printf("CTRLA %u\n",RTC->MODE0.CTRLA.reg);
// printf("CTRLB %u\n",RTC->MODE0.CTRLB.reg);
// printf("EVCTRL %lu\n",RTC->MODE0.EVCTRL.reg);
// printf("INTENCLR %u\n",RTC->MODE0.INTENCLR.reg);
// printf("INTENSET %u\n",RTC->MODE0.INTENSET.reg);
// printf("INTFLAG %u\n",RTC->MODE0.INTFLAG.reg);
// printf("SYNCBUSY %lu\n",RTC->MODE0.SYNCBUSY.reg);
// printf("COMP0 %lu\n",RTC->MODE0.COMP[0].reg);
// printf("COMP1 %lu\n",RTC->MODE0.COMP[1].reg);
RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_CMP1; // clear flag
printf("fake sleep finished (manual way)\n");
}
if (!fake_sleep) {
SAMD_ALARM_FLAG = 1;
while(RTC->MODE0.SYNCBUSY.reg);
fake_sleep = true;
// if () {
// pin_alarm=true;
// }
} else {
port_idle_until_interrupt();
}
}

View File

@ -159,6 +159,9 @@ void alarm_pin_pinalarm_reset(void) {
// sure to clear any reserved tables, deinit both PORT and TAMPER
// settings, etc. If flags are set to indicate this module is in
// use, reset them.
// Disable TAMPER interrupt
RTC->MODE0.INTENCLR.bit.TAMPER = 1;
}
void alarm_pin_pinalarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms) {
@ -175,6 +178,8 @@ void alarm_pin_pinalarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_ob
mp_raise_ValueError(translate("Pin cannot wake from Deep Sleep"));
}
deep_wkup_enabled = true;
// Set tamper interrupt so deep sleep knows that's the intent
RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_TAMPER;
// TODO: Set up deep sleep alarms.
// For deep sleep alarms, first check if the
// alarm pin value is valid for RTC->TAMPER. Ensure

View File

@ -26,8 +26,8 @@
#include "py/runtime.h"
#include "hpl/pm/hpl_pm_base.h"
#include <stdio.h>
#include "shared-bindings/microcontroller/__init__.h"
// #include <stdio.h>
// #include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/alarm/time/TimeAlarm.h"
@ -72,14 +72,11 @@ mp_obj_t alarm_time_timealarm_create_wakeup_alarm(void) {
}
void timer_callback(void) {
RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_CMP1 | RTC_MODE0_INTENCLR_CMP0 | RTC_MODE0_INTENCLR_OVF; // clear flags
woke_up = true;
}
bool alarm_time_timealarm_woke_this_cycle(void) {
if (RTC->MODE0.INTFLAG.reg & RTC_MODE0_INTFLAG_CMP1){
RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP1; // clear flag
woke_up = true;
}
return woke_up;
}
@ -87,7 +84,9 @@ void alarm_time_timealarm_reset(void) {
woke_up = false;
}
uint32_t alarm_time_timealarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms) {
void alarm_time_timealarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms) {
// Turn on debug control
RTC->MODE0.DBGCTRL.bit.DBGRUN = 1;
// Search through alarms for TimeAlarm instances, and check that there's only one
bool timealarm_set = false;
alarm_time_timealarm_obj_t *timealarm = MP_OBJ_NULL;
@ -102,7 +101,7 @@ uint32_t alarm_time_timealarm_set_alarms(bool deep_sleep, size_t n_alarms, const
timealarm_set = true;
}
if (!timealarm_set) {
return 0;
return;
}
// Compute how long to actually sleep, considering the time now.
@ -118,17 +117,13 @@ uint32_t alarm_time_timealarm_set_alarms(bool deep_sleep, size_t n_alarms, const
} else {
deep_sleep_ticks = 0;
}
// Set COMP1 for fake sleep. This will be reset for real deep sleep anyways.
uint32_t current_cnt = port_get_raw_ticks(NULL);
RTC->MODE0.COMP[1].reg = current_cnt + wakeup_in_ticks;
while ((RTC->MODE0.SYNCBUSY.reg & (RTC_MODE0_SYNCBUSY_COMP1)) != 0) {
}
RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP1;
RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_CMP1;
return wakeup_in_ticks;
RTC->MODE0.COMP[1].reg = wakeup_in_ticks;
while (RTC->MODE0.SYNCBUSY.reg);
// This is set for fake sleep. Max fake sleep time is ~72 hours
// True deep sleep isn't limited by this
port_interrupt_after_ticks(wakeup_in_ticks);
// TODO: set up RTC->COMP[1] and create a callback pointing to
// timer_callback. See atmel-samd/supervisor/port.c -> _port_interrupt_after_ticks()
@ -142,8 +137,7 @@ uint32_t alarm_time_timealarm_set_alarms(bool deep_sleep, size_t n_alarms, const
}
uint32_t alarm_time_timealarm_prepare_for_deep_sleep(void) {
uint32_t temp_ticks = deep_sleep_ticks;
void alarm_time_timealarm_prepare_for_deep_sleep(void) {
if (deep_sleep_ticks) {
// TODO: set up RTC->COMP[1] again, since it needs to start AFTER the USB enumeration delay.
// Just do the exact same setup as alarm_time_timealarm_set_alarms(). Note, this
@ -155,5 +149,4 @@ uint32_t alarm_time_timealarm_prepare_for_deep_sleep(void) {
// }
deep_sleep_ticks = 0;
}
return temp_ticks;
}

View File

@ -53,6 +53,7 @@
#error Unknown chip family
#endif
#include "common-hal/alarm/__init__.h"
#include "common-hal/analogio/AnalogIn.h"
#include "common-hal/analogio/AnalogOut.h"
#include "common-hal/audiobusio/PDMIn.h"
@ -77,6 +78,7 @@
#include "samd/dma.h"
#include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/rtc/__init__.h"
#include "shared-bindings/alarm/time/TimeAlarm.h"
#include "shared_timers.h"
#include "reset.h"
@ -496,6 +498,11 @@ void RTC_Handler(void) {
// SAMD21 ticks are handled by EVSYS
#ifdef SAM_D5X_E5X
RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_CMP0;
// Check if we're sleeping
if (SAMD_ALARM_FLAG){
timer_callback();
SAMD_ALARM_FLAG = 0;
}
#endif
}
}