Merge pull request #4236 from jun2sak/nrf52-sleep
sleep and wakeup for nrf52
This commit is contained in:
commit
d4d96bb25f
|
@ -681,6 +681,7 @@ msgid "Cannot vary frequency on a timer that is already in use"
|
|||
msgstr ""
|
||||
|
||||
#: ports/esp32s2/common-hal/alarm/pin/PinAlarm.c
|
||||
#: ports/nrf/common-hal/alarm/pin/PinAlarm.c
|
||||
msgid "Cannot wake on pin edge. Only level."
|
||||
msgstr ""
|
||||
|
||||
|
@ -1285,7 +1286,8 @@ msgstr ""
|
|||
#: ports/atmel-samd/common-hal/audioio/AudioOut.c
|
||||
#: ports/atmel-samd/common-hal/touchio/TouchIn.c
|
||||
#: ports/esp32s2/common-hal/alarm/touch/TouchAlarm.c
|
||||
#: ports/esp32s2/common-hal/touchio/TouchIn.c shared-bindings/pwmio/PWMOut.c
|
||||
#: ports/esp32s2/common-hal/touchio/TouchIn.c
|
||||
#: ports/nrf/common-hal/alarm/pin/PinAlarm.c shared-bindings/pwmio/PWMOut.c
|
||||
#: shared-module/rgbmatrix/RGBMatrix.c
|
||||
msgid "Invalid pin"
|
||||
msgstr ""
|
||||
|
@ -1663,6 +1665,7 @@ msgid "Only one TouchAlarm can be set in deep sleep."
|
|||
msgstr ""
|
||||
|
||||
#: ports/esp32s2/common-hal/alarm/time/TimeAlarm.c
|
||||
#: ports/nrf/common-hal/alarm/time/TimeAlarm.c
|
||||
msgid "Only one alarm.time alarm can be set."
|
||||
msgstr ""
|
||||
|
||||
|
|
1
main.c
1
main.c
|
@ -427,6 +427,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
|
|||
// it may also return due to another interrupt, that's why we check
|
||||
// for deep sleep alarms above. If it wasn't a deep sleep alarm,
|
||||
// then we'll idle here again.
|
||||
|
||||
#if CIRCUITPY_ALARM
|
||||
common_hal_alarm_pretending_deep_sleep();
|
||||
#else
|
||||
|
|
|
@ -94,6 +94,11 @@ else
|
|||
CFLAGS += -flto -flto-partition=none
|
||||
endif
|
||||
|
||||
ifeq ($(NRF_DEBUG_PRINT), 1)
|
||||
CFLAGS += -DNRF_DEBUG_PRINT=1
|
||||
SRC_SUPERVISOR += supervisor/debug_uart.c
|
||||
endif
|
||||
|
||||
# option to override compiler optimization level, set in boards/$(BOARD)/mpconfigboard.mk
|
||||
CFLAGS += $(OPTIMIZATION_FLAGS)
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ MCU_CHIP = nrf52833
|
|||
|
||||
INTERNAL_FLASH_FILESYSTEM = 1
|
||||
|
||||
CIRCUITPY_ALARM = 0
|
||||
CIRCUITPY_AUDIOMP3 = 0
|
||||
CIRCUITPY_BITBANGIO = 0
|
||||
CIRCUITPY_BITMAPTOOLS = 0
|
||||
|
|
|
@ -10,6 +10,7 @@ MCU_CHIP = nrf52833
|
|||
|
||||
INTERNAL_FLASH_FILESYSTEM = 1
|
||||
|
||||
CIRCUITPY_ALARM = 0
|
||||
CIRCUITPY_AESIO = 1
|
||||
CIRCUITPY_AUDIOMP3 = 0
|
||||
CIRCUITPY_BITMAPTOOLS = 0
|
||||
|
@ -24,6 +25,8 @@ CIRCUITPY_MSGPACK = 0
|
|||
CIRCUITPY_NEOPIXEL_WRITE = 0
|
||||
CIRCUITPY_NVM = 0
|
||||
CIRCUITPY_PIXELBUF = 0
|
||||
CIRCUITPY_PULSEIO = 0
|
||||
CIRCUITPY_PWMIO = 1
|
||||
CIRCUITPY_RGBMATRIX = 0
|
||||
CIRCUITPY_ROTARYIO = 0
|
||||
CIRCUITPY_RTC = 1
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Junji Sakai
|
||||
*
|
||||
* 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/__init__.h"
|
||||
#include "common-hal/alarm/SleepMemory.h"
|
||||
#include "nrf_power.h"
|
||||
|
||||
#ifdef NRF_DEBUG_PRINT
|
||||
extern void dbg_dump_RAMreg(void);
|
||||
#include "supervisor/serial.h" // dbg_printf()
|
||||
#endif
|
||||
|
||||
__attribute__((section(".uninitialized"))) static uint8_t _sleepmem[SLEEP_MEMORY_LENGTH];
|
||||
__attribute__((section(".uninitialized"))) uint8_t sleepmem_wakeup_event;
|
||||
__attribute__((section(".uninitialized"))) uint8_t sleepmem_wakeup_pin;
|
||||
__attribute__((section(".uninitialized"))) static uint32_t _sleepmem_magicnum;
|
||||
#define SLEEP_MEMORY_DATA_GUARD 0xad0000af
|
||||
#define SLEEP_MEMORY_DATA_GUARD_MASK 0xff0000ff
|
||||
|
||||
static int is_sleep_memory_valid(void) {
|
||||
if ((_sleepmem_magicnum & SLEEP_MEMORY_DATA_GUARD_MASK)
|
||||
== SLEEP_MEMORY_DATA_GUARD) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void set_memory_retention(void) {
|
||||
// set RAM[n].POWER register for RAM retention
|
||||
// nRF52840 has RAM[0..7].Section[0..1] and RAM[8].Section[0..5]
|
||||
// nRF52833 has RAM[0..7].Section[0..1] and RAM[8].Section[0,1]
|
||||
for(int block = 0; block <= 7; ++block) {
|
||||
nrf_power_rampower_mask_on(NRF_POWER, block,
|
||||
NRF_POWER_RAMPOWER_S0RETENTION_MASK |
|
||||
NRF_POWER_RAMPOWER_S1RETENTION_MASK);
|
||||
};
|
||||
#ifdef NRF52840
|
||||
nrf_power_rampower_mask_on(NRF_POWER, 8,
|
||||
NRF_POWER_RAMPOWER_S0RETENTION_MASK |
|
||||
NRF_POWER_RAMPOWER_S1RETENTION_MASK |
|
||||
NRF_POWER_RAMPOWER_S2RETENTION_MASK |
|
||||
NRF_POWER_RAMPOWER_S3RETENTION_MASK |
|
||||
NRF_POWER_RAMPOWER_S4RETENTION_MASK |
|
||||
NRF_POWER_RAMPOWER_S5RETENTION_MASK);
|
||||
#endif
|
||||
#ifdef NRF52833
|
||||
nrf_power_rampower_mask_on(NRF_POWER, 8,
|
||||
NRF_POWER_RAMPOWER_S0RETENTION_MASK |
|
||||
NRF_POWER_RAMPOWER_S1RETENTION_MASK);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void initialize_sleep_memory(void) {
|
||||
memset((uint8_t *)_sleepmem, 0, SLEEP_MEMORY_LENGTH);
|
||||
sleepmem_wakeup_event = 0;
|
||||
sleepmem_wakeup_pin = 0;
|
||||
|
||||
set_memory_retention();
|
||||
#ifdef NRF_DEBUG_PRINT
|
||||
//dbg_dump_RAMreg();
|
||||
#endif
|
||||
|
||||
_sleepmem_magicnum = SLEEP_MEMORY_DATA_GUARD;
|
||||
}
|
||||
|
||||
void alarm_sleep_memory_reset(void) {
|
||||
if (!is_sleep_memory_valid()) {
|
||||
initialize_sleep_memory();
|
||||
#ifdef NRF_DEBUG_PRINT
|
||||
dbg_printf("sleep memory initialized\r\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t common_hal_alarm_sleep_memory_get_length(alarm_sleep_memory_obj_t *self) {
|
||||
return sizeof(_sleepmem);
|
||||
}
|
||||
|
||||
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) {
|
||||
if (start_index + len > sizeof(_sleepmem)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy((uint8_t *) (_sleepmem + start_index), values, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
void common_hal_alarm_sleep_memory_get_bytes(alarm_sleep_memory_obj_t *self, uint32_t start_index, uint8_t* values, uint32_t len) {
|
||||
if (start_index + len > sizeof(_sleepmem)) {
|
||||
return;
|
||||
}
|
||||
memcpy(values, (uint8_t *) (_sleepmem + start_index), len);
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Junji Sakai
|
||||
*
|
||||
* 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_NRF_COMMON_HAL_ALARM_SLEEPMEMORY_H
|
||||
#define MICROPY_INCLUDED_NRF_COMMON_HAL_ALARM_SLEEPMEMORY_H
|
||||
|
||||
#include "py/obj.h"
|
||||
|
||||
#define SLEEP_MEMORY_LENGTH (256)
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
} alarm_sleep_memory_obj_t;
|
||||
|
||||
extern void set_memory_retention(void);
|
||||
extern void alarm_sleep_memory_reset(void);
|
||||
|
||||
#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_ALARM_SLEEPMEMORY_H
|
|
@ -0,0 +1,349 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
|
||||
* Copyright (c) 2020 Dan Halbert for Adafruit Industries
|
||||
* Copyright (c) 2021 Junji Sakai
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <string.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/alarm/touch/TouchAlarm.h"
|
||||
#include "shared-bindings/time/__init__.h"
|
||||
|
||||
#include "supervisor/port.h"
|
||||
#include "supervisor/serial.h" // serial_connected()
|
||||
#ifdef NRF_DEBUG_PRINT
|
||||
#include "supervisor/serial.h" // dbg_printf()
|
||||
extern int dbg_check_RTCprescaler(void);
|
||||
#endif
|
||||
#include "supervisor/qspi_flash.h"
|
||||
|
||||
#include "nrf.h"
|
||||
#include "nrf_power.h"
|
||||
#include "nrfx.h"
|
||||
#include "nrfx_gpiote.h"
|
||||
|
||||
// Singleton instance of SleepMemory.
|
||||
const alarm_sleep_memory_obj_t alarm_sleep_memory_obj = {
|
||||
.base = {
|
||||
.type = &alarm_sleep_memory_type,
|
||||
},
|
||||
};
|
||||
|
||||
void alarm_reset(void) {
|
||||
alarm_sleep_memory_reset();
|
||||
alarm_pin_pinalarm_reset();
|
||||
alarm_time_timealarm_reset();
|
||||
alarm_touch_touchalarm_reset();
|
||||
}
|
||||
|
||||
extern uint32_t reset_reason_saved;
|
||||
STATIC nrf_sleep_source_t _get_wakeup_cause(void) {
|
||||
if (alarm_pin_pinalarm_woke_us_up()) {
|
||||
return NRF_SLEEP_WAKEUP_GPIO;
|
||||
}
|
||||
if (alarm_time_timealarm_woke_us_up()) {
|
||||
return NRF_SLEEP_WAKEUP_TIMER;
|
||||
}
|
||||
if (alarm_touch_touchalarm_woke_us_up()) {
|
||||
return NRF_SLEEP_WAKEUP_TOUCHPAD;
|
||||
}
|
||||
if (reset_reason_saved & NRF_POWER_RESETREAS_RESETPIN_MASK) {
|
||||
return NRF_SLEEP_WAKEUP_RESETPIN;
|
||||
}
|
||||
else if (reset_reason_saved & NRF_POWER_RESETREAS_OFF_MASK) {
|
||||
return NRF_SLEEP_WAKEUP_GPIO;
|
||||
}
|
||||
else if (reset_reason_saved & NRF_POWER_RESETREAS_VBUS_MASK) {
|
||||
return NRF_SLEEP_WAKEUP_VBUS;
|
||||
}
|
||||
return NRF_SLEEP_WAKEUP_UNDEFINED;
|
||||
}
|
||||
|
||||
#ifdef NRF_DEBUG_PRINT
|
||||
static const char* cause_str[] = {
|
||||
"UNDEFINED",
|
||||
"GPIO",
|
||||
"TIMER",
|
||||
"TOUCHPAD",
|
||||
"VBUS",
|
||||
"RESETPIN",
|
||||
};
|
||||
void print_wakeup_cause(nrf_sleep_source_t cause) {
|
||||
if (cause >= 0 && cause < NRF_SLEEP_WAKEUP_ZZZ) {
|
||||
dbg_printf("wakeup cause = NRF_SLEEP_WAKEUP_%s\r\n",
|
||||
cause_str[(int)cause]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool common_hal_alarm_woken_from_sleep(void) {
|
||||
nrf_sleep_source_t cause = _get_wakeup_cause();
|
||||
#ifdef NRF_DEBUG_PRINT
|
||||
if (cause != NRF_SLEEP_WAKEUP_UNDEFINED) {
|
||||
//print_wakeup_cause(cause);
|
||||
}
|
||||
#endif
|
||||
return (cause == NRF_SLEEP_WAKEUP_GPIO || cause == NRF_SLEEP_WAKEUP_TIMER
|
||||
|| cause == NRF_SLEEP_WAKEUP_TOUCHPAD);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t _get_wake_alarm(size_t n_alarms, const mp_obj_t *alarms) {
|
||||
nrf_sleep_source_t cause = _get_wakeup_cause();
|
||||
switch (cause) {
|
||||
case NRF_SLEEP_WAKEUP_TIMER: {
|
||||
return alarm_time_timealarm_get_wakeup_alarm(n_alarms, alarms);
|
||||
}
|
||||
case NRF_SLEEP_WAKEUP_TOUCHPAD: {
|
||||
return alarm_touch_touchalarm_get_wakeup_alarm(n_alarms, alarms);
|
||||
}
|
||||
case NRF_SLEEP_WAKEUP_GPIO: {
|
||||
return alarm_pin_pinalarm_get_wakeup_alarm(n_alarms, alarms);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t common_hal_alarm_get_wake_alarm(void) {
|
||||
mp_obj_t obj = _get_wake_alarm(0, NULL);
|
||||
return obj;
|
||||
}
|
||||
|
||||
// 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);
|
||||
alarm_touch_touchalarm_set_alarm(deep_sleep, n_alarms, alarms);
|
||||
}
|
||||
|
||||
// TODO: this handles all possible types of wakeup, which is redundant with main.
|
||||
// revise to extract all parts essential to enabling sleep wakeup, but leave the
|
||||
// alarm/non-alarm sorting to the existing main loop.
|
||||
void system_on_idle_until_alarm(int64_t timediff_ms, uint32_t prescaler) {
|
||||
bool have_timeout = false;
|
||||
uint64_t start_tick = 0, end_tick = 0;
|
||||
int64_t tickdiff;
|
||||
|
||||
#if defined(MICROPY_QSPI_CS)
|
||||
qspi_flash_enter_sleep();
|
||||
#endif
|
||||
|
||||
if (timediff_ms != -1) {
|
||||
have_timeout = true;
|
||||
#if 0
|
||||
int64_t now = common_hal_time_monotonic_ms();
|
||||
dbg_printf("now_ms=%ld timediff_ms=%ld\r\n", (long)now, (long)timediff_ms);
|
||||
#endif
|
||||
if (timediff_ms < 0) timediff_ms = 0;
|
||||
if (prescaler == 0) {
|
||||
// 1 tick = 1/1024 sec = 1000/1024 ms
|
||||
// -> 1 ms = 1024/1000 ticks
|
||||
tickdiff = (mp_uint_t)(timediff_ms * 1024 / 1000); // ms -> ticks
|
||||
}
|
||||
else {
|
||||
// 1 tick = prescaler/1024 sec = prescaler*1000/1024 ms
|
||||
// -> 1ms = 1024/(1000*prescaler) ticks
|
||||
tickdiff = (mp_uint_t)(timediff_ms * 1024 / (1000 * prescaler));
|
||||
}
|
||||
start_tick = port_get_raw_ticks(NULL);
|
||||
end_tick = start_tick + tickdiff;
|
||||
}
|
||||
#if 0
|
||||
dbg_printf("start_tick=%ld end_tick=%ld have_timeout=%c\r\n", (long)start_tick, (long)end_tick, have_timeout ? 'T' : 'F');
|
||||
#endif
|
||||
|
||||
int64_t remaining;
|
||||
sleepmem_wakeup_event = SLEEPMEM_WAKEUP_BY_NONE;
|
||||
sleepmem_wakeup_pin = WAKEUP_PIN_UNDEF;
|
||||
|
||||
#ifdef NRF_DEBUG_PRINT
|
||||
int ct = 40;
|
||||
char reason = '?';
|
||||
#define WAKEUP_REASON(x) reason = (x)
|
||||
#else
|
||||
#define WAKEUP_REASON(x)
|
||||
#endif
|
||||
|
||||
while(1) {
|
||||
if (mp_hal_is_interrupted()) {
|
||||
WAKEUP_REASON('I');
|
||||
break;
|
||||
}
|
||||
if (serial_connected() && serial_bytes_available()) {
|
||||
WAKEUP_REASON('S');
|
||||
break;
|
||||
}
|
||||
RUN_BACKGROUND_TASKS;
|
||||
if (common_hal_alarm_woken_from_sleep()) {
|
||||
WAKEUP_REASON('W');
|
||||
break;
|
||||
}
|
||||
if (have_timeout) {
|
||||
remaining = end_tick - port_get_raw_ticks(NULL);
|
||||
// We break a bit early so we don't risk setting the alarm before the time when we call
|
||||
// sleep.
|
||||
if (remaining < 1) {
|
||||
WAKEUP_REASON('t');
|
||||
break;
|
||||
}
|
||||
port_interrupt_after_ticks(remaining);
|
||||
}
|
||||
// Idle until an interrupt happens.
|
||||
port_idle_until_interrupt();
|
||||
#ifdef NRF_DEBUG_PRINT
|
||||
if (ct > 0) {
|
||||
dbg_printf("_");
|
||||
--ct;
|
||||
}
|
||||
#endif
|
||||
if (have_timeout) {
|
||||
remaining = end_tick - port_get_raw_ticks(NULL);
|
||||
if (remaining <= 0) {
|
||||
sleepmem_wakeup_event = SLEEPMEM_WAKEUP_BY_TIMER;
|
||||
WAKEUP_REASON('T');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef NRF_DEBUG_PRINT
|
||||
dbg_printf("%c\r\n", reason);
|
||||
#endif
|
||||
|
||||
#if defined(MICROPY_QSPI_CS)
|
||||
qspi_flash_exit_sleep();
|
||||
#endif
|
||||
|
||||
#ifdef NRF_DEBUG_PRINT
|
||||
tickdiff = port_get_raw_ticks(NULL) - start_tick;
|
||||
double sec;
|
||||
if (prescaler == 0) {
|
||||
sec = (double)tickdiff / 1024;
|
||||
}
|
||||
else {
|
||||
sec = (double)(tickdiff * prescaler) / 1024;
|
||||
}
|
||||
dbg_printf("lapse %6.1f sec\r\n", sec);
|
||||
#endif
|
||||
}
|
||||
|
||||
mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj_t *alarms) {
|
||||
mp_obj_t wake_alarm;
|
||||
alarm_time_timealarm_clear_wakeup_time();
|
||||
_setup_sleep_alarms(false, n_alarms, alarms);
|
||||
|
||||
#ifdef NRF_DEBUG_PRINT
|
||||
dbg_printf("\r\nlight sleep...");
|
||||
#endif
|
||||
|
||||
int64_t timediff_ms = alarm_time_timealarm_get_wakeup_timediff_ms();
|
||||
system_on_idle_until_alarm(timediff_ms, 0);
|
||||
|
||||
if (mp_hal_is_interrupted()) {
|
||||
wake_alarm = mp_const_none;
|
||||
}
|
||||
else {
|
||||
wake_alarm = _get_wake_alarm(n_alarms, alarms);
|
||||
}
|
||||
alarm_reset();
|
||||
return wake_alarm;
|
||||
}
|
||||
|
||||
void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms) {
|
||||
alarm_time_timealarm_clear_wakeup_time();
|
||||
_setup_sleep_alarms(true, n_alarms, alarms);
|
||||
}
|
||||
|
||||
#define PRESCALER_VALUE_IN_DEEP_SLEEP (1024)
|
||||
|
||||
void NORETURN common_hal_alarm_enter_deep_sleep(void) {
|
||||
alarm_pin_pinalarm_prepare_for_deep_sleep();
|
||||
alarm_time_timealarm_prepare_for_deep_sleep();
|
||||
|
||||
#ifdef NRF_DEBUG_PRINT
|
||||
dbg_printf("\r\ndeep sleep...");
|
||||
#endif
|
||||
int64_t timediff_ms = alarm_time_timealarm_get_wakeup_timediff_ms();
|
||||
tick_set_prescaler(PRESCALER_VALUE_IN_DEEP_SLEEP -1);
|
||||
#ifdef NRF_DEBUG_PRINT
|
||||
dbg_check_RTCprescaler(); //XXX
|
||||
#endif
|
||||
system_on_idle_until_alarm(timediff_ms, PRESCALER_VALUE_IN_DEEP_SLEEP);
|
||||
|
||||
#ifdef NRF_DEBUG_PRINT
|
||||
dbg_printf("RESET...\r\n\r\n");
|
||||
#endif
|
||||
|
||||
reset_cpu();
|
||||
|
||||
// should not reach here..
|
||||
while(1) ;
|
||||
}
|
||||
|
||||
// old version deep sleep code that was used in common_hal_alarm_enter_deep_sleep()
|
||||
// for anyone who might want true System OFF sleep ..
|
||||
#if 0
|
||||
void OLD_go_system_off(void) {
|
||||
sleepmem_wakeup_event = SLEEPMEM_WAKEUP_BY_NONE;
|
||||
sleepmem_wakeup_pin = WAKEUP_PIN_UNDEF;
|
||||
uint8_t sd_enabled;
|
||||
sd_softdevice_is_enabled(&sd_enabled);
|
||||
set_memory_retention();
|
||||
dbg_printf("OLD go system off.. %d\r\n", sd_enabled);
|
||||
if (sd_enabled) {
|
||||
sd_power_system_off();
|
||||
}
|
||||
else {
|
||||
NRF_POWER->SYSTEMOFF = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void common_hal_alarm_pretending_deep_sleep(void) {
|
||||
alarm_pin_pinalarm_prepare_for_deep_sleep();
|
||||
alarm_time_timealarm_prepare_for_deep_sleep();
|
||||
|
||||
#ifdef NRF_DEBUG_PRINT
|
||||
dbg_printf("\r\npretending to deep sleep...");
|
||||
#endif
|
||||
|
||||
int64_t timediff_ms = alarm_time_timealarm_get_wakeup_timediff_ms();
|
||||
system_on_idle_until_alarm(timediff_ms, 0);
|
||||
|
||||
alarm_reset();
|
||||
}
|
||||
|
||||
void common_hal_alarm_gc_collect(void) {
|
||||
gc_collect_ptr(shared_alarm_get_wake_alarm());
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Dan Halbert for Adafruit Industries.
|
||||
* Copyright (c) 2021 Junji Sakai
|
||||
*
|
||||
* 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_NRF_COMMON_HAL_ALARM__INIT__H
|
||||
#define MICROPY_INCLUDED_NRF_COMMON_HAL_ALARM__INIT__H
|
||||
|
||||
#include "common-hal/alarm/SleepMemory.h"
|
||||
|
||||
typedef enum {
|
||||
NRF_SLEEP_WAKEUP_UNDEFINED,
|
||||
NRF_SLEEP_WAKEUP_GPIO,
|
||||
NRF_SLEEP_WAKEUP_TIMER,
|
||||
NRF_SLEEP_WAKEUP_TOUCHPAD,
|
||||
NRF_SLEEP_WAKEUP_VBUS,
|
||||
NRF_SLEEP_WAKEUP_RESETPIN,
|
||||
NRF_SLEEP_WAKEUP_ZZZ
|
||||
} nrf_sleep_source_t;
|
||||
|
||||
extern const alarm_sleep_memory_obj_t alarm_sleep_memory_obj;
|
||||
|
||||
enum {
|
||||
SLEEPMEM_WAKEUP_BY_NONE = 0,
|
||||
SLEEPMEM_WAKEUP_BY_PIN = 1,
|
||||
SLEEPMEM_WAKEUP_BY_TIMER = 2,
|
||||
};
|
||||
#define WAKEUP_PIN_UNDEF 0xFF
|
||||
extern uint8_t sleepmem_wakeup_event;
|
||||
extern uint8_t sleepmem_wakeup_pin;
|
||||
|
||||
extern void alarm_reset(void);
|
||||
|
||||
#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_ALARM__INIT__H
|
|
@ -0,0 +1,242 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Dan Halbert for Adafruit Industries
|
||||
* Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
|
||||
* Copyright (c) 2021 Junji Sakai
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <assert.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"
|
||||
|
||||
#include "nrfx.h"
|
||||
#include "nrf_gpio.h"
|
||||
#include "nrfx_gpiote.h"
|
||||
#include "nrf_soc.h"
|
||||
#include <string.h>
|
||||
|
||||
#include "supervisor/serial.h" // dbg_print
|
||||
|
||||
#define WPIN_UNUSED 0xFF
|
||||
volatile char _pinhandler_gpiote_count;
|
||||
static bool pins_configured = false;
|
||||
|
||||
extern uint32_t reset_reason_saved;
|
||||
extern void dbg_dump_GPIOregs(void);
|
||||
|
||||
void common_hal_alarm_pin_pinalarm_construct(alarm_pin_pinalarm_obj_t *self, mcu_pin_obj_t *pin, bool value, bool edge, bool pull) {
|
||||
if (edge) {
|
||||
mp_raise_ValueError(translate("Cannot wake on pin edge. Only level."));
|
||||
}
|
||||
if (pin->number >= NUMBER_OF_PINS) {
|
||||
mp_raise_ValueError(translate("Invalid pin"));
|
||||
}
|
||||
self->pin = pin;
|
||||
self->value = value;
|
||||
self->pull = pull;
|
||||
}
|
||||
|
||||
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 false;
|
||||
}
|
||||
|
||||
bool common_hal_alarm_pin_pinalarm_get_pull(alarm_pin_pinalarm_obj_t *self) {
|
||||
return self->pull;
|
||||
}
|
||||
|
||||
|
||||
static void pinalarm_gpiote_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) {
|
||||
++_pinhandler_gpiote_count;
|
||||
sleepmem_wakeup_event = SLEEPMEM_WAKEUP_BY_PIN;
|
||||
sleepmem_wakeup_pin = pin & 0xFF;
|
||||
}
|
||||
|
||||
bool alarm_pin_pinalarm_woke_us_up(void) {
|
||||
return (sleepmem_wakeup_event == SLEEPMEM_WAKEUP_BY_PIN &&
|
||||
sleepmem_wakeup_pin != WAKEUP_PIN_UNDEF);
|
||||
}
|
||||
|
||||
mp_obj_t alarm_pin_pinalarm_get_wakeup_alarm(size_t n_alarms, const mp_obj_t *alarms) {
|
||||
// First, check to see if we match any given 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]);
|
||||
if (alarm->pin->number == sleepmem_wakeup_pin) {
|
||||
return alarms[i];
|
||||
}
|
||||
}
|
||||
alarm_pin_pinalarm_obj_t *alarm = m_new_obj(alarm_pin_pinalarm_obj_t);
|
||||
alarm->base.type = &alarm_pin_pinalarm_type;
|
||||
alarm->pin = NULL;
|
||||
// Map the pin number back to a pin object.
|
||||
for (size_t i = 0; i < mcu_pin_globals.map.used; i++) {
|
||||
const mcu_pin_obj_t* pin_obj = MP_OBJ_TO_PTR(mcu_pin_globals.map.table[i].value);
|
||||
if ((size_t) pin_obj->number == sleepmem_wakeup_pin) {
|
||||
alarm->pin = mcu_pin_globals.map.table[i].value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return alarm;
|
||||
}
|
||||
|
||||
// These must be static because we need to configure pulls later, right before
|
||||
// deep sleep.
|
||||
static uint64_t high_alarms = 0;
|
||||
static uint64_t low_alarms = 0;
|
||||
static uint64_t pull_pins = 0;
|
||||
|
||||
void alarm_pin_pinalarm_reset(void) {
|
||||
for (size_t i = 0; i < 64; i++) {
|
||||
uint64_t mask = 1ull << i;
|
||||
bool high = (high_alarms & mask) != 0;
|
||||
bool low = (low_alarms & mask) != 0;
|
||||
if (!(high || low)) {
|
||||
continue;
|
||||
}
|
||||
reset_pin_number(i);
|
||||
nrfx_gpiote_in_event_disable((nrfx_gpiote_pin_t)i);
|
||||
nrfx_gpiote_in_uninit((nrfx_gpiote_pin_t)i);
|
||||
}
|
||||
|
||||
high_alarms = 0;
|
||||
low_alarms = 0;
|
||||
pull_pins = 0;
|
||||
}
|
||||
|
||||
static void configure_pins_for_sleep(void) {
|
||||
nrfx_err_t err;
|
||||
if ( nrfx_gpiote_is_init() ) {
|
||||
nrfx_gpiote_uninit();
|
||||
}
|
||||
err = nrfx_gpiote_init(NRFX_GPIOTE_CONFIG_IRQ_PRIORITY);
|
||||
assert(err == NRFX_SUCCESS);
|
||||
(void)err; // to suppress unused warning
|
||||
|
||||
_pinhandler_gpiote_count = 0;
|
||||
|
||||
nrfx_gpiote_in_config_t cfg = {
|
||||
.sense = NRF_GPIOTE_POLARITY_TOGGLE,
|
||||
.pull = NRF_GPIO_PIN_PULLUP,
|
||||
.is_watcher = false,
|
||||
.hi_accuracy = true,
|
||||
.skip_gpio_setup = false
|
||||
};
|
||||
for(size_t i = 0; i < 64; ++i) {
|
||||
uint64_t mask = 1ull << i;
|
||||
if (((high_alarms & mask) == 0) && ((low_alarms & mask) == 0)) {
|
||||
continue;
|
||||
}
|
||||
if (((high_alarms & mask) != 0) && ((low_alarms & mask) == 0)) {
|
||||
cfg.sense = NRF_GPIOTE_POLARITY_LOTOHI;
|
||||
cfg.pull = ((pull_pins & mask) != 0) ?
|
||||
NRF_GPIO_PIN_PULLDOWN : NRF_GPIO_PIN_NOPULL;
|
||||
}
|
||||
else
|
||||
if (((high_alarms & mask) == 0) && ((low_alarms & mask) != 0)) {
|
||||
cfg.sense = NRF_GPIOTE_POLARITY_HITOLO;
|
||||
cfg.pull = ((pull_pins & mask) != 0) ?
|
||||
NRF_GPIO_PIN_PULLUP : NRF_GPIO_PIN_NOPULL;
|
||||
}
|
||||
else {
|
||||
cfg.sense = NRF_GPIOTE_POLARITY_TOGGLE;
|
||||
cfg.pull = NRF_GPIO_PIN_NOPULL;
|
||||
}
|
||||
err = nrfx_gpiote_in_init((nrfx_gpiote_pin_t)i, &cfg,
|
||||
pinalarm_gpiote_handler);
|
||||
assert(err == NRFX_SUCCESS);
|
||||
nrfx_gpiote_in_event_enable((nrfx_gpiote_pin_t)i, true);
|
||||
if (((high_alarms & mask) != 0) && ((low_alarms & mask) == 0)) {
|
||||
nrf_gpio_cfg_sense_set((uint32_t)i, NRF_GPIO_PIN_SENSE_HIGH);
|
||||
}
|
||||
if (((high_alarms & mask) == 0) && ((low_alarms & mask) != 0)) {
|
||||
nrf_gpio_cfg_sense_set((uint32_t)i, NRF_GPIO_PIN_SENSE_LOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void alarm_pin_pinalarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms) {
|
||||
// Bitmask of wake up settings.
|
||||
size_t high_count = 0;
|
||||
size_t low_count = 0;
|
||||
int pin_number = -1;
|
||||
|
||||
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]);
|
||||
|
||||
pin_number = alarm->pin->number;
|
||||
//dbg_printf("alarm_pin_pinalarm_set_alarms(pin#=%d, val=%d, pull=%d)\r\n", pin_number, alarm->value, alarm->pull);
|
||||
if (alarm->value) {
|
||||
high_alarms |= 1ull << pin_number;
|
||||
high_count++;
|
||||
} else {
|
||||
low_alarms |= 1ull << pin_number;
|
||||
low_count++;
|
||||
}
|
||||
if (alarm->pull) {
|
||||
pull_pins |= 1ull << pin_number;
|
||||
}
|
||||
}
|
||||
if (pin_number != -1) {
|
||||
if (!deep_sleep) {
|
||||
configure_pins_for_sleep();
|
||||
}
|
||||
else {
|
||||
// we don't setup gpio HW here but do them in
|
||||
// alarm_pin_pinalarm_prepare_for_deep_sleep() below
|
||||
reset_reason_saved = 0;
|
||||
pins_configured = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//dbg_printf("alarm_pin_pinalarm_set_alarms() no valid pins\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
void alarm_pin_pinalarm_prepare_for_deep_sleep(void) {
|
||||
if (!pins_configured) {
|
||||
configure_pins_for_sleep();
|
||||
pins_configured = true;
|
||||
#ifdef NRF_DEBUG_PRINT
|
||||
//dbg_dump_GPIOregs();
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Junji Sakai
|
||||
*
|
||||
* 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/obj.h"
|
||||
#include "py/objtuple.h"
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
mcu_pin_obj_t *pin;
|
||||
bool value;
|
||||
bool pull;
|
||||
} alarm_pin_pinalarm_obj_t;
|
||||
|
||||
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);
|
||||
mp_obj_t alarm_pin_pinalarm_get_wakeup_alarm(size_t n_alarms, const mp_obj_t *alarms);
|
||||
bool alarm_pin_pinalarm_woke_us_up(void);
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Dan Halbert for Adafruit Industries
|
||||
* Copyright (c) 2021 Junji Sakai
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
|
||||
#include "common-hal/alarm/__init__.h"
|
||||
#include "shared-bindings/alarm/time/TimeAlarm.h"
|
||||
#include "shared-bindings/time/__init__.h"
|
||||
|
||||
void common_hal_alarm_time_timealarm_construct(alarm_time_timealarm_obj_t *self, mp_float_t monotonic_time) {
|
||||
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_get_wakeup_alarm(size_t n_alarms, const mp_obj_t *alarms) {
|
||||
// First, check to see if we match
|
||||
for (size_t i = 0; i < n_alarms; i++) {
|
||||
if (MP_OBJ_IS_TYPE(alarms[i], &alarm_time_timealarm_type)) {
|
||||
return alarms[i];
|
||||
}
|
||||
}
|
||||
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.
|
||||
timer->monotonic_time = 0.0f;
|
||||
return timer;
|
||||
}
|
||||
|
||||
bool alarm_time_timealarm_woke_us_up(void) {
|
||||
return sleepmem_wakeup_event == SLEEPMEM_WAKEUP_BY_TIMER;
|
||||
}
|
||||
|
||||
int64_t wakeup_time_saved =0;
|
||||
|
||||
int64_t alarm_time_timealarm_get_wakeup_timediff_ms(void) {
|
||||
if (wakeup_time_saved == 0) {
|
||||
return -1;
|
||||
}
|
||||
return wakeup_time_saved - common_hal_time_monotonic_ms();
|
||||
}
|
||||
|
||||
void alarm_time_timealarm_clear_wakeup_time(void) {
|
||||
wakeup_time_saved = 0;
|
||||
}
|
||||
|
||||
void alarm_time_timealarm_reset(void) {
|
||||
port_disable_interrupt_after_ticks_ch(1);
|
||||
wakeup_time_saved = 0;
|
||||
}
|
||||
|
||||
void alarm_time_timealarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms) {
|
||||
bool timealarm_set = false;
|
||||
alarm_time_timealarm_obj_t *timealarm = MP_OBJ_NULL;
|
||||
wakeup_time_saved = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
wakeup_time_saved = (int64_t)(timealarm->monotonic_time * 1000.0f);
|
||||
}
|
||||
|
||||
void alarm_time_timealarm_prepare_for_deep_sleep(void) {
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Junji Sakai
|
||||
*
|
||||
* 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/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;
|
||||
|
||||
extern volatile int rtc_woke_up_counter;
|
||||
extern void port_disable_interrupt_after_ticks_ch(uint32_t channel);
|
||||
extern void port_interrupt_after_ticks_ch(uint32_t channel, uint32_t ticks);
|
||||
|
||||
// Find the alarm object that caused us to wake up or create an equivalent one.
|
||||
mp_obj_t alarm_time_timealarm_get_wakeup_alarm(size_t n_alarms, const mp_obj_t *alarms);
|
||||
// Check for the wake up alarm from pretend deep sleep.
|
||||
bool alarm_time_timealarm_woke_us_up(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);
|
||||
|
||||
extern void alarm_time_timealarm_prepare_for_deep_sleep(void);
|
||||
extern int64_t alarm_time_timealarm_get_wakeup_timediff_ms(void);
|
||||
extern void alarm_time_timealarm_clear_wakeup_time(void);
|
||||
extern void dbg_dump_RTCreg(void);
|
||||
extern void tick_set_prescaler(uint32_t prescaler_val);
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 microDev
|
||||
*
|
||||
* 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 "shared-bindings/alarm/touch/TouchAlarm.h"
|
||||
#include "shared-bindings/microcontroller/__init__.h"
|
||||
|
||||
//static volatile bool woke_up = false;
|
||||
|
||||
void common_hal_alarm_touch_touchalarm_construct(alarm_touch_touchalarm_obj_t *self, const mcu_pin_obj_t *pin) {
|
||||
mp_raise_NotImplementedError(NULL);
|
||||
(void)pin;
|
||||
}
|
||||
|
||||
mp_obj_t alarm_touch_touchalarm_get_wakeup_alarm(const size_t n_alarms, const mp_obj_t *alarms) {
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
void alarm_touch_touchalarm_set_alarm(const bool deep_sleep, const size_t n_alarms, const mp_obj_t *alarms) {
|
||||
}
|
||||
|
||||
void alarm_touch_touchalarm_prepare_for_deep_sleep(void) {
|
||||
}
|
||||
|
||||
bool alarm_touch_touchalarm_woke_us_up(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void alarm_touch_touchalarm_reset(void) {
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 microDev
|
||||
*
|
||||
* 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_COMMON_HAL_ALARM_TOUCH_TOUCHALARM_H
|
||||
#define MICROPY_INCLUDED_COMMON_HAL_ALARM_TOUCH_TOUCHALARM_H
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "common-hal/microcontroller/Pin.h"
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
const mcu_pin_obj_t *pin;
|
||||
} alarm_touch_touchalarm_obj_t;
|
||||
|
||||
// Find the alarm object that caused us to wake up or create an equivalent one.
|
||||
mp_obj_t alarm_touch_touchalarm_get_wakeup_alarm(const size_t n_alarms, const mp_obj_t *alarms);
|
||||
// Check for the wake up alarm from pretend deep sleep.
|
||||
void alarm_touch_touchalarm_set_alarm(const bool deep_sleep, const size_t n_alarms, const mp_obj_t *alarms);
|
||||
void alarm_touch_touchalarm_prepare_for_deep_sleep(void);
|
||||
bool alarm_touch_touchalarm_woke_us_up(void);
|
||||
void alarm_touch_touchalarm_reset(void);
|
||||
|
||||
#endif // MICROPY_INCLUDED_COMMON_HAL_ALARM_TOUCH_TOUCHALARM_H
|
|
@ -127,5 +127,24 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) {
|
|||
}
|
||||
|
||||
mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) {
|
||||
return RESET_REASON_UNKNOWN;
|
||||
mcu_reset_reason_t r = RESET_REASON_UNKNOWN;
|
||||
if (reset_reason_saved == 0) {
|
||||
r = RESET_REASON_POWER_ON;
|
||||
}
|
||||
else if (reset_reason_saved & POWER_RESETREAS_RESETPIN_Msk) {
|
||||
r = RESET_REASON_RESET_PIN;
|
||||
}
|
||||
else if (reset_reason_saved & POWER_RESETREAS_DOG_Msk) {
|
||||
r = RESET_REASON_WATCHDOG;
|
||||
}
|
||||
else if (reset_reason_saved & POWER_RESETREAS_SREQ_Msk) {
|
||||
r = RESET_REASON_SOFTWARE;
|
||||
}
|
||||
else if ((reset_reason_saved & POWER_RESETREAS_OFF_Msk) ||
|
||||
(reset_reason_saved & POWER_RESETREAS_LPCOMP_Msk) ||
|
||||
(reset_reason_saved & POWER_RESETREAS_NFC_Msk) ||
|
||||
(reset_reason_saved & POWER_RESETREAS_VBUS_Msk)) {
|
||||
r = RESET_REASON_DEEP_SLEEP_ALARM;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -36,4 +36,6 @@ typedef struct {
|
|||
// Stores no state currently.
|
||||
} mcu_processor_obj_t;
|
||||
|
||||
extern uint32_t reset_reason_saved;
|
||||
|
||||
#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_MICROCONTROLLER_PROCESSOR_H
|
||||
|
|
|
@ -46,6 +46,9 @@ CIRCUITPY_FRAMEBUFFERIO ?= 1
|
|||
CIRCUITPY_COUNTIO ?= 1
|
||||
CIRCUITPY_WATCHDOG ?= 1
|
||||
|
||||
# Sleep and Wakeup
|
||||
CIRCUITPY_ALARM ?= 1
|
||||
|
||||
# nRF52840-specific
|
||||
|
||||
ifeq ($(MCU_CHIP),nrf52840)
|
||||
|
|
|
@ -116,7 +116,7 @@
|
|||
|
||||
// GPIO interrupt
|
||||
#define NRFX_GPIOTE_ENABLED 1
|
||||
#define NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS 1
|
||||
#define NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS 2
|
||||
#define NRFX_GPIOTE_CONFIG_IRQ_PRIORITY 7
|
||||
|
||||
// NVM controller
|
||||
|
|
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Jun2Sak
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef NRF_DEBUG_PRINT
|
||||
|
||||
#define DEBUG_UART_TXPIN 26
|
||||
#define DEBUG_UART_RXPIN 15
|
||||
|
||||
#include "nrfx.h"
|
||||
#include "nrf_uart.h"
|
||||
#include "nrf_gpio.h"
|
||||
#include "nrf_rtc.h"
|
||||
#include "nrfx_uarte.h"
|
||||
#include "nrfx_rtc.h"
|
||||
#include "supervisor/serial.h" // dbg_printf()
|
||||
#include "shared-bindings/microcontroller/Processor.h"
|
||||
#include "common-hal/alarm/__init__.h"
|
||||
|
||||
extern const nrfx_rtc_t rtc_instance; // port.c
|
||||
extern uint32_t reset_reason_saved;
|
||||
|
||||
const nrfx_uarte_t _dbg_uart_inst = NRFX_UARTE_INSTANCE(1);
|
||||
static int _dbg_uart_initialized = 0;
|
||||
#define DBG_PBUF_LEN 80
|
||||
static char _dbg_pbuf[DBG_PBUF_LEN+1];
|
||||
|
||||
void _debug_uart_uninit(void) {
|
||||
nrf_gpio_cfg(DEBUG_UART_TXPIN,
|
||||
NRF_GPIO_PIN_DIR_INPUT,
|
||||
NRF_GPIO_PIN_INPUT_DISCONNECT,
|
||||
NRF_GPIO_PIN_NOPULL,
|
||||
NRF_GPIO_PIN_S0S1,
|
||||
NRF_GPIO_PIN_NOSENSE);
|
||||
nrfx_uarte_uninit(&_dbg_uart_inst);
|
||||
}
|
||||
|
||||
void _debug_uart_init(void) {
|
||||
//if (_dbg_uart_initialized) return;
|
||||
nrfx_uarte_config_t config = {
|
||||
.pseltxd = DEBUG_UART_TXPIN,
|
||||
.pselrxd = DEBUG_UART_RXPIN,
|
||||
.pselcts = NRF_UARTE_PSEL_DISCONNECTED,
|
||||
.pselrts = NRF_UARTE_PSEL_DISCONNECTED,
|
||||
.p_context = NULL,
|
||||
.baudrate = NRF_UART_BAUDRATE_115200,
|
||||
.interrupt_priority = 7,
|
||||
.hal_cfg = {
|
||||
.hwfc = NRF_UARTE_HWFC_DISABLED,
|
||||
.parity = NRF_UARTE_PARITY_EXCLUDED
|
||||
}
|
||||
};
|
||||
nrfx_uarte_init(&_dbg_uart_inst, &config, NULL);
|
||||
// drive config
|
||||
nrf_gpio_cfg(config.pseltxd,
|
||||
NRF_GPIO_PIN_DIR_OUTPUT,
|
||||
NRF_GPIO_PIN_INPUT_DISCONNECT,
|
||||
NRF_GPIO_PIN_PULLUP, // orig=NOPULL
|
||||
NRF_GPIO_PIN_H0H1, // orig=S0S1
|
||||
NRF_GPIO_PIN_NOSENSE);
|
||||
_dbg_uart_initialized = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
void _debug_print_substr(const char* text, uint32_t length) {
|
||||
char* data = (char*)text;
|
||||
int siz;
|
||||
while(length != 0) {
|
||||
if (length <= DBG_PBUF_LEN) {
|
||||
siz = length;
|
||||
}
|
||||
else {
|
||||
siz = DBG_PBUF_LEN;
|
||||
}
|
||||
memcpy(_dbg_pbuf, data, siz);
|
||||
_dbg_pbuf[siz] = 0;
|
||||
nrfx_uarte_tx(&_dbg_uart_inst, (uint8_t const*)_dbg_pbuf, siz);
|
||||
data += siz;
|
||||
length -= siz;
|
||||
}
|
||||
}
|
||||
|
||||
void _debug_uart_deinit(void) {
|
||||
nrfx_uarte_uninit(&_dbg_uart_inst);
|
||||
}
|
||||
|
||||
int dbg_printf(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
int ret = vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dbg_dump_RTCreg(void) {
|
||||
dbg_printf("\r\nRTC2\r\n");
|
||||
NRF_RTC_Type *r = rtc_instance.p_reg;
|
||||
dbg_printf("PRESCALER=%08X, ", (int)r->PRESCALER);
|
||||
dbg_printf("COUNTER=%08X ", (int)r->COUNTER);
|
||||
dbg_printf("INTENSET=%08X ", (int)r->INTENSET);
|
||||
dbg_printf("EVTENSET=%08X\r\n", (int)r->EVTENSET);
|
||||
dbg_printf("EVENTS_COMPARE[0..3]=%X,%X,%X,%X ", (int)r->EVENTS_COMPARE[0], (int)r->EVENTS_COMPARE[1], (int)r->EVENTS_COMPARE[2], (int)r->EVENTS_COMPARE[3]);
|
||||
dbg_printf("CC[0..3]=%08X,%08X,%08X,%08X\r\n", (int)r->CC[0], (int)r->CC[1], (int)r->CC[2], (int)r->CC[3]);
|
||||
}
|
||||
|
||||
int dbg_check_RTCprescaler(void) {
|
||||
NRF_RTC_Type *r = rtc_instance.p_reg;
|
||||
if ((int)r->PRESCALER == 0) {
|
||||
dbg_printf("****** PRESCALER == 0\r\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dbg_dump_RAMreg(void) {
|
||||
int i;
|
||||
for(i = 0; i <= 8; ++i) {
|
||||
dbg_printf(" RAM%d:%08X", i, (int)(NRF_POWER->RAM[i].POWER));
|
||||
if (i==4) dbg_printf("\r\n");
|
||||
}
|
||||
dbg_printf("\r\n");
|
||||
}
|
||||
|
||||
void dbg_dump_GPIOregs(void) {
|
||||
int i, port, col;
|
||||
|
||||
NRF_GPIO_Type *gpio[] = { NRF_P0, NRF_P1 };
|
||||
const char cnf_pull_chr[] = "-D*U"; // pull down, pull up
|
||||
const char cnf_sense_chr[] = "-?HL"; // sense high, sense low
|
||||
for(port=0, col=0; port<=1; ++port) {
|
||||
for(i=0; i<32; ++i) {
|
||||
uint32_t cnf = gpio[port]->PIN_CNF[i];
|
||||
if (cnf != 0x0002) { // changed from default value
|
||||
dbg_printf("[%d_%02d]:%c%c%c%d%c ", port, i,
|
||||
(cnf & 1) ? 'O' : 'I', // output, input
|
||||
(cnf & 2) ? 'd' : 'c', // disconnected, connected
|
||||
cnf_pull_chr[(cnf >> 2) & 3],
|
||||
(int)((cnf >> 8) & 7), // drive config 0-7
|
||||
cnf_sense_chr[(cnf >> 16) & 3]);
|
||||
if (++col >= 6) {
|
||||
dbg_printf("\r\n");
|
||||
col = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (col > 0) dbg_printf("\r\n");
|
||||
|
||||
dbg_printf("GPIOTE\r\n");
|
||||
NRF_GPIOTE_Type const *reg = NRF_GPIOTE;
|
||||
const char config_mode_chr[] = "-E-T"; // event, task
|
||||
const char config_pol_chr[] = "-HLT"; // low-to-Hi, hi-to-Low, Toggle
|
||||
const char config_outinit_chr[] = "01"; // initial value is 0 or 1
|
||||
for(i=0, col=0; i<8; ++i) {
|
||||
uint32_t conf = reg->CONFIG[i];
|
||||
if (conf != 0) { // changed from default value
|
||||
dbg_printf("CONFIG[%d]:%d_%02d,%c%c%c ", i,
|
||||
(int)((conf >> 13) & 1), (int)((conf >> 8) & 0x1F),
|
||||
config_mode_chr[conf & 3],
|
||||
config_pol_chr[(conf >> 16) & 3],
|
||||
(conf & 3) == 3 ?
|
||||
config_outinit_chr[(conf >> 20) & 1] : '-');
|
||||
if (++col >= 4) {
|
||||
dbg_printf("\r\n");
|
||||
col = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (col > 0) dbg_printf("\r\n");
|
||||
for(i=0; i<8; ++i) {
|
||||
dbg_printf("EVENTS_IN[%d]:%X ", i, (int)(reg->EVENTS_IN[i]));
|
||||
if ((i & 3) == 3) dbg_printf("\r\n");
|
||||
}
|
||||
dbg_printf("EVENTS_PORT:%X INTENSET:%08X\r\n",
|
||||
(int)(reg->EVENTS_PORT), (int)(reg->INTENSET));
|
||||
}
|
||||
|
||||
void dbg_dumpQSPIreg(void) {
|
||||
uint32_t r;
|
||||
dbg_printf("QSPI\r\n");
|
||||
r = NRF_QSPI->IFCONFIG0;
|
||||
dbg_printf("IFCONFIG0 READ=%ld write=%ld ADDR=%ld DPM=%ld PPSIZE=%ld\r\n",
|
||||
r & 7, (r >> 3) & 7, (r >> 6) & 1, (r >> 7) & 1, (r >> 12) & 1);
|
||||
r = NRF_QSPI->IFCONFIG1;
|
||||
dbg_printf("IFCONFIG1 SCKDELAY=%ld SPIMODE=%ld SCKFREQ=%ld\r\n",
|
||||
r & 0xFF, (r >> 25) & 1, (r >> 28) & 0xF);
|
||||
r = NRF_QSPI->STATUS;
|
||||
dbg_printf("STATUS DPM=%ld READY=%ld SREG=0x%02lX\r\n",
|
||||
(r >> 2) & 1, (r >> 3) & 1, (r >> 24) & 0xFF);
|
||||
r = NRF_QSPI->DPMDUR;
|
||||
dbg_printf("DPMDUR ENTER=%ld EXIT=%ld\r\n", r & 0xFFFF, (r >> 16) & 0xFFFF);
|
||||
}
|
||||
|
||||
void dbg_dump_reset_reason(void) {
|
||||
int reset_reason = (int)common_hal_mcu_processor_get_reset_reason();
|
||||
const char* rr_str[] = {
|
||||
"POWER_ON", "BROWNOUT", "SOFTWARE", "DEEPSLEEPALARM",
|
||||
"RESET_PIN", "WATCHDOG", "UNKNOWN"
|
||||
};
|
||||
dbg_printf("reset_reason=%s\r\n", rr_str[reset_reason]);
|
||||
}
|
||||
|
||||
#else /*!NRF_DEBUG_PRINT*/
|
||||
int dbg_printf(const char *fmt, ...) {
|
||||
return 0;
|
||||
}
|
||||
#endif /*!NRF_DEBUG_PRINT*/
|
|
@ -4,6 +4,7 @@
|
|||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
|
||||
* Copyright (c) 2021 Junji Sakai
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -51,6 +52,7 @@
|
|||
#include "common-hal/rtc/RTC.h"
|
||||
#include "common-hal/neopixel_write/__init__.h"
|
||||
#include "common-hal/watchdog/WatchDogTimer.h"
|
||||
#include "common-hal/alarm/__init__.h"
|
||||
|
||||
#include "shared-bindings/microcontroller/__init__.h"
|
||||
#include "shared-bindings/rtc/__init__.h"
|
||||
|
@ -73,9 +75,14 @@ static void power_warning_handler(void) {
|
|||
reset_into_safe_mode(BROWNOUT);
|
||||
}
|
||||
|
||||
#ifdef NRF_DEBUG_PRINT
|
||||
extern void _debug_uart_init(void);
|
||||
#endif
|
||||
|
||||
uint32_t reset_reason_saved = 0;
|
||||
const nrfx_rtc_t rtc_instance = NRFX_RTC_INSTANCE(2);
|
||||
|
||||
const nrfx_rtc_config_t rtc_config = {
|
||||
nrfx_rtc_config_t rtc_config = {
|
||||
.prescaler = RTC_FREQ_TO_PRESCALER(0x8000),
|
||||
.reliable = 0,
|
||||
.tick_latency = 0,
|
||||
|
@ -100,6 +107,12 @@ void rtc_handler(nrfx_rtc_int_type_t int_type) {
|
|||
supervisor_tick();
|
||||
} else if (int_type == NRFX_RTC_INT_COMPARE0) {
|
||||
nrfx_rtc_cc_set(&rtc_instance, 0, 0, false);
|
||||
} else if (int_type == NRFX_RTC_INT_COMPARE1) {
|
||||
// used in light sleep
|
||||
#if CIRCUITPY_ALARM
|
||||
sleepmem_wakeup_event = SLEEPMEM_WAKEUP_BY_TIMER;
|
||||
#endif
|
||||
nrfx_rtc_cc_set(&rtc_instance, 1, 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,6 +137,22 @@ void tick_init(void) {
|
|||
}
|
||||
}
|
||||
|
||||
void tick_uninit(void) {
|
||||
nrfx_rtc_counter_clear(&rtc_instance);
|
||||
nrfx_rtc_disable(&rtc_instance);
|
||||
nrfx_rtc_uninit(&rtc_instance);
|
||||
}
|
||||
|
||||
void tick_set_prescaler(uint32_t prescaler_val) {
|
||||
tick_uninit();
|
||||
// update of prescaler value sometimes fails if we skip this delay..
|
||||
NRFX_DELAY_US(1000);
|
||||
uint16_t prescaler_saved = rtc_config.prescaler;
|
||||
rtc_config.prescaler = prescaler_val;
|
||||
tick_init();
|
||||
rtc_config.prescaler = prescaler_saved;
|
||||
}
|
||||
|
||||
safe_mode_t port_init(void) {
|
||||
nrf_peripherals_clocks_init();
|
||||
|
||||
|
@ -153,11 +182,21 @@ safe_mode_t port_init(void) {
|
|||
analogin_init();
|
||||
#endif
|
||||
|
||||
reset_reason_saved = NRF_POWER->RESETREAS;
|
||||
// clear all RESET reason bits
|
||||
NRF_POWER->RESETREAS = reset_reason_saved;
|
||||
// clear wakeup event/pin when reset by reset-pin
|
||||
if (reset_reason_saved & NRF_POWER_RESETREAS_RESETPIN_MASK) {
|
||||
#if CIRCUITPY_ALARM
|
||||
sleepmem_wakeup_event = SLEEPMEM_WAKEUP_BY_NONE;
|
||||
#endif
|
||||
}
|
||||
|
||||
// If the board was reset by the WatchDogTimer, we may
|
||||
// need to boot into safe mode. Reset the RESETREAS bit
|
||||
// for the WatchDogTimer so we don't encounter this the
|
||||
// next time we reboot.
|
||||
if (NRF_POWER->RESETREAS & POWER_RESETREAS_DOG_Msk) {
|
||||
if (reset_reason_saved & POWER_RESETREAS_DOG_Msk) {
|
||||
NRF_POWER->RESETREAS = POWER_RESETREAS_DOG_Msk;
|
||||
uint32_t usb_reg = NRF_POWER->USBREGSTATUS;
|
||||
|
||||
|
@ -219,6 +258,10 @@ void reset_port(void) {
|
|||
#endif
|
||||
|
||||
reset_all_pins();
|
||||
|
||||
#ifdef NRF_DEBUG_PRINT
|
||||
_debug_uart_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
void reset_to_bootloader(void) {
|
||||
|
@ -295,7 +338,7 @@ void port_disable_tick(void) {
|
|||
nrfx_rtc_tick_disable(&rtc_instance);
|
||||
}
|
||||
|
||||
void port_interrupt_after_ticks(uint32_t ticks) {
|
||||
void port_interrupt_after_ticks_ch(uint32_t channel, uint32_t ticks) {
|
||||
uint32_t current_ticks = nrfx_rtc_counter_get(&rtc_instance);
|
||||
uint32_t diff = 3;
|
||||
if (ticks > diff) {
|
||||
|
@ -304,7 +347,15 @@ void port_interrupt_after_ticks(uint32_t ticks) {
|
|||
if (diff > 0xffffff) {
|
||||
diff = 0xffffff;
|
||||
}
|
||||
nrfx_rtc_cc_set(&rtc_instance, 0, current_ticks + diff, true);
|
||||
nrfx_rtc_cc_set(&rtc_instance, channel, current_ticks + diff, true);
|
||||
}
|
||||
|
||||
void port_disable_interrupt_after_ticks_ch(uint32_t channel) {
|
||||
nrfx_rtc_cc_disable(&rtc_instance, channel);
|
||||
}
|
||||
|
||||
void port_interrupt_after_ticks(uint32_t ticks) {
|
||||
port_interrupt_after_ticks_ch(0, ticks);
|
||||
}
|
||||
|
||||
void port_idle_until_interrupt(void) {
|
||||
|
@ -355,3 +406,9 @@ void HardFault_Handler(void) {
|
|||
asm ("nop;");
|
||||
}
|
||||
}
|
||||
|
||||
#if CIRCUITPY_ALARM
|
||||
// in case boards/xxx/board.c does not provide board_deinit()
|
||||
MP_WEAK void board_deinit(void) {
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -37,6 +37,31 @@
|
|||
|
||||
#include "supervisor/shared/external_flash/common_commands.h"
|
||||
#include "supervisor/shared/external_flash/qspi_flash.h"
|
||||
#ifdef NRF_DEBUG_PRINT
|
||||
#include "supervisor/serial.h" // dbg_printf()
|
||||
#endif
|
||||
|
||||
#ifdef QSPI_FLASH_POWERDOWN
|
||||
// Parameters for external QSPI Flash power-down
|
||||
// for W25Q128FV,
|
||||
// tDP (nCS high to Power-down mode) = 3us
|
||||
// tRES (nCS high to Standby mode) = 3us
|
||||
// sck_delay = max(tDP, tRES) / 62.5ns = 48 -> 50 (w/ margin)
|
||||
#define DUR_DPM_ENTER 1 // tDP in (256*62.5ns) units
|
||||
#define DUR_DPM_EXIT 1 // tRES in (256*62.5ns) units
|
||||
#define SCK_DELAY 50 // max(tDP, tRES) in (62.5ns) units
|
||||
// wait necessary just after DPM enter/exit (cut and try)
|
||||
#define WAIT_AFTER_DPM_ENTER 10 // usec
|
||||
#define WAIT_AFTER_DPM_EXIT 50 // usec
|
||||
|
||||
static int sck_delay_saved = 0;
|
||||
#endif
|
||||
|
||||
#ifdef NRF_DEBUG_PRINT
|
||||
extern void dbg_dumpQSPIreg(void);
|
||||
#else
|
||||
#define dbg_dumpQSPIreg(...)
|
||||
#endif
|
||||
|
||||
// When USB is disconnected, disable QSPI in sleep mode to save energy
|
||||
void qspi_disable(void) {
|
||||
|
@ -188,7 +213,11 @@ void spi_flash_init(void) {
|
|||
.readoc = NRF_QSPI_READOC_FASTREAD,
|
||||
.writeoc = NRF_QSPI_WRITEOC_PP,
|
||||
.addrmode = NRF_QSPI_ADDRMODE_24BIT,
|
||||
#ifdef QSPI_FLASH_POWERDOWN
|
||||
.dpmconfig = true
|
||||
#else
|
||||
.dpmconfig = false
|
||||
#endif
|
||||
},
|
||||
.phy_if = {
|
||||
.sck_freq = NRF_QSPI_FREQ_32MDIV16, // Start at a slow 2MHz and speed up once we know what we're talking to.
|
||||
|
@ -213,6 +242,13 @@ void spi_flash_init(void) {
|
|||
|
||||
// No callback for blocking API
|
||||
nrfx_qspi_init(&qspi_cfg, NULL, NULL);
|
||||
|
||||
#ifdef QSPI_FLASH_POWERDOWN
|
||||
// If pin-reset while flash is in power-down mode,
|
||||
// the flash cannot accept any commands. Send CMD_WAKE to release it.
|
||||
spi_flash_write_command(CMD_WAKE, NULL, 0);
|
||||
NRFX_DELAY_US(WAIT_AFTER_DPM_EXIT);
|
||||
#endif
|
||||
}
|
||||
|
||||
void spi_flash_init_device(const external_flash_device *device) {
|
||||
|
@ -236,3 +272,61 @@ void spi_flash_init_device(const external_flash_device *device) {
|
|||
NRF_QSPI->IFCONFIG1 &= ~QSPI_IFCONFIG1_SCKFREQ_Msk;
|
||||
NRF_QSPI->IFCONFIG1 |= sckfreq << QSPI_IFCONFIG1_SCKFREQ_Pos;
|
||||
}
|
||||
|
||||
void qspi_flash_enter_sleep(void) {
|
||||
#ifdef QSPI_FLASH_POWERDOWN
|
||||
uint32_t r;
|
||||
NRF_QSPI->DPMDUR =
|
||||
((DUR_DPM_ENTER & 0xFFFF) << 16) | (DUR_DPM_EXIT & 0xFFFF);
|
||||
// set sck_delay tempolarily
|
||||
r = NRF_QSPI->IFCONFIG1;
|
||||
sck_delay_saved = (r & QSPI_IFCONFIG1_SCKDELAY_Msk)
|
||||
>> QSPI_IFCONFIG1_SCKDELAY_Pos;
|
||||
NRF_QSPI->IFCONFIG1
|
||||
= (NRF_QSPI->IFCONFIG1 & ~QSPI_IFCONFIG1_SCKDELAY_Msk)
|
||||
| (SCK_DELAY << QSPI_IFCONFIG1_SCKDELAY_Pos);
|
||||
|
||||
// enabling IFCONFIG0.DPMENABLE here won't work.
|
||||
// -> do it in spi_flash_init()
|
||||
//NRF_QSPI->IFCONFIG0 |= QSPI_IFCONFIG0_DPMENABLE_Msk;
|
||||
//dbg_dumpQSPIreg();
|
||||
|
||||
// enter deep power-down mode (DPM)
|
||||
NRF_QSPI->IFCONFIG1 |= QSPI_IFCONFIG1_DPMEN_Msk;
|
||||
NRFX_DELAY_US(WAIT_AFTER_DPM_ENTER);
|
||||
if (!(NRF_QSPI->STATUS & QSPI_STATUS_DPM_Msk)) {
|
||||
#ifdef NRF_DEBUG_PRINT
|
||||
dbg_printf("qspi flash: DPM failed\r\n");
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
qspi_disable();
|
||||
//dbg_dumpQSPIreg();
|
||||
}
|
||||
|
||||
void qspi_flash_exit_sleep(void) {
|
||||
qspi_enable();
|
||||
|
||||
#ifdef QSPI_FLASH_POWERDOWN
|
||||
if (NRF_QSPI->STATUS & QSPI_STATUS_DPM_Msk) {
|
||||
// exit deep power-down mode
|
||||
NRF_QSPI->IFCONFIG1 &= ~QSPI_IFCONFIG1_DPMEN_Msk;
|
||||
NRFX_DELAY_US(WAIT_AFTER_DPM_EXIT);
|
||||
|
||||
if (NRF_QSPI->STATUS & QSPI_STATUS_DPM_Msk) {
|
||||
#ifdef NRF_DEBUG_PRINT
|
||||
dbg_printf("qspi flash: exiting DPM failed\r\n");
|
||||
#endif
|
||||
}
|
||||
// restore sck_delay
|
||||
if (sck_delay_saved == 0) {
|
||||
sck_delay_saved = 10; // default
|
||||
}
|
||||
NRF_QSPI->IFCONFIG1
|
||||
= (NRF_QSPI->IFCONFIG1 & ~QSPI_IFCONFIG1_SCKDELAY_Msk)
|
||||
| (sck_delay_saved << QSPI_IFCONFIG1_SCKDELAY_Pos);
|
||||
}
|
||||
//dbg_dumpQSPIreg();
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
extern void qspi_flash_enter_sleep(void);
|
||||
extern void qspi_flash_exit_sleep(void);
|
|
@ -244,6 +244,7 @@ const mp_obj_module_t alarm_module = {
|
|||
};
|
||||
|
||||
extern void port_idle_until_interrupt(void);
|
||||
|
||||
MP_WEAK void common_hal_alarm_pretending_deep_sleep(void) {
|
||||
port_idle_until_interrupt();
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
|
||||
|
@ -47,4 +48,7 @@ char serial_read(void);
|
|||
bool serial_bytes_available(void);
|
||||
bool serial_connected(void);
|
||||
|
||||
// XXX used in nrf52-sleep debug
|
||||
int dbg_printf(const char *fmt, ...)__attribute__((format (printf, 1, 2)));
|
||||
|
||||
#endif // MICROPY_INCLUDED_SUPERVISOR_SERIAL_H
|
||||
|
|
|
@ -37,6 +37,12 @@
|
|||
|
||||
#include "tusb.h"
|
||||
|
||||
#ifdef NRF_DEBUG_PRINT
|
||||
// XXX these functions are in nrf/supervisor/debug_uart.c
|
||||
extern void _debug_uart_init(void);
|
||||
extern void _debug_print_substr(const char *text, uint32_t length);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Note: DEBUG_UART currently only works on STM32,
|
||||
* enabling on another platform will cause a crash.
|
||||
|
@ -64,10 +70,17 @@ void serial_early_init(void) {
|
|||
buf_array, true);
|
||||
common_hal_busio_uart_never_reset(&debug_uart);
|
||||
#endif
|
||||
|
||||
#ifdef NRF_DEBUG_PRINT
|
||||
_debug_uart_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
void serial_init(void) {
|
||||
usb_init();
|
||||
#ifdef NRF_DEBUG_PRINT
|
||||
_debug_uart_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool serial_connected(void) {
|
||||
|
@ -146,8 +159,14 @@ void serial_write_substring(const char *text, uint32_t length) {
|
|||
|
||||
#if defined(DEBUG_UART_TX) && defined(DEBUG_UART_RX)
|
||||
int uart_errcode;
|
||||
|
||||
common_hal_busio_uart_write(&debug_uart, (const uint8_t *)text, length, &uart_errcode);
|
||||
#endif
|
||||
|
||||
#ifdef NRF_DEBUG_PRINT
|
||||
_debug_print_substr(text, length);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void serial_write(const char *text) {
|
||||
|
|
Loading…
Reference in New Issue