diff options
| author | microDev <70126934+microDev1@users.noreply.github.com> | 2020-12-30 22:44:22 +0530 |
|---|---|---|
| committer | microDev <70126934+microDev1@users.noreply.github.com> | 2020-12-30 22:44:22 +0530 |
| commit | 28ce5e898864a6205ab3c0483991f27707164954 (patch) | |
| tree | 0f5f353feb7b8b4f1ce0b6fd8e147e74083d9b26 /ports | |
| parent | c7f68022efa1306b0c7cb2fa47dcc84dbca2c605 (diff) | |
| parent | 48de52c8ab62fae93e1382cb774802828cf92edd (diff) | |
Merge branch 'main' into touch-s2
Diffstat (limited to 'ports')
54 files changed, 976 insertions, 157 deletions
diff --git a/ports/atmel-samd/boards/stackrduino_m0_pro/board.c b/ports/atmel-samd/boards/stackrduino_m0_pro/board.c new file mode 100644 index 000000000..84960e73c --- /dev/null +++ b/ports/atmel-samd/boards/stackrduino_m0_pro/board.c @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft 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 "supervisor/board.h" + +void board_init(void) { +} + +bool board_requests_safe_mode(void) { + return false; +} + +void reset_board(void) { +} diff --git a/ports/atmel-samd/boards/stackrduino_m0_pro/mpconfigboard.h b/ports/atmel-samd/boards/stackrduino_m0_pro/mpconfigboard.h new file mode 100644 index 000000000..f0b2764a4 --- /dev/null +++ b/ports/atmel-samd/boards/stackrduino_m0_pro/mpconfigboard.h @@ -0,0 +1,33 @@ +#define MICROPY_HW_BOARD_NAME "StackRduino M0 PRO" +#define MICROPY_HW_MCU_NAME "samd21g18" + +#define MICROPY_HW_LED_STATUS (&pin_PA17) +#define MICROPY_HW_NEOPIXEL (&pin_PA06) + +#define SPI_FLASH_BAUDRATE (8000000) + +#define SPI_FLASH_MOSI_PIN &pin_PB22 +#define SPI_FLASH_MISO_PIN &pin_PB03 +#define SPI_FLASH_SCK_PIN &pin_PB23 +#define SPI_FLASH_CS_PIN &pin_PA27 + +// These are pins not to reset. +#define MICROPY_PORT_A (PORT_PA06) +#define MICROPY_PORT_B (0) +#define MICROPY_PORT_C (0) + +#define BOARD_HAS_CRYSTAL 1 + +#define DEFAULT_I2C_BUS_SCL (&pin_PA23) +#define DEFAULT_I2C_BUS_SDA (&pin_PA22) + +#define DEFAULT_SPI_BUS_SCK (&pin_PB11) +#define DEFAULT_SPI_BUS_MOSI (&pin_PB10) +#define DEFAULT_SPI_BUS_MISO (&pin_PA12) + +#define DEFAULT_UART_BUS_RX (&pin_PA11) +#define DEFAULT_UART_BUS_TX (&pin_PA10) + +// USB is always used internally so skip the pin objects for it. +#define IGNORE_PIN_PA24 1 +#define IGNORE_PIN_PA25 1 diff --git a/ports/atmel-samd/boards/stackrduino_m0_pro/mpconfigboard.mk b/ports/atmel-samd/boards/stackrduino_m0_pro/mpconfigboard.mk new file mode 100644 index 000000000..704d26514 --- /dev/null +++ b/ports/atmel-samd/boards/stackrduino_m0_pro/mpconfigboard.mk @@ -0,0 +1,58 @@ +USB_VID = 0x1209 +USB_PID = 0xE3E3 +USB_PRODUCT = "StackRduino M0 PRO" +USB_MANUFACTURER = "StackRduino" + +CHIP_VARIANT = SAMD21G18A +CHIP_FAMILY = samd21 + +SPI_FLASH_FILESYSTEM = 1 +EXTERNAL_FLASH_DEVICE_COUNT = 1 +EXTERNAL_FLASH_DEVICES = "W25Q64JV_IQ" +LONGINT_IMPL = MPZ + + +CIRCUITPY_BITBANGIO = 0 +CIRCUITPY_FREQUENCYIO = 0 +CIRCUITPY_COUNTIO = 0 +CIRCUITPY_I2CPERIPHERAL = 0 +CIRCUITPY_VECTORIO = 0 +CIRCUITPY_BUSDEVICE = 0 + +CFLAGS_INLINE_LIMIT = 55 +SUPEROPT_GC = 0 + +CFLAGS_BOARD = --param max-inline-insns-auto=15 +ifeq ($(TRANSLATION), ja) +RELEASE_NEEDS_CLEAN_BUILD = 1 +CFLAGS_INLINE_LIMIT = 35 +endif +ifeq ($(TRANSLATION), zh_Latn_pinyin) +RELEASE_NEEDS_CLEAN_BUILD = 1 +CFLAGS_INLINE_LIMIT = 35 +endif +ifeq ($(TRANSLATION), de_DE) +RELEASE_NEEDS_CLEAN_BUILD = 1 +CFLAGS_INLINE_LIMIT = 35 +SUPEROPT_VM = 0 +endif +ifeq ($(TRANSLATION), pl) +RELEASE_NEEDS_CLEAN_BUILD = 1 +CFLAGS_INLINE_LIMIT = 35 +SUPEROPT_VM = 0 +endif +ifeq ($(TRANSLATION), fr) +RELEASE_NEEDS_CLEAN_BUILD = 1 +CFLAGS_INLINE_LIMIT = 35 +SUPEROPT_VM = 0 +endif +ifeq ($(TRANSLATION), pt_BR) +RELEASE_NEEDS_CLEAN_BUILD = 1 +CFLAGS_INLINE_LIMIT = 35 +SUPEROPT_VM = 0 +endif +ifeq ($(TRANSLATION), es) +RELEASE_NEEDS_CLEAN_BUILD = 1 +CFLAGS_INLINE_LIMIT = 35 +SUPEROPT_VM = 0 +endif diff --git a/ports/atmel-samd/boards/stackrduino_m0_pro/pins.c b/ports/atmel-samd/boards/stackrduino_m0_pro/pins.c new file mode 100644 index 000000000..95d2eb5a3 --- /dev/null +++ b/ports/atmel-samd/boards/stackrduino_m0_pro/pins.c @@ -0,0 +1,40 @@ +#include "shared-bindings/board/__init__.h" + +STATIC const mp_rom_map_elem_t board_global_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_PA02) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_PB08) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_PB09) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_PA04) }, + { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_PA05) }, + { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_PB02) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_PB11) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_PB10) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_PA12) }, + { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_PA11) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_PA11) }, + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_PA10) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_PA10) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_PA22) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_PA23) }, + { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_PA08) }, + { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_PA09) }, + { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_PA14) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_PA15) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_PA20) }, + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_PA21) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_PA06) }, + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_PA06) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_PA07) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_PA18) }, + { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_PA16) }, + { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_PA19) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PA17) }, + { MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_PA28) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_PA28) }, + { MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_PA13) }, + { MP_ROM_QSTR(MP_QSTR_CHRG_EN), MP_ROM_PTR(&pin_PA13) }, + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table); diff --git a/ports/atmel-samd/common-hal/audioio/AudioOut.c b/ports/atmel-samd/common-hal/audioio/AudioOut.c index 5cefba56f..34b718dca 100644 --- a/ports/atmel-samd/common-hal/audioio/AudioOut.c +++ b/ports/atmel-samd/common-hal/audioio/AudioOut.c @@ -197,7 +197,7 @@ void common_hal_audioio_audioout_construct(audioio_audioout_obj_t* self, #endif #ifdef SAM_D5X_E5X DAC->EVCTRL.reg |= DAC_EVCTRL_STARTEI0; - DAC->DACCTRL[0].reg = DAC_DACCTRL_CCTRL_CC100K | + DAC->DACCTRL[0].reg = DAC_DACCTRL_CCTRL_CC12M | DAC_DACCTRL_ENABLE | DAC_DACCTRL_LEFTADJ; DAC->CTRLB.reg = DAC_CTRLB_REFSEL_VREFPU; @@ -206,7 +206,7 @@ void common_hal_audioio_audioout_construct(audioio_audioout_obj_t* self, #ifdef SAM_D5X_E5X if (channel1_enabled) { DAC->EVCTRL.reg |= DAC_EVCTRL_STARTEI1; - DAC->DACCTRL[1].reg = DAC_DACCTRL_CCTRL_CC100K | + DAC->DACCTRL[1].reg = DAC_DACCTRL_CCTRL_CC12M | DAC_DACCTRL_ENABLE | DAC_DACCTRL_LEFTADJ; DAC->CTRLB.reg = DAC_CTRLB_REFSEL_VREFPU; diff --git a/ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c b/ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c index 02d0482dc..f973db90b 100644 --- a/ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c +++ b/ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c @@ -82,7 +82,8 @@ void frequencyin_emergency_cancel_capture(uint8_t index) { #ifdef SAM_D5X_E5X NVIC_EnableIRQ(EIC_0_IRQn + self->channel); #endif - mp_raise_RuntimeError(translate("Frequency captured is above capability. Capture Paused.")); + // Frequency captured is above capability. Capture paused. + // We can't raise an error here; we're in an interrupt handler. } void frequencyin_interrupt_handler(uint8_t index) { diff --git a/ports/atmel-samd/common-hal/microcontroller/Pin.c b/ports/atmel-samd/common-hal/microcontroller/Pin.c index 7dd87a3b2..564d037e0 100644 --- a/ports/atmel-samd/common-hal/microcontroller/Pin.c +++ b/ports/atmel-samd/common-hal/microcontroller/Pin.c @@ -169,6 +169,9 @@ void common_hal_never_reset_pin(const mcu_pin_obj_t* pin) { } void common_hal_reset_pin(const mcu_pin_obj_t* pin) { + if (pin == NULL) { + return; + } reset_pin_number(pin->number); } diff --git a/ports/esp32s2/Makefile b/ports/esp32s2/Makefile index 3291c7fac..f33a1d2eb 100644 --- a/ports/esp32s2/Makefile +++ b/ports/esp32s2/Makefile @@ -106,6 +106,8 @@ INC += -isystem esp-idf/components/heap/include INC += -isystem esp-idf/components/esp_system/include INC += -isystem esp-idf/components/spi_flash/include INC += -isystem esp-idf/components/nvs_flash/include +INC += -isystem esp-idf/components/app_update/include +INC += -isystem esp-idf/components/bootloader_support/include INC += -I$(BUILD)/esp-idf/config CFLAGS += -DHAVE_CONFIG_H \ @@ -143,7 +145,6 @@ LDFLAGS += -L$(BUILD)/esp-idf/esp-idf/esp32s2 \ -Tesp32s2.peripherals.ld \ -Lesp-idf/components/esp_rom/esp32s2/ld \ -Tesp32s2.rom.ld \ - -Tesp32s2.rom.api.ld \ -Tesp32s2.rom.libgcc.ld \ -Tesp32s2.rom.newlib-data.ld \ -Tesp32s2.rom.newlib-funcs.ld \ @@ -277,7 +278,7 @@ menuconfig: $(BUILD)/esp-idf/config # qstr builds include headers so we need to make sure they are up to date $(HEADER_BUILD)/qstr.split: | $(BUILD)/esp-idf/config/sdkconfig.h -ESP_IDF_COMPONENTS_LINK = freertos log hal esp_system esp_adc_cal esp32s2 bootloader_support pthread esp_timer vfs spi_flash app_update esp_common esp32s2 heap newlib driver xtensa soc esp_ringbuf esp_wifi esp_event wpa_supplicant mbedtls efuse nvs_flash esp_netif lwip esp_rom esp-tls +ESP_IDF_COMPONENTS_LINK = freertos log esp_system esp_adc_cal esp32s2 bootloader_support pthread esp_timer vfs spi_flash app_update esp_common esp32s2 heap newlib driver xtensa soc esp_ringbuf esp_wifi esp_event wpa_supplicant mbedtls efuse nvs_flash esp_netif lwip esp-tls ESP_IDF_COMPONENTS_INCLUDE = driver freertos log soc @@ -289,11 +290,11 @@ ESP_IDF_WIFI_COMPONENTS_EXPANDED = $(foreach component, $(ESP_IDF_WIFI_COMPONENT MBEDTLS_COMPONENTS_LINK = crypto tls x509 MBEDTLS_COMPONENTS_LINK_EXPANDED = $(foreach component, $(MBEDTLS_COMPONENTS_LINK), $(BUILD)/esp-idf/esp-idf/mbedtls/mbedtls/library/libmbed$(component).a) -BINARY_BLOBS = esp-idf/components/xtensa/esp32s2/libxt_hal.a +BINARY_BLOBS = esp-idf/components/xtensa/esp32s2/libhal.a BINARY_WIFI_BLOBS = libcoexist.a libcore.a libespnow.a libmesh.a libnet80211.a libpp.a librtc.a libsmartconfig.a libphy.a BINARY_BLOBS += $(addprefix esp-idf/components/esp_wifi/lib/esp32s2/, $(BINARY_WIFI_BLOBS)) -ESP_IDF_COMPONENTS_EXPANDED += $(BUILD)/esp-idf/esp-idf/soc/soc/esp32s2/libsoc_esp32s2.a esp-idf/components/xtensa/esp32s2/libxt_hal.a +ESP_IDF_COMPONENTS_EXPANDED += $(BUILD)/esp-idf/esp-idf/soc/soc/esp32s2/libsoc_esp32s2.a ESP_AUTOGEN_LD = $(BUILD)/esp-idf/esp-idf/esp32s2/esp32s2_out.ld $(BUILD)/esp-idf/esp-idf/esp32s2/ld/esp32s2.project.ld FLASH_FLAGS = --flash_mode $(CIRCUITPY_ESP_FLASH_MODE) --flash_freq $(CIRCUITPY_ESP_FLASH_FREQ) --flash_size $(CIRCUITPY_ESP_FLASH_SIZE) @@ -309,7 +310,6 @@ esp-idf-stamp: $(BUILD)/esp-idf/config/sdkconfig.h esp-idf/esp32s2/ld/esp32s2.project.ld \ esp-idf/esp_event/libesp_event.a \ esp-idf/esp_netif/libesp_netif.a \ - esp-idf/esp_rom/libesp_rom.a \ esp-idf/esp_system/libesp_system.a \ esp-idf/esp_wifi/libesp_wifi.a \ esp-idf/lwip/liblwip.a \ @@ -337,10 +337,10 @@ $(BUILD)/firmware.uf2: $(BUILD)/circuitpython-firmware.bin $(Q)$(PYTHON3) $(TOP)/tools/uf2/utils/uf2conv.py -f 0xbfdd4eee -b 0x0000 -c -o $@ $^ flash: $(BUILD)/firmware.bin - esptool.py --chip esp32s2 -p $(PORT) --no-stub -b 460800 --before=default_reset --after=no_reset write_flash $(FLASH_FLAGS) 0x0000 $^ + esptool.py --chip esp32s2 -p $(PORT) -b 460800 --before=default_reset --after=no_reset write_flash $(FLASH_FLAGS) 0x0000 $^ flash-circuitpython-only: $(BUILD)/circuitpython-firmware.bin - esptool.py --chip esp32s2 -p $(PORT) --no-stub -b 460800 --before=default_reset --after=no_reset write_flash $(FLASH_FLAGS) 0x10000 $^ + esptool.py --chip esp32s2 -p $(PORT) -b 460800 --before=default_reset --after=no_reset write_flash $(FLASH_FLAGS) 0x10000 $^ include $(TOP)/py/mkrules.mk diff --git a/ports/esp32s2/boards/adafruit_magtag_2.9_grayscale/mpconfigboard.h b/ports/esp32s2/boards/adafruit_magtag_2.9_grayscale/mpconfigboard.h index be376e5a9..8dfe91271 100644 --- a/ports/esp32s2/boards/adafruit_magtag_2.9_grayscale/mpconfigboard.h +++ b/ports/esp32s2/boards/adafruit_magtag_2.9_grayscale/mpconfigboard.h @@ -26,7 +26,7 @@ //Micropython setup -#define MICROPY_HW_BOARD_NAME "MagTag" +#define MICROPY_HW_BOARD_NAME "Adafruit MagTag" #define MICROPY_HW_MCU_NAME "ESP32S2" #define MICROPY_HW_NEOPIXEL (&pin_GPIO1) diff --git a/ports/esp32s2/boards/adafruit_metro_esp32s2/mpconfigboard.h b/ports/esp32s2/boards/adafruit_metro_esp32s2/mpconfigboard.h index 7280aab9c..b25d7d116 100644 --- a/ports/esp32s2/boards/adafruit_metro_esp32s2/mpconfigboard.h +++ b/ports/esp32s2/boards/adafruit_metro_esp32s2/mpconfigboard.h @@ -26,7 +26,7 @@ //Micropython setup -#define MICROPY_HW_BOARD_NAME "Metro ESP32S2" +#define MICROPY_HW_BOARD_NAME "Adafruit Metro ESP32S2" #define MICROPY_HW_MCU_NAME "ESP32S2" #define MICROPY_HW_NEOPIXEL (&pin_GPIO45) diff --git a/ports/esp32s2/common-hal/alarm/__init__.c b/ports/esp32s2/common-hal/alarm/__init__.c index 9e5772eac..0b1a7f049 100644 --- a/ports/esp32s2/common-hal/alarm/__init__.c +++ b/ports/esp32s2/common-hal/alarm/__init__.c @@ -25,10 +25,12 @@ * THE SOFTWARE. */ +#include "py/gc.h" #include "py/obj.h" #include "py/objtuple.h" #include "py/runtime.h" +#include "shared-bindings/alarm/__init__.h" #include "shared-bindings/alarm/SleepMemory.h" #include "shared-bindings/alarm/pin/PinAlarm.h" #include "shared-bindings/alarm/time/TimeAlarm.h" @@ -40,10 +42,11 @@ #include "supervisor/port.h" #include "supervisor/shared/workflow.h" -#include "common-hal/alarm/__init__.h" - #include "esp_sleep.h" +#include "components/soc/soc/esp32s2/include/soc/rtc_cntl_reg.h" +#include "components/driver/include/driver/uart.h" + // Singleton instance of SleepMemory. const alarm_sleep_memory_obj_t alarm_sleep_memory_obj = { .base = { @@ -53,19 +56,22 @@ const alarm_sleep_memory_obj_t alarm_sleep_memory_obj = { void 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 esp_sleep_wakeup_cause_t _get_wakeup_cause(void) { + if (alarm_pin_pinalarm_woke_us_up()) { + return ESP_SLEEP_WAKEUP_GPIO; + } if (alarm_time_timealarm_woke_us_up()) { return ESP_SLEEP_WAKEUP_TIMER; } if (alarm_touch_touchalarm_woke_us_up()) { return ESP_SLEEP_WAKEUP_TOUCHPAD; } - return esp_sleep_get_wakeup_cause(); } @@ -74,14 +80,16 @@ bool alarm_woken_from_sleep(void) { } STATIC mp_obj_t _get_wake_alarm(size_t n_alarms, const mp_obj_t *alarms) { - switch (_get_wakeup_cause()) { + 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_EXT0: { - // TODO: implement pin alarm wake. - break; + 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: @@ -102,24 +110,8 @@ mp_obj_t common_hal_alarm_get_wake_alarm(void) { // 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) { - bool time_alarm_set = false; - alarm_time_time_alarm_obj_t *time_alarm = MP_OBJ_NULL; - - for (size_t i = 0; i < n_alarms; i++) { - if (MP_OBJ_IS_TYPE(alarms[i], &alarm_pin_pin_alarm_type)) { - mp_raise_NotImplementedError(translate("PinAlarm not yet implemented")); - } else if (MP_OBJ_IS_TYPE(alarms[i], &alarm_time_time_alarm_type)) { - if (time_alarm_set) { - mp_raise_ValueError(translate("Only one alarm.time alarm can be set.")); - } - time_alarm = MP_OBJ_TO_PTR(alarms[i]); - time_alarm_set = true; - } - } - - if (time_alarm_set) { - alarm_time_timealarm_set_alarm(time_alarm); - } + 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); } @@ -136,21 +128,16 @@ STATIC void _idle_until_alarm(void) { } } -// Is it safe to do a light sleep? Check whether WiFi is on or there are -// other ongoing tasks that should not be shut down. -STATIC bool _light_sleep_ok(void) { - return !common_hal_wifi_radio_get_enabled(&common_hal_wifi_radio_obj) && !supervisor_workflow_active(); -} - mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj_t *alarms) { _setup_sleep_alarms(false, n_alarms, alarms); - // Light sleep can break some functionality so only do it when possible. Otherwise we idle. - if (_light_sleep_ok()) { - esp_light_sleep_start(); - } else { - _idle_until_alarm(); + // We cannot esp_light_sleep_start() here because it shuts down all non-RTC peripherals. + _idle_until_alarm(); + + if (mp_hal_is_interrupted()) { + return mp_const_none; // Shouldn't be given to python code because exception handling should kick in. } + mp_obj_t wake_alarm = _get_wake_alarm(n_alarms, alarms); alarm_reset(); return wake_alarm; @@ -161,8 +148,13 @@ void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *ala } void NORETURN alarm_enter_deep_sleep(void) { + alarm_pin_pinalarm_prepare_for_deep_sleep(); alarm_touch_touchalarm_prepare_for_deep_sleep(); // 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(alarm_get_wake_alarm()); +} diff --git a/ports/esp32s2/common-hal/alarm/pin/PinAlarm.c b/ports/esp32s2/common-hal/alarm/pin/PinAlarm.c index 582a66572..df8d10ef9 100644 --- a/ports/esp32s2/common-hal/alarm/pin/PinAlarm.c +++ b/ports/esp32s2/common-hal/alarm/pin/PinAlarm.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2020 Dan Halbert for Adafruit Industries + * Copyright (c) 2020 Scott Shawcroft 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 @@ -24,30 +25,283 @@ * THE SOFTWARE. */ -#include "esp_sleep.h" +#include "py/runtime.h" #include "shared-bindings/alarm/pin/PinAlarm.h" +#include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/microcontroller/Pin.h" +#include "supervisor/esp_port.h" -void common_hal_alarm_pin_pin_alarm_construct(alarm_pin_pin_alarm_obj_t *self, mcu_pin_obj_t *pin, bool value, bool edge, bool pull) { +#include "components/driver/include/driver/rtc_io.h" +#include "components/esp32s2/include/esp_sleep.h" +#include "components/freertos/include/freertos/FreeRTOS.h" +#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) { + if (edge) { + mp_raise_ValueError(translate("Cannot wake on pin edge. Only level.")); + } + + if (pull && !GPIO_IS_VALID_OUTPUT_GPIO(pin->number)) { + mp_raise_ValueError(translate("Cannot pull on input-only pin.")); + } self->pin = pin; self->value = value; - self->edge = edge; self->pull = pull; } -mcu_pin_obj_t *common_hal_alarm_pin_pin_alarm_get_pin(alarm_pin_pin_alarm_obj_t *self) { +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_pin_alarm_get_value(alarm_pin_pin_alarm_obj_t *self) { +bool common_hal_alarm_pin_pinalarm_get_value(alarm_pin_pinalarm_obj_t *self) { return self->value; } -bool common_hal_alarm_pin_pin_alarm_get_edge(alarm_pin_pin_alarm_obj_t *self) { - return self->edge; +bool common_hal_alarm_pin_pinalarm_get_edge(alarm_pin_pinalarm_obj_t *self) { + return false; } -bool common_hal_alarm_pin_pin_alarm_get_pull(alarm_pin_pin_alarm_obj_t *self) { +bool common_hal_alarm_pin_pinalarm_get_pull(alarm_pin_pinalarm_obj_t *self) { return self->pull; } + +gpio_isr_handle_t gpio_interrupt_handle; +// Low and high are relative to pin number. 32+ is high. <32 is low. +static volatile uint32_t pin_31_0_status = 0; +static volatile uint32_t pin_63_32_status = 0; +void gpio_interrupt(void *arg) { + (void) arg; + + gpio_ll_get_intr_status(&GPIO, xPortGetCoreID(), (uint32_t*) &pin_31_0_status); + gpio_ll_clear_intr_status(&GPIO, pin_31_0_status); + gpio_ll_get_intr_status_high(&GPIO, xPortGetCoreID(), (uint32_t*) &pin_63_32_status); + gpio_ll_clear_intr_status_high(&GPIO, pin_63_32_status); + + // disable the interrupts that fired, maybe all of them + for (size_t i = 0; i < 32; i++) { + uint32_t mask = 1 << i; + if ((pin_31_0_status & mask) != 0) { + gpio_ll_intr_disable(&GPIO, i); + } + if ((pin_63_32_status & mask) != 0) { + gpio_ll_intr_disable(&GPIO, 32 + i); + } + } + BaseType_t high_task_wakeup; + vTaskNotifyGiveFromISR(circuitpython_task, &high_task_wakeup); + if (high_task_wakeup) { + portYIELD_FROM_ISR(); + } +} + +bool alarm_pin_pinalarm_woke_us_up(void) { + return pin_31_0_status != 0 || pin_63_32_status != 0; +} + +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. + 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)) { + continue; + } + alarm_pin_pinalarm_obj_t *alarm = MP_OBJ_TO_PTR(alarms[i]); + if ((pin_status & (1ull << alarm->pin->number)) != 0) { + return alarms[i]; + } + } + esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause(); + size_t pin_number = 64; + if (cause == ESP_SLEEP_WAKEUP_EXT0) { + pin_number = REG_GET_FIELD(RTC_IO_EXT_WAKEUP0_REG, RTC_IO_EXT_WAKEUP0_SEL); + } else { + if (cause == ESP_SLEEP_WAKEUP_EXT1) { + pin_status = esp_sleep_get_ext1_wakeup_status(); + } + // If the cause is GPIO, we've already snagged pin_status in the interrupt. + // We'll only get here if we pretended to deep sleep. Light sleep will + // pass in existing objects. + for (size_t i = 0; i < 64; i++) { + if ((pin_status & (1ull << i)) != 0) { + pin_number = i; + break; + } + } + } + + alarm_pin_pinalarm_obj_t *alarm = m_new_obj(alarm_pin_pinalarm_obj_t); + alarm->base.type = &alarm_pin_pinalarm_type; + alarm->pin = NULL; + // Map the pin number back to a pin object. + for (size_t i = 0; i < mcu_pin_globals.map.used; i++) { + const mcu_pin_obj_t* pin_obj = MP_OBJ_TO_PTR(mcu_pin_globals.map.table[i].value); + if ((size_t) pin_obj->number == pin_number) { + alarm->pin = mcu_pin_globals.map.table[i].value; + break; + } + } + return alarm; +} + +// These must be static because we need to configure pulls later, right before +// deep sleep. +static uint64_t high_alarms = 0; +static uint64_t low_alarms = 0; +static uint64_t pull_pins = 0; + +void alarm_pin_pinalarm_reset(void) { + if (gpio_interrupt_handle != NULL) { + esp_intr_free(gpio_interrupt_handle); + gpio_interrupt_handle = NULL; + } + for (size_t i = 0; i < 64; i++) { + uint64_t mask = 1ull << i; + bool high = (high_alarms & mask) != 0; + bool low = (low_alarms & mask) != 0; + if (!(high || low)) { + continue; + } + reset_pin_number(i); + } + high_alarms = 0; + low_alarms = 0; + pull_pins = 0; + pin_63_32_status = 0; + pin_31_0_status = 0; +} + +void alarm_pin_pinalarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms) { + // Bitmask of wake up settings. + size_t high_count = 0; + size_t low_count = 0; + + for (size_t i = 0; i < n_alarms; i++) { + // TODO: Check for ULP or touch alarms because they can't coexist with GPIO alarms. + if (!MP_OBJ_IS_TYPE(alarms[i], &alarm_pin_pinalarm_type)) { + continue; + } + alarm_pin_pinalarm_obj_t *alarm = MP_OBJ_TO_PTR(alarms[i]); + + gpio_num_t pin_number = alarm->pin->number; + if (alarm->value) { + high_alarms |= 1ull << pin_number; + high_count++; + } else { + low_alarms |= 1ull << pin_number; + low_count++; + } + if (alarm->pull) { + pull_pins |= 1ull << pin_number; + } + } + if (high_count == 0 && low_count == 0) { + return; + } + if (deep_sleep && low_count > 2 && high_count == 0) { + mp_raise_ValueError(translate("Can only alarm on two low pins from deep sleep.")); + } + if (deep_sleep && low_count > 1 && high_count > 0) { + mp_raise_ValueError(translate("Can only alarm on one low pin while others alarm high from deep sleep.")); + } + // Only use ext0 and ext1 during deep sleep. + if (deep_sleep) { + if (high_count > 0) { + if (esp_sleep_enable_ext1_wakeup(high_alarms, ESP_EXT1_WAKEUP_ANY_HIGH) != ESP_OK) { + mp_raise_ValueError(translate("Can only alarm on RTC IO from deep sleep.")); + } + } + size_t low_pins[2]; + size_t j = 0; + for (size_t i = 0; i < 64; i++) { + uint64_t mask = 1ull << i; + if ((low_alarms & mask) != 0) { + low_pins[j++] = i; + } + if (j == 2) { + break; + } + } + if (low_count > 1) { + if (esp_sleep_enable_ext1_wakeup(1ull << low_pins[1], ESP_EXT1_WAKEUP_ALL_LOW) != ESP_OK) { + mp_raise_ValueError(translate("Can only alarm on RTC IO from deep sleep.")); + } + } + if (low_count > 0) { + if (esp_sleep_enable_ext0_wakeup(low_pins[0], 0) != ESP_OK) { + mp_raise_ValueError(translate("Can only alarm on RTC IO from deep sleep.")); + } + } + } else { + // Enable GPIO wake up if we're sleeping. + esp_sleep_enable_gpio_wakeup(); + } + // Set GPIO interrupts so they wake us from light sleep or from idle via the + // interrupt handler above. + pin_31_0_status = 0; + pin_63_32_status = 0; + if (gpio_isr_register(gpio_interrupt, NULL, 0, &gpio_interrupt_handle) != ESP_OK) { + mp_raise_ValueError(translate("Can only alarm on RTC IO from deep sleep.")); + } + for (size_t i = 0; i < 64; i++) { + uint64_t mask = 1ull << i; + bool high = (high_alarms & mask) != 0; + bool low = (low_alarms & mask) != 0; + bool pull = (pull_pins & mask) != 0; + if (!(high || low)) { + continue; + } + if (rtc_gpio_is_valid_gpio(i)) { + rtc_gpio_deinit(i); + } + gpio_int_type_t interrupt_mode = GPIO_INTR_DISABLE; + gpio_pull_mode_t pull_mode = GPIO_FLOATING; + if (high) { + interrupt_mode = GPIO_INTR_HIGH_LEVEL; + pull_mode = GPIO_PULLDOWN_ONLY; + } + if (low) { + interrupt_mode = GPIO_INTR_LOW_LEVEL; + pull_mode = GPIO_PULLUP_ONLY; + } + gpio_set_direction(i, GPIO_MODE_DEF_INPUT); + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[i], PIN_FUNC_GPIO); + if (pull) { + gpio_set_pull_mode(i, pull_mode); + size_t j = 0; + while (gpio_get_level(i) == false) { + j++; + } + } + never_reset_pin_number(i); + // Sets interrupt type and wakeup bits. + gpio_wakeup_enable(i, interrupt_mode); + gpio_intr_enable(i); + } +} + + +void alarm_pin_pinalarm_prepare_for_deep_sleep(void) { + if (pull_pins == 0) { + return; + } + for (size_t i = 0; i < 64; i++) { + uint64_t mask = 1ull << i; + bool pull = (pull_pins & mask) != 0; + if (!pull) { + continue; + } + bool high = (high_alarms & mask) != 0; + bool low = (low_alarms & mask) != 0; + // The pull direction is opposite from alarm value. + if (high) { + rtc_gpio_pullup_dis(i); + rtc_gpio_pulldown_en(i); + } + if (low) { + rtc_gpio_pullup_en(i); + rtc_gpio_pulldown_dis(i); + } + } +} diff --git a/ports/esp32s2/common-hal/alarm/pin/PinAlarm.h b/ports/esp32s2/common-hal/alarm/pin/PinAlarm.h index 0eaa7777f..93672c1f2 100644 --- a/ports/esp32s2/common-hal/alarm/pin/PinAlarm.h +++ b/ports/esp32s2/common-hal/alarm/pin/PinAlarm.h @@ -31,7 +31,11 @@ typedef struct { mp_obj_base_t base; mcu_pin_obj_t *pin; bool value; - bool all_same_value; - bool edge; bool pull; -} alarm_pin_pin_alarm_obj_t; +} 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); diff --git a/ports/esp32s2/common-hal/alarm/time/TimeAlarm.c b/ports/esp32s2/common-hal/alarm/time/TimeAlarm.c index 4d0bba238..bcde0ab3c 100644 --- a/ports/esp32s2/common-hal/alarm/time/TimeAlarm.c +++ b/ports/esp32s2/common-hal/alarm/time/TimeAlarm.c @@ -34,23 +34,23 @@ #include "shared-bindings/alarm/time/TimeAlarm.h" #include "shared-bindings/time/__init__.h" -void common_hal_alarm_time_time_alarm_construct(alarm_time_time_alarm_obj_t *self, mp_float_t monotonic_time) { +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_time_alarm_get_monotonic_time(alarm_time_time_alarm_obj_t *self) { +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_time_alarm_type)) { + if (MP_OBJ_IS_TYPE(alarms[i], &alarm_time_timealarm_type)) { return alarms[i]; } } - alarm_time_time_alarm_obj_t *timer = m_new_obj(alarm_time_time_alarm_obj_t); - timer->base.type = &alarm_time_time_alarm_type; + 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; @@ -63,9 +63,7 @@ STATIC bool woke_up = false; void timer_callback(void *arg) { (void) arg; woke_up = true; - if (sleeping_circuitpython_task) { - xTaskNotifyGive(sleeping_circuitpython_task); - } + xTaskNotifyGive(circuitpython_task); } bool alarm_time_timealarm_woke_us_up(void) { @@ -79,7 +77,24 @@ void alarm_time_timealarm_reset(void) { woke_up = false; } -void alarm_time_timealarm_set_alarm(alarm_time_time_alarm_obj_t *self) { +void alarm_time_timealarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms) { + bool timealarm_set = false; + alarm_time_timealarm_obj_t *timealarm = MP_OBJ_NULL; + + 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; + } + if (pretend_sleep_timer != NULL) { esp_timer_stop(pretend_sleep_timer); } else { @@ -94,7 +109,7 @@ void alarm_time_timealarm_set_alarm(alarm_time_time_alarm_obj_t *self) { // 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; - mp_float_t wakeup_in_secs = MAX(0.0f, self->monotonic_time - now_secs); + mp_float_t wakeup_in_secs = MAX(0.0f, timealarm->monotonic_time - now_secs); const uint64_t sleep_for_us = (uint64_t) (wakeup_in_secs * 1000000); esp_sleep_enable_timer_wakeup(sleep_for_us); diff --git a/ports/esp32s2/common-hal/alarm/time/TimeAlarm.h b/ports/esp32s2/common-hal/alarm/time/TimeAlarm.h index 04c553009..dfd75524f 100644 --- a/ports/esp32s2/common-hal/alarm/time/TimeAlarm.h +++ b/ports/esp32s2/common-hal/alarm/time/TimeAlarm.h @@ -30,11 +30,11 @@ typedef struct { mp_obj_base_t base; mp_float_t monotonic_time; // values compatible with time.monotonic_time() -} alarm_time_time_alarm_obj_t; +} 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_alarm(alarm_time_time_alarm_obj_t *self); +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/esp32s2/common-hal/analogio/AnalogIn.h b/ports/esp32s2/common-hal/analogio/AnalogIn.h index fed4d0217..b9c4866f2 100644 --- a/ports/esp32s2/common-hal/analogio/AnalogIn.h +++ b/ports/esp32s2/common-hal/analogio/AnalogIn.h @@ -29,7 +29,7 @@ #include "common-hal/microcontroller/Pin.h" -#include "components/hal/include/hal/adc_types.h" +#include "components/soc/include/hal/adc_types.h" #include "FreeRTOS.h" #include "freertos/semphr.h" #include "py/obj.h" diff --git a/ports/esp32s2/common-hal/busio/I2C.h b/ports/esp32s2/common-hal/busio/I2C.h index c39d6d744..1a989e30a 100644 --- a/ports/esp32s2/common-hal/busio/I2C.h +++ b/ports/esp32s2/common-hal/busio/I2C.h @@ -29,7 +29,7 @@ #include "common-hal/microcontroller/Pin.h" -#include "components/hal/include/hal/i2c_types.h" +#include "components/soc/include/hal/i2c_types.h" #include "FreeRTOS.h" #include "freertos/semphr.h" #include "py/obj.h" diff --git a/ports/esp32s2/common-hal/busio/SPI.c b/ports/esp32s2/common-hal/busio/SPI.c index 562881585..c4d54ec81 100644 --- a/ports/esp32s2/common-hal/busio/SPI.c +++ b/ports/esp32s2/common-hal/busio/SPI.c @@ -248,12 +248,8 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { spi_bus_free(self->host_id); common_hal_reset_pin(self->clock_pin); - if (self->MOSI_pin != NULL) { - common_hal_reset_pin(self->MOSI_pin); - } - if (self->MISO_pin != NULL) { - common_hal_reset_pin(self->MISO_pin); - } + common_hal_reset_pin(self->MOSI_pin); + common_hal_reset_pin(self->MISO_pin); self->clock_pin = NULL; self->MISO_pin = NULL; self->MOSI_pin = NULL; @@ -273,7 +269,7 @@ bool common_hal_busio_spi_configure(busio_spi_obj_t *self, self->bits = bits; self->target_frequency = baudrate; self->hal_context.timing_conf = &self->timing_conf; - esp_err_t result = spi_hal_cal_clock_conf(&self->hal_context, + esp_err_t result = spi_hal_get_clock_conf(&self->hal_context, self->target_frequency, 128 /* duty_cycle */, self->connected_through_gpio, @@ -366,7 +362,8 @@ bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, const uint8_t *data_ou burst_length = sizeof(hal->hw->data_buf); // When switching to non-DMA, we need to make sure DMA is off. Otherwise, // the S2 will transmit zeroes instead of our data. - spi_ll_txdma_disable(hal->hw); + hal->hw->dma_out_link.dma_tx_ena = 0; + hal->hw->dma_out_link.stop = 1; } // This rounds up. diff --git a/ports/esp32s2/common-hal/busio/SPI.h b/ports/esp32s2/common-hal/busio/SPI.h index f6c1c344a..d6203feae 100644 --- a/ports/esp32s2/common-hal/busio/SPI.h +++ b/ports/esp32s2/common-hal/busio/SPI.h @@ -30,8 +30,8 @@ #include "common-hal/microcontroller/Pin.h" #include "components/driver/include/driver/spi_common_internal.h" -#include "components/hal/include/hal/spi_hal.h" -#include "components/hal/include/hal/spi_types.h" +#include "components/soc/include/hal/spi_hal.h" +#include "components/soc/include/hal/spi_types.h" #include "py/obj.h" typedef struct { diff --git a/ports/esp32s2/common-hal/busio/UART.h b/ports/esp32s2/common-hal/busio/UART.h index 1d7f13511..751fb2e00 100644 --- a/ports/esp32s2/common-hal/busio/UART.h +++ b/ports/esp32s2/common-hal/busio/UART.h @@ -29,7 +29,7 @@ #include "common-hal/microcontroller/Pin.h" -#include "components/hal/include/hal/uart_types.h" +#include "components/soc/include/hal/uart_types.h" #include "py/obj.h" typedef struct { diff --git a/ports/esp32s2/common-hal/digitalio/DigitalInOut.c b/ports/esp32s2/common-hal/digitalio/DigitalInOut.c index 152db1e71..a2a0209f9 100644 --- a/ports/esp32s2/common-hal/digitalio/DigitalInOut.c +++ b/ports/esp32s2/common-hal/digitalio/DigitalInOut.c @@ -30,7 +30,7 @@ #include "components/driver/include/driver/gpio.h" -#include "components/hal/include/hal/gpio_hal.h" +#include "components/soc/include/hal/gpio_hal.h" void common_hal_digitalio_digitalinout_never_reset( digitalio_digitalinout_obj_t *self) { diff --git a/ports/esp32s2/common-hal/dualbank/__init__.c b/ports/esp32s2/common-hal/dualbank/__init__.c new file mode 100644 index 000000000..1414f131d --- /dev/null +++ b/ports/esp32s2/common-hal/dualbank/__init__.c @@ -0,0 +1,139 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 microDev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "common-hal/dualbank/__init__.h" +#include "shared-bindings/dualbank/__init__.h" + +#include <string.h> + +#include "esp_log.h" +#include "esp_ota_ops.h" + +static const esp_partition_t *update_partition = NULL; +static esp_ota_handle_t update_handle = 0; + +static const char *TAG = "dualbank"; + +void dualbank_reset(void) { + // should use `abort` instead of `end` + // but not in idf v4.2 + // esp_ota_abort(update_handle); + if (esp_ota_end(update_handle) == ESP_OK) { + update_handle = 0; + update_partition = NULL; + } +} + +static void __attribute__((noreturn)) task_fatal_error(void) { + ESP_LOGE(TAG, "Exiting task due to fatal error..."); + mp_raise_RuntimeError(translate("Update Failed")); +} + +void common_hal_dualbank_flash(const void *buf, const size_t len, const size_t offset) { + esp_err_t err; + + const esp_partition_t *running = esp_ota_get_running_partition(); + const esp_partition_t *last_invalid = esp_ota_get_last_invalid_partition(); + + if (update_partition == NULL) { + update_partition = esp_ota_get_next_update_partition(NULL); + + ESP_LOGI(TAG, "Running partition type %d subtype %d (offset 0x%08x)", + running->type, running->subtype, running->address); + + ESP_LOGI(TAG, "Writing partition type %d subtype %d (offset 0x%08x)\n", + update_partition->type, update_partition->subtype, update_partition->address); + + assert(update_partition != NULL); + } + + if (update_handle == 0) { + if (len > sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t)) { + esp_app_desc_t new_app_info; + memcpy(&new_app_info, &((char *)buf)[sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t)], sizeof(esp_app_desc_t)); + ESP_LOGI(TAG, "New firmware version: %s", new_app_info.version); + + esp_app_desc_t running_app_info; + if (esp_ota_get_partition_description(running, &running_app_info) == ESP_OK) { + ESP_LOGI(TAG, "Running firmware version: %s", running_app_info.version); + } + + esp_app_desc_t invalid_app_info; + if (esp_ota_get_partition_description(last_invalid, &invalid_app_info) == ESP_OK) { + ESP_LOGI(TAG, "Last invalid firmware version: %s", invalid_app_info.version); + } + + // check new version with running version + if (memcmp(new_app_info.version, running_app_info.version, sizeof(new_app_info.version)) == 0) { + ESP_LOGW(TAG, "New version is the same as running version."); + task_fatal_error(); + } + + // check new version with last invalid partition + if (last_invalid != NULL) { + if (memcmp(new_app_info.version, invalid_app_info.version, sizeof(new_app_info.version)) == 0) { + ESP_LOGW(TAG, "New version is the same as invalid version."); + task_fatal_error(); + } + } + + err = esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &update_handle); + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err)); + task_fatal_error(); + } + } else { + ESP_LOGE(TAG, "received package is not fit len"); + task_fatal_error(); + } + } + + if (offset == 0) { + err = esp_ota_write(update_handle, buf, len); + } else { + err = esp_ota_write_with_offset(update_handle, buf, len, offset); + } + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_ota_write failed (%s)", esp_err_to_name(err)); + task_fatal_error(); + } +} + +void common_hal_dualbank_switch(void) { + if (esp_ota_end(update_handle) == ESP_OK) { + update_handle = 0; + update_partition = NULL; + } + esp_err_t err = esp_ota_set_boot_partition(esp_ota_get_next_update_partition(NULL)); + if (err != ESP_OK) { + if (err == ESP_ERR_OTA_VALIDATE_FAILED) { + ESP_LOGE(TAG, "Image validation failed, image is corrupted"); + mp_raise_RuntimeError(translate("Firmware image is invalid")); + } + ESP_LOGE(TAG, "esp_ota_set_boot_partition failed (%s)!", esp_err_to_name(err)); + task_fatal_error(); + } +} diff --git a/ports/esp32s2/common-hal/dualbank/__init__.h b/ports/esp32s2/common-hal/dualbank/__init__.h new file mode 100644 index 000000000..8b18336c9 --- /dev/null +++ b/ports/esp32s2/common-hal/dualbank/__init__.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 microDev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_ESP32S2_COMMON_HAL_DUALBANK___INIT___H +#define MICROPY_INCLUDED_ESP32S2_COMMON_HAL_DUALBANK___INIT___H + +extern void dualbank_reset(void); + +#endif //MICROPY_INCLUDED_ESP32S2_COMMON_HAL_DUALBANK___INIT___H diff --git a/ports/esp32s2/common-hal/microcontroller/Pin.c b/ports/esp32s2/common-hal/microcontroller/Pin.c index 81dfa1308..fca89ce8e 100644 --- a/ports/esp32s2/common-hal/microcontroller/Pin.c +++ b/ports/esp32s2/common-hal/microcontroller/Pin.c @@ -32,7 +32,7 @@ #include "py/mphal.h" #include "components/driver/include/driver/gpio.h" -#include "components/hal/include/hal/gpio_hal.h" +#include "components/soc/include/hal/gpio_hal.h" #ifdef MICROPY_HW_NEOPIXEL bool neopixel_in_use; @@ -89,6 +89,9 @@ void reset_pin_number(gpio_num_t pin_number) { } void common_hal_reset_pin(const mcu_pin_obj_t* pin) { + if (pin == NULL) { + return; + } reset_pin_number(pin->number); } diff --git a/ports/esp32s2/common-hal/wifi/Network.c b/ports/esp32s2/common-hal/wifi/Network.c index e90b3d552..2674df065 100644 --- a/ports/esp32s2/common-hal/wifi/Network.c +++ b/ports/esp32s2/common-hal/wifi/Network.c @@ -48,3 +48,9 @@ mp_obj_t common_hal_wifi_network_get_rssi(wifi_network_obj_t *self) { mp_obj_t common_hal_wifi_network_get_channel(wifi_network_obj_t *self) { return mp_obj_new_int(self->record.primary); } + +mp_obj_t common_hal_wifi_network_get_country(wifi_network_obj_t *self) { + const char* cstr = (const char*) self->record.country.cc; + // 2 instead of strlen(cstr) as this gives us only the country-code + return mp_obj_new_str(cstr, 2); +} diff --git a/ports/esp32s2/common-hal/wifi/Radio.c b/ports/esp32s2/common-hal/wifi/Radio.c index 05506783e..3bc2258a4 100644 --- a/ports/esp32s2/common-hal/wifi/Radio.c +++ b/ports/esp32s2/common-hal/wifi/Radio.c @@ -198,6 +198,17 @@ mp_obj_t common_hal_wifi_radio_get_ap_info(wifi_radio_obj_t *self) { if (esp_wifi_sta_get_ap_info(&self->ap_info.record) != ESP_OK){ return mp_const_none; } else { + if (strlen(self->ap_info.record.country.cc) == 0) { + // Workaround to fill country related information in ap_info until ESP-IDF carries a fix + // esp_wifi_sta_get_ap_info does not appear to fill wifi_country_t (e.g. country.cc) details + // (IDFGH-4437) #6267 + // Note: It is possible that Wi-Fi APs don't have a CC set, then even after this workaround + // the element would remain empty. + memset(&self->ap_info.record.country, 0, sizeof(wifi_country_t)); + if (esp_wifi_get_country(&self->ap_info.record.country) != ESP_OK) { + return mp_const_none; + } + } memcpy(&ap_info->record, &self->ap_info.record, sizeof(wifi_ap_record_t)); return MP_OBJ_FROM_PTR(ap_info); } diff --git a/ports/esp32s2/esp-idf b/ports/esp32s2/esp-idf -Subproject d06744f5efc382c61cbad8758107cec308feef0 +Subproject ebe7784258d8c10e9cc334ccc00c3fd270746c8 diff --git a/ports/esp32s2/mpconfigport.mk b/ports/esp32s2/mpconfigport.mk index b3b2a6d70..2ad8afb51 100644 --- a/ports/esp32s2/mpconfigport.mk +++ b/ports/esp32s2/mpconfigport.mk @@ -19,6 +19,7 @@ CIRCUITPY_AUDIOBUSIO = 0 CIRCUITPY_AUDIOIO = 0 CIRCUITPY_CANIO = 1 CIRCUITPY_COUNTIO = 1 +CIRCUITPY_DUALBANK = 1 CIRCUITPY_FREQUENCYIO = 1 CIRCUITPY_I2CPERIPHERAL = 0 CIRCUITPY_ROTARYIO = 1 diff --git a/ports/esp32s2/peripherals/pins.h b/ports/esp32s2/peripherals/pins.h index dc28385bd..e0f5e7ddf 100644 --- a/ports/esp32s2/peripherals/pins.h +++ b/ports/esp32s2/peripherals/pins.h @@ -35,9 +35,9 @@ #include "esp32s2_peripherals_config.h" #include "esp-idf/config/sdkconfig.h" -#include "components/hal/include/hal/gpio_types.h" -#include "components/hal/include/hal/adc_types.h" -#include "components/hal/include/hal/touch_sensor_types.h" +#include "components/soc/include/hal/gpio_types.h" +#include "components/soc/include/hal/adc_types.h" +#include "components/soc/include/hal/touch_sensor_types.h" typedef struct { PIN_PREFIX_FIELDS diff --git a/ports/esp32s2/supervisor/esp_port.h b/ports/esp32s2/supervisor/esp_port.h index 1164666cd..8b9e13829 100644 --- a/ports/esp32s2/supervisor/esp_port.h +++ b/ports/esp32s2/supervisor/esp_port.h @@ -30,6 +30,6 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" -extern TaskHandle_t sleeping_circuitpython_task; +extern TaskHandle_t circuitpython_task; #endif // MICROPY_INCLUDED_ESP32S2_SUPERVISOR_PORT_H diff --git a/ports/esp32s2/supervisor/port.c b/ports/esp32s2/supervisor/port.c index 4dc985cfe..213473b8d 100644 --- a/ports/esp32s2/supervisor/port.c +++ b/ports/esp32s2/supervisor/port.c @@ -41,6 +41,7 @@ #include "common-hal/busio/I2C.h" #include "common-hal/busio/SPI.h" #include "common-hal/busio/UART.h" +#include "common-hal/dualbank/__init__.h" #include "common-hal/ps2io/Ps2.h" #include "common-hal/pulseio/PulseIn.h" #include "common-hal/pwmio/PWMOut.h" @@ -54,7 +55,7 @@ #include "peripherals/pcnt.h" #include "peripherals/timer.h" #include "peripherals/touch.h" -#include "components/esp_rom/include/esp_rom_uart.h" +#include "components/esp_rom/include/esp32s2/rom/ets_sys.h" #include "components/heap/include/esp_heap_caps.h" #include "components/xtensa/include/esp_debug_helpers.h" #include "components/soc/soc/esp32s2/include/soc/cache_memory.h" @@ -66,13 +67,22 @@ uint32_t* heap; uint32_t heap_size; STATIC esp_timer_handle_t _tick_timer; +STATIC esp_timer_handle_t _sleep_timer; + +TaskHandle_t circuitpython_task = NULL; extern void esp_restart(void) NORETURN; void tick_timer_cb(void* arg) { supervisor_tick(); + + // CircuitPython's VM is run in a separate FreeRTOS task from timer callbacks. So, we have to + // notify the main task every time in case it's waiting for us. + xTaskNotifyGive(circuitpython_task); } +void sleep_timer_cb(void* arg); + safe_mode_t port_init(void) { esp_timer_create_args_t args; args.callback = &tick_timer_cb; @@ -81,9 +91,17 @@ safe_mode_t port_init(void) { args.name = "CircuitPython Tick"; esp_timer_create(&args, &_tick_timer); - #ifdef DEBUG + args.callback = &sleep_timer_cb; + args.arg = NULL; + args.dispatch_method = ESP_TIMER_TASK; + args.name = "CircuitPython Sleep"; + esp_timer_create(&args, &_sleep_timer); + + circuitpython_task = xTaskGetCurrentTaskHandle(); + // Send the ROM output out of the UART. This includes early logs. - esp_rom_install_channel_putc(1, esp_rom_uart_putc); + #ifdef DEBUG + ets_install_uart_printf(); #endif heap = NULL; @@ -103,11 +121,15 @@ safe_mode_t port_init(void) { } esp_reset_reason_t reason = esp_reset_reason(); - if (reason == ESP_RST_BROWNOUT) { - return BROWNOUT; - } - if (reason == ESP_RST_PANIC) { - return HARD_CRASH; + switch (reason) { + case ESP_RST_BROWNOUT: + return BROWNOUT; + case ESP_RST_PANIC: + case ESP_RST_INT_WDT: + case ESP_RST_WDT: + return HARD_CRASH; + default: + break; } return NO_SAFE_MODE; @@ -123,6 +145,10 @@ void reset_port(void) { analogout_reset(); #endif +#if CIRCUITPY_DUALBANK + dualbank_reset(); +#endif + #if CIRCUITPY_PS2IO ps2_reset(); #endif @@ -247,32 +273,24 @@ void port_enable_tick(void) { // Disable 1/1024 second tick. void port_disable_tick(void) { esp_timer_stop(_tick_timer); - - // CircuitPython's VM is run in a separate FreeRTOS task from TinyUSB. - // Tick disable can happen via auto-reload so poke the main task here. - if (sleeping_circuitpython_task != NULL) { - xTaskNotifyGive(sleeping_circuitpython_task); - } } -TickType_t sleep_time_duration; +void sleep_timer_cb(void* arg) { + xTaskNotifyGive(circuitpython_task); +} void port_interrupt_after_ticks(uint32_t ticks) { - sleep_time_duration = (ticks * 100)/1024; + uint64_t timeout_us = ticks * 1000000ull / 1024; + if (esp_timer_start_once(_sleep_timer, timeout_us) != ESP_OK) { + esp_timer_stop(_sleep_timer); + esp_timer_start_once(_sleep_timer, timeout_us); + } } +// On the ESP we use FreeRTOS notifications instead of interrupts so this is a +// bit of a misnomer. void port_idle_until_interrupt(void) { - uint32_t notify_value = 0; - - if (sleep_time_duration == 0) { - return; - } - sleeping_circuitpython_task = xTaskGetCurrentTaskHandle(); - xTaskNotifyWait(0x01, 0x01, ¬ify_value, sleep_time_duration ); - sleeping_circuitpython_task = NULL; - if (notify_value == 1) { - mp_handle_pending(); - } + xTaskNotifyWait(0x01, 0x01, NULL, portMAX_DELAY); } // Wrap main in app_main that the IDF expects. diff --git a/ports/esp32s2/supervisor/usb.c b/ports/esp32s2/supervisor/usb.c index 2bfcdfb12..16657d407 100644 --- a/ports/esp32s2/supervisor/usb.c +++ b/ports/esp32s2/supervisor/usb.c @@ -26,6 +26,7 @@ */ #include "supervisor/usb.h" +#include "supervisor/esp_port.h" #include "lib/utils/interrupt_char.h" #include "lib/mp-readline/readline.h" @@ -33,8 +34,7 @@ #include "components/driver/include/driver/periph_ctrl.h" #include "components/driver/include/driver/gpio.h" #include "components/esp_rom/include/esp32s2/rom/gpio.h" -#include "components/esp_rom/include/esp_rom_gpio.h" -#include "components/hal/esp32s2/include/hal/gpio_ll.h" +#include "components/soc/src/esp32s2/include/hal/gpio_ll.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -52,8 +52,6 @@ StackType_t usb_device_stack[USBD_STACK_SIZE]; StaticTask_t usb_device_taskdef; -TaskHandle_t sleeping_circuitpython_task = NULL; - // USB Device Driver task // This top level thread process all usb events and invoke callbacks void usb_device_task(void* param) @@ -78,23 +76,20 @@ static void configure_pins (usb_hal_context_t *usb) * Introduce additional parameters in usb_hal_context_t when adding support * for USB Host. */ - for ( const usb_iopin_dsc_t *iopin = usb_periph_iopins; iopin->pin != -1; ++iopin ) { - if ( (usb->use_external_phy) || (iopin->ext_phy_only == 0) ) { - esp_rom_gpio_pad_select_gpio(iopin->pin); - if ( iopin->is_output ) { - esp_rom_gpio_connect_out_signal(iopin->pin, iopin->func, false, false); - } - else { - esp_rom_gpio_connect_in_signal(iopin->pin, iopin->func, false); - if ( (iopin->pin != GPIO_FUNC_IN_LOW) && (iopin->pin != GPIO_FUNC_IN_HIGH) ) { - gpio_ll_input_enable(&GPIO, iopin->pin); - } + for (const usb_iopin_dsc_t* iopin = usb_periph_iopins; iopin->pin != -1; ++iopin) { + if ((usb->use_external_phy) || (iopin->ext_phy_only == 0)) { + gpio_pad_select_gpio(iopin->pin); + if (iopin->is_output) { + gpio_matrix_out(iopin->pin, iopin->func, false, false); + } else { + gpio_matrix_in(iopin->pin, iopin->func, false); + gpio_pad_input_enable(iopin->pin); } - esp_rom_gpio_pad_unhold(iopin->pin); + gpio_pad_unhold(iopin->pin); } } - if ( !usb->use_external_phy ) { - gpio_set_drive_capability(USBPHY_DM_NUM, GPIO_DRIVE_CAP_3); + if (!usb->use_external_phy) { + gpio_set_drive_capability(USBPHY_DP_NUM, GPIO_DRIVE_CAP_3); gpio_set_drive_capability(USBPHY_DP_NUM, GPIO_DRIVE_CAP_3); } } @@ -131,8 +126,6 @@ void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char) mp_keyboard_interrupt(); // CircuitPython's VM is run in a separate FreeRTOS task from TinyUSB. // So, we must notify the other task when a CTRL-C is received. - if (sleeping_circuitpython_task != NULL) { - xTaskNotifyGive(sleeping_circuitpython_task); - } + xTaskNotifyGive(circuitpython_task); } } diff --git a/ports/litex/boards/fomu/fomu-spi.ld b/ports/litex/boards/fomu/fomu-spi.ld index 9b6443c67..e7db25b0c 100644 --- a/ports/litex/boards/fomu/fomu-spi.ld +++ b/ports/litex/boards/fomu/fomu-spi.ld @@ -51,6 +51,11 @@ SECTIONS *(.text.tu_edpt_dir) *(.text.tu_fifo_empty) *(.text.usbd_edpt_busy) + *(.text.usb_irq_handler) + *(.text.supervisor_tick) + *(.text.port_get_raw_ticks) + *(.text.__modsi3) + *(.text.__udivsi3) *(.text.irq_getmask) *(.text.irq_setmask) *(.text.irq_pending) diff --git a/ports/litex/common-hal/microcontroller/Pin.c b/ports/litex/common-hal/microcontroller/Pin.c index 38601e0d3..4d088a076 100644 --- a/ports/litex/common-hal/microcontroller/Pin.c +++ b/ports/litex/common-hal/microcontroller/Pin.c @@ -42,6 +42,9 @@ void reset_pin_number(uint8_t pin_port, uint8_t pin_number) { } void common_hal_reset_pin(const mcu_pin_obj_t* pin) { + if (pin == NULL) { + return; + } reset_pin_number(0, pin->number); } diff --git a/ports/litex/common-hal/microcontroller/__init__.c b/ports/litex/common-hal/microcontroller/__init__.c index 3c9166114..522a41e2e 100644 --- a/ports/litex/common-hal/microcontroller/__init__.c +++ b/ports/litex/common-hal/microcontroller/__init__.c @@ -59,12 +59,15 @@ void common_hal_mcu_delay_us(uint32_t delay) { volatile uint32_t nesting_count = 0; +__attribute__((section(".ramtext"))) void common_hal_mcu_disable_interrupts(void) { - irq_setie(0); - // __DMB(); + if (nesting_count == 0) { + irq_setie(0); + } nesting_count++; } +__attribute__((section(".ramtext"))) void common_hal_mcu_enable_interrupts(void) { if (nesting_count == 0) { // This is very very bad because it means there was mismatched disable/enables so we diff --git a/ports/litex/mphalport.c b/ports/litex/mphalport.c index 862f16393..c7369dc05 100644 --- a/ports/litex/mphalport.c +++ b/ports/litex/mphalport.c @@ -44,16 +44,31 @@ void mp_hal_delay_us(mp_uint_t delay) { extern void SysTick_Handler(void); +// This value contains the number of times "common_hal_mcu_disable_interrupts()" +// has been called without calling "common_hal_mcu_enable_interrupts()". Since +// this is the interrupt handler, that means we're handling an interrupt, so +// this value should be `0`. +// +// Interrupts should already be disabled when this handler is running, which means +// this value is logically already `1`. If we didn't do this, then interrupts would +// be prematurely enabled by interrupt handlers that enable and disable interrupts. +extern volatile uint32_t nesting_count; + __attribute__((section(".ramtext"))) void isr(void) { uint8_t irqs = irq_pending() & irq_getmask(); + // Increase the "nesting count". Note: This should be going from 0 -> 1. + nesting_count += 1; #ifdef CFG_TUSB_MCU if (irqs & (1 << USB_INTERRUPT)) usb_irq_handler(); #endif if (irqs & (1 << TIMER0_INTERRUPT)) SysTick_Handler(); + + // Decrease the "nesting count". Note: This should be going from 1 -> 0. + nesting_count -= 1; } mp_uint_t cpu_get_regs_and_sp(mp_uint_t *regs) { diff --git a/ports/litex/supervisor/port.c b/ports/litex/supervisor/port.c index 4dea02065..04ff1c09b 100644 --- a/ports/litex/supervisor/port.c +++ b/ports/litex/supervisor/port.c @@ -32,6 +32,8 @@ #include "irq.h" #include "csr.h" +#include "shared-bindings/microcontroller/__init__.h" + // Global millisecond tick count. 1024 per second because most RTCs are clocked with 32.768khz // crystals. volatile uint64_t raw_ticks = 0; @@ -129,9 +131,9 @@ uint32_t port_get_saved_word(void) { uint64_t port_get_raw_ticks(uint8_t* subticks) { // Reading 64 bits may take two loads, so turn of interrupts while we do it. - irq_setie(false); + common_hal_mcu_disable_interrupts(); uint64_t raw_tick_snapshot = raw_ticks; - irq_setie(true); + common_hal_mcu_enable_interrupts(); return raw_tick_snapshot; } diff --git a/ports/mimxrt10xx/boards/feather_m7_1011/mpconfigboard.h b/ports/mimxrt10xx/boards/feather_m7_1011/mpconfigboard.h index e96ec13dd..e027e2b5e 100644 --- a/ports/mimxrt10xx/boards/feather_m7_1011/mpconfigboard.h +++ b/ports/mimxrt10xx/boards/feather_m7_1011/mpconfigboard.h @@ -1,4 +1,4 @@ -#define MICROPY_HW_BOARD_NAME "Feather MIMXRT1011" +#define MICROPY_HW_BOARD_NAME "Adafruit Feather MIMXRT1011" #define MICROPY_HW_MCU_NAME "IMXRT1011DAE5A" #define MICROPY_HW_NEOPIXEL (&pin_GPIO_00) diff --git a/ports/mimxrt10xx/common-hal/busio/SPI.c b/ports/mimxrt10xx/common-hal/busio/SPI.c index 8fe1b799d..ce7cbea7e 100644 --- a/ports/mimxrt10xx/common-hal/busio/SPI.c +++ b/ports/mimxrt10xx/common-hal/busio/SPI.c @@ -220,12 +220,9 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { never_reset_spi[self->clock->bank_idx - 1] = false; common_hal_reset_pin(self->clock->pin); - if (self->mosi != NULL) { - common_hal_reset_pin(self->mosi->pin); - } - if (self->miso != NULL) { - common_hal_reset_pin(self->miso->pin); - } + common_hal_reset_pin(self->mosi->pin); + common_hal_reset_pin(self->miso->pin); + self->clock = NULL; self->mosi = NULL; self->miso = NULL; diff --git a/ports/mimxrt10xx/common-hal/busio/UART.c b/ports/mimxrt10xx/common-hal/busio/UART.c index db5582d15..03a6e8f3e 100644 --- a/ports/mimxrt10xx/common-hal/busio/UART.c +++ b/ports/mimxrt10xx/common-hal/busio/UART.c @@ -295,12 +295,10 @@ void common_hal_busio_uart_deinit(busio_uart_obj_t *self) { LPUART_Deinit(self->uart); gc_free(self->ringbuf); - if (self->rx) { - common_hal_reset_pin(self->rx->pin); - } - if (self->tx) { - common_hal_reset_pin(self->tx->pin); - } + + common_hal_reset_pin(self->rx->pin); + common_hal_reset_pin(self->tx->pin); + self->rx = NULL; self->tx = NULL; diff --git a/ports/mimxrt10xx/common-hal/microcontroller/Pin.c b/ports/mimxrt10xx/common-hal/microcontroller/Pin.c index a005924e2..50970f8e2 100644 --- a/ports/mimxrt10xx/common-hal/microcontroller/Pin.c +++ b/ports/mimxrt10xx/common-hal/microcontroller/Pin.c @@ -67,6 +67,9 @@ void reset_all_pins(void) { // Since i.MX pins need extra register and reset information to reset properly, // resetting pins by number alone has been removed. void common_hal_reset_pin(const mcu_pin_obj_t* pin) { + if (pin == NULL) { + return; + } never_reset_pins[pin->mux_idx] = false; claimed_pins[pin->mux_idx] = false; *(uint32_t*)pin->mux_reg = pin->mux_reset; diff --git a/ports/nrf/boards/bastble/README.md b/ports/nrf/boards/bastble/README.md new file mode 100644 index 000000000..0af6209bd --- /dev/null +++ b/ports/nrf/boards/bastble/README.md @@ -0,0 +1,4 @@ +# Electronic Cats BastBLE + +The [BastBLE](https://electroniccats.com/store/bast-ble/) based on Nordic nRF 52840 and containing +a powerful Cortex M4F. This board include a external memory QSPI flash. diff --git a/ports/nrf/boards/bastble/board.c b/ports/nrf/boards/bastble/board.c new file mode 100644 index 000000000..b6fb04f06 --- /dev/null +++ b/ports/nrf/boards/bastble/board.c @@ -0,0 +1,41 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft 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 "supervisor/board.h" +#include "nrf.h" +#include "nrf_rtc.h" + +void board_init(void) { + +} + +bool board_requests_safe_mode(void) { + return false; +} + +void reset_board(void) { + +} diff --git a/ports/nrf/boards/bastble/mpconfigboard.h b/ports/nrf/boards/bastble/mpconfigboard.h new file mode 100644 index 000000000..e36227c6b --- /dev/null +++ b/ports/nrf/boards/bastble/mpconfigboard.h @@ -0,0 +1,25 @@ +#include "nrfx/hal/nrf_gpio.h" + +#define MICROPY_HW_BOARD_NAME "BastBLE" +#define MICROPY_HW_MCU_NAME "nRF52840" + +#define CIRCUITPY_AUTORELOAD_DELAY_MS 500 + +#if QSPI_FLASH_FILESYSTEM +#define MICROPY_QSPI_DATA0 NRF_GPIO_PIN_MAP(0, 30) +#define MICROPY_QSPI_DATA1 NRF_GPIO_PIN_MAP(0, 29) +#define MICROPY_QSPI_DATA2 NRF_GPIO_PIN_MAP(0, 28) +#define MICROPY_QSPI_DATA3 NRF_GPIO_PIN_MAP(0, 2) +#define MICROPY_QSPI_SCK NRF_GPIO_PIN_MAP(0, 3) +#define MICROPY_QSPI_CS NRF_GPIO_PIN_MAP(0, 26) +#endif + +#define DEFAULT_I2C_BUS_SCL (&pin_P1_10) +#define DEFAULT_I2C_BUS_SDA (&pin_P1_11) + +#define DEFAULT_SPI_BUS_SCK (&pin_P1_00) +#define DEFAULT_SPI_BUS_MOSI (&pin_P1_06) +#define DEFAULT_SPI_BUS_MISO (&pin_P0_15) + +#define DEFAULT_UART_BUS_RX (&pin_P0_09) +#define DEFAULT_UART_BUS_TX (&pin_P0_10) diff --git a/ports/nrf/boards/bastble/mpconfigboard.mk b/ports/nrf/boards/bastble/mpconfigboard.mk new file mode 100644 index 000000000..eca900de7 --- /dev/null +++ b/ports/nrf/boards/bastble/mpconfigboard.mk @@ -0,0 +1,10 @@ +USB_VID = 0x1209 +USB_PID = 0x805A +USB_PRODUCT = "BastBLE" +USB_MANUFACTURER = "ElectronicCats" + +MCU_CHIP = nrf52840 + +QSPI_FLASH_FILESYSTEM = 1 +EXTERNAL_FLASH_DEVICE_COUNT = 1 +EXTERNAL_FLASH_DEVICES = "GD25Q16C" diff --git a/ports/nrf/boards/bastble/pins.c b/ports/nrf/boards/bastble/pins.c new file mode 100644 index 000000000..b35dad43d --- /dev/null +++ b/ports/nrf/boards/bastble/pins.c @@ -0,0 +1,47 @@ +#include "shared-bindings/board/__init__.h" + +STATIC const mp_rom_map_elem_t board_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_P1_11) }, + { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_P1_10) }, + { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_P1_00) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_P1_02) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_P1_13) }, + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_P1_06) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_P0_15) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_P0_06) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_P1_09) }, + { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_P0_08) }, + { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_P0_26) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_P0_07) }, + + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_P0_02) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_P0_28) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_P0_05) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_P0_03) }, + + { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_P0_30) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_P1_11) }, + + { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_P0_29) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_P1_10) }, + + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_P1_06) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_P0_15) }, + + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_P1_00) }, + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_P0_24) }, + + { MP_ROM_QSTR(MP_QSTR_AREF), MP_ROM_PTR(&pin_P0_31) }, + + // voltage sense battery + { MP_ROM_QSTR(MP_QSTR_VBAT), MP_ROM_PTR(&pin_P0_26) }, + + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_P0_10) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_P0_09) }, + + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, +}; + +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/nrf/common-hal/_bleio/Adapter.c b/ports/nrf/common-hal/_bleio/Adapter.c index 537f43f23..53a40f9a6 100644 --- a/ports/nrf/common-hal/_bleio/Adapter.c +++ b/ports/nrf/common-hal/_bleio/Adapter.c @@ -470,7 +470,16 @@ mp_obj_t common_hal_bleio_adapter_start_scan(bleio_adapter_obj_t *self, uint8_t* ble_drv_add_event_handler(scan_on_ble_evt, self->scan_results); uint32_t nrf_timeout = SEC_TO_UNITS(timeout, UNIT_10_MS); - if (timeout <= 0.0001) { + if (nrf_timeout > UINT16_MAX) { + // 0xffff / 100 + mp_raise_ValueError(translate("timeout must be < 655.35 secs")); + } + if (nrf_timeout == 0 && timeout > 0.0f) { + // Make sure converted timeout is > 0 if original timeout is > 0. + mp_raise_ValueError(translate("non-zero timeout must be > 0.01")); + } + + if (nrf_timeout) { nrf_timeout = BLE_GAP_SCAN_TIMEOUT_UNLIMITED; } diff --git a/ports/nrf/common-hal/microcontroller/Pin.c b/ports/nrf/common-hal/microcontroller/Pin.c index bc7ff831a..23d6e23bf 100644 --- a/ports/nrf/common-hal/microcontroller/Pin.c +++ b/ports/nrf/common-hal/microcontroller/Pin.c @@ -134,6 +134,9 @@ void common_hal_never_reset_pin(const mcu_pin_obj_t* pin) { } void common_hal_reset_pin(const mcu_pin_obj_t* pin) { + if (pin == NULL) { + return; + } reset_pin_number(pin->number); } diff --git a/ports/stm/boards/feather_stm32f405_express/mpconfigboard.h b/ports/stm/boards/feather_stm32f405_express/mpconfigboard.h index 0d49748c8..e69be6cf9 100644 --- a/ports/stm/boards/feather_stm32f405_express/mpconfigboard.h +++ b/ports/stm/boards/feather_stm32f405_express/mpconfigboard.h @@ -26,7 +26,7 @@ //Micropython setup -#define MICROPY_HW_BOARD_NAME "Feather STM32F405 Express" +#define MICROPY_HW_BOARD_NAME "Adafruit Feather STM32F405 Express" #define MICROPY_HW_MCU_NAME "STM32F405RG" #define FLASH_SIZE (0x100000) diff --git a/ports/stm/boards/stm32f411ce_blackpill/mpconfigboard.h b/ports/stm/boards/stm32f411ce_blackpill/mpconfigboard.h index 83a8bded3..435133954 100644 --- a/ports/stm/boards/stm32f411ce_blackpill/mpconfigboard.h +++ b/ports/stm/boards/stm32f411ce_blackpill/mpconfigboard.h @@ -42,6 +42,9 @@ // #define SPI_FLASH_SCK_PIN (&pin_PA05) // #define SPI_FLASH_CS_PIN (&pin_PA04) +#define DEFAULT_I2C_BUS_SCL (&pin_PB06) +#define DEFAULT_I2C_BUS_SDA (&pin_PB07) + #define CIRCUITPY_AUTORELOAD_DELAY_MS (500) #define BOARD_FLASH_SIZE (FLASH_SIZE - 0x2000 - 0xC000) diff --git a/ports/stm/boards/stm32f411ce_blackpill/pins.c b/ports/stm/boards/stm32f411ce_blackpill/pins.c index 2f8aab6e8..16946b8be 100644 --- a/ports/stm/boards/stm32f411ce_blackpill/pins.c +++ b/ports/stm/boards/stm32f411ce_blackpill/pins.c @@ -35,5 +35,10 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_C14), MP_ROM_PTR(&pin_PC14) }, { MP_ROM_QSTR(MP_QSTR_C13), MP_ROM_PTR(&pin_PC13) }, { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_PC13) }, + + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_PB07) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_PB06) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, }; MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/stm/common-hal/microcontroller/Pin.c b/ports/stm/common-hal/microcontroller/Pin.c index 0e333c71c..37c202d86 100644 --- a/ports/stm/common-hal/microcontroller/Pin.c +++ b/ports/stm/common-hal/microcontroller/Pin.c @@ -125,6 +125,9 @@ void common_hal_never_reset_pin(const mcu_pin_obj_t* pin) { } void common_hal_reset_pin(const mcu_pin_obj_t* pin) { + if (pin == NULL) { + return; + } reset_pin_number(pin->port, pin->number); } diff --git a/ports/unix/mphalport.h b/ports/unix/mphalport.h index 6f2880d4e..4e459ffca 100644 --- a/ports/unix/mphalport.h +++ b/ports/unix/mphalport.h @@ -24,12 +24,14 @@ * THE SOFTWARE. */ #include <unistd.h> +#include <stdbool.h> #ifndef CHAR_CTRL_C #define CHAR_CTRL_C (3) #endif void mp_hal_set_interrupt_char(char c); +bool mp_hal_is_interrupted(void); void mp_hal_stdio_mode_raw(void); void mp_hal_stdio_mode_orig(void); diff --git a/ports/unix/unix_mphal.c b/ports/unix/unix_mphal.c index e9494d7ff..77deb3152 100644 --- a/ports/unix/unix_mphal.c +++ b/ports/unix/unix_mphal.c @@ -81,6 +81,10 @@ void mp_hal_set_interrupt_char(char c) { } } +bool mp_hal_is_interrupted(void) { + return false; +} + #if MICROPY_USE_READLINE == 1 #include <termios.h> |
