Merge pull request #4388 from hierophect/stm-alarm
STM32: Alarms and sleep
This commit is contained in:
commit
35ee4add63
@ -846,6 +846,10 @@ msgstr ""
|
||||
msgid "Data too large for advertisement packet"
|
||||
msgstr ""
|
||||
|
||||
#: ports/stm/common-hal/alarm/pin/PinAlarm.c
|
||||
msgid "Deep sleep pins must use a rising edge with pulldown"
|
||||
msgstr ""
|
||||
|
||||
#: shared-bindings/audiobusio/PDMIn.c
|
||||
msgid "Destination capacity is smaller than destination_length."
|
||||
msgstr ""
|
||||
@ -1670,6 +1674,10 @@ msgid ""
|
||||
"Only Windows format, uncompressed BMP supported: given header size is %d"
|
||||
msgstr ""
|
||||
|
||||
#: ports/stm/common-hal/alarm/pin/PinAlarm.c
|
||||
msgid "Only edge detection is available on this hardware"
|
||||
msgstr ""
|
||||
|
||||
#: shared-module/displayio/OnDiskBitmap.c
|
||||
#, c-format
|
||||
msgid ""
|
||||
@ -1683,6 +1691,7 @@ msgstr ""
|
||||
|
||||
#: ports/esp32s2/common-hal/alarm/time/TimeAlarm.c
|
||||
#: ports/nrf/common-hal/alarm/time/TimeAlarm.c
|
||||
#: ports/stm/common-hal/alarm/time/TimeAlarm.c
|
||||
msgid "Only one alarm.time alarm can be set."
|
||||
msgstr ""
|
||||
|
||||
@ -1758,6 +1767,10 @@ msgstr ""
|
||||
msgid "Permission denied"
|
||||
msgstr ""
|
||||
|
||||
#: ports/stm/common-hal/alarm/pin/PinAlarm.c
|
||||
msgid "Pin cannot wake from Deep Sleep"
|
||||
msgstr ""
|
||||
|
||||
#: ports/raspberrypi/bindings/rp2pio/StateMachine.c
|
||||
msgid "Pin count must be at least 1"
|
||||
msgstr ""
|
||||
@ -1776,6 +1789,11 @@ msgstr ""
|
||||
msgid "Pin does not have ADC capabilities"
|
||||
msgstr ""
|
||||
|
||||
#: ports/stm/common-hal/alarm/pin/PinAlarm.c
|
||||
#: ports/stm/common-hal/pulseio/PulseIn.c
|
||||
msgid "Pin interrupt already in use"
|
||||
msgstr ""
|
||||
|
||||
#: shared-bindings/adafruit_bus_device/SPIDevice.c
|
||||
#: shared-bindings/digitalio/DigitalInOut.c
|
||||
msgid "Pin is input only"
|
||||
@ -1789,10 +1807,6 @@ msgstr ""
|
||||
msgid "Pin must support hardware interrupts"
|
||||
msgstr ""
|
||||
|
||||
#: ports/stm/common-hal/pulseio/PulseIn.c
|
||||
msgid "Pin number already reserved by EXTI"
|
||||
msgstr ""
|
||||
|
||||
#: shared-bindings/rgbmatrix/RGBMatrix.c
|
||||
#, c-format
|
||||
msgid ""
|
||||
@ -2013,6 +2027,10 @@ msgstr ""
|
||||
msgid "Size not supported"
|
||||
msgstr ""
|
||||
|
||||
#: ports/stm/common-hal/alarm/SleepMemory.c
|
||||
msgid "Sleep Memory not available"
|
||||
msgstr ""
|
||||
|
||||
#: shared-bindings/alarm/SleepMemory.c shared-bindings/nvm/ByteArray.c
|
||||
msgid "Slice and value different lengths."
|
||||
msgstr ""
|
||||
@ -2153,6 +2171,10 @@ msgstr ""
|
||||
msgid "Total data to write is larger than %q"
|
||||
msgstr ""
|
||||
|
||||
#: ports/stm/common-hal/alarm/touch/TouchAlarm.c
|
||||
msgid "Touch alarms not available"
|
||||
msgstr ""
|
||||
|
||||
#: py/obj.c
|
||||
msgid "Traceback (most recent call last):\n"
|
||||
msgstr ""
|
||||
|
5
main.c
5
main.c
@ -297,13 +297,17 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
|
||||
stack_resize();
|
||||
filesystem_flush();
|
||||
supervisor_allocation* heap = allocate_remaining_memory();
|
||||
|
||||
// Prepare the VM state. Includes an alarm check/reset for sleep.
|
||||
start_mp(heap);
|
||||
|
||||
#if CIRCUITPY_USB
|
||||
usb_setup_with_vm();
|
||||
#endif
|
||||
|
||||
// This is where the user's python code is actually executed:
|
||||
found_main = maybe_run_list(supported_filenames, &result);
|
||||
// If that didn't work, double check the extensions
|
||||
#if CIRCUITPY_FULL_BUILD
|
||||
if (!found_main){
|
||||
found_main = maybe_run_list(double_extension_filenames, &result);
|
||||
@ -313,6 +317,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Finished executing python code. Cleanup includes a board reset.
|
||||
cleanup_after_vm(heap);
|
||||
|
||||
if (result.return_code & PYEXEC_FORCED_EXIT) {
|
||||
|
@ -79,6 +79,8 @@ bool common_hal_alarm_woken_from_sleep(void) {
|
||||
return _get_wakeup_cause() != ESP_SLEEP_WAKEUP_UNDEFINED;
|
||||
}
|
||||
|
||||
// When called to populate the global dict, the module functions create new alarm objects.
|
||||
// Otherwise, they scan the existing alarms for matches.
|
||||
STATIC mp_obj_t _get_wake_alarm(size_t n_alarms, const mp_obj_t *alarms) {
|
||||
esp_sleep_wakeup_cause_t cause = _get_wakeup_cause();
|
||||
switch (cause) {
|
||||
@ -104,6 +106,8 @@ STATIC mp_obj_t _get_wake_alarm(size_t n_alarms, const mp_obj_t *alarms) {
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
// This function is used to create a new alarm object for the global dict after deep sleep,
|
||||
// rather than finding an existing one during runtime.
|
||||
mp_obj_t common_hal_alarm_get_wake_alarm(void) {
|
||||
return _get_wake_alarm(0, NULL);
|
||||
}
|
||||
@ -121,6 +125,7 @@ STATIC void _idle_until_alarm(void) {
|
||||
RUN_BACKGROUND_TASKS;
|
||||
// Allow ctrl-C interrupt.
|
||||
if (common_hal_alarm_woken_from_sleep()) {
|
||||
// This saves the return of common_hal_alarm_get_wake_alarm through Shared Bindings
|
||||
shared_alarm_save_wake_alarm();
|
||||
return;
|
||||
}
|
||||
|
@ -38,7 +38,7 @@
|
||||
#include "components/soc/src/esp32s2/include/hal/gpio_ll.h"
|
||||
#include "components/xtensa/include/esp_debug_helpers.h"
|
||||
|
||||
void common_hal_alarm_pin_pinalarm_construct(alarm_pin_pinalarm_obj_t *self, mcu_pin_obj_t *pin, bool value, bool edge, bool pull) {
|
||||
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) {
|
||||
if (edge) {
|
||||
mp_raise_ValueError(translate("Cannot wake on pin edge. Only level."));
|
||||
}
|
||||
@ -51,7 +51,7 @@ void common_hal_alarm_pin_pinalarm_construct(alarm_pin_pinalarm_obj_t *self, mcu
|
||||
self->pull = pull;
|
||||
}
|
||||
|
||||
mcu_pin_obj_t *common_hal_alarm_pin_pinalarm_get_pin(alarm_pin_pinalarm_obj_t *self) {
|
||||
const mcu_pin_obj_t *common_hal_alarm_pin_pinalarm_get_pin(alarm_pin_pinalarm_obj_t *self) {
|
||||
return self->pin;
|
||||
}
|
||||
|
||||
@ -101,7 +101,7 @@ bool alarm_pin_pinalarm_woke_us_up(void) {
|
||||
}
|
||||
|
||||
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 light sleep, we check if we match any existing alarms
|
||||
uint64_t pin_status = ((uint64_t)pin_63_32_status) << 32 | pin_31_0_status;
|
||||
for (size_t i = 0; i < n_alarms; i++) {
|
||||
if (!mp_obj_is_type(alarms[i], &alarm_pin_pinalarm_type)) {
|
||||
@ -112,6 +112,7 @@ mp_obj_t alarm_pin_pinalarm_get_wakeup_alarm(size_t n_alarms, const mp_obj_t *al
|
||||
return alarms[i];
|
||||
}
|
||||
}
|
||||
// For deep sleep, a new alarm must be created
|
||||
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
|
||||
size_t pin_number = 64;
|
||||
if (cause == ESP_SLEEP_WAKEUP_EXT0) {
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
mcu_pin_obj_t *pin;
|
||||
const mcu_pin_obj_t *pin;
|
||||
bool value;
|
||||
bool pull;
|
||||
} alarm_pin_pinalarm_obj_t;
|
||||
|
@ -50,7 +50,7 @@ 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) {
|
||||
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) {
|
||||
if (edge) {
|
||||
mp_raise_ValueError(translate("Cannot wake on pin edge. Only level."));
|
||||
}
|
||||
@ -62,7 +62,7 @@ void common_hal_alarm_pin_pinalarm_construct(alarm_pin_pinalarm_obj_t *self, mcu
|
||||
self->pull = pull;
|
||||
}
|
||||
|
||||
mcu_pin_obj_t *common_hal_alarm_pin_pinalarm_get_pin(alarm_pin_pinalarm_obj_t *self) {
|
||||
const mcu_pin_obj_t *common_hal_alarm_pin_pinalarm_get_pin(alarm_pin_pinalarm_obj_t *self) {
|
||||
return self->pin;
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
mcu_pin_obj_t *pin;
|
||||
const mcu_pin_obj_t *pin;
|
||||
bool value;
|
||||
bool pull;
|
||||
} alarm_pin_pinalarm_obj_t;
|
||||
|
@ -220,6 +220,8 @@ SRC_C += \
|
||||
boards/$(BOARD)/board.c \
|
||||
boards/$(BOARD)/pins.c \
|
||||
peripherals/timers.c \
|
||||
peripherals/exti.c \
|
||||
peripherals/rtc.c \
|
||||
peripherals/stm32$(MCU_SERIES_LOWER)/clocks.c \
|
||||
peripherals/stm32$(MCU_SERIES_LOWER)/$(MCU_VARIANT_LOWER)/pins.c \
|
||||
peripherals/stm32$(MCU_SERIES_LOWER)/$(MCU_VARIANT_LOWER)/gpio.c \
|
||||
|
@ -17,5 +17,9 @@ MCU_PACKAGE = UFQFPN48
|
||||
LD_COMMON = boards/common_default.ld
|
||||
LD_FILE = boards/STM32F411_nvm_nofs.ld
|
||||
|
||||
# Too big for the flash
|
||||
CIRCUITPY_AUDIOCORE = 0
|
||||
CIRCUITPY_AUDIOPWMIO = 0
|
||||
CIRCUITPY_SYNTHIO = 0
|
||||
CIRCUITPY_BITMAPTOOLS = 0
|
||||
CIRCUITPY_VECTORIO = 0
|
||||
|
49
ports/stm/common-hal/alarm/SleepMemory.c
Normal file
49
ports/stm/common-hal/alarm/SleepMemory.c
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
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;
|
||||
}
|
38
ports/stm/common-hal/alarm/SleepMemory.h
Normal file
38
ports/stm/common-hal/alarm/SleepMemory.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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_STM32_COMMON_HAL_ALARM_SLEEPMEMORY_H
|
||||
#define MICROPY_INCLUDED_STM32_COMMON_HAL_ALARM_SLEEPMEMORY_H
|
||||
|
||||
#include "py/obj.h"
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
} alarm_sleep_memory_obj_t;
|
||||
|
||||
extern void alarm_sleep_memory_reset(void);
|
||||
|
||||
#endif // MICROPY_INCLUDED_STM32_COMMON_HAL_ALARM_SLEEPMEMORY_H
|
190
ports/stm/common-hal/alarm/__init__.c
Normal file
190
ports/stm/common-hal/alarm/__init__.c
Normal file
@ -0,0 +1,190 @@
|
||||
/*
|
||||
* 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 "lib/utils/interrupt_char.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 "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,
|
||||
},
|
||||
};
|
||||
|
||||
STATIC stm_sleep_source_t true_deep_wake_reason;
|
||||
STATIC mp_obj_t most_recent_alarm;
|
||||
|
||||
void alarm_reset(void) {
|
||||
most_recent_alarm = NULL;
|
||||
// Reset the alarm flag
|
||||
STM_ALARM_FLAG = 0x00;
|
||||
alarm_pin_pinalarm_reset();
|
||||
alarm_time_timealarm_reset();
|
||||
}
|
||||
|
||||
// Kind of a hack, required as RTC is reset in port.c
|
||||
// TODO: in the future, don't reset it at all, just override critical flags
|
||||
void alarm_set_wakeup_reason(stm_sleep_source_t reason) {
|
||||
true_deep_wake_reason = reason;
|
||||
}
|
||||
|
||||
STATIC stm_sleep_source_t _get_wakeup_cause(void) {
|
||||
// If in light/fake sleep, check modules
|
||||
if (alarm_pin_pinalarm_woke_us_up()) {
|
||||
return STM_WAKEUP_GPIO;
|
||||
}
|
||||
if (alarm_time_timealarm_woke_us_up()) {
|
||||
return STM_WAKEUP_RTC;
|
||||
}
|
||||
// Check to see if we woke from deep sleep (reason set in port_init)
|
||||
if (true_deep_wake_reason) {
|
||||
return true_deep_wake_reason;
|
||||
}
|
||||
return STM_WAKEUP_UNDEF;
|
||||
}
|
||||
|
||||
bool common_hal_alarm_woken_from_sleep(void) {
|
||||
return _get_wakeup_cause() != STM_WAKEUP_UNDEF;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t _get_wake_alarm(size_t n_alarms, const mp_obj_t *alarms) {
|
||||
stm_sleep_source_t cause = _get_wakeup_cause();
|
||||
switch (cause) {
|
||||
case STM_WAKEUP_RTC: {
|
||||
return alarm_time_timealarm_get_wakeup_alarm(n_alarms, alarms);
|
||||
}
|
||||
case STM_WAKEUP_GPIO: {
|
||||
return alarm_pin_pinalarm_get_wakeup_alarm(n_alarms, alarms);
|
||||
}
|
||||
case STM_WAKEUP_UNDEF:
|
||||
default:
|
||||
// Not a deep sleep reset.
|
||||
break;
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t common_hal_alarm_get_wake_alarm(void) {
|
||||
// If we woke from light sleep, override with that alarm
|
||||
if (most_recent_alarm != NULL) {
|
||||
return most_recent_alarm;
|
||||
}
|
||||
return _get_wake_alarm(0, NULL);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
STATIC void _idle_until_alarm(void) {
|
||||
// Poll for alarms.
|
||||
while (!mp_hal_is_interrupted()) {
|
||||
RUN_BACKGROUND_TASKS;
|
||||
// Detect if interrupt was alarm or ctrl-C interrupt.
|
||||
if (common_hal_alarm_woken_from_sleep()) {
|
||||
return;
|
||||
}
|
||||
port_idle_until_interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj_t *alarms) {
|
||||
// If USB is active, only pretend to sleep. Otherwise, light sleep
|
||||
if (supervisor_workflow_active()) {
|
||||
_setup_sleep_alarms(false, n_alarms, alarms);
|
||||
_idle_until_alarm();
|
||||
} else {
|
||||
_setup_sleep_alarms(false, n_alarms, alarms);
|
||||
port_disable_tick();
|
||||
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
|
||||
port_enable_tick();
|
||||
}
|
||||
|
||||
mp_obj_t wake_alarm = _get_wake_alarm(n_alarms, alarms);
|
||||
|
||||
// TODO: make assignment to global array less roundabout
|
||||
most_recent_alarm = wake_alarm;
|
||||
shared_alarm_save_wake_alarm();
|
||||
|
||||
// Can't use alarm_reset since it resets most_recent_alarm
|
||||
alarm_pin_pinalarm_reset();
|
||||
alarm_time_timealarm_reset();
|
||||
return wake_alarm;
|
||||
}
|
||||
|
||||
void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms) {
|
||||
most_recent_alarm = NULL;
|
||||
_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();
|
||||
port_disable_tick();
|
||||
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
|
||||
|
||||
// Set a flag in the backup registers to indicate sleep wakeup
|
||||
STM_ALARM_FLAG = 0x01;
|
||||
|
||||
HAL_PWR_EnterSTANDBYMode();
|
||||
|
||||
// The above shuts down RAM, so we should never hit this
|
||||
while (1) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
void common_hal_alarm_pretending_deep_sleep(void) {
|
||||
// Re-enable the WKUP pin (PA00) since VM cleanup resets it
|
||||
// If there are no PinAlarms, EXTI won't be turned on, and this won't do anything
|
||||
// TODO: replace with `prepare_for_fake_deep_sleep` if other WKUP are added.
|
||||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
GPIO_InitStruct.Pin = pin_mask(0);
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
|
||||
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
|
||||
port_idle_until_interrupt();
|
||||
}
|
||||
|
||||
void common_hal_alarm_gc_collect(void) {
|
||||
gc_collect_ptr(shared_alarm_get_wake_alarm());
|
||||
}
|
45
ports/stm/common-hal/alarm/__init__.h
Normal file
45
ports/stm/common-hal/alarm/__init__.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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_STM32_COMMON_HAL_ALARM__INIT__H
|
||||
#define MICROPY_INCLUDED_STM32_COMMON_HAL_ALARM__INIT__H
|
||||
|
||||
#include "common-hal/alarm/SleepMemory.h"
|
||||
|
||||
extern const alarm_sleep_memory_obj_t alarm_sleep_memory_obj;
|
||||
|
||||
typedef enum {
|
||||
STM_WAKEUP_UNDEF,
|
||||
STM_WAKEUP_GPIO,
|
||||
STM_WAKEUP_RTC
|
||||
} stm_sleep_source_t;
|
||||
|
||||
#define STM_ALARM_FLAG (RTC->BKP0R)
|
||||
|
||||
extern void alarm_set_wakeup_reason(stm_sleep_source_t reason);
|
||||
extern void alarm_reset(void);
|
||||
|
||||
#endif // MICROPY_INCLUDED_STM32_COMMON_HAL_ALARM__INIT__H
|
163
ports/stm/common-hal/alarm/pin/PinAlarm.c
Normal file
163
ports/stm/common-hal/alarm/pin/PinAlarm.c
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* 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 "shared-bindings/alarm/pin/PinAlarm.h"
|
||||
#include "shared-bindings/microcontroller/__init__.h"
|
||||
#include "shared-bindings/microcontroller/Pin.h"
|
||||
|
||||
#include "peripherals/exti.h"
|
||||
|
||||
STATIC bool woke_up;
|
||||
|
||||
STATIC uint16_t alarm_pin_triggered;
|
||||
STATIC bool deep_wkup_enabled;
|
||||
STATIC bool reserved_alarms[STM32_GPIO_PORT_SIZE];
|
||||
|
||||
STATIC void pin_alarm_callback(uint8_t num) {
|
||||
alarm_pin_triggered |= (1 << num);
|
||||
woke_up = true;
|
||||
HAL_GPIO_EXTI_IRQHandler(pin_mask(num));
|
||||
}
|
||||
|
||||
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) {
|
||||
if (!edge) {
|
||||
mp_raise_NotImplementedError(translate("Only edge detection is available on this hardware"));
|
||||
}
|
||||
if (!stm_peripherals_exti_is_free(pin->number)) {
|
||||
mp_raise_RuntimeError(translate("Pin interrupt already in use"));
|
||||
}
|
||||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
GPIO_InitStruct.Pin = pin_mask(pin->number);
|
||||
GPIO_InitStruct.Mode = value ? GPIO_MODE_IT_RISING : GPIO_MODE_IT_FALLING;
|
||||
// Pull is automatically set to oppose value.
|
||||
// TODO: match digitalIO API instead?
|
||||
if (value) {
|
||||
GPIO_InitStruct.Pull = pull ? GPIO_PULLDOWN : GPIO_NOPULL;
|
||||
} else {
|
||||
GPIO_InitStruct.Pull = pull ? GPIO_PULLUP : GPIO_NOPULL;
|
||||
}
|
||||
HAL_GPIO_Init(pin_port(pin->port), &GPIO_InitStruct);
|
||||
|
||||
// EXTI is set up and enabled in set_alarm
|
||||
self->pin = pin;
|
||||
self->value = value;
|
||||
self->pull = pull;
|
||||
}
|
||||
|
||||
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_us_up(void) {
|
||||
return woke_up;
|
||||
}
|
||||
|
||||
mp_obj_t alarm_pin_pinalarm_get_wakeup_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]);
|
||||
if (alarm_pin_triggered & (1 << alarm->pin->number)) {
|
||||
return alarms[i];
|
||||
}
|
||||
}
|
||||
|
||||
// If the above isn't true, we woke from deep sleep, so create a new alarm
|
||||
alarm_pin_pinalarm_obj_t *alarm = m_new_obj(alarm_pin_pinalarm_obj_t);
|
||||
alarm->base.type = &alarm_pin_pinalarm_type;
|
||||
// TODO: replace this if/when other WKUP pins are supported
|
||||
alarm->pin = &pin_PA00;
|
||||
return alarm;
|
||||
}
|
||||
|
||||
void alarm_pin_pinalarm_reset(void) {
|
||||
HAL_PWR_DisableWakeUpPin(PWR_WAKEUP_PIN1);
|
||||
alarm_pin_triggered = 0;
|
||||
woke_up = false;
|
||||
deep_wkup_enabled = false;
|
||||
for (uint8_t i = 0; i < STM32_GPIO_PORT_SIZE; i++) {
|
||||
if (reserved_alarms[i]) {
|
||||
stm_peripherals_exti_reset_exti(i);
|
||||
reserved_alarms[i] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Deep sleep alarms don't actually make use of EXTI, but we pretend they're the same.
|
||||
void alarm_pin_pinalarm_set_alarms(bool deep_sleep, 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)) {
|
||||
alarm_pin_pinalarm_obj_t *alarm = MP_OBJ_TO_PTR(alarms[i]);
|
||||
if (deep_sleep) {
|
||||
// Deep sleep only wakes on a rising edge from one pin, WKUP (PA00)
|
||||
// All pin settings are handled automatically.
|
||||
if (alarm->pin != &pin_PA00) {
|
||||
mp_raise_ValueError(translate("Pin cannot wake from Deep Sleep"));
|
||||
}
|
||||
if (alarm->value == false || alarm->pull == false) {
|
||||
// Enabling WakeUp automatically sets this, but warn anyway to set expectations
|
||||
mp_raise_ValueError(translate("Deep sleep pins must use a rising edge with pulldown"));
|
||||
}
|
||||
// We can't actually turn WakeUp on here, since enabling it disables EXTI,
|
||||
// so we put it off until right before sleeping.
|
||||
deep_wkup_enabled = true;
|
||||
// EXTI needs to persist past the VM cleanup for fake deep sleep
|
||||
stm_peripherals_exti_never_reset(alarm->pin->number);
|
||||
}
|
||||
if (!stm_peripherals_exti_reserve(alarm->pin->number)) {
|
||||
mp_raise_RuntimeError(translate("Pin interrupt already in use"));
|
||||
}
|
||||
stm_peripherals_exti_set_callback(pin_alarm_callback,alarm->pin->number);
|
||||
stm_peripherals_exti_enable(alarm->pin->number);
|
||||
reserved_alarms[alarm->pin->number] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we don't have WKUP enabled, ensure it's disabled
|
||||
// TODO; is this really required?
|
||||
void alarm_pin_pinalarm_prepare_for_deep_sleep(void) {
|
||||
if (deep_wkup_enabled) {
|
||||
HAL_PWR_DisableWakeUpPin(PWR_WAKEUP_PIN1);
|
||||
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
|
||||
HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);
|
||||
}
|
||||
}
|
46
ports/stm/common-hal/alarm/pin/PinAlarm.h
Normal file
46
ports/stm/common-hal/alarm/pin/PinAlarm.h
Normal 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_STM32_COMMON_HAL_ALARM_PINALARM_H
|
||||
#define MICROPY_INCLUDED_STM32_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;
|
||||
} 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);
|
||||
|
||||
#endif // MICROPY_INCLUDED_STM32_COMMON_HAL_ALARM_PINALARM_H
|
117
ports/stm/common-hal/alarm/time/TimeAlarm.c
Normal file
117
ports/stm/common-hal/alarm/time/TimeAlarm.c
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* 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 "shared-bindings/alarm/time/TimeAlarm.h"
|
||||
#include "shared-bindings/time/__init__.h"
|
||||
#include "supervisor/port.h"
|
||||
#include "peripherals/rtc.h"
|
||||
|
||||
#include STM32_HAL_H
|
||||
|
||||
STATIC volatile bool woke_up;
|
||||
STATIC uint32_t deep_sleep_ticks;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// This is run in the timer task. We use it to wake the main CircuitPython task.
|
||||
STATIC void timer_callback(void) {
|
||||
woke_up = true;
|
||||
}
|
||||
|
||||
bool alarm_time_timealarm_woke_us_up(void) {
|
||||
return woke_up;
|
||||
}
|
||||
|
||||
void alarm_time_timealarm_reset(void) {
|
||||
woke_up = false;
|
||||
}
|
||||
|
||||
void alarm_time_timealarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms) {
|
||||
// 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
|
||||
if (deep_sleep) {
|
||||
deep_sleep_ticks = wakeup_in_ticks;
|
||||
} else {
|
||||
deep_sleep_ticks = 0;
|
||||
}
|
||||
// Use alarm B, since port reserves A
|
||||
// If true deep sleep is called, it will either ignore or overwrite this depending on
|
||||
// whether it is shorter or longer than the USB delay
|
||||
stm32_peripherals_rtc_assign_alarm_callback(PERIPHERALS_ALARM_B,timer_callback);
|
||||
stm32_peripherals_rtc_set_alarm(PERIPHERALS_ALARM_B,wakeup_in_ticks);
|
||||
}
|
||||
|
||||
void alarm_time_timealarm_prepare_for_deep_sleep(void) {
|
||||
if (deep_sleep_ticks) {
|
||||
// This is used for both fake and real deep sleep, so it still needs the callback
|
||||
stm32_peripherals_rtc_assign_alarm_callback(PERIPHERALS_ALARM_B,timer_callback);
|
||||
stm32_peripherals_rtc_set_alarm(PERIPHERALS_ALARM_B,deep_sleep_ticks);
|
||||
deep_sleep_ticks = 0;
|
||||
}
|
||||
}
|
46
ports/stm/common-hal/alarm/time/TimeAlarm.h
Normal file
46
ports/stm/common-hal/alarm/time/TimeAlarm.h
Normal 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_STM32_COMMON_HAL_ALARM_TIMEALARM_H
|
||||
#define MICROPY_INCLUDED_STM32_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;
|
||||
|
||||
// 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);
|
||||
|
||||
void alarm_time_timealarm_prepare_for_deep_sleep(void);
|
||||
|
||||
#endif // MICROPY_INCLUDED_STM32_COMMON_HAL_ALARM_TIMEALARM_H
|
32
ports/stm/common-hal/alarm/touch/TouchAlarm.c
Normal file
32
ports/stm/common-hal/alarm/touch/TouchAlarm.c
Normal 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"));
|
||||
}
|
35
ports/stm/common-hal/alarm/touch/TouchAlarm.h
Normal file
35
ports/stm/common-hal/alarm/touch/TouchAlarm.h
Normal 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_STM32_COMMON_HAL_ALARM_TOUCHALARM_H
|
||||
#define MICROPY_INCLUDED_STM32_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_STM32_COMMON_HAL_ALARM_TOUCHALARM_H
|
@ -35,17 +35,17 @@
|
||||
#include "shared-bindings/pulseio/PulseIn.h"
|
||||
#include "timers.h"
|
||||
|
||||
#include "peripherals/exti.h"
|
||||
|
||||
#include STM32_HAL_H
|
||||
|
||||
#define STM32_GPIO_PORT_SIZE 16
|
||||
static pulseio_pulsein_obj_t *_objs[STM32_GPIO_PORT_SIZE];
|
||||
STATIC pulseio_pulsein_obj_t *callback_obj_ref[STM32_GPIO_PORT_SIZE];
|
||||
|
||||
STATIC TIM_HandleTypeDef tim_handle;
|
||||
static uint32_t overflow_count = 0;
|
||||
STATIC uint32_t overflow_count = 0;
|
||||
STATIC uint8_t refcount = 0;
|
||||
|
||||
static void assign_EXTI_Interrupt(pulseio_pulsein_obj_t *self, uint8_t num);
|
||||
|
||||
void pulsein_timer_event_handler(void) {
|
||||
// Detect TIM Update event
|
||||
if (__HAL_TIM_GET_FLAG(&tim_handle, TIM_FLAG_UPDATE) != RESET) {
|
||||
@ -56,7 +56,7 @@ void pulsein_timer_event_handler(void) {
|
||||
}
|
||||
}
|
||||
|
||||
static void pulsein_exti_event_handler(uint8_t num) {
|
||||
STATIC void pulsein_exti_event_handler(uint8_t num) {
|
||||
// Grab the current time first.
|
||||
uint32_t current_overflow = overflow_count;
|
||||
uint32_t current_count = tim_handle.Instance->CNT;
|
||||
@ -64,7 +64,7 @@ static void pulsein_exti_event_handler(uint8_t num) {
|
||||
// Interrupt register must be cleared manually
|
||||
EXTI->PR = 1 << num;
|
||||
|
||||
pulseio_pulsein_obj_t *self = _objs[num];
|
||||
pulseio_pulsein_obj_t *self = callback_obj_ref[num];
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
@ -96,11 +96,11 @@ static void pulsein_exti_event_handler(uint8_t num) {
|
||||
void pulsein_reset(void) {
|
||||
// Disable all active interrupts and clear array
|
||||
for (uint i = 0; i < STM32_GPIO_PORT_SIZE; i++) {
|
||||
if (_objs[i] != NULL) {
|
||||
HAL_NVIC_DisableIRQ(_objs[i]->irq);
|
||||
if (callback_obj_ref[i] != NULL) {
|
||||
stm_peripherals_exti_disable(callback_obj_ref[i]->pin->number);
|
||||
}
|
||||
}
|
||||
memset(_objs, 0, sizeof(_objs));
|
||||
memset(callback_obj_ref, 0, sizeof(callback_obj_ref));
|
||||
|
||||
HAL_TIM_Base_DeInit(&tim_handle);
|
||||
tim_clock_disable(stm_peripherals_timer_get_index(tim_handle.Instance));
|
||||
@ -111,15 +111,14 @@ void pulsein_reset(void) {
|
||||
void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t *self, const mcu_pin_obj_t *pin,
|
||||
uint16_t maxlen, bool idle_state) {
|
||||
// STM32 has one shared EXTI for each pin number, 0-15
|
||||
uint8_t p_num = pin->number;
|
||||
if (_objs[p_num]) {
|
||||
mp_raise_ValueError(translate("Pin number already reserved by EXTI"));
|
||||
if (!stm_peripherals_exti_is_free(pin->number)) {
|
||||
mp_raise_RuntimeError(translate("Pin interrupt already in use"));
|
||||
}
|
||||
_objs[p_num] = self;
|
||||
|
||||
// Allocate pulse buffer
|
||||
self->buffer = (uint16_t *)m_malloc(maxlen * sizeof(uint16_t), false);
|
||||
if (self->buffer == NULL) {
|
||||
// TODO: free the EXTI here?
|
||||
mp_raise_msg_varg(&mp_type_MemoryError, translate("Failed to allocate RX buffer of %d bytes"),
|
||||
maxlen * sizeof(uint16_t));
|
||||
}
|
||||
@ -164,16 +163,21 @@ void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t *self, const mcu
|
||||
// Add to active PulseIns
|
||||
refcount++;
|
||||
|
||||
// EXTI pins can also be read as an input
|
||||
if (!stm_peripherals_exti_reserve(pin->number)) {
|
||||
mp_raise_RuntimeError(translate("Pin interrupt already in use"));
|
||||
}
|
||||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
GPIO_InitStruct.Pin = pin_mask(pin->number);
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(pin_port(pin->port), &GPIO_InitStruct);
|
||||
|
||||
stm_peripherals_exti_set_callback(pulsein_exti_event_handler, pin->number);
|
||||
// Store PulseIn object for use in callback
|
||||
callback_obj_ref[pin->number] = self;
|
||||
// Interrupt starts immediately
|
||||
assign_EXTI_Interrupt(self, pin->number);
|
||||
HAL_NVIC_EnableIRQ(self->irq);
|
||||
stm_peripherals_exti_enable(pin->number);
|
||||
|
||||
common_hal_mcu_pin_claim(pin);
|
||||
}
|
||||
|
||||
@ -186,7 +190,8 @@ void common_hal_pulseio_pulsein_deinit(pulseio_pulsein_obj_t *self) {
|
||||
return;
|
||||
}
|
||||
// Remove pulsein slot from shared array
|
||||
_objs[self->pin->number] = NULL;
|
||||
callback_obj_ref[self->pin->number] = NULL;
|
||||
stm_peripherals_exti_free(self->pin->number);
|
||||
reset_pin_number(self->pin->port, self->pin->number);
|
||||
self->pin = NULL;
|
||||
|
||||
@ -197,7 +202,7 @@ void common_hal_pulseio_pulsein_deinit(pulseio_pulsein_obj_t *self) {
|
||||
}
|
||||
|
||||
void common_hal_pulseio_pulsein_pause(pulseio_pulsein_obj_t *self) {
|
||||
HAL_NVIC_DisableIRQ(self->irq);
|
||||
stm_peripherals_exti_disable(self->pin->number);
|
||||
self->paused = true;
|
||||
}
|
||||
|
||||
@ -231,27 +236,27 @@ void common_hal_pulseio_pulsein_resume(pulseio_pulsein_obj_t *self, uint16_t tri
|
||||
self->last_count = 0;
|
||||
self->last_overflow = 0;
|
||||
|
||||
HAL_NVIC_EnableIRQ(self->irq);
|
||||
stm_peripherals_exti_enable(self->pin->number);
|
||||
}
|
||||
|
||||
void common_hal_pulseio_pulsein_clear(pulseio_pulsein_obj_t *self) {
|
||||
HAL_NVIC_DisableIRQ(self->irq);
|
||||
stm_peripherals_exti_disable(self->pin->number);
|
||||
self->start = 0;
|
||||
self->len = 0;
|
||||
HAL_NVIC_EnableIRQ(self->irq);
|
||||
stm_peripherals_exti_enable(self->pin->number);
|
||||
}
|
||||
|
||||
uint16_t common_hal_pulseio_pulsein_get_item(pulseio_pulsein_obj_t *self, int16_t index) {
|
||||
HAL_NVIC_DisableIRQ(self->irq);
|
||||
stm_peripherals_exti_disable(self->pin->number);
|
||||
if (index < 0) {
|
||||
index += self->len;
|
||||
}
|
||||
if (index < 0 || index >= self->len) {
|
||||
HAL_NVIC_EnableIRQ(self->irq);
|
||||
stm_peripherals_exti_enable(self->pin->number);
|
||||
mp_raise_IndexError_varg(translate("%q index out of range"), MP_QSTR_PulseIn);
|
||||
}
|
||||
uint16_t value = self->buffer[(self->start + index) % self->maxlen];
|
||||
HAL_NVIC_EnableIRQ(self->irq);
|
||||
stm_peripherals_exti_enable(self->pin->number);
|
||||
return value;
|
||||
}
|
||||
|
||||
@ -259,11 +264,11 @@ uint16_t common_hal_pulseio_pulsein_popleft(pulseio_pulsein_obj_t *self) {
|
||||
if (self->len == 0) {
|
||||
mp_raise_IndexError_varg(translate("pop from empty %q"), MP_QSTR_PulseIn);
|
||||
}
|
||||
HAL_NVIC_DisableIRQ(self->irq);
|
||||
stm_peripherals_exti_disable(self->pin->number);
|
||||
uint16_t value = self->buffer[self->start];
|
||||
self->start = (self->start + 1) % self->maxlen;
|
||||
self->len--;
|
||||
HAL_NVIC_EnableIRQ(self->irq);
|
||||
stm_peripherals_exti_enable(self->pin->number);
|
||||
|
||||
return value;
|
||||
}
|
||||
@ -279,55 +284,3 @@ bool common_hal_pulseio_pulsein_get_paused(pulseio_pulsein_obj_t *self) {
|
||||
uint16_t common_hal_pulseio_pulsein_get_len(pulseio_pulsein_obj_t *self) {
|
||||
return self->len;
|
||||
}
|
||||
|
||||
static void assign_EXTI_Interrupt(pulseio_pulsein_obj_t *self, uint8_t num) {
|
||||
if (num == 0) {
|
||||
self->irq = EXTI0_IRQn;
|
||||
} else if (num == 1) {
|
||||
self->irq = EXTI1_IRQn;
|
||||
} else if (num == 2) {
|
||||
self->irq = EXTI2_IRQn;
|
||||
} else if (num == 3) {
|
||||
self->irq = EXTI3_IRQn;
|
||||
} else if (num == 4) {
|
||||
self->irq = EXTI4_IRQn;
|
||||
} else if (num >= 5 && num <= 9) {
|
||||
self->irq = EXTI9_5_IRQn;
|
||||
} else if (num >= 10 && num <= 15) {
|
||||
self->irq = EXTI15_10_IRQn;
|
||||
}
|
||||
}
|
||||
|
||||
void EXTI0_IRQHandler(void) {
|
||||
pulsein_exti_event_handler(0);
|
||||
}
|
||||
void EXTI1_IRQHandler(void) {
|
||||
pulsein_exti_event_handler(1);
|
||||
}
|
||||
void EXTI2_IRQHandler(void) {
|
||||
pulsein_exti_event_handler(2);
|
||||
}
|
||||
void EXTI3_IRQHandler(void) {
|
||||
pulsein_exti_event_handler(3);
|
||||
}
|
||||
void EXTI4_IRQHandler(void) {
|
||||
pulsein_exti_event_handler(4);
|
||||
}
|
||||
|
||||
void EXTI9_5_IRQHandler(void) {
|
||||
uint32_t pending = EXTI->PR;
|
||||
for (uint i = 5; i <= 9; i++) {
|
||||
if (pending & (1 << i)) {
|
||||
pulsein_exti_event_handler(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EXTI15_10_IRQHandler(void) {
|
||||
uint32_t pending = EXTI->PR;
|
||||
for (uint i = 10; i <= 15; i++) {
|
||||
if (pending & (1 << i)) {
|
||||
pulsein_exti_event_handler(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,6 @@ typedef struct {
|
||||
mp_obj_base_t base;
|
||||
|
||||
const mcu_pin_obj_t *pin;
|
||||
IRQn_Type irq;
|
||||
bool idle_state;
|
||||
bool paused;
|
||||
volatile bool first_edge;
|
||||
|
@ -3,6 +3,7 @@ LONGINT_IMPL ?= MPZ
|
||||
INTERNAL_LIBM ?= 1
|
||||
|
||||
ifeq ($(MCU_VARIANT),$(filter $(MCU_VARIANT),STM32F405xx STM32F407xx))
|
||||
CIRCUITPY_ALARM = 1
|
||||
CIRCUITPY_CANIO = 1
|
||||
CIRCUITPY_FRAMEBUFFERIO ?= 1
|
||||
CIRCUITPY_SDIOIO ?= 1
|
||||
@ -41,7 +42,7 @@ ifeq ($(MCU_SERIES),H7)
|
||||
CIRCUITPY_NEOPIXEL_WRITE ?= 0
|
||||
CIRCUITPY_NVM ?= 0
|
||||
CIRCUITPY_PULSEIO ?= 0
|
||||
CIRCUITPY_PWMIO ?= 0
|
||||
CIRCUITPY_PWMIO ?= 0
|
||||
CIRCUITPY_ROTARYIO ?= 0
|
||||
CIRCUITPY_RTC ?= 0
|
||||
CIRCUITPY_USB_HID ?= 0
|
||||
|
144
ports/stm/peripherals/exti.c
Normal file
144
ports/stm/peripherals/exti.c
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* This file is part of the Micro Python 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 <stdbool.h>
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/gc.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
#include "peripherals/exti.h"
|
||||
|
||||
#if !(CPY_STM32H7)
|
||||
|
||||
STATIC bool stm_exti_reserved[STM32_GPIO_PORT_SIZE];
|
||||
STATIC bool stm_exti_never_reset[STM32_GPIO_PORT_SIZE];
|
||||
STATIC void (*stm_exti_callback[STM32_GPIO_PORT_SIZE])(uint8_t num);
|
||||
|
||||
void exti_reset(void) {
|
||||
for (size_t i = 0; i < STM32_GPIO_PORT_SIZE; i++) {
|
||||
if (!stm_exti_never_reset[i]) {
|
||||
stm_exti_reserved[i] = false;
|
||||
stm_exti_callback[i] = NULL;
|
||||
stm_peripherals_exti_disable(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void stm_peripherals_exti_never_reset(uint8_t num) {
|
||||
stm_exti_never_reset[num] = true;
|
||||
}
|
||||
|
||||
void stm_peripherals_exti_reset_exti(uint8_t num) {
|
||||
stm_peripherals_exti_disable(num);
|
||||
stm_exti_never_reset[num] = false;
|
||||
stm_exti_reserved[num] = false;
|
||||
stm_exti_callback[num] = NULL;
|
||||
}
|
||||
|
||||
bool stm_peripherals_exti_is_free(uint8_t num) {
|
||||
return !stm_exti_reserved[num];
|
||||
}
|
||||
|
||||
bool stm_peripherals_exti_reserve(uint8_t num) {
|
||||
if (!stm_peripherals_exti_is_free(num)) {
|
||||
return false;
|
||||
}
|
||||
stm_exti_reserved[num] = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void stm_peripherals_exti_enable(uint8_t num) {
|
||||
HAL_NVIC_EnableIRQ(stm_peripherals_exti_get_irq(num));
|
||||
}
|
||||
|
||||
void stm_peripherals_exti_disable(uint8_t num) {
|
||||
HAL_NVIC_DisableIRQ(stm_peripherals_exti_get_irq(num));
|
||||
}
|
||||
|
||||
void stm_peripherals_exti_set_callback(void (*callback)(uint8_t num), uint8_t number) {
|
||||
stm_exti_callback[number] = callback;
|
||||
}
|
||||
|
||||
void stm_peripherals_exti_free(uint8_t num) {
|
||||
stm_exti_reserved[num] = true;
|
||||
}
|
||||
|
||||
IRQn_Type stm_peripherals_exti_get_irq(uint8_t num) {
|
||||
if (num == 0) {
|
||||
return EXTI0_IRQn;
|
||||
} else if (num == 1) {
|
||||
return EXTI1_IRQn;
|
||||
} else if (num == 2) {
|
||||
return EXTI2_IRQn;
|
||||
} else if (num == 3) {
|
||||
return EXTI3_IRQn;
|
||||
} else if (num == 4) {
|
||||
return EXTI4_IRQn;
|
||||
} else if (num >= 5 && num <= 9) {
|
||||
return EXTI9_5_IRQn;
|
||||
} else if (num >= 10 && num <= 15) {
|
||||
return EXTI15_10_IRQn;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void EXTI0_IRQHandler(void) {
|
||||
stm_exti_callback[0](0);
|
||||
}
|
||||
void EXTI1_IRQHandler(void) {
|
||||
stm_exti_callback[1](1);
|
||||
}
|
||||
void EXTI2_IRQHandler(void) {
|
||||
stm_exti_callback[2](2);
|
||||
}
|
||||
void EXTI3_IRQHandler(void) {
|
||||
stm_exti_callback[3](3);
|
||||
}
|
||||
void EXTI4_IRQHandler(void) {
|
||||
stm_exti_callback[4](4);
|
||||
}
|
||||
|
||||
void EXTI9_5_IRQHandler(void) {
|
||||
uint32_t pending = EXTI->PR;
|
||||
for (uint i = 5; i <= 9; i++) {
|
||||
if (pending & (1 << i)) {
|
||||
stm_exti_callback[i](i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EXTI15_10_IRQHandler(void) {
|
||||
uint32_t pending = EXTI->PR;
|
||||
for (uint i = 10; i <= 15; i++) {
|
||||
if (pending & (1 << i)) {
|
||||
stm_exti_callback[i](i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
45
ports/stm/peripherals/exti.h
Normal file
45
ports/stm/peripherals/exti.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* This file is part of the Micro Python 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_STM32_PERIPHERALS_EXTI_H__
|
||||
#define __MICROPY_INCLUDED_STM32_PERIPHERALS_EXTI_H__
|
||||
|
||||
#include STM32_HAL_H
|
||||
|
||||
#define STM32_GPIO_PORT_SIZE 16
|
||||
|
||||
void exti_reset(void);
|
||||
void stm_peripherals_exti_never_reset(uint8_t num);
|
||||
void stm_peripherals_exti_reset_exti(uint8_t num);
|
||||
bool stm_peripherals_exti_is_free(uint8_t num);
|
||||
bool stm_peripherals_exti_reserve(uint8_t num);
|
||||
void stm_peripherals_exti_enable(uint8_t num);
|
||||
void stm_peripherals_exti_disable(uint8_t num);
|
||||
void stm_peripherals_exti_set_callback(void (*callback)(uint8_t num), uint8_t number);
|
||||
void stm_peripherals_exti_free(uint8_t num);
|
||||
IRQn_Type stm_peripherals_exti_get_irq(uint8_t num);
|
||||
|
||||
#endif // __MICROPY_INCLUDED_STM32_PERIPHERALS_EXTI_H__
|
230
ports/stm/peripherals/rtc.c
Normal file
230
ports/stm/peripherals/rtc.c
Normal file
@ -0,0 +1,230 @@
|
||||
/*
|
||||
* This file is part of the Micro Python 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 "peripherals/rtc.h"
|
||||
#include STM32_HAL_H
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/gc.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "lib/timeutils/timeutils.h"
|
||||
|
||||
// Default period for ticks is 1/1024 second
|
||||
#define TICK_DIVISOR 1024
|
||||
|
||||
STATIC RTC_HandleTypeDef hrtc;
|
||||
|
||||
#if BOARD_HAS_LOW_SPEED_CRYSTAL
|
||||
STATIC uint32_t rtc_clock_frequency = LSE_VALUE;
|
||||
#else
|
||||
STATIC uint32_t rtc_clock_frequency = LSI_VALUE;
|
||||
#endif
|
||||
|
||||
volatile uint32_t seconds_to_date = 0;
|
||||
volatile uint32_t cached_date = 0;
|
||||
volatile uint32_t seconds_to_minute = 0;
|
||||
volatile uint32_t cached_hours_minutes = 0;
|
||||
|
||||
volatile bool alarmed_already[2];
|
||||
|
||||
bool peripherals_wkup_on = false;
|
||||
|
||||
static void (*wkup_callback)(void);
|
||||
static void (*alarm_callbacks[2])(void);
|
||||
|
||||
uint32_t stm32_peripherals_get_rtc_freq(void) {
|
||||
return rtc_clock_frequency;
|
||||
}
|
||||
|
||||
void stm32_peripherals_rtc_init(void) {
|
||||
// RTC oscillator selection is handled in peripherals/<family>/<line>/clocks.c
|
||||
__HAL_RCC_RTC_ENABLE();
|
||||
hrtc.Instance = RTC;
|
||||
hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
|
||||
// Divide async as little as possible so that we have rtc_clock_frequency count in subseconds.
|
||||
// This ensures our timing > 1 second is correct.
|
||||
hrtc.Init.AsynchPrediv = 0x0;
|
||||
hrtc.Init.SynchPrediv = rtc_clock_frequency - 1;
|
||||
hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
|
||||
|
||||
HAL_RTC_Init(&hrtc);
|
||||
HAL_RTCEx_EnableBypassShadow(&hrtc);
|
||||
HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn);
|
||||
}
|
||||
|
||||
// This function is called often for timing so we cache the seconds elapsed computation based on the
|
||||
// register value. The STM HAL always does shifts and conversion if we use it directly.
|
||||
uint64_t stm32_peripherals_rtc_raw_ticks(uint8_t *subticks) {
|
||||
// Disable IRQs to ensure we read all of the RTC registers as close in time as possible. Read
|
||||
// SSR twice to make sure we didn't read across a tick.
|
||||
__disable_irq();
|
||||
uint32_t first_ssr = (uint32_t)(RTC->SSR);
|
||||
uint32_t time = (uint32_t)(RTC->TR & RTC_TR_RESERVED_MASK);
|
||||
uint32_t date = (uint32_t)(RTC->DR & RTC_DR_RESERVED_MASK);
|
||||
uint32_t ssr = (uint32_t)(RTC->SSR);
|
||||
while (ssr != first_ssr) {
|
||||
first_ssr = ssr;
|
||||
time = (uint32_t)(RTC->TR & RTC_TR_RESERVED_MASK);
|
||||
date = (uint32_t)(RTC->DR & RTC_DR_RESERVED_MASK);
|
||||
ssr = (uint32_t)(RTC->SSR);
|
||||
}
|
||||
__enable_irq();
|
||||
|
||||
uint32_t subseconds = rtc_clock_frequency - 1 - ssr;
|
||||
|
||||
if (date != cached_date) {
|
||||
uint32_t year = (uint8_t)((date & (RTC_DR_YT | RTC_DR_YU)) >> 16U);
|
||||
uint8_t month = (uint8_t)((date & (RTC_DR_MT | RTC_DR_MU)) >> 8U);
|
||||
uint8_t day = (uint8_t)(date & (RTC_DR_DT | RTC_DR_DU));
|
||||
// Add 2000 since the year is only the last two digits.
|
||||
year = 2000 + (uint32_t)RTC_Bcd2ToByte(year);
|
||||
month = (uint8_t)RTC_Bcd2ToByte(month);
|
||||
day = (uint8_t)RTC_Bcd2ToByte(day);
|
||||
seconds_to_date = timeutils_seconds_since_2000(year, month, day, 0, 0, 0);
|
||||
cached_date = date;
|
||||
}
|
||||
uint32_t hours_minutes = time & (RTC_TR_HT | RTC_TR_HU | RTC_TR_MNT | RTC_TR_MNU);
|
||||
if (hours_minutes != cached_hours_minutes) {
|
||||
uint8_t hours = (uint8_t)((time & (RTC_TR_HT | RTC_TR_HU)) >> 16U);
|
||||
uint8_t minutes = (uint8_t)((time & (RTC_TR_MNT | RTC_TR_MNU)) >> 8U);
|
||||
hours = (uint8_t)RTC_Bcd2ToByte(hours);
|
||||
minutes = (uint8_t)RTC_Bcd2ToByte(minutes);
|
||||
seconds_to_minute = 60 * (60 * hours + minutes);
|
||||
cached_hours_minutes = hours_minutes;
|
||||
}
|
||||
uint8_t seconds = (uint8_t)(time & (RTC_TR_ST | RTC_TR_SU));
|
||||
seconds = (uint8_t)RTC_Bcd2ToByte(seconds);
|
||||
if (subticks != NULL) {
|
||||
*subticks = subseconds % 32;
|
||||
}
|
||||
|
||||
uint64_t raw_ticks = ((uint64_t)TICK_DIVISOR) * (seconds_to_date + seconds_to_minute + seconds) + subseconds / 32;
|
||||
return raw_ticks;
|
||||
}
|
||||
|
||||
void stm32_peripherals_rtc_assign_wkup_callback(void (*callback)(void)) {
|
||||
wkup_callback = callback;
|
||||
}
|
||||
|
||||
void stm32_peripherals_rtc_set_wakeup_mode_seconds(uint32_t seconds) {
|
||||
// prep stuff from CubeMX
|
||||
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
|
||||
__HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(&hrtc, RTC_FLAG_WUTF);
|
||||
|
||||
HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, (rtc_clock_frequency / 16) * seconds, RTC_WAKEUPCLOCK_RTCCLK_DIV16);
|
||||
}
|
||||
|
||||
void stm32_peripherals_rtc_set_wakeup_mode_tick(void) {
|
||||
HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, (rtc_clock_frequency / 16) / TICK_DIVISOR, RTC_WAKEUPCLOCK_RTCCLK_DIV2);
|
||||
}
|
||||
|
||||
void stm32_peripherals_rtc_enable_wakeup_timer(void) {
|
||||
peripherals_wkup_on = true;
|
||||
HAL_NVIC_SetPriority(RTC_WKUP_IRQn, 1, 0U);
|
||||
HAL_NVIC_EnableIRQ(RTC_WKUP_IRQn);
|
||||
}
|
||||
|
||||
void stm32_peripherals_rtc_disable_wakeup_timer(void) {
|
||||
peripherals_wkup_on = false;
|
||||
HAL_NVIC_DisableIRQ(RTC_WKUP_IRQn);
|
||||
HAL_RTCEx_DeactivateWakeUpTimer(&hrtc);
|
||||
}
|
||||
|
||||
void stm32_peripherals_rtc_reset_alarms(void) {
|
||||
HAL_RTC_DeactivateAlarm(&hrtc, RTC_ALARM_A);
|
||||
HAL_RTC_DeactivateAlarm(&hrtc, RTC_ALARM_B);
|
||||
}
|
||||
|
||||
void stm32_peripherals_rtc_assign_alarm_callback(uint8_t alarm_idx, void (*callback)(void)) {
|
||||
alarm_callbacks[alarm_idx] = callback;
|
||||
}
|
||||
|
||||
void stm32_peripherals_rtc_set_alarm(uint8_t alarm_idx, uint32_t ticks) {
|
||||
uint64_t raw_ticks = stm32_peripherals_rtc_raw_ticks(NULL) + ticks;
|
||||
|
||||
RTC_AlarmTypeDef alarm;
|
||||
if (ticks > TICK_DIVISOR) {
|
||||
timeutils_struct_time_t tm;
|
||||
timeutils_seconds_since_2000_to_struct_time(raw_ticks / TICK_DIVISOR, &tm);
|
||||
alarm.AlarmTime.Hours = tm.tm_hour;
|
||||
alarm.AlarmTime.Minutes = tm.tm_min;
|
||||
alarm.AlarmTime.Seconds = tm.tm_sec;
|
||||
alarm.AlarmDateWeekDay = tm.tm_mday;
|
||||
// Masking here means that the value is ignored so we set none.
|
||||
alarm.AlarmMask = RTC_ALARMMASK_NONE;
|
||||
} else {
|
||||
// Masking here means that the value is ignored so we set them all. Only the subseconds
|
||||
// value matters.
|
||||
alarm.AlarmMask = RTC_ALARMMASK_ALL;
|
||||
}
|
||||
|
||||
alarm.AlarmTime.SubSeconds = rtc_clock_frequency - 1 -
|
||||
((raw_ticks % TICK_DIVISOR) * 32);
|
||||
alarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
|
||||
alarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_SET;
|
||||
// Masking here means that the bits are ignored so we set none of them.
|
||||
alarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_NONE;
|
||||
alarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
|
||||
alarm.Alarm = (alarm_idx == PERIPHERALS_ALARM_A) ? RTC_ALARM_A : RTC_ALARM_B;
|
||||
|
||||
HAL_RTC_SetAlarm_IT(&hrtc, &alarm, RTC_FORMAT_BIN);
|
||||
HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn);
|
||||
alarmed_already[alarm_idx] = false;
|
||||
}
|
||||
|
||||
bool stm32_peripherals_rtc_alarm_triggered(uint8_t alarm_idx) {
|
||||
return alarmed_already[alarm_idx];
|
||||
}
|
||||
|
||||
void RTC_WKUP_IRQHandler(void) {
|
||||
if (wkup_callback) {
|
||||
wkup_callback();
|
||||
}
|
||||
__HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(&hrtc, RTC_FLAG_WUTF);
|
||||
__HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_FLAG();
|
||||
hrtc.State = HAL_RTC_STATE_READY;
|
||||
}
|
||||
|
||||
void RTC_Alarm_IRQHandler(void) {
|
||||
HAL_RTC_AlarmIRQHandler(&hrtc);
|
||||
}
|
||||
|
||||
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *_hrtc) {
|
||||
if (alarm_callbacks[PERIPHERALS_ALARM_A]) {
|
||||
alarm_callbacks[PERIPHERALS_ALARM_A]();
|
||||
}
|
||||
HAL_RTC_DeactivateAlarm(_hrtc, RTC_ALARM_A);
|
||||
alarmed_already[PERIPHERALS_ALARM_A] = true;
|
||||
}
|
||||
|
||||
void HAL_RTCEx_AlarmBEventCallback(RTC_HandleTypeDef *_hrtc) {
|
||||
if (alarm_callbacks[PERIPHERALS_ALARM_B]) {
|
||||
alarm_callbacks[PERIPHERALS_ALARM_B]();
|
||||
}
|
||||
HAL_RTC_DeactivateAlarm(_hrtc, RTC_ALARM_B);
|
||||
alarmed_already[PERIPHERALS_ALARM_B] = true;
|
||||
}
|
51
ports/stm/peripherals/rtc.h
Normal file
51
ports/stm/peripherals/rtc.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* This file is part of the Micro Python 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_STM32_PERIPHERALS_RTC_H__
|
||||
#define __MICROPY_INCLUDED_STM32_PERIPHERALS_RTC_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define PERIPHERALS_ALARM_A 0
|
||||
#define PERIPHERALS_ALARM_B 1
|
||||
|
||||
uint32_t stm32_peripherals_get_rtc_freq(void);
|
||||
void stm32_peripherals_rtc_init(void);
|
||||
uint64_t stm32_peripherals_rtc_raw_ticks(uint8_t *subticks);
|
||||
|
||||
void stm32_peripherals_rtc_assign_wkup_callback(void (*callback)(void));
|
||||
void stm32_peripherals_rtc_set_wakeup_mode_seconds(uint32_t seconds);
|
||||
void stm32_peripherals_rtc_set_wakeup_mode_tick(void);
|
||||
void stm32_peripherals_rtc_enable_wakeup_timer(void);
|
||||
void stm32_peripherals_rtc_disable_wakeup_timer(void);
|
||||
|
||||
void stm32_peripherals_rtc_reset_alarms(void);
|
||||
void stm32_peripherals_rtc_assign_alarm_callback(uint8_t alarm_idx, void (*callback)(void));
|
||||
void stm32_peripherals_rtc_set_alarm(uint8_t alarm_idx, uint32_t ticks);
|
||||
bool stm32_peripherals_rtc_alarm_triggered(uint8_t alarm_idx);
|
||||
|
||||
#endif // __MICROPY_INCLUDED_STM32_PERIPHERALS_RTC_H__
|
@ -48,14 +48,21 @@
|
||||
#include "common-hal/pwmio/PWMOut.h"
|
||||
#endif
|
||||
#if CIRCUITPY_PULSEIO || CIRCUITPY_PWMIO
|
||||
#include "timers.h"
|
||||
#include "peripherals/timers.h"
|
||||
#endif
|
||||
#if CIRCUITPY_SDIOIO
|
||||
#include "common-hal/sdioio/SDCard.h"
|
||||
#endif
|
||||
#if CIRCUITPY_PULSEIO || CIRCUITPY_ALARM
|
||||
#include "peripherals/exti.h"
|
||||
#endif
|
||||
#if CIRCUITPY_ALARM
|
||||
#include "common-hal/alarm/__init__.h"
|
||||
#endif
|
||||
|
||||
#include "clocks.h"
|
||||
#include "gpio.h"
|
||||
#include "peripherals/clocks.h"
|
||||
#include "peripherals/gpio.h"
|
||||
#include "peripherals/rtc.h"
|
||||
|
||||
#include STM32_HAL_H
|
||||
|
||||
@ -163,38 +170,39 @@ __attribute__((used, naked)) void Reset_Handler(void) {
|
||||
|
||||
// Low power clock variables
|
||||
static volatile uint32_t systick_ms;
|
||||
static RTC_HandleTypeDef _hrtc;
|
||||
|
||||
#if BOARD_HAS_LOW_SPEED_CRYSTAL
|
||||
static uint32_t rtc_clock_frequency = LSE_VALUE;
|
||||
#else
|
||||
static uint32_t rtc_clock_frequency = LSI_VALUE;
|
||||
#endif
|
||||
|
||||
safe_mode_t port_init(void) {
|
||||
HAL_Init(); // Turns on SysTick
|
||||
__HAL_RCC_SYSCFG_CLK_ENABLE();
|
||||
|
||||
#if (CPY_STM32F4)
|
||||
#if CPY_STM32F4
|
||||
__HAL_RCC_PWR_CLK_ENABLE();
|
||||
HAL_PWR_EnableBkUpAccess();
|
||||
|
||||
#if CIRCUITPY_ALARM
|
||||
// TODO: don't reset RTC entirely and move this back to alarm
|
||||
if (STM_ALARM_FLAG & 0x01) {
|
||||
// We've woken from deep sleep. Was it the WKUP pin or the RTC?
|
||||
if (RTC->ISR & RTC_FLAG_ALRBF) {
|
||||
// Alarm B is the deep sleep alarm
|
||||
alarm_set_wakeup_reason(STM_WAKEUP_RTC);
|
||||
} else {
|
||||
alarm_set_wakeup_reason(STM_WAKEUP_GPIO);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
__HAL_RCC_BACKUPRESET_FORCE();
|
||||
__HAL_RCC_BACKUPRESET_RELEASE();
|
||||
|
||||
#endif
|
||||
|
||||
stm32_peripherals_clocks_init();
|
||||
stm32_peripherals_gpio_init();
|
||||
stm32_peripherals_rtc_init();
|
||||
|
||||
// RTC oscillator selection is handled in peripherals/<family>/<line>/clocks.c
|
||||
__HAL_RCC_RTC_ENABLE();
|
||||
_hrtc.Instance = RTC;
|
||||
_hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
|
||||
// Divide async as little as possible so that we have rtc_clock_frequency count in subseconds.
|
||||
// This ensures our timing > 1 second is correct.
|
||||
_hrtc.Init.AsynchPrediv = 0x0;
|
||||
_hrtc.Init.SynchPrediv = rtc_clock_frequency - 1;
|
||||
_hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
|
||||
|
||||
HAL_RTC_Init(&_hrtc);
|
||||
HAL_RTCEx_EnableBypassShadow(&_hrtc);
|
||||
HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn);
|
||||
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
|
||||
stm32_peripherals_rtc_reset_alarms();
|
||||
|
||||
// Turn off SysTick
|
||||
SysTick->CTRL = 0;
|
||||
@ -223,7 +231,6 @@ uint32_t HAL_GetTick() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SysTick_Handler(void) {
|
||||
systick_ms += 1;
|
||||
// Read the CTRL register to clear the SysTick interrupt.
|
||||
@ -253,6 +260,9 @@ void reset_port(void) {
|
||||
#if CIRCUITPY_PWMIO
|
||||
pwmout_reset();
|
||||
#endif
|
||||
#if CIRCUITPY_PULSEIO || CIRCUITPY_ALARM
|
||||
exti_reset();
|
||||
#endif
|
||||
}
|
||||
|
||||
void reset_to_bootloader(void) {
|
||||
@ -324,118 +334,26 @@ __attribute__((used)) void HardFault_Handler(void) {
|
||||
}
|
||||
}
|
||||
|
||||
// This function is called often for timing so we cache the seconds elapsed computation based on the
|
||||
// register value. The STM HAL always does shifts and conversion if we use it directly.
|
||||
volatile uint32_t seconds_to_date = 0;
|
||||
volatile uint32_t cached_date = 0;
|
||||
volatile uint32_t seconds_to_minute = 0;
|
||||
volatile uint32_t cached_hours_minutes = 0;
|
||||
uint64_t port_get_raw_ticks(uint8_t *subticks) {
|
||||
// Disable IRQs to ensure we read all of the RTC registers as close in time as possible. Read
|
||||
// SSR twice to make sure we didn't read across a tick.
|
||||
__disable_irq();
|
||||
uint32_t first_ssr = (uint32_t)(RTC->SSR);
|
||||
uint32_t time = (uint32_t)(RTC->TR & RTC_TR_RESERVED_MASK);
|
||||
uint32_t date = (uint32_t)(RTC->DR & RTC_DR_RESERVED_MASK);
|
||||
uint32_t ssr = (uint32_t)(RTC->SSR);
|
||||
while (ssr != first_ssr) {
|
||||
first_ssr = ssr;
|
||||
time = (uint32_t)(RTC->TR & RTC_TR_RESERVED_MASK);
|
||||
date = (uint32_t)(RTC->DR & RTC_DR_RESERVED_MASK);
|
||||
ssr = (uint32_t)(RTC->SSR);
|
||||
}
|
||||
__enable_irq();
|
||||
|
||||
uint32_t subseconds = rtc_clock_frequency - 1 - ssr;
|
||||
|
||||
if (date != cached_date) {
|
||||
uint32_t year = (uint8_t)((date & (RTC_DR_YT | RTC_DR_YU)) >> 16U);
|
||||
uint8_t month = (uint8_t)((date & (RTC_DR_MT | RTC_DR_MU)) >> 8U);
|
||||
uint8_t day = (uint8_t)(date & (RTC_DR_DT | RTC_DR_DU));
|
||||
// Add 2000 since the year is only the last two digits.
|
||||
year = 2000 + (uint32_t)RTC_Bcd2ToByte(year);
|
||||
month = (uint8_t)RTC_Bcd2ToByte(month);
|
||||
day = (uint8_t)RTC_Bcd2ToByte(day);
|
||||
seconds_to_date = timeutils_seconds_since_2000(year, month, day, 0, 0, 0);
|
||||
cached_date = date;
|
||||
}
|
||||
uint32_t hours_minutes = time & (RTC_TR_HT | RTC_TR_HU | RTC_TR_MNT | RTC_TR_MNU);
|
||||
if (hours_minutes != cached_hours_minutes) {
|
||||
uint8_t hours = (uint8_t)((time & (RTC_TR_HT | RTC_TR_HU)) >> 16U);
|
||||
uint8_t minutes = (uint8_t)((time & (RTC_TR_MNT | RTC_TR_MNU)) >> 8U);
|
||||
hours = (uint8_t)RTC_Bcd2ToByte(hours);
|
||||
minutes = (uint8_t)RTC_Bcd2ToByte(minutes);
|
||||
seconds_to_minute = 60 * (60 * hours + minutes);
|
||||
cached_hours_minutes = hours_minutes;
|
||||
}
|
||||
uint8_t seconds = (uint8_t)(time & (RTC_TR_ST | RTC_TR_SU));
|
||||
seconds = (uint8_t)RTC_Bcd2ToByte(seconds);
|
||||
if (subticks != NULL) {
|
||||
*subticks = subseconds % 32;
|
||||
}
|
||||
|
||||
uint64_t raw_ticks = ((uint64_t)1024) * (seconds_to_date + seconds_to_minute + seconds) + subseconds / 32;
|
||||
return raw_ticks;
|
||||
}
|
||||
|
||||
void RTC_WKUP_IRQHandler(void) {
|
||||
supervisor_tick();
|
||||
__HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(&_hrtc, RTC_FLAG_WUTF);
|
||||
__HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_FLAG();
|
||||
}
|
||||
|
||||
volatile bool alarmed_already = false;
|
||||
void RTC_Alarm_IRQHandler(void) {
|
||||
HAL_RTC_DeactivateAlarm(&_hrtc, RTC_ALARM_A);
|
||||
__HAL_RTC_ALARM_EXTI_CLEAR_FLAG();
|
||||
__HAL_RTC_ALARM_CLEAR_FLAG(&_hrtc, RTC_FLAG_ALRAF);
|
||||
alarmed_already = true;
|
||||
return stm32_peripherals_rtc_raw_ticks(subticks);
|
||||
}
|
||||
|
||||
// Enable 1/1024 second tick.
|
||||
void port_enable_tick(void) {
|
||||
HAL_RTCEx_SetWakeUpTimer_IT(&_hrtc, rtc_clock_frequency / 1024 / 2, RTC_WAKEUPCLOCK_RTCCLK_DIV2);
|
||||
HAL_NVIC_SetPriority(RTC_WKUP_IRQn, 1, 0U);
|
||||
HAL_NVIC_EnableIRQ(RTC_WKUP_IRQn);
|
||||
stm32_peripherals_rtc_set_wakeup_mode_tick();
|
||||
stm32_peripherals_rtc_assign_wkup_callback(supervisor_tick);
|
||||
stm32_peripherals_rtc_enable_wakeup_timer();
|
||||
}
|
||||
// TODO: what is this? can I get rid of it?
|
||||
extern volatile uint32_t autoreload_delay_ms;
|
||||
|
||||
// Disable 1/1024 second tick.
|
||||
void port_disable_tick(void) {
|
||||
HAL_NVIC_DisableIRQ(RTC_WKUP_IRQn);
|
||||
HAL_RTCEx_DeactivateWakeUpTimer(&_hrtc);
|
||||
stm32_peripherals_rtc_disable_wakeup_timer();
|
||||
}
|
||||
|
||||
void port_interrupt_after_ticks(uint32_t ticks) {
|
||||
uint64_t raw_ticks = port_get_raw_ticks(NULL) + ticks;
|
||||
|
||||
RTC_AlarmTypeDef alarm;
|
||||
if (ticks > 1024) {
|
||||
timeutils_struct_time_t tm;
|
||||
timeutils_seconds_since_2000_to_struct_time(raw_ticks / 1024, &tm);
|
||||
alarm.AlarmTime.Hours = tm.tm_hour;
|
||||
alarm.AlarmTime.Minutes = tm.tm_min;
|
||||
alarm.AlarmTime.Seconds = tm.tm_sec;
|
||||
alarm.AlarmDateWeekDay = tm.tm_mday;
|
||||
// Masking here means that the value is ignored so we set none.
|
||||
alarm.AlarmMask = RTC_ALARMMASK_NONE;
|
||||
} else {
|
||||
// Masking here means that the value is ignored so we set them all. Only the subseconds
|
||||
// value matters.
|
||||
alarm.AlarmMask = RTC_ALARMMASK_ALL;
|
||||
}
|
||||
|
||||
alarm.AlarmTime.SubSeconds = rtc_clock_frequency - 1 -
|
||||
((raw_ticks % 1024) * 32);
|
||||
alarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
|
||||
alarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_SET;
|
||||
// Masking here means that the bits are ignored so we set none of them.
|
||||
alarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_NONE;
|
||||
alarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
|
||||
alarm.Alarm = RTC_ALARM_A;
|
||||
|
||||
HAL_RTC_SetAlarm_IT(&_hrtc, &alarm, RTC_FORMAT_BIN);
|
||||
alarmed_already = false;
|
||||
stm32_peripherals_rtc_set_alarm(PERIPHERALS_ALARM_A, ticks);
|
||||
}
|
||||
|
||||
void port_idle_until_interrupt(void) {
|
||||
@ -444,7 +362,8 @@ void port_idle_until_interrupt(void) {
|
||||
__set_FPSCR(__get_FPSCR() & ~(0x9f));
|
||||
(void)__get_FPSCR();
|
||||
}
|
||||
if (alarmed_already) {
|
||||
// The alarm might have triggered before we even reach the WFI
|
||||
if (stm32_peripherals_rtc_alarm_triggered(PERIPHERALS_ALARM_A)) {
|
||||
return;
|
||||
}
|
||||
__WFI();
|
||||
@ -455,3 +374,9 @@ void port_idle_until_interrupt(void) {
|
||||
void _init(void) {
|
||||
|
||||
}
|
||||
|
||||
#if CIRCUITPY_ALARM
|
||||
// in case boards/xxx/board.c does not provide board_deinit()
|
||||
MP_WEAK void board_deinit(void) {
|
||||
}
|
||||
#endif
|
||||
|
@ -40,7 +40,7 @@ extern mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const
|
||||
// call alarm_woken_from_sleep to see if we've been woken by an alarm and if so,
|
||||
// it will exit idle as if deep sleep was exited.
|
||||
extern void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms);
|
||||
|
||||
// Deep sleep is entered outside of the VM so we omit the `common_hal_` prefix.
|
||||
extern NORETURN void common_hal_alarm_enter_deep_sleep(void);
|
||||
extern void common_hal_alarm_pretending_deep_sleep(void);
|
||||
|
||||
|
@ -73,7 +73,7 @@ STATIC mp_obj_t alarm_pin_pinalarm_make_new(const mp_obj_type_t *type, mp_uint_t
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(0, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[ARG_pin].u_obj);
|
||||
const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[ARG_pin].u_obj);
|
||||
|
||||
common_hal_alarm_pin_pinalarm_construct(self,
|
||||
pin,
|
||||
@ -89,7 +89,7 @@ STATIC mp_obj_t alarm_pin_pinalarm_make_new(const mp_obj_type_t *type, mp_uint_t
|
||||
//|
|
||||
STATIC mp_obj_t alarm_pin_pinalarm_obj_get_pin(mp_obj_t self_in) {
|
||||
alarm_pin_pinalarm_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mcu_pin_obj_t *pin = common_hal_alarm_pin_pinalarm_get_pin(self);
|
||||
const mcu_pin_obj_t *pin = common_hal_alarm_pin_pinalarm_get_pin(self);
|
||||
if (pin == NULL) {
|
||||
return mp_const_none;
|
||||
}
|
||||
|
@ -34,8 +34,8 @@
|
||||
|
||||
extern const mp_obj_type_t alarm_pin_pinalarm_type;
|
||||
|
||||
void common_hal_alarm_pin_pinalarm_construct(alarm_pin_pinalarm_obj_t *self, mcu_pin_obj_t *pin, bool value, bool edge, bool pull);
|
||||
extern mcu_pin_obj_t *common_hal_alarm_pin_pinalarm_get_pin(alarm_pin_pinalarm_obj_t *self);
|
||||
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);
|
||||
extern const mcu_pin_obj_t *common_hal_alarm_pin_pinalarm_get_pin(alarm_pin_pinalarm_obj_t *self);
|
||||
extern bool common_hal_alarm_pin_pinalarm_get_value(alarm_pin_pinalarm_obj_t *self);
|
||||
extern bool common_hal_alarm_pin_pinalarm_get_edge(alarm_pin_pinalarm_obj_t *self);
|
||||
extern bool common_hal_alarm_pin_pinalarm_get_pull(alarm_pin_pinalarm_obj_t *self);
|
||||
|
Loading…
x
Reference in New Issue
Block a user