Merge pull request #5425 from maholli/samd-sleep

functioning samd deep sleep ('alarm.time' & 'alarm.pin')
This commit is contained in:
Scott Shawcroft 2021-10-25 14:42:12 -07:00 committed by GitHub
commit 5315348b11
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 1092 additions and 46 deletions

View File

@ -1727,6 +1727,7 @@ msgstr ""
msgid "Only connectable advertisements can be directed"
msgstr ""
#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
#: ports/stm/common-hal/alarm/pin/PinAlarm.c
msgid "Only edge detection is available on this hardware"
msgstr ""
@ -1750,6 +1751,7 @@ msgstr ""
msgid "Only one address is allowed"
msgstr ""
#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c
#: ports/espressif/common-hal/alarm/time/TimeAlarm.c
#: ports/nrf/common-hal/alarm/time/TimeAlarm.c
#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c
@ -2070,6 +2072,7 @@ msgstr ""
msgid "Size not supported"
msgstr ""
#: ports/atmel-samd/common-hal/alarm/SleepMemory.c
#: ports/raspberrypi/common-hal/alarm/SleepMemory.c
msgid "Sleep Memory not available"
msgstr ""
@ -2224,6 +2227,7 @@ msgstr ""
msgid "Total data to write is larger than %q"
msgstr ""
#: ports/atmel-samd/common-hal/alarm/touch/TouchAlarm.c
#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c
#: ports/stm/common-hal/alarm/touch/TouchAlarm.c
msgid "Touch alarms not available"

View File

@ -24,25 +24,12 @@
* THE SOFTWARE.
*/
#include <string.h>
#include "supervisor/board.h"
#include "py/mpconfig.h"
#include "shared-bindings/nvm/ByteArray.h"
#include "mpconfigboard.h"
#include "common-hal/microcontroller/Pin.h"
#include "hal/include/hal_gpio.h"
#include "shared-bindings/pwmio/PWMOut.h"
nvm_bytearray_obj_t bootcnt = {
.base = {
.type = &nvm_bytearray_type
},
.len = (uint32_t)8192,
.start_address = (uint8_t *)(0x00080000 - 8192)
};
void board_init(void) {
pwmio_pwmout_obj_t pwm;
common_hal_pwmio_pwmout_construct(&pwm, &pin_PA23, 4096, 2, false);
@ -54,8 +41,7 @@ bool board_requests_safe_mode(void) {
}
void reset_board(void) {
uint8_t value_out = 0;
common_hal_nvm_bytearray_get_bytes(&bootcnt,0,1,&value_out);
++value_out;
common_hal_nvm_bytearray_set_bytes(&bootcnt,0,&value_out,1);
}
void board_deinit(void) {
}

View File

@ -15,6 +15,9 @@
// External flash W25Q80DV
#define EXTERNAL_FLASH_QSPI_DUAL
#define CIRCUITPY_DRIVE_LABEL "PYCUBED"
#define CIRCUITPY_BOOT_COUNTER 1
#define BOARD_HAS_CRYSTAL 1
#define DEFAULT_I2C_BUS_SCL (&pin_PB13)

View File

@ -10,17 +10,25 @@ QSPI_FLASH_FILESYSTEM = 1
EXTERNAL_FLASH_DEVICES = W25Q80DV
LONGINT_IMPL = MPZ
CIRCUITPY_DRIVE_LABEL = "PYCUBED"
CIRCUITPY_ULAB = 1
CIRCUITPY_BINASCII = 1
CIRCUITPY_SDCARDIO = 1
CIRCUITPY_JSON = 1
CIRCUITPY_MSGPACK = 1
CIRCUITPY_ALARM = 1
# Not needed.
# no SAMD51 support... yet ;)
# CIRCUITPY_DUALBANK=1
# Not needed
CIRCUITPY_AUDIOBUSIO = 0
CIRCUITPY_BITMAPTOOLS = 0
CIRCUITPY_DISPLAYIO = 0
CIRCUITPY_FRAMEBUFFERIO = 0
CIRCUITPY_KEYPAD = 0
CIRCUITPY_RGBMATRIX = 0
CIRCUITPY_PS2IO = 0
CIRCUITPY_BLEIO_HCI=0
CIRCUITPY_BLEIO=0
FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel
FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Register
FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_SD

View File

@ -24,25 +24,12 @@
* THE SOFTWARE.
*/
#include <string.h>
#include "supervisor/board.h"
#include "py/mpconfig.h"
#include "shared-bindings/nvm/ByteArray.h"
#include "mpconfigboard.h"
#include "common-hal/microcontroller/Pin.h"
#include "hal/include/hal_gpio.h"
#include "shared-bindings/pwmio/PWMOut.h"
nvm_bytearray_obj_t bootcnt = {
.base = {
.type = &nvm_bytearray_type
},
.len = (uint32_t)8192,
.start_address = (uint8_t *)(0x00080000 - 8192)
};
void board_init(void) {
pwmio_pwmout_obj_t pwm;
common_hal_pwmio_pwmout_construct(&pwm, &pin_PA23, 4096, 2, false);
@ -54,8 +41,7 @@ bool board_requests_safe_mode(void) {
}
void reset_board(void) {
uint8_t value_out = 0;
common_hal_nvm_bytearray_get_bytes(&bootcnt,0,1,&value_out);
++value_out;
common_hal_nvm_bytearray_set_bytes(&bootcnt,0,&value_out,1);
}
void board_deinit(void) {
}

View File

@ -15,6 +15,9 @@
#define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000 - CIRCUITPY_INTERNAL_NVM_SIZE)
#define CIRCUITPY_DRIVE_LABEL "PYCUBED"
#define CIRCUITPY_BOOT_COUNTER 1
#define BOARD_HAS_CRYSTAL 1
#define DEFAULT_I2C_BUS_SCL (&pin_PB13)

View File

@ -10,17 +10,25 @@ QSPI_FLASH_FILESYSTEM = 1
EXTERNAL_FLASH_DEVICES = MR2xH40
LONGINT_IMPL = MPZ
CIRCUITPY_DRIVE_LABEL = "PYCUBED"
CIRCUITPY_ULAB = 1
CIRCUITPY_BINASCII = 1
CIRCUITPY_SDCARDIO = 1
CIRCUITPY_JSON = 1
CIRCUITPY_MSGPACK = 1
CIRCUITPY_ALARM = 1
# Not needed.
# no SAMD51 support... yet ;)
# CIRCUITPY_DUALBANK=1
# Not needed
CIRCUITPY_AUDIOBUSIO = 0
CIRCUITPY_BITMAPTOOLS = 0
CIRCUITPY_DISPLAYIO = 0
CIRCUITPY_FRAMEBUFFERIO = 0
CIRCUITPY_KEYPAD = 0
CIRCUITPY_RGBMATRIX = 0
CIRCUITPY_PS2IO = 0
CIRCUITPY_BLEIO_HCI=0
CIRCUITPY_BLEIO=0
FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel
FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Register
FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_SD

View File

@ -42,3 +42,6 @@ bool board_requests_safe_mode(void) {
void reset_board(void) {
}
void board_deinit(void) {
}

View File

@ -15,9 +15,9 @@ CIRCUITPY_BINASCII = 1
CIRCUITPY_SDCARDIO = 1
CIRCUITPY_JSON = 1
CIRCUITPY_MSGPACK = 1
CIRCUITPY_ALARM = 1
# no SAMD51 support... yet ;)
# CIRCUITPY_ALARM = 1
# CIRCUITPY_DUALBANK=1
# Not needed

View File

@ -42,3 +42,6 @@ bool board_requests_safe_mode(void) {
void reset_board(void) {
}
void board_deinit(void) {
}

View File

@ -16,9 +16,9 @@ CIRCUITPY_BINASCII = 1
CIRCUITPY_SDCARDIO = 1
CIRCUITPY_JSON = 1
CIRCUITPY_MSGPACK = 1
CIRCUITPY_ALARM = 1
# no SAMD51 support... yet ;)
# CIRCUITPY_ALARM = 1
# CIRCUITPY_DUALBANK=1
# Not needed

View File

@ -0,0 +1,50 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Lucian Copeland for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <string.h>
#include "py/runtime.h"
#include "common-hal/alarm/SleepMemory.h"
#include "shared-bindings/nvm/ByteArray.h"
void alarm_sleep_memory_reset(void) {
}
uint32_t common_hal_alarm_sleep_memory_get_length(alarm_sleep_memory_obj_t *self) {
mp_raise_NotImplementedError(translate("Sleep Memory not available"));
return 0;
}
bool common_hal_alarm_sleep_memory_set_bytes(alarm_sleep_memory_obj_t *self, uint32_t start_index, const uint8_t *values, uint32_t len) {
mp_raise_NotImplementedError(translate("Sleep Memory not available"));
return false;
}
void common_hal_alarm_sleep_memory_get_bytes(alarm_sleep_memory_obj_t *self, uint32_t start_index, uint8_t *values, uint32_t len) {
mp_raise_NotImplementedError(translate("Sleep Memory not available"));
return;
}

View File

@ -0,0 +1,40 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Lucian Copeland for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ALARM_SLEEPMEMORY_H
#define MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ALARM_SLEEPMEMORY_H
#include "py/obj.h"
typedef struct {
mp_obj_base_t base;
uint8_t *start_address;
uint8_t len;
} alarm_sleep_memory_obj_t;
extern void alarm_sleep_memory_reset(void);
#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ALARM_SLEEPMEMORY_H

View File

@ -0,0 +1,261 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Lucian Copeland for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/gc.h"
#include "py/obj.h"
#include "py/objtuple.h"
#include "py/runtime.h"
#include "shared-bindings/alarm/__init__.h"
#include "shared-bindings/alarm/SleepMemory.h"
#include "shared-bindings/alarm/pin/PinAlarm.h"
#include "shared-bindings/alarm/time/TimeAlarm.h"
#include "shared-bindings/microcontroller/__init__.h"
#include "shared/runtime/interrupt_char.h"
#include "samd/external_interrupts.h"
#include "supervisor/port.h"
#include "supervisor/workflow.h"
// Singleton instance of SleepMemory.
const alarm_sleep_memory_obj_t alarm_sleep_memory_obj = {
.base = {
.type = &alarm_sleep_memory_type,
},
};
// 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_wake;
void alarm_reset(void) {
// Reset the alarm flag
SAMD_ALARM_FLAG = 0x00;
alarm_pin_pinalarm_reset();
alarm_time_timealarm_reset();
}
samd_sleep_source_t alarm_get_wakeup_cause(void) {
// If in light/fake sleep, check modules
if (alarm_pin_pinalarm_woke_this_cycle()) {
return SAMD_WAKEUP_GPIO;
}
if (alarm_time_timealarm_woke_this_cycle()) {
return SAMD_WAKEUP_RTC;
}
if (!fake_sleep && RSTC->RCAUSE.bit.BACKUP) {
// This is checked during rtc_init to cache TAMPID if necessary
if (pin_wake || RTC->MODE0.TAMPID.reg) {
pin_wake = true;
return SAMD_WAKEUP_GPIO;
}
return SAMD_WAKEUP_RTC;
}
return SAMD_WAKEUP_UNDEF;
}
bool common_hal_alarm_woken_from_sleep(void) {
return alarm_get_wakeup_cause() != SAMD_WAKEUP_UNDEF;
}
mp_obj_t common_hal_alarm_create_wake_alarm(void) {
// If woken from deep sleep, create a copy alarm similar to what would have
// been passed in originally. Otherwise, just return none
samd_sleep_source_t cause = alarm_get_wakeup_cause();
switch (cause) {
case SAMD_WAKEUP_RTC: {
return alarm_time_timealarm_create_wakeup_alarm();
}
case SAMD_WAKEUP_GPIO: {
return alarm_pin_pinalarm_create_wakeup_alarm();
}
case SAMD_WAKEUP_UNDEF:
default:
// Not a deep sleep reset.
break;
}
return mp_const_none;
}
// 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);
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) {
_setup_sleep_alarms(false, n_alarms, alarms);
mp_obj_t wake_alarm = mp_const_none;
while (!mp_hal_is_interrupted()) {
RUN_BACKGROUND_TASKS;
// Detect if interrupt was alarm or ctrl-C interrupt.
if (common_hal_alarm_woken_from_sleep()) {
samd_sleep_source_t cause = alarm_get_wakeup_cause();
switch (cause) {
case SAMD_WAKEUP_RTC: {
wake_alarm = alarm_time_timealarm_find_triggered_alarm(n_alarms,alarms);
break;
}
case SAMD_WAKEUP_GPIO: {
wake_alarm = alarm_pin_pinalarm_find_triggered_alarm(n_alarms,alarms);
break;
}
default:
// Should not reach this, if all light sleep types are covered correctly
break;
}
shared_alarm_save_wake_alarm(wake_alarm);
break;
}
// ATTEMPT ------------------------------
// This works but achieves same power consumption as time.sleep()
// Clear the FPU interrupt because it can prevent us from sleeping.
if (__get_FPSCR() & ~(0x9f)) {
__set_FPSCR(__get_FPSCR() & ~(0x9f));
(void)__get_FPSCR();
}
// Disable RTC interrupts
NVIC_DisableIRQ(RTC_IRQn);
// Set standby power domain stuff
PM->STDBYCFG.reg = PM_STDBYCFG_RAMCFG_OFF;
// Set-up Sleep Mode
PM->SLEEPCFG.reg = PM_SLEEPCFG_SLEEPMODE_STANDBY;
while (PM->SLEEPCFG.bit.SLEEPMODE != PM_SLEEPCFG_SLEEPMODE_STANDBY_Val) {
;
}
__DSB(); // Data Synchronization Barrier
__WFI(); // Wait For Interrupt
// Enable RTC interrupts
NVIC_EnableIRQ(RTC_IRQn);
// END ATTEMPT ------------------------------
}
if (mp_hal_is_interrupted()) {
return mp_const_none; // Shouldn't be given to python code because exception handling should kick in.
}
alarm_reset();
return wake_alarm;
}
void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms) {
_setup_sleep_alarms(true, n_alarms, alarms);
}
void NORETURN common_hal_alarm_enter_deep_sleep(void) {
alarm_pin_pinalarm_prepare_for_deep_sleep();
alarm_time_timealarm_prepare_for_deep_sleep();
_target = RTC->MODE0.COMP[1].reg;
port_disable_tick(); // TODO: Required for SAMD?
// cache alarm flag since backup registers about to be reset
uint32_t _SAMD_ALARM_FLAG = SAMD_ALARM_FLAG;
// Clear the FPU interrupt because it can prevent us from sleeping.
if (__get_FPSCR() & ~(0x9f)) {
__set_FPSCR(__get_FPSCR() & ~(0x9f));
(void)__get_FPSCR();
}
NVIC_DisableIRQ(RTC_IRQn);
// Must disable the RTC before writing to EVCTRL and TMPCTRL
RTC->MODE0.CTRLA.bit.ENABLE = 0; // Disable the RTC
while (RTC->MODE0.SYNCBUSY.bit.ENABLE) { // Wait for synchronization
;
}
RTC->MODE0.CTRLA.bit.SWRST = 1; // Software reset the RTC
while (RTC->MODE0.SYNCBUSY.bit.SWRST) { // Wait for synchronization
;
}
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
// Check if we're setting TimeAlarm
if (_SAMD_ALARM_FLAG & SAMD_ALARM_FLAG_TIME) {
RTC->MODE0.COMP[1].reg = (_target / 1024) * 32;
while (RTC->MODE0.SYNCBUSY.reg) {
;
}
}
// Check if we're setting PinAlarm
if (_SAMD_ALARM_FLAG & SAMD_ALARM_FLAG_PIN) {
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
// PA02 = IN2
RTC->MODE0.TAMPCTRL.bit.IN2ACT = 1; // WAKE on IN2 (doesn't save timestamp)
}
// Enable interrupts
NVIC_SetPriority(RTC_IRQn, 0);
NVIC_EnableIRQ(RTC_IRQn);
if (_SAMD_ALARM_FLAG & SAMD_ALARM_FLAG_TIME) {
// Set interrupts for COMPARE1
RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_CMP1;
}
if (_SAMD_ALARM_FLAG & SAMD_ALARM_FLAG_PIN) {
// Set interrupts for TAMPER pins
RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_TAMPER;
}
// Set-up Deep Sleep Mode & RAM retention
PM->BKUPCFG.reg = PM_BKUPCFG_BRAMCFG(0x2); // No RAM retention 0x2 partial:0x1
while (PM->BKUPCFG.bit.BRAMCFG != 0x2) { // Wait for synchronization
;
}
PM->SLEEPCFG.reg = PM_SLEEPCFG_SLEEPMODE_BACKUP;
while (PM->SLEEPCFG.bit.SLEEPMODE != PM_SLEEPCFG_SLEEPMODE_BACKUP_Val) {
;
}
RTC->MODE0.CTRLA.bit.ENABLE = 1; // Enable the RTC
while (RTC->MODE0.SYNCBUSY.bit.ENABLE) { // Wait for synchronization
;
}
__DSB(); // Data Synchronization Barrier
__WFI(); // Wait For Interrupt
// The above shuts down RAM and triggers a reset, so we should never hit this
while (1) {
;
}
}
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.
if (!fake_sleep) {
fake_sleep = true;
}
}
void common_hal_alarm_gc_collect(void) {
gc_collect_ptr(shared_alarm_get_wake_alarm());
}

View File

@ -0,0 +1,52 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Lucian Copeland for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ALARM__INIT__H
#define MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ALARM__INIT__H
#include "common-hal/alarm/SleepMemory.h"
extern const alarm_sleep_memory_obj_t alarm_sleep_memory_obj;
// This is the first byte of the BKUP register bank.
// We use it to store which alarms are set.
#ifndef SAMD_ALARM_FLAG
#define SAMD_ALARM_FLAG (RTC->MODE0.BKUP[0].reg)
#define SAMD_ALARM_FLAG_TIME (_U_(0x1) << 0)
#define SAMD_ALARM_FLAG_PIN (_U_(0x1) << 1)
#endif
typedef enum {
SAMD_WAKEUP_UNDEF,
SAMD_WAKEUP_GPIO,
SAMD_WAKEUP_RTC
} samd_sleep_source_t;
extern void alarm_set_wakeup_reason(samd_sleep_source_t reason);
samd_sleep_source_t alarm_get_wakeup_cause(void);
extern void alarm_reset(void);
#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ALARM__INIT__H

View File

@ -0,0 +1,276 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Lucian Copeland for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/runtime.h"
#include "samd/external_interrupts.h"
#include "eic_handler.h"
#include "atmel_start_pins.h"
#include "hal/include/hal_gpio.h"
// #include <stdio.h>
#include "shared-bindings/alarm/pin/PinAlarm.h"
#include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/microcontroller/Pin.h"
#include "common-hal/alarm/__init__.h"
// 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 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
// STATIC bool reserved_alarms[SOME_VAL];
// STATIC uint16_t triggered_pins[SOME_VAL];
void pin_alarm_callback(uint8_t num) { // parameters can be changed
// TODO: This is responsible for resetting the IRQ (so it doesn't
// go off constantly, and recording what pin was responsible for
// the trigger. This will only work for light sleep/fake deep
// sleep, in conjunction with the find_triggered_alarm function
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) {
// Tamper Pins: IN0:PB00; IN1:PB02; IN2:PA02; IN3:PC00; IN4:PC01; OUT:PB01
// TODO: Catch edge or level mode if not supported
if (!pin->has_extint) {
mp_raise_RuntimeError(translate("No hardware support on pin"));
}
if (eic_get_enable()) {
if (!eic_channel_free(pin->extint_channel)) {
mp_raise_RuntimeError(translate("A hardware interrupt channel is already in use"));
}
} else {
turn_on_external_interrupt_controller();
}
// TODO: determine if pin has an interrupt channel available
// TODO: set pin pull settings, input/output, etc
// QUESTION: can PORT/EVSYS interrupts (lightsleep) coexist with RTC->TAMPER (deepsleep) settings?
// Actual initialization of the interrupt should be delayed until set_alarm
self->channel = pin->extint_channel;
self->pin = pin;
self->value = value;
self->pull = pull;
gpio_set_pin_function(pin->number, GPIO_PIN_FUNCTION_A);
if (self->pull) {
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);
claim_pin(self->pin);
}
const mcu_pin_obj_t *common_hal_alarm_pin_pinalarm_get_pin(alarm_pin_pinalarm_obj_t *self) {
return self->pin;
}
bool common_hal_alarm_pin_pinalarm_get_value(alarm_pin_pinalarm_obj_t *self) {
return self->value;
}
bool common_hal_alarm_pin_pinalarm_get_edge(alarm_pin_pinalarm_obj_t *self) {
return true;
}
bool common_hal_alarm_pin_pinalarm_get_pull(alarm_pin_pinalarm_obj_t *self) {
return self->pull;
}
bool alarm_pin_pinalarm_woke_this_cycle(void) {
if (pinalarm_on && RTC->MODE0.INTFLAG.bit.TAMPER) {
woke_up = true;
}
return woke_up;
}
mp_obj_t alarm_pin_pinalarm_find_triggered_alarm(size_t n_alarms, const mp_obj_t *alarms) {
for (size_t i = 0; i < n_alarms; i++) {
if (!mp_obj_is_type(alarms[i], &alarm_pin_pinalarm_type)) {
continue;
}
alarm_pin_pinalarm_obj_t *alarm = MP_OBJ_TO_PTR(alarms[i]);
(void)alarm;
// 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;
}
mp_obj_t alarm_pin_pinalarm_create_wakeup_alarm(void) {
alarm_pin_pinalarm_obj_t *alarm = m_new_obj(alarm_pin_pinalarm_obj_t);
alarm->base.type = &alarm_pin_pinalarm_type;
// TODO: Extract information about what pin woke the device.
// Because this interrupt occurs in deep sleep, the callback
// cannot be used to store this information. It must be extracted
// from the registers, if possible. It may be impossible to
// obtain, in which case return a dummy value.
return alarm;
}
void alarm_pin_pinalarm_reset(void) {
// TODO: this is responsible for resetting ALL pinalarms. Make
// 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;
SAMD_ALARM_FLAG &= ~SAMD_ALARM_FLAG_PIN; // clear flag
// 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) {
// The outer layer of this loop simply checks if there are any pin
// alarms in the parameter array
for (size_t i = 0; i < n_alarms; i++) {
if (mp_obj_is_type(alarms[i], &alarm_pin_pinalarm_type)) {
alarm_pin_pinalarm_obj_t *alarm = MP_OBJ_TO_PTR(alarms[i]);
gpio_set_pin_function(alarm->pin->number, GPIO_PIN_FUNCTION_A);
if (alarm->pull) {
if (alarm->value) {
// detect rising edge means pull down
gpio_set_pin_pull_mode(alarm->pin->number, GPIO_PULL_DOWN);
} else {
// detect falling edge means pull up
gpio_set_pin_pull_mode(alarm->pin->number, GPIO_PULL_UP);
}
}
if (deep_sleep) {
// Tamper Pins: IN0:PB00; IN1:PB02; IN2:PA02; IN3:PC00; IN4:PC01; OUT:PB01
// Only these pins can do TAMPER
if (alarm->pin != &pin_PB00 && alarm->pin != &pin_PB02 &&
alarm->pin != &pin_PA02) {
mp_raise_ValueError(translate("Pin cannot wake from Deep Sleep"));
}
pinalarm_on = true;
SAMD_ALARM_FLAG |= SAMD_ALARM_FLAG_PIN;
// 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 = 1; // 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
// that the PULL and VALUE values are possible to
// implement with TAMPER, and throw value errors if
// not.
// A VM reset will occur before deep sleep
// starts, so either init these settings now and
// protect them with a `never_reset` function, or
// store them all in static variables and only
// actually implement the settings in
// `alarm_pin_pinalarm_prepare_for_deep_sleep`
// below.
} // use else-if here if RTC-TAMPER can wake from IDLE
else {
// Light sleep so turn on EIC channel
set_eic_handler(alarm->channel, EIC_HANDLER_ALARM);
turn_on_eic_channel(alarm->channel, EIC_CONFIG_SENSE0_RISE_Val);
}
// TODO: Set up light sleep / fake deep sleep alarms.
// PORT/EVSYS should have more valid pin combinations
// than the TAMPER system. Check if there is a valid
// PORT/EVSYS combination, set it up, and reserve it with
// the tables at the start of this file so it can't be
// reused. Also set up IRQ callbacks and any other
// busywork.
// TODO: Might want to reserve or otherwise interact with
// peripherals/sam_d5x/external_interrupts.c or events.c here
// TODO: Even if an alarm is being set for deep sleep, it
// still needs to be able to wake from fake deep sleep,
// which is actually just like a light sleep. If the
// RTC Tamper IRQs are capable of waking from IDLE mode,
// this isn't a big deal, and there can be a strict
// if-else statement here. Otherwise, it will need to
// either set PORT and TAMPER IRQs simultaniously, or if that
// isn't possible, make a new function that can shunt fake deep
// sleep setup to common_hal_alarm_pretending_deep_sleep
}
}
}
void alarm_pin_pinalarm_prepare_for_deep_sleep(void) {
// TODO: This function is called after the VM reset, right before
// the program actually enters deep sleep. If the VM reset
// (see port_reset) resets any pins/EVSYS settings/RTC values
// needed by the pinalarms, this function is responsible for setting them
// back up again.
}

View File

@ -0,0 +1,50 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Lucian Copeland for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ALARM_PINALARM_H
#define MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ALARM_PINALARM_H
#include "py/obj.h"
#include "py/objtuple.h"
typedef struct {
mp_obj_base_t base;
const mcu_pin_obj_t *pin;
bool value;
bool pull;
uint8_t channel;
} alarm_pin_pinalarm_obj_t;
mp_obj_t alarm_pin_pinalarm_find_triggered_alarm(size_t n_alarms, const mp_obj_t *alarms);
mp_obj_t alarm_pin_pinalarm_create_wakeup_alarm(void);
void pin_alarm_callback(uint8_t num);
void alarm_pin_pinalarm_reset(void);
void alarm_pin_pinalarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms);
void alarm_pin_pinalarm_prepare_for_deep_sleep(void);
bool alarm_pin_pinalarm_woke_this_cycle(void);
#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ALARM_PINALARM_H

View File

@ -0,0 +1,168 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Lucian Copeland for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/runtime.h"
#include "hpl/pm/hpl_pm_base.h"
// #include <stdio.h>
#include "shared-bindings/alarm/time/TimeAlarm.h"
#include "shared-bindings/time/__init__.h"
#include "common-hal/alarm/__init__.h"
#include "supervisor/port.h"
STATIC volatile bool woke_up;
STATIC uint32_t deep_sleep_ticks;
// TODO: replace timealarm_on with SAMD_ALARM_FLAG bit flags
STATIC volatile 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
// value of the Compare register. This must be calculated from the
// setup values in port.c. Should be ~3 days. Give it some margin.
//
// UPDATE: for deep sleep at least, it's far more than 3 days since
// prescalar is set to 1024. (2^32)/32 seconds so >1500 days?
self->monotonic_time = monotonic_time;
}
mp_float_t common_hal_alarm_time_timealarm_get_monotonic_time(alarm_time_timealarm_obj_t *self) {
return self->monotonic_time;
}
mp_obj_t alarm_time_timealarm_find_triggered_alarm(size_t n_alarms, const mp_obj_t *alarms) {
// TODO: this function currently assumes you can only have a single TimeAlarm
// If you want to support more, it will need to somehow detect which one went off.
for (size_t i = 0; i < n_alarms; i++) {
if (mp_obj_is_type(alarms[i], &alarm_time_timealarm_type)) {
return alarms[i];
}
}
return mp_const_none;
}
mp_obj_t alarm_time_timealarm_create_wakeup_alarm(void) {
alarm_time_timealarm_obj_t *timer = m_new_obj(alarm_time_timealarm_obj_t);
timer->base.type = &alarm_time_timealarm_type;
// TODO: Set monotonic_time based on the RTC state.
// Or don't, most of the other ports don't have this either.
timer->monotonic_time = 0.0f;
return timer;
}
void time_alarm_callback(void) {
if (timealarm_on) {
RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_CMP1; // 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;
SAMD_ALARM_FLAG &= ~SAMD_ALARM_FLAG_TIME; // clear flag
}
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;
for (size_t i = 0; i < n_alarms; i++) {
if (!mp_obj_is_type(alarms[i], &alarm_time_timealarm_type)) {
continue;
}
if (timealarm_set) {
mp_raise_ValueError(translate("Only one alarm.time alarm can be set."));
}
timealarm = MP_OBJ_TO_PTR(alarms[i]);
timealarm_set = true;
}
if (!timealarm_set) {
return;
}
// Compute how long to actually sleep, considering the time now.
mp_float_t now_secs = uint64_to_float(common_hal_time_monotonic_ms()) / 1000.0f;
uint32_t wakeup_in_secs = MAX(0.0f, timealarm->monotonic_time - now_secs);
uint32_t wakeup_in_ticks = wakeup_in_secs * 1024;
// In the deep sleep case, we can't start the timer until the USB delay has finished
// (otherwise it will go off while USB enumerates, and we'll risk entering deep sleep
// without any way to wake up again)
if (deep_sleep) {
deep_sleep_ticks = wakeup_in_ticks;
} else {
deep_sleep_ticks = 0;
}
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;
SAMD_ALARM_FLAG |= SAMD_ALARM_FLAG_TIME; // set TimeAlarm flag
// 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);
// 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
// time_alarm_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
// COMP[1], since port.c uses COMP[0] already and needs to set that for
// things like the USB enumeration delay.
// If true deep sleep is called, it will either ignore or overwrite the above setup depending on
// whether it is shorter or longer than the USB delay
// printf("set deep alarm finished\n");
}
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
// 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) {
}
deep_sleep_ticks = 0;
}
}

View File

@ -0,0 +1,46 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Lucian Copeland for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ALARM_TIMEALARM_H
#define MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ALARM_TIMEALARM_H
#include "py/obj.h"
typedef struct {
mp_obj_base_t base;
mp_float_t monotonic_time; // values compatible with time.monotonic_time()
} alarm_time_timealarm_obj_t;
mp_obj_t alarm_time_timealarm_find_triggered_alarm(size_t n_alarms, const mp_obj_t *alarms);
mp_obj_t alarm_time_timealarm_create_wakeup_alarm(void);
void time_alarm_callback(void);
bool alarm_time_timealarm_woke_this_cycle(void);
void alarm_time_timealarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms);
void alarm_time_timealarm_reset(void);
void alarm_time_timealarm_prepare_for_deep_sleep(void);
#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ALARM_TIMEALARM_H

View File

@ -0,0 +1,32 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Lucian Copeland for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "shared-bindings/alarm/touch/TouchAlarm.h"
#include "shared-bindings/microcontroller/__init__.h"
void common_hal_alarm_touch_touchalarm_construct(alarm_touch_touchalarm_obj_t *self, const mcu_pin_obj_t *pin) {
mp_raise_NotImplementedError(translate("Touch alarms not available"));
}

View File

@ -0,0 +1,35 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Lucian Copeland for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ALARM_TOUCHALARM_H
#define MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ALARM_TOUCHALARM_H
typedef struct {
mp_obj_base_t base;
const mcu_pin_obj_t *pin;
} alarm_touch_touchalarm_obj_t;
#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ALARM_TOUCHALARM_H

View File

@ -29,6 +29,7 @@
#include "common-hal/rotaryio/IncrementalEncoder.h"
#include "common-hal/countio/Counter.h"
#include "shared-bindings/microcontroller/__init__.h"
#include "common-hal/alarm/pin/PinAlarm.h"
// #include "samd/external_interrupts.h"
#include "eic_handler.h"
@ -66,6 +67,12 @@ void shared_eic_handler(uint8_t channel) {
break;
#endif
#if CIRCUITPY_ALARM
case EIC_HANDLER_ALARM:
pin_alarm_callback(channel);
break;
#endif
default:
break;
}

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

@ -98,6 +98,8 @@ CIRCUITPY_TOUCHIO_USE_NATIVE = 0
# The ?='s allow overriding in mpconfigboard.mk.
CIRCUITPY_ALARM ?= 0
CIRCUITPY_PS2IO ?= 1
CIRCUITPY_SAMD ?= 1
CIRCUITPY_RGBMATRIX ?= $(CIRCUITPY_FULL_BUILD)

View File

@ -90,6 +90,12 @@
#include "common-hal/rtc/RTC.h"
#endif
#if CIRCUITPY_ALARM
#include "common-hal/alarm/__init__.h"
#include "common-hal/alarm/time/TimeAlarm.h"
#include "common-hal/alarm/pin/PinAlarm.h"
#endif
#if CIRCUITPY_TOUCHIO_USE_NATIVE
#include "common-hal/touchio/TouchIn.h"
#endif
@ -215,6 +221,10 @@ static void rtc_init(void) {
#endif
#ifdef SAM_D5X_E5X
hri_mclk_set_APBAMASK_RTC_bit(MCLK);
#if CIRCUITPY_ALARM
// Cache TAMPID for wake up cause
(void)alarm_get_wakeup_cause();
#endif
RTC->MODE0.CTRLA.bit.SWRST = true;
while (RTC->MODE0.SYNCBUSY.bit.SWRST != 0) {
}
@ -512,6 +522,18 @@ void RTC_Handler(void) {
// Do things common to all ports when the tick occurs
supervisor_tick();
}
#if CIRCUITPY_ALARM
if (intflag & RTC_MODE0_INTFLAG_CMP1) {
// Likely TimeAlarm fake sleep wake
time_alarm_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
#endif
if (intflag & RTC_MODE0_INTFLAG_CMP0) {
// Clear the interrupt because we may have hit a sleep