From f1792c8474e15d006ba39a07e1b7cf5b03e52bac Mon Sep 17 00:00:00 2001 From: Lucian Copeland Date: Tue, 2 Mar 2021 11:41:53 -0500 Subject: [PATCH] Extract EXTI, create base sleep framework --- main.c | 8 +- ports/esp32s2/common-hal/alarm/__init__.c | 17 +- ports/esp32s2/common-hal/alarm/__init__.h | 2 +- ports/esp32s2/common-hal/alarm/pin/__init__.c | 35 ---- ports/stm/Makefile | 2 + .../boards/feather_stm32f405_express/board.c | 3 + ports/stm/common-hal/alarm/SleepMemory.c | 46 +++++ ports/stm/common-hal/alarm/SleepMemory.h | 38 +++++ ports/stm/common-hal/alarm/__init__.c | 158 ++++++++++++++++++ ports/stm/common-hal/alarm/__init__.h | 36 ++++ ports/stm/common-hal/alarm/pin/PinAlarm.c | 136 +++++++++++++++ ports/stm/common-hal/alarm/pin/PinAlarm.h | 42 +++++ ports/stm/common-hal/alarm/time/TimeAlarm.c | 78 +++++++++ ports/stm/common-hal/alarm/time/TimeAlarm.h | 40 +++++ ports/stm/common-hal/alarm/touch/TouchAlarm.c | 32 ++++ ports/stm/common-hal/alarm/touch/TouchAlarm.h | 35 ++++ ports/stm/common-hal/pulseio/PulseIn.c | 116 ++++--------- ports/stm/common-hal/pulseio/PulseIn.h | 1 - ports/stm/mpconfigport.mk | 1 + ports/stm/peripherals/exti.c | 134 +++++++++++++++ ports/stm/peripherals/exti.h | 43 +++++ ports/stm/peripherals/rtc.c | 25 +++ ports/stm/peripherals/rtc.h | 25 +++ ports/stm/supervisor/port.c | 7 + shared-bindings/alarm/__init__.c | 2 +- shared-bindings/alarm/__init__.h | 8 +- shared-bindings/alarm/time/TimeAlarm.c | 1 + 27 files changed, 934 insertions(+), 137 deletions(-) delete mode 100644 ports/esp32s2/common-hal/alarm/pin/__init__.c create mode 100644 ports/stm/common-hal/alarm/SleepMemory.c create mode 100644 ports/stm/common-hal/alarm/SleepMemory.h create mode 100644 ports/stm/common-hal/alarm/__init__.c create mode 100644 ports/stm/common-hal/alarm/__init__.h create mode 100644 ports/stm/common-hal/alarm/pin/PinAlarm.c create mode 100644 ports/stm/common-hal/alarm/pin/PinAlarm.h create mode 100644 ports/stm/common-hal/alarm/time/TimeAlarm.c create mode 100644 ports/stm/common-hal/alarm/time/TimeAlarm.h create mode 100644 ports/stm/common-hal/alarm/touch/TouchAlarm.c create mode 100644 ports/stm/common-hal/alarm/touch/TouchAlarm.h create mode 100644 ports/stm/peripherals/exti.c create mode 100644 ports/stm/peripherals/exti.h create mode 100644 ports/stm/peripherals/rtc.c create mode 100644 ports/stm/peripherals/rtc.h diff --git a/main.c b/main.c index 7bfa565df4..1d0f5453f0 100755 --- a/main.c +++ b/main.c @@ -157,9 +157,9 @@ STATIC void start_mp(supervisor_allocation* heap) { #if CIRCUITPY_ALARM // Record which alarm woke us up, if any. An object may be created so the heap must be functional. - alarm_save_wake_alarm(); + common_hal_alarm_save_wake_alarm(); // Reset alarm module only after we retrieved the wakeup alarm. - alarm_reset(); + common_hal_alarm_reset(); #endif #if CIRCUITPY_NETWORK @@ -357,7 +357,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode) { // an alarm alerts faster than our USB delay or if we pretended to deep // sleep. #if CIRCUITPY_ALARM - if (asleep && alarm_woken_from_sleep()) { + if (asleep && common_hal_alarm_woken_from_sleep()) { serial_write_compressed(translate("Woken up by alarm.\n")); board_init(); supervisor_set_run_reason(RUN_REASON_STARTUP); @@ -409,7 +409,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode) { if (!supervisor_workflow_active()) { // Enter true deep sleep. When we wake up we'll be back at the // top of main(), not in this loop. - alarm_enter_deep_sleep(); + common_hal_alarm_enter_deep_sleep(); // Does not return. } else { serial_write_compressed(translate("Pretending to deep sleep until alarm, CTRL-C or file write.\n")); diff --git a/ports/esp32s2/common-hal/alarm/__init__.c b/ports/esp32s2/common-hal/alarm/__init__.c index be435e2104..c0a2a1a555 100644 --- a/ports/esp32s2/common-hal/alarm/__init__.c +++ b/ports/esp32s2/common-hal/alarm/__init__.c @@ -54,7 +54,7 @@ const alarm_sleep_memory_obj_t alarm_sleep_memory_obj = { }, }; -void alarm_reset(void) { +void common_hal_alarm_reset(void) { alarm_sleep_memory_reset(); alarm_pin_pinalarm_reset(); alarm_time_timealarm_reset(); @@ -75,10 +75,12 @@ STATIC esp_sleep_wakeup_cause_t _get_wakeup_cause(void) { return esp_sleep_get_wakeup_cause(); } -bool alarm_woken_from_sleep(void) { +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); } @@ -120,8 +124,9 @@ STATIC void _idle_until_alarm(void) { while (!mp_hal_is_interrupted()) { RUN_BACKGROUND_TASKS; // Allow ctrl-C interrupt. - if (alarm_woken_from_sleep()) { - alarm_save_wake_alarm(); + if (common_hal_alarm_woken_from_sleep()) { + // This saves the return of common_hal_alarm_get_wake_alarm through Shared Bindings + common_hal_alarm_save_wake_alarm(); return; } port_idle_until_interrupt(); @@ -139,7 +144,7 @@ mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj } mp_obj_t wake_alarm = _get_wake_alarm(n_alarms, alarms); - alarm_reset(); + alarm_pin_pinalarm_reset_alarms(n_alarms, alarms); return wake_alarm; } @@ -147,7 +152,7 @@ void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *ala _setup_sleep_alarms(true, n_alarms, alarms); } -void NORETURN alarm_enter_deep_sleep(void) { +void NORETURN common_hal_alarm_enter_deep_sleep(void) { alarm_pin_pinalarm_prepare_for_deep_sleep(); alarm_touch_touchalarm_prepare_for_deep_sleep(); diff --git a/ports/esp32s2/common-hal/alarm/__init__.h b/ports/esp32s2/common-hal/alarm/__init__.h index 0823ff842e..2b46907778 100644 --- a/ports/esp32s2/common-hal/alarm/__init__.h +++ b/ports/esp32s2/common-hal/alarm/__init__.h @@ -31,6 +31,6 @@ const alarm_sleep_memory_obj_t alarm_sleep_memory_obj; -extern void alarm_reset(void); +extern void common_hal_alarm_reset(void); #endif // MICROPY_INCLUDED_ESP32S2_COMMON_HAL_ALARM__INIT__H diff --git a/ports/esp32s2/common-hal/alarm/pin/__init__.c b/ports/esp32s2/common-hal/alarm/pin/__init__.c deleted file mode 100644 index b39693c6af..0000000000 --- a/ports/esp32s2/common-hal/alarm/pin/__init__.c +++ /dev/null @@ -1,35 +0,0 @@ -#include "shared-bindings/alarm_io/__init__.h" - -#include "esp_sleep.h" -#include "driver/rtc_io.h" - -mp_obj_t common_hal_alarm_io_pin_state (alarm_io_obj_t *self_in) { - if (!rtc_gpio_is_valid_gpio(self_in->gpio)) { - mp_raise_ValueError(translate("io must be rtc io")); - } - - if (self_in->pull && !self_in->level) { - for (uint8_t i = 0; i<=4; i+=2) { - if (self_in->gpio == i) { - mp_raise_ValueError(translate("IOs 0, 2 & 4 do not support internal pullup in sleep")); - } - } - } - - switch(esp_sleep_enable_ext0_wakeup(self_in->gpio, self_in->level)) { - case ESP_ERR_INVALID_ARG: - mp_raise_ValueError(translate("trigger level must be 0 or 1")); - case ESP_ERR_INVALID_STATE: - mp_raise_RuntimeError(translate("wakeup conflict")); - default: - break; - } - - if (self_in->pull) { (self_in->level) ? rtc_gpio_pulldown_en(self_in->gpio) : rtc_gpio_pullup_en(self_in->gpio); } - - return self_in; -} - -void common_hal_alarm_io_disable (void) { - esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_EXT0 | ESP_SLEEP_WAKEUP_EXT1); -} diff --git a/ports/stm/Makefile b/ports/stm/Makefile index e09fe736cc..661beccfed 100755 --- a/ports/stm/Makefile +++ b/ports/stm/Makefile @@ -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 \ diff --git a/ports/stm/boards/feather_stm32f405_express/board.c b/ports/stm/boards/feather_stm32f405_express/board.c index f8e462f938..6652c840c6 100644 --- a/ports/stm/boards/feather_stm32f405_express/board.c +++ b/ports/stm/boards/feather_stm32f405_express/board.c @@ -37,3 +37,6 @@ bool board_requests_safe_mode(void) { void reset_board(void) { } + +void board_deinit(void) { +} \ No newline at end of file diff --git a/ports/stm/common-hal/alarm/SleepMemory.c b/ports/stm/common-hal/alarm/SleepMemory.c new file mode 100644 index 0000000000..f1e2772abb --- /dev/null +++ b/ports/stm/common-hal/alarm/SleepMemory.c @@ -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. + */ + +#include + +#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) { + 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) { + 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) { + return; +} diff --git a/ports/stm/common-hal/alarm/SleepMemory.h b/ports/stm/common-hal/alarm/SleepMemory.h new file mode 100644 index 0000000000..0e9fc54904 --- /dev/null +++ b/ports/stm/common-hal/alarm/SleepMemory.h @@ -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 diff --git a/ports/stm/common-hal/alarm/__init__.c b/ports/stm/common-hal/alarm/__init__.c new file mode 100644 index 0000000000..70da36c294 --- /dev/null +++ b/ports/stm/common-hal/alarm/__init__.c @@ -0,0 +1,158 @@ +/* + * 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/pin/PinAlarm.h" +#include "shared-bindings/alarm/time/TimeAlarm.h" + +#include "shared-bindings/microcontroller/__init__.h" + +#include "supervisor/port.h" +#include "supervisor/shared/workflow.h" + +#define STM_WAKEUP_GPIO 1 +#define STM_WAKEUP_TIMER 2 + +void common_hal_alarm_reset(void) { + // alarm_sleep_memory_reset(); + alarm_pin_pinalarm_reset(); + // alarm_time_timealarm_reset(); + // alarm_touch_touchalarm_reset(); + // esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL); +} + +STATIC uint8_t _get_wakeup_cause(void) { + if (alarm_pin_pinalarm_woke_us_up()) { + return STM_WAKEUP_GPIO; + } + if (alarm_time_timealarm_woke_us_up()) { + return STM_WAKEUP_TIMER; + } + return 0; +} + +bool common_hal_alarm_woken_from_sleep(void) { + return _get_wakeup_cause() != 0; +} + +STATIC mp_obj_t _get_wake_alarm(size_t n_alarms, const mp_obj_t *alarms) { + if (alarm_pin_pinalarm_woke_us_up()) { + return alarm_pin_pinalarm_get_wakeup_alarm(n_alarms, alarms); + } + // esp_sleep_wakeup_cause_t cause = _get_wakeup_cause(); + // switch (cause) { + // case ESP_SLEEP_WAKEUP_TIMER: { + // return alarm_time_timealarm_get_wakeup_alarm(n_alarms, alarms); + // } + + // case ESP_SLEEP_WAKEUP_GPIO: + // case ESP_SLEEP_WAKEUP_EXT0: + // case ESP_SLEEP_WAKEUP_EXT1: { + // return alarm_pin_pinalarm_get_wakeup_alarm(n_alarms, alarms); + // } + + // case ESP_SLEEP_WAKEUP_TOUCHPAD: { + // return alarm_touch_touchalarm_get_wakeup_alarm(n_alarms, alarms); + // } + + // case ESP_SLEEP_WAKEUP_UNDEFINED: + // default: + // // Not a deep sleep reset. + // break; + // } + // return mp_const_none; + return mp_const_none; +} + +mp_obj_t common_hal_alarm_get_wake_alarm(void) { + //return _get_wake_alarm(0, NULL); + return mp_const_none; +} + +// Set up light sleep or deep sleep alarms. +STATIC void _setup_sleep_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms) { + alarm_pin_pinalarm_set_alarms(deep_sleep, n_alarms, alarms); + // alarm_time_timealarm_set_alarms(deep_sleep, n_alarms, alarms); + // alarm_touch_touchalarm_set_alarm(deep_sleep, n_alarms, alarms); +} + +STATIC void _idle_until_alarm(void) { + // Poll for alarms. + while (!mp_hal_is_interrupted()) { + RUN_BACKGROUND_TASKS; + // Allow ctrl-C interrupt. + if (common_hal_alarm_woken_from_sleep()) { + common_hal_alarm_save_wake_alarm(); + 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 (supervisor_workflow_active()) { + // mp_raise_NotImplementedError(translate("Cannot sleep with USB connected")); + // } + _setup_sleep_alarms(false, n_alarms, alarms); + + // If USB is active, only pretend to sleep. Otherwise, light sleep + if (supervisor_workflow_active()) { + _idle_until_alarm(); + } else { + 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); + common_hal_alarm_reset(); + return wake_alarm; +} + +void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms) { + _setup_sleep_alarms(true, n_alarms, alarms); +} + +//#define NORETURN __attribute__((noreturn)) +void NORETURN common_hal_alarm_enter_deep_sleep(void) { + // alarm_pin_pinalarm_prepare_for_deep_sleep(); + // alarm_touch_touchalarm_prepare_for_deep_sleep(); + while(1); + + // The ESP-IDF caches the deep sleep settings and applies them before sleep. + // We don't need to worry about resetting them in the interim. + // esp_deep_sleep_start(); +} + +void common_hal_alarm_gc_collect(void) { + gc_collect_ptr(common_hal_alarm_get_wake_alarm()); +} diff --git a/ports/stm/common-hal/alarm/__init__.h b/ports/stm/common-hal/alarm/__init__.h new file mode 100644 index 0000000000..18defefc0b --- /dev/null +++ b/ports/stm/common-hal/alarm/__init__.h @@ -0,0 +1,36 @@ +/* + * 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" + +const alarm_sleep_memory_obj_t alarm_sleep_memory_obj; + +extern void common_hal_alarm_reset(void); + +#endif // MICROPY_INCLUDED_STM32_COMMON_HAL_ALARM__INIT__H diff --git a/ports/stm/common-hal/alarm/pin/PinAlarm.c b/ports/stm/common-hal/alarm/pin/PinAlarm.c new file mode 100644 index 0000000000..aecc3a0e22 --- /dev/null +++ b/ports/stm/common-hal/alarm/pin/PinAlarm.c @@ -0,0 +1,136 @@ +/* + * 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 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, 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")); + } + stm_peripherals_exti_reserve(pin->number); + 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); + + stm_peripherals_exti_set_callback(pin_alarm_callback,pin->number); + + 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 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]; + } + } + + // Placeholder for deep sleep + alarm_pin_pinalarm_obj_t *alarm = m_new_obj(alarm_pin_pinalarm_obj_t); + alarm->base.type = &alarm_pin_pinalarm_type; + alarm->pin = NULL; + return alarm; +} + +void alarm_pin_pinalarm_reset(void) { + alarm_pin_triggered = 0; + woke_up = false; +} + +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]); + stm_peripherals_exti_enable(alarm->pin->number); + } + } +} + +void alarm_pin_pinalarm_reset_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms) { + alarm_pin_triggered = 0; + 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]); + stm_peripherals_exti_disable(alarm->pin->number); + } + } +} + +void alarm_pin_pinalarm_prepare_for_deep_sleep(void) { + +} diff --git a/ports/stm/common-hal/alarm/pin/PinAlarm.h b/ports/stm/common-hal/alarm/pin/PinAlarm.h new file mode 100644 index 0000000000..b26930b103 --- /dev/null +++ b/ports/stm/common-hal/alarm/pin/PinAlarm.h @@ -0,0 +1,42 @@ +/* + * 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/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_reset_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); diff --git a/ports/stm/common-hal/alarm/time/TimeAlarm.c b/ports/stm/common-hal/alarm/time/TimeAlarm.c new file mode 100644 index 0000000000..f9ceefdb40 --- /dev/null +++ b/ports/stm/common-hal/alarm/time/TimeAlarm.c @@ -0,0 +1,78 @@ +/* + * 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" + +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. +// void timer_callback(void *arg) { +// (void) arg; +// woke_up = true; +// xTaskNotifyGive(circuitpython_task); +// } + +bool alarm_time_timealarm_woke_us_up(void) { + // return woke_up; + return false; +} + +// void alarm_time_timealarm_reset(void) { +// esp_timer_stop(pretend_sleep_timer); +// esp_timer_delete(pretend_sleep_timer); +// pretend_sleep_timer = NULL; +// woke_up = false; +// } + +void alarm_time_timealarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms) { + // HAL_RTCEx_SetWakeUpTimer_IT(&RTCHandle, 0xA017, RTC_WAKEUPCLOCK_RTCCLK_DIV16); + // 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); +} diff --git a/ports/stm/common-hal/alarm/time/TimeAlarm.h b/ports/stm/common-hal/alarm/time/TimeAlarm.h new file mode 100644 index 0000000000..af786d81b0 --- /dev/null +++ b/ports/stm/common-hal/alarm/time/TimeAlarm.h @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Lucian Copeland for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#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); diff --git a/ports/stm/common-hal/alarm/touch/TouchAlarm.c b/ports/stm/common-hal/alarm/touch/TouchAlarm.c new file mode 100644 index 0000000000..88c73726ee --- /dev/null +++ b/ports/stm/common-hal/alarm/touch/TouchAlarm.c @@ -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")); +} diff --git a/ports/stm/common-hal/alarm/touch/TouchAlarm.h b/ports/stm/common-hal/alarm/touch/TouchAlarm.h new file mode 100644 index 0000000000..6c89353f93 --- /dev/null +++ b/ports/stm/common-hal/alarm/touch/TouchAlarm.h @@ -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 diff --git a/ports/stm/common-hal/pulseio/PulseIn.c b/ports/stm/common-hal/pulseio/PulseIn.c index 015ee8536d..c030e8255b 100644 --- a/ports/stm/common-hal/pulseio/PulseIn.c +++ b/ports/stm/common-hal/pulseio/PulseIn.c @@ -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 @@ -59,7 +59,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; @@ -67,7 +67,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; if (self->first_edge) { @@ -97,11 +97,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)); @@ -112,15 +112,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)); } @@ -165,16 +164,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); } @@ -187,7 +191,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; @@ -198,7 +203,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; } @@ -232,27 +237,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; } @@ -260,11 +265,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; } @@ -280,62 +285,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); - } - } -} diff --git a/ports/stm/common-hal/pulseio/PulseIn.h b/ports/stm/common-hal/pulseio/PulseIn.h index 34d0cc731a..a3454bb540 100644 --- a/ports/stm/common-hal/pulseio/PulseIn.h +++ b/ports/stm/common-hal/pulseio/PulseIn.h @@ -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; diff --git a/ports/stm/mpconfigport.mk b/ports/stm/mpconfigport.mk index bcecaa5170..86cd3c009a 100644 --- a/ports/stm/mpconfigport.mk +++ b/ports/stm/mpconfigport.mk @@ -4,6 +4,7 @@ INTERNAL_LIBM ?= 1 USB_SERIAL_NUMBER_LENGTH ?= 24 ifeq ($(MCU_VARIANT),STM32F405xx) + CIRCUITPY_ALARM = 1 CIRCUITPY_CANIO = 1 CIRCUITPY_FRAMEBUFFERIO ?= 1 CIRCUITPY_RGBMATRIX ?= 1 diff --git a/ports/stm/peripherals/exti.c b/ports/stm/peripherals/exti.c new file mode 100644 index 0000000000..c0b3a750ad --- /dev/null +++ b/ports/stm/peripherals/exti.c @@ -0,0 +1,134 @@ +/* + * 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 +#include "py/mpconfig.h" +#include "py/gc.h" +#include "py/obj.h" +#include "py/runtime.h" + +#include "peripherals/exti.h" + + +STATIC bool stm_exti_reserved[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++) { + stm_exti_reserved[i] = false; + stm_exti_callback[i] = NULL; + stm_peripherals_exti_disable(i); + } +} + +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); + } + } +} diff --git a/ports/stm/peripherals/exti.h b/ports/stm/peripherals/exti.h new file mode 100644 index 0000000000..15e2207c9c --- /dev/null +++ b/ports/stm/peripherals/exti.h @@ -0,0 +1,43 @@ +/* + * 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); +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__ \ No newline at end of file diff --git a/ports/stm/peripherals/rtc.c b/ports/stm/peripherals/rtc.c new file mode 100644 index 0000000000..72336f0314 --- /dev/null +++ b/ports/stm/peripherals/rtc.c @@ -0,0 +1,25 @@ +/* + * 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. + */ \ No newline at end of file diff --git a/ports/stm/peripherals/rtc.h b/ports/stm/peripherals/rtc.h new file mode 100644 index 0000000000..72336f0314 --- /dev/null +++ b/ports/stm/peripherals/rtc.h @@ -0,0 +1,25 @@ +/* + * 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. + */ \ No newline at end of file diff --git a/ports/stm/supervisor/port.c b/ports/stm/supervisor/port.c index 3103a07160..afbe333e38 100644 --- a/ports/stm/supervisor/port.c +++ b/ports/stm/supervisor/port.c @@ -50,6 +50,9 @@ #if CIRCUITPY_SDIOIO #include "common-hal/sdioio/SDCard.h" #endif +#if CIRCUITPY_PULSEIO || CIRCUITPY_ALARM +#include "exti.h" +#endif #include "clocks.h" #include "gpio.h" @@ -247,6 +250,9 @@ void reset_port(void) { #if CIRCUITPY_PWMIO pwmout_reset(); #endif +#if CIRCUITPY_PULSEIO || CIRCUITPY_ALARM + exti_reset(); +#endif } void reset_to_bootloader(void) { @@ -380,6 +386,7 @@ void RTC_WKUP_IRQHandler(void) { supervisor_tick(); __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(&_hrtc, RTC_FLAG_WUTF); __HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_FLAG(); + _hrtc.State = HAL_RTC_STATE_READY; } volatile bool alarmed_already = false; diff --git a/shared-bindings/alarm/__init__.c b/shared-bindings/alarm/__init__.c index 7023c70e5d..7be629d52b 100644 --- a/shared-bindings/alarm/__init__.c +++ b/shared-bindings/alarm/__init__.c @@ -228,7 +228,7 @@ mp_obj_t alarm_get_wake_alarm(void) { } // Initialize .wake_alarm value. -void alarm_save_wake_alarm(void) { +void common_hal_alarm_save_wake_alarm(void) { // Equivalent of: // alarm.wake_alarm = alarm mp_map_elem_t *elem = diff --git a/shared-bindings/alarm/__init__.h b/shared-bindings/alarm/__init__.h index 154f91e265..12ee0f1aad 100644 --- a/shared-bindings/alarm/__init__.h +++ b/shared-bindings/alarm/__init__.h @@ -41,20 +41,20 @@ extern mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const // 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 alarm_enter_deep_sleep(void); +extern NORETURN void common_hal_alarm_enter_deep_sleep(void); // Fetches value from module dict. -extern mp_obj_t alarm_get_wake_alarm(void); +extern mp_obj_t common_hal_alarm_get_wake_alarm(void); extern void common_hal_alarm_gc_collect(void); extern mp_obj_t common_hal_alarm_get_wake_alarm(void); // Used by wake-up code. -void alarm_save_wake_alarm(void); +void common_hal_alarm_save_wake_alarm(void); // True if an alarm is alerting. This is most useful for pretend deep sleep. -extern bool alarm_woken_from_sleep(void); +extern bool common_hal_alarm_woken_from_sleep(void); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_ALARM___INIT___H diff --git a/shared-bindings/alarm/time/TimeAlarm.c b/shared-bindings/alarm/time/TimeAlarm.c index 1c9b8d37c5..1ce805ba6b 100644 --- a/shared-bindings/alarm/time/TimeAlarm.c +++ b/shared-bindings/alarm/time/TimeAlarm.c @@ -58,6 +58,7 @@ mp_obj_t MP_WEAK rtc_get_time_source_time(void) { //| STATIC mp_obj_t alarm_time_timealarm_make_new(const mp_obj_type_t *type, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + alarm_time_timealarm_obj_t *self = m_new_obj(alarm_time_timealarm_obj_t); self->base.type = &alarm_time_timealarm_type;