reworked fake sleep. functional for pin and time

This commit is contained in:
Max Holliday 2021-10-09 11:44:10 -06:00
parent 6811c5e881
commit 8486502e65
6 changed files with 93 additions and 43 deletions

View File

@ -66,7 +66,7 @@ samd_sleep_source_t alarm_get_wakeup_cause(void) {
if (alarm_time_timealarm_woke_this_cycle()) {
return SAMD_WAKEUP_RTC;
}
if (RSTC->RCAUSE.bit.BACKUP) {
if (!fake_sleep && RSTC->RCAUSE.bit.BACKUP) {
// not able to detect PinAlarm wake since registers are getting reset
// TODO: come up with a way to detect a TAMPER
if (RTC->MODE0.TAMPID.reg || RTC->MODE0.INTFLAG.bit.TAMPER) {
@ -192,6 +192,7 @@ void NORETURN common_hal_alarm_enter_deep_sleep(void) {
(void)__get_FPSCR();
}
// TODO: Be able to set PinAlarm and TimeAlarm together
// PinAlarm (hacky way of checking if time alarm or pin alarm)
if (RTC->MODE0.INTENSET.bit.TAMPER) {
// Disable interrupts
@ -274,7 +275,7 @@ void NORETURN common_hal_alarm_enter_deep_sleep(void) {
}
}
MP_NOINLINE void common_hal_alarm_pretending_deep_sleep(void) {
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
@ -286,8 +287,6 @@ MP_NOINLINE void common_hal_alarm_pretending_deep_sleep(void) {
;
}
fake_sleep = true;
} else {
port_idle_until_interrupt();
}
}

View File

@ -38,8 +38,9 @@
// This variable stores whether a PinAlarm woke in light sleep or fake deep sleep
// It CANNOT detect if the program woke from deep sleep.
STATIC bool woke_up;
STATIC bool deep_wkup_enabled;
STATIC volatile bool woke_up;
// TODO: replace pinalarm_on with SAMD_ALARM_FLAG bit flags
STATIC volatile bool pinalarm_on;
// TODO: Create tables here reserving IRQ instances, and for the IRQ
// callback to store what pin triggered the interrupt
@ -55,12 +56,16 @@ void pin_alarm_callback(uint8_t num) { // parameters can be changed
// Turn off interrupts while in handler
// printf("Woke up from pin!!\n");
// printf("EIC Flags: %lu\n",EIC->INTFLAG.reg);
// QUESTION: How to reference the correct EIC?
// set_eic_handler(self->channel, EIC_HANDLER_NO_INTERRUPT);
// turn_off_eic_channel(self->channel);
// reset_pin_number(self->pin);
woke_up = true;
if (pinalarm_on) {
// clear flag and interrupt setting
RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_TAMPER;
pinalarm_on = false;
// QUESTION: How to reference the correct EIC?
// set_eic_handler(self->channel, EIC_HANDLER_NO_INTERRUPT);
// turn_off_eic_channel(self->channel);
// reset_pin_number(self->pin);
woke_up = true;
}
}
void common_hal_alarm_pin_pinalarm_construct(alarm_pin_pinalarm_obj_t *self, const mcu_pin_obj_t *pin, bool value, bool edge, bool pull) {
@ -89,9 +94,13 @@ void common_hal_alarm_pin_pinalarm_construct(alarm_pin_pinalarm_obj_t *self, con
gpio_set_pin_function(pin->number, GPIO_PIN_FUNCTION_A);
if (self->pull) {
gpio_set_pin_pull_mode(pin->number, GPIO_PULL_UP);
} else {
gpio_set_pin_pull_mode(pin->number, GPIO_PULL_DOWN);
if (self->value) {
// detect rising edge means pull down
gpio_set_pin_pull_mode(pin->number, GPIO_PULL_DOWN);
} else {
// detect falling edge means pull up
gpio_set_pin_pull_mode(pin->number, GPIO_PULL_UP);
}
}
set_eic_channel_data(self->channel, (void *)self);
@ -107,7 +116,6 @@ bool common_hal_alarm_pin_pinalarm_get_value(alarm_pin_pinalarm_obj_t *self) {
}
bool common_hal_alarm_pin_pinalarm_get_edge(alarm_pin_pinalarm_obj_t *self) {
// TODO: is SAMD edge or level only?
return true;
}
@ -116,9 +124,8 @@ bool common_hal_alarm_pin_pinalarm_get_pull(alarm_pin_pinalarm_obj_t *self) {
}
bool alarm_pin_pinalarm_woke_this_cycle(void) {
if (RTC->MODE0.INTFLAG.bit.TAMPER) {
if (pinalarm_on && RTC->MODE0.INTFLAG.bit.TAMPER) {
woke_up = true;
RTC->MODE0.INTENCLR.bit.TAMPER = 1; // clear flag and interrupt setting
}
return woke_up;
}
@ -135,9 +142,6 @@ mp_obj_t alarm_pin_pinalarm_find_triggered_alarm(size_t n_alarms, const mp_obj_t
// TODO: Determine whether any pins have been marked as
// triggering the alarm (using the static vars at
// start of file) and if so return that alarm.
}
// Return nothing if no matching alarms are found.
return mp_const_none;
@ -159,9 +163,22 @@ 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.
pinalarm_on = false;
woke_up = false;
// Disable TAMPER interrupt
RTC->MODE0.INTENCLR.bit.TAMPER = 1;
// Disable TAMPER control
common_hal_mcu_disable_interrupts();
RTC->MODE0.CTRLA.bit.ENABLE = 0; // Disable the RTC
while (RTC->MODE0.SYNCBUSY.bit.ENABLE) { // Wait for synchronization
;
}
RTC->MODE0.TAMPCTRL.reg = 0; // reset everything
RTC->MODE0.CTRLA.bit.ENABLE = 1; // Enable the RTC
while (RTC->MODE0.SYNCBUSY.bit.ENABLE) { // Wait for synchronization
;
}
common_hal_mcu_enable_interrupts();
}
void alarm_pin_pinalarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms) {
@ -177,9 +194,25 @@ void alarm_pin_pinalarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_ob
alarm->pin != &pin_PA02) {
mp_raise_ValueError(translate("Pin cannot wake from Deep Sleep"));
}
deep_wkup_enabled = true;
pinalarm_on = true;
// Set tamper interrupt so deep sleep knows that's the intent
RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_TAMPER;
common_hal_mcu_disable_interrupts();
RTC->MODE0.CTRLA.bit.ENABLE = 0; // Disable the RTC
while (RTC->MODE0.SYNCBUSY.bit.ENABLE) { // Wait for synchronization
;
}
// TODO: map requested pin to limited selection of TAMPER pins
// PA02 is n=2: IN2, LVL2, etc...
RTC->MODE0.TAMPCTRL.bit.DEBNC2 = 1; // Edge triggered when INn is stable for 4 CLK_RTC_DEB periods
RTC->MODE0.TAMPCTRL.bit.TAMLVL2 = alarm->value; // rising or falling edge
RTC->MODE0.TAMPCTRL.bit.IN2ACT = 0x1; // WAKE on IN2 (doesn't save timestamp)
common_hal_mcu_enable_interrupts();
RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_TAMPER;
RTC->MODE0.CTRLA.bit.ENABLE = 1; // Enable the RTC
while (RTC->MODE0.SYNCBUSY.bit.ENABLE) { // Wait for synchronization
;
}
// 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

@ -27,7 +27,6 @@
#include "py/runtime.h"
#include "hpl/pm/hpl_pm_base.h"
// #include <stdio.h>
// #include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/alarm/time/TimeAlarm.h"
#include "shared-bindings/time/__init__.h"
@ -35,6 +34,8 @@
STATIC volatile bool woke_up;
STATIC uint32_t deep_sleep_ticks;
// TODO: replace timealarm_on with SAMD_ALARM_FLAG bit flags
STATIC bool timealarm_on;
void common_hal_alarm_time_timealarm_construct(alarm_time_timealarm_obj_t *self, mp_float_t monotonic_time) {
// TODO: throw a ValueError if the input time exceeds the maximum
@ -72,21 +73,28 @@ 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;
if (timealarm_on) {
RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_CMP1 | RTC_MODE0_INTENCLR_CMP0 | RTC_MODE0_INTENCLR_OVF; // clear flags
woke_up = true;
timealarm_on = false;
}
}
bool alarm_time_timealarm_woke_this_cycle(void) {
if (timealarm_on && (((uint32_t)port_get_raw_ticks(NULL)<<4) > RTC->MODE0.COMP[1].reg)) {
woke_up = true;
}
return woke_up;
}
void alarm_time_timealarm_reset(void) {
timealarm_on = false;
woke_up = false;
}
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;
// 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;
@ -117,16 +125,19 @@ void alarm_time_timealarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_
} else {
deep_sleep_ticks = 0;
}
// Set COMP1 for fake sleep. This will be reset for real deep sleep anyways.
RTC->MODE0.COMP[1].reg = wakeup_in_ticks;
while (RTC->MODE0.SYNCBUSY.reg) {
;
timealarm_on = true;
// Set COMP1 for fake sleep. This will be read and reset for real deep sleep anyways.
// RTC->MODE0.COMP[1].reg = wakeup_in_ticks;
RTC->MODE0.COMP[1].reg = ((uint32_t)port_get_raw_ticks(NULL)+wakeup_in_ticks)<<4;
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;
// 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);
// port_interrupt_after_ticks(wakeup_in_ticks);
// 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);
// TODO: set up RTC->COMP[1] and create a callback pointing to
// timer_callback. See atmel-samd/supervisor/port.c -> _port_interrupt_after_ticks()
// for how to set this up. I don't know how you do the callback, though. You MUST use
@ -146,9 +157,9 @@ void alarm_time_timealarm_prepare_for_deep_sleep(void) {
// is used for both fake and real deep sleep, so it still needs the callback.
// See STM32 for reference.
// RTC->MODE0.COMP[1].reg = deep_sleep_ticks;
// while ((RTC->MODE0.SYNCBUSY.reg & (RTC_MODE0_SYNCBUSY_COMP1)) != 0) {
// }
RTC->MODE0.COMP[1].reg = deep_sleep_ticks;
while ((RTC->MODE0.SYNCBUSY.reg & (RTC_MODE0_SYNCBUSY_COMP1)) != 0) {
}
deep_sleep_ticks = 0;
}
}

View File

@ -38,9 +38,9 @@ mp_obj_t alarm_time_timealarm_find_triggered_alarm(size_t n_alarms, const mp_obj
mp_obj_t alarm_time_timealarm_create_wakeup_alarm(void);
void timer_callback(void);
bool alarm_time_timealarm_woke_this_cycle(void);
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);
void alarm_time_timealarm_reset(void);
uint32_t alarm_time_timealarm_prepare_for_deep_sleep(void);
void alarm_time_timealarm_prepare_for_deep_sleep(void);
#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ALARM_TIMEALARM_H

View File

@ -31,6 +31,7 @@
#define EIC_HANDLER_INCREMENTAL_ENCODER 0x2
#define EIC_HANDLER_PS2 0x3
#define EIC_HANDLER_COUNTER 0x04
#define EIC_HANDLER_ALARM 0x05
void set_eic_handler(uint8_t channel, uint8_t eic_handler);
void shared_eic_handler(uint8_t channel);

View File

@ -79,6 +79,7 @@
#include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/rtc/__init__.h"
#include "shared-bindings/alarm/time/TimeAlarm.h"
#include "shared-bindings/alarm/pin/PinAlarm.h"
#include "shared_timers.h"
#include "reset.h"
@ -490,6 +491,16 @@ void RTC_Handler(void) {
// Do things common to all ports when the tick occurs
supervisor_tick();
}
if (intflag & RTC_MODE0_INTFLAG_CMP1) {
// Likely TimeAlarm fake sleep wake
timer_callback();
RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP1;
}
if (intflag & RTC_MODE0_INTFLAG_TAMPER) {
// Likely PinAlarm fake sleep wake
pin_alarm_callback(1); // TODO: set channel?
RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_TAMPER;
}
#endif
if (intflag & RTC_MODE0_INTFLAG_CMP0) {
// Clear the interrupt because we may have hit a sleep
@ -498,11 +509,6 @@ 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
}
}