From 89b91493ef11ea03a2f57c647fab3629646cbcab Mon Sep 17 00:00:00 2001 From: Liz Date: Tue, 15 Apr 2025 13:23:51 -0400 Subject: [PATCH 01/30] adding feather rp2350 adalogger --- .../adafruit_feather_rp2350_adalogger/board.c | 9 +++ .../mpconfigboard.h | 29 +++++++++ .../mpconfigboard.mk | 10 +++ .../pico-sdk-configboard.h | 10 +++ .../adafruit_feather_rp2350_adalogger/pins.c | 61 +++++++++++++++++++ 5 files changed, 119 insertions(+) create mode 100644 ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/board.c create mode 100644 ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/mpconfigboard.h create mode 100644 ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/mpconfigboard.mk create mode 100644 ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/pico-sdk-configboard.h create mode 100644 ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/pins.c diff --git a/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/board.c b/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/board.c new file mode 100644 index 000000000000..e6a868ab2122 --- /dev/null +++ b/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/mpconfigboard.h b/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/mpconfigboard.h new file mode 100644 index 000000000000..b77664cf85c1 --- /dev/null +++ b/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/mpconfigboard.h @@ -0,0 +1,29 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#define MICROPY_HW_BOARD_NAME "Adafruit Feather RP2350 Adalogger" +#define MICROPY_HW_MCU_NAME "rp2350a" + +#define MICROPY_HW_NEOPIXEL (&pin_GPIO21) + +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO3) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO2) + +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO22) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO23) +#define DEFAULT_SPI_BUS_MISO (&pin_GPIO20) + +#define DEFAULT_UART_BUS_RX (&pin_GPIO1) +#define DEFAULT_UART_BUS_TX (&pin_GPIO0) + +#define CIRCUITPY_PSRAM_CHIP_SELECT (&pin_GPIO8) + +#define DEFAULT_SD_SCK (&pin_GPIO14) +#define DEFAULT_SD_MOSI (&pin_GPIO15) +#define DEFAULT_SD_MISO (&pin_GPIO16) +#define DEFAULT_SD_CS (&pin_GPIO19) +#define DEFAULT_SD_CARD_DETECT (&pin_GPIO13) +#define DEFAULT_SD_CARD_INSERTED false diff --git a/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/mpconfigboard.mk new file mode 100644 index 000000000000..88cce7c4a4ce --- /dev/null +++ b/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/mpconfigboard.mk @@ -0,0 +1,10 @@ +USB_VID = 0x239A +USB_PID = 0x816E +USB_PRODUCT = "Feather RP2350 Adalogger" +USB_MANUFACTURER = "Adafruit" + +CHIP_VARIANT = RP2350 +CHIP_PACKAGE = A +CHIP_FAMILY = rp2 + +EXTERNAL_FLASH_DEVICES = "GD25Q64C,W25Q64JVxQ" diff --git a/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/pico-sdk-configboard.h b/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/pico-sdk-configboard.h new file mode 100644 index 000000000000..2d9283a9192f --- /dev/null +++ b/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/pico-sdk-configboard.h @@ -0,0 +1,10 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// Put board-specific pico-sdk definitions here. This file must exist. + +// Allow extra time for xosc to start. +#define PICO_XOSC_STARTUP_DELAY_MULTIPLIER 64 diff --git a/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/pins.c b/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/pins.c new file mode 100644 index 000000000000..65be197e41ba --- /dev/null +++ b/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/pins.c @@ -0,0 +1,61 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_D24), MP_ROM_PTR(&pin_GPIO24) }, + { MP_ROM_QSTR(MP_QSTR_D25), MP_ROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO0) }, + + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO7) }, + + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO21) }, + + { MP_ROM_QSTR(MP_QSTR_SD_CARD_DETECT), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_SD_CLK), MP_ROM_PTR(&pin_GPIO14) }, + + { MP_ROM_QSTR(MP_QSTR_SD_MOSI), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_SD_CMD), MP_ROM_PTR(&pin_GPIO15) }, + + { MP_ROM_QSTR(MP_QSTR_SD_MISO), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_SD_DAT0), MP_ROM_PTR(&pin_GPIO16) }, + + { MP_ROM_QSTR(MP_QSTR_SD_DAT1), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_SD_DAT2), MP_ROM_PTR(&pin_GPIO18) }, + + { MP_ROM_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_SD_DAT3), MP_ROM_PTR(&pin_GPIO19) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_STEMMA_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_module_globals_table); From 7b7b10a4968eee5e3645f26a503cd2469c900723 Mon Sep 17 00:00:00 2001 From: Liz <23021834+BlitzCityDIY@users.noreply.github.com> Date: Tue, 15 Apr 2025 14:30:26 -0400 Subject: [PATCH 02/30] Update ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/pins.c Co-authored-by: Dan Halbert --- .../adafruit_feather_rp2350_adalogger/pins.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/pins.c b/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/pins.c index 65be197e41ba..d957e6f65220 100644 --- a/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/pins.c +++ b/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/pins.c @@ -13,28 +13,32 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO27) }, { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO28) }, { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_D24), MP_ROM_PTR(&pin_GPIO24) }, { MP_ROM_QSTR(MP_QSTR_D25), MP_ROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO22) }, { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO23) }, { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO20) }, - { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO1) }, - { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO0) }, { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO2) }, { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO3) }, + + { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_GPIO4) }, { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO5) }, { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO6) }, { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO10) }, { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO11) }, - { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, - { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO4) }, - { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO7) }, - { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO7) }, { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO21) }, From eae8d2ab6aab083aedd52c906a4f6c090a65fdbd Mon Sep 17 00:00:00 2001 From: Liz <23021834+BlitzCityDIY@users.noreply.github.com> Date: Tue, 15 Apr 2025 14:47:24 -0400 Subject: [PATCH 03/30] Update ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/pins.c Co-authored-by: Dan Halbert --- .../boards/adafruit_feather_rp2350_adalogger/pins.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/pins.c b/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/pins.c index d957e6f65220..2240a1678fef 100644 --- a/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/pins.c +++ b/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/pins.c @@ -30,7 +30,9 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO2) }, { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO3) }, - { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_D12, MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO5) }, { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO6) }, { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, From 10b1087fc9234ddd806f1103a12f641d8af3b56a Mon Sep 17 00:00:00 2001 From: Liz <23021834+BlitzCityDIY@users.noreply.github.com> Date: Tue, 15 Apr 2025 14:47:34 -0400 Subject: [PATCH 04/30] Update ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/pins.c Co-authored-by: Dan Halbert --- .../boards/adafruit_feather_rp2350_adalogger/pins.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/pins.c b/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/pins.c index 2240a1678fef..929c3f8ba1b6 100644 --- a/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/pins.c +++ b/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/pins.c @@ -40,7 +40,9 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO11) }, { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO7) }, - { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO21) }, From c9b81971f82ad997aa400d7a397d9c05bfc06f00 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 15 Apr 2025 15:01:34 -0400 Subject: [PATCH 05/30] Update ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/pins.c --- .../raspberrypi/boards/adafruit_feather_rp2350_adalogger/pins.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/pins.c b/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/pins.c index 929c3f8ba1b6..ac9a29abaad9 100644 --- a/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/pins.c +++ b/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/pins.c @@ -31,7 +31,7 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO3) }, { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, - { MP_ROM_QSTR(MP_QSTR_D12, MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO4) }, { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO5) }, { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO6) }, From 973cd4bc4563f1a7136461f3b66abe9cfbabdf94 Mon Sep 17 00:00:00 2001 From: eightycc Date: Wed, 16 Apr 2025 15:35:48 -0700 Subject: [PATCH 06/30] Upgrade ESP-IDF v5.3.2 to v5.4.1. --- .gitmodules | 4 ++-- ports/espressif/Makefile | 3 +++ ports/espressif/esp-idf | 2 +- ports/espressif/mphalport.c | 20 +------------------- ports/espressif/supervisor/usb.c | 10 +--------- 5 files changed, 8 insertions(+), 31 deletions(-) diff --git a/.gitmodules b/.gitmodules index f52ca8e7fa75..f297dae58473 100644 --- a/.gitmodules +++ b/.gitmodules @@ -142,8 +142,8 @@ url = https://github.com/adafruit/Adafruit_CircuitPython_RFM69.git [submodule "ports/espressif/esp-idf"] path = ports/espressif/esp-idf - url = https://github.com/adafruit/esp-idf.git - branch = circuitpython-v5.3.2 + url = https://github.com/eightycc/esp-idf.git + branch = circuitpython-v5.4.1 [submodule "ports/espressif/esp-protocols"] path = ports/espressif/esp-protocols url = https://github.com/adafruit/esp-protocols.git diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index ea6b91fdf4ca..def6ab10dcff 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -83,6 +83,8 @@ INC += \ -isystem esp-idf/components/esp_psram/include \ -isystem esp-idf/components/esp_ringbuf/include \ -isystem esp-idf/components/esp_rom/include \ + -isystem esp-idf/components/esp_rom/$(IDF_TARGET)/include \ + -isystem esp-idf/components/esp_rom/$(IDF_TARGET)/include/$(IDF_TARGET) \ -isystem esp-idf/components/esp_system/include \ -isystem esp-idf/components/esp_timer/include \ -isystem esp-idf/components/esp_wifi/include \ @@ -115,6 +117,7 @@ INC += \ -isystem esp-idf/components/sdmmc/include \ -isystem esp-idf/components/soc/include \ -isystem esp-idf/components/soc/$(IDF_TARGET)/include \ + -isystem esp-idf/components/soc/$(IDF_TARGET)/register \ -isystem esp-idf/components/spi_flash/include \ -isystem esp-idf/components/usb/include \ -isystem esp-idf/components/ulp/ulp_fsm/include \ diff --git a/ports/espressif/esp-idf b/ports/espressif/esp-idf index f388200aba73..4c2820d377d1 160000 --- a/ports/espressif/esp-idf +++ b/ports/espressif/esp-idf @@ -1 +1 @@ -Subproject commit f388200aba73826b9039be6f4fb5385c6b7136c6 +Subproject commit 4c2820d377d1375e787bcef612f0c32c1427d183 diff --git a/ports/espressif/mphalport.c b/ports/espressif/mphalport.c index 87b16ac3e4ca..d6a7ef1bfce4 100644 --- a/ports/espressif/mphalport.c +++ b/ports/espressif/mphalport.c @@ -8,25 +8,7 @@ #include "py/mphal.h" #include "supervisor/cpu.h" -#if defined(CONFIG_IDF_TARGET_ESP32) -#include "components/esp_rom/include/esp32/rom/ets_sys.h" -#elif defined(CONFIG_IDF_TARGET_ESP32C2) -#include "components/esp_rom/include/esp32c2/rom/ets_sys.h" -#elif defined(CONFIG_IDF_TARGET_ESP32P4) -#include "components/esp_rom/include/esp32p4/rom/ets_sys.h" -#elif defined(CONFIG_IDF_TARGET_ESP32C3) -#include "components/esp_rom/include/esp32c3/rom/ets_sys.h" -#elif defined(CONFIG_IDF_TARGET_ESP32C6) -#include "components/esp_rom/include/esp32c6/rom/ets_sys.h" -#elif defined(CONFIG_IDF_TARGET_ESP32H2) -#include "components/esp_rom/include/esp32h2/rom/ets_sys.h" -#elif defined(CONFIG_IDF_TARGET_ESP32S2) -#include "components/esp_rom/include/esp32s2/rom/ets_sys.h" -#elif defined(CONFIG_IDF_TARGET_ESP32S3) -#include "components/esp_rom/include/esp32s3/rom/ets_sys.h" -#else -#error Unknown CONFIG_IDF_TARGET_xxx -#endif +#include "rom/ets_sys.h" #include "esp_attr.h" diff --git a/ports/espressif/supervisor/usb.c b/ports/espressif/supervisor/usb.c index c2bf90b21b1f..612abaa808ae 100644 --- a/ports/espressif/supervisor/usb.c +++ b/ports/espressif/supervisor/usb.c @@ -20,15 +20,7 @@ #include "driver/gpio.h" #include "esp_private/periph_ctrl.h" -#if defined(CONFIG_IDF_TARGET_ESP32C3) -#include "components/esp_rom/include/esp32c3/rom/gpio.h" -#elif defined(CONFIG_IDF_TARGET_ESP32C6) -#include "components/esp_rom/include/esp32c6/rom/gpio.h" -#elif defined(CONFIG_IDF_TARGET_ESP32S2) -#include "components/esp_rom/include/esp32s2/rom/gpio.h" -#elif defined(CONFIG_IDF_TARGET_ESP32S3) -#include "components/esp_rom/include/esp32s3/rom/gpio.h" -#endif +#include "rom/gpio.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" From 94f1ec6523e0e87287f21877c4ac414a3b0821e1 Mon Sep 17 00:00:00 2001 From: eightycc Date: Wed, 16 Apr 2025 15:44:03 -0700 Subject: [PATCH 07/30] Get updated ESP-IDF branch circuitpython-v5.4.1. --- ports/espressif/esp-idf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/esp-idf b/ports/espressif/esp-idf index 4c2820d377d1..8a8c214ea69e 160000 --- a/ports/espressif/esp-idf +++ b/ports/espressif/esp-idf @@ -1 +1 @@ -Subproject commit 4c2820d377d1375e787bcef612f0c32c1427d183 +Subproject commit 8a8c214ea69e72ea5a5e6152ffbf66afb2affcae From 45b8f76fe3d88b553648130ec945e63802572dd2 Mon Sep 17 00:00:00 2001 From: eightycc Date: Thu, 17 Apr 2025 07:02:46 -0700 Subject: [PATCH 08/30] ESP-IDF 5.4.1 update: Add esp_security component, fixup flash spi clock speed settings. --- ports/espressif/Makefile | 3 ++- ports/espressif/esp-idf | 2 +- .../esp-idf-config/sdkconfig-flash-120m.defaults | 13 ------------- .../esp-idf-config/sdkconfig-flash-40m.defaults | 13 ------------- .../esp-idf-config/sdkconfig-flash-48m.defaults | 13 ------------- .../esp-idf-config/sdkconfig-flash-60m.defaults | 13 ------------- .../esp-idf-config/sdkconfig-flash-80m.defaults | 13 ------------- 7 files changed, 3 insertions(+), 67 deletions(-) diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index def6ab10dcff..927906d5a0f2 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -85,6 +85,7 @@ INC += \ -isystem esp-idf/components/esp_rom/include \ -isystem esp-idf/components/esp_rom/$(IDF_TARGET)/include \ -isystem esp-idf/components/esp_rom/$(IDF_TARGET)/include/$(IDF_TARGET) \ + -isystem esp-idf/components/esp_security/include \ -isystem esp-idf/components/esp_system/include \ -isystem esp-idf/components/esp_timer/include \ -isystem esp-idf/components/esp_wifi/include \ @@ -597,7 +598,7 @@ endif ESP_IDF_COMPONENTS_LINK = $(IDF_TARGET_ARCH) $(CHIP_COMPONENTS) app_update bootloader_support driver esp_driver_gpio esp_driver_gptimer esp_driver_i2c esp_driver_ledc esp_driver_spi esp_driver_uart efuse esp_adc esp_app_format esp_common esp_event esp_hw_support esp_mm esp_partition esp_pm esp_ringbuf esp_rom esp_system esp_timer freertos hal heap log newlib nvs_flash pthread soc spi_flash vfs esp_vfs_console ifneq ($(CIRCUITPY_WIFI),0) - ESP_IDF_COMPONENTS_LINK += esp_coex esp_netif esp-tls esp_wifi lwip mbedtls mdns wpa_supplicant esp_phy + ESP_IDF_COMPONENTS_LINK += esp_coex esp_netif esp_security esp-tls esp_wifi lwip mbedtls mdns wpa_supplicant esp_phy endif ifneq ($(CIRCUITPY_BLEIO_NATIVE),0) BLE_IMPL_esp32 := esp32 diff --git a/ports/espressif/esp-idf b/ports/espressif/esp-idf index 8a8c214ea69e..e6c5c73c5b6c 160000 --- a/ports/espressif/esp-idf +++ b/ports/espressif/esp-idf @@ -1 +1 @@ -Subproject commit 8a8c214ea69e72ea5a5e6152ffbf66afb2affcae +Subproject commit e6c5c73c5b6caa552c56e724facb3faa596e3022 diff --git a/ports/espressif/esp-idf-config/sdkconfig-flash-120m.defaults b/ports/espressif/esp-idf-config/sdkconfig-flash-120m.defaults index fadf55d8d796..6a2285a2936a 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-flash-120m.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-flash-120m.defaults @@ -1,15 +1,2 @@ CONFIG_ESPTOOLPY_FLASHFREQ_120M=y -# CONFIG_ESPTOOLPY_FLASHFREQ_80M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_64M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_60M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_48M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_40M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_32M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_30M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_24M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_16M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_15M is not set -CONFIG_ESPTOOLPY_FLASHFREQ_80M_DEFAULT=y CONFIG_SPI_FLASH_UNDER_HIGH_FREQ=y diff --git a/ports/espressif/esp-idf-config/sdkconfig-flash-40m.defaults b/ports/espressif/esp-idf-config/sdkconfig-flash-40m.defaults index 235a62a57ee0..ffc4b5c1cb8f 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-flash-40m.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-flash-40m.defaults @@ -1,14 +1 @@ -# CONFIG_ESPTOOLPY_FLASHFREQ_120M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_80M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_64M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_60M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_48M is not set CONFIG_ESPTOOLPY_FLASHFREQ_40M=y -# CONFIG_ESPTOOLPY_FLASHFREQ_32M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_30M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_24M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_16M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_15M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_80M_DEFAULT is not set diff --git a/ports/espressif/esp-idf-config/sdkconfig-flash-48m.defaults b/ports/espressif/esp-idf-config/sdkconfig-flash-48m.defaults index b710fd22554e..f6838e88703b 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-flash-48m.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-flash-48m.defaults @@ -1,14 +1 @@ -# CONFIG_ESPTOOLPY_FLASHFREQ_120M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_80M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_64M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_60M is not set CONFIG_ESPTOOLPY_FLASHFREQ_48M=y -# CONFIG_ESPTOOLPY_FLASHFREQ_40M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_32M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_30M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_24M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_16M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_15M is not set -CONFIG_ESPTOOLPY_FLASHFREQ_48M_DEFAULT=y diff --git a/ports/espressif/esp-idf-config/sdkconfig-flash-60m.defaults b/ports/espressif/esp-idf-config/sdkconfig-flash-60m.defaults index 7068d0ce7408..797665f527fb 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-flash-60m.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-flash-60m.defaults @@ -1,14 +1 @@ -# CONFIG_ESPTOOLPY_FLASHFREQ_120M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_80M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_64M is not set CONFIG_ESPTOOLPY_FLASHFREQ_60M=y -# CONFIG_ESPTOOLPY_FLASHFREQ_48M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_40M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_32M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_30M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_24M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_16M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_15M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_80M_DEFAULT is not set diff --git a/ports/espressif/esp-idf-config/sdkconfig-flash-80m.defaults b/ports/espressif/esp-idf-config/sdkconfig-flash-80m.defaults index 2ea441900379..7014fa95495b 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-flash-80m.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-flash-80m.defaults @@ -1,14 +1 @@ -# CONFIG_ESPTOOLPY_FLASHFREQ_120M is not set CONFIG_ESPTOOLPY_FLASHFREQ_80M=y -# CONFIG_ESPTOOLPY_FLASHFREQ_64M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_60M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_48M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_40M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_32M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_30M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_24M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_16M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_15M is not set -CONFIG_ESPTOOLPY_FLASHFREQ_80M_DEFAULT=y From 521fb5ac117798bdf4665193b61e0b5277ba7634 Mon Sep 17 00:00:00 2001 From: eightycc Date: Thu, 17 Apr 2025 11:38:39 -0700 Subject: [PATCH 09/30] Workaround ESP-IDF issue #15035. --- .github/actions/deps/ports/espressif/action.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/deps/ports/espressif/action.yml b/.github/actions/deps/ports/espressif/action.yml index 122940bb95a1..25965eb7ef04 100644 --- a/.github/actions/deps/ports/espressif/action.yml +++ b/.github/actions/deps/ports/espressif/action.yml @@ -7,6 +7,7 @@ runs: run: | echo >> $GITHUB_ENV "IDF_PATH=$GITHUB_WORKSPACE/ports/espressif/esp-idf" echo >> $GITHUB_ENV "IDF_TOOLS_PATH=$GITHUB_WORKSPACE/.idf_tools" + echo >> $GITHUB_ENV "ESP_ROM_ELF_DIR=$GITHUB_WORKSPACE/.idf_tools" shell: bash - name: Get IDF commit From f834b771af20d8b59784caa6f5a7aa04dbd1d48b Mon Sep 17 00:00:00 2001 From: eightycc Date: Thu, 17 Apr 2025 12:55:21 -0700 Subject: [PATCH 10/30] Update ESP32 MSPI IOMUX pin names. --- ports/espressif/supervisor/port.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/espressif/supervisor/port.c b/ports/espressif/supervisor/port.c index b84b2c49a318..2217cf503dc8 100644 --- a/ports/espressif/supervisor/port.c +++ b/ports/espressif/supervisor/port.c @@ -190,8 +190,8 @@ static void _never_reset_spi_ram_flash(void) { const uint32_t spiconfig = esp_rom_efuse_get_flash_gpio_info(); if (spiconfig == ESP_ROM_EFUSE_FLASH_DEFAULT_SPI) { - never_reset_pin_number(SPI_IOMUX_PIN_NUM_CLK); - never_reset_pin_number(SPI_IOMUX_PIN_NUM_CS); + never_reset_pin_number(MSPI_IOMUX_PIN_NUM_CLK); + never_reset_pin_number(MSPI_IOMUX_PIN_NUM_CS0); never_reset_pin_number(PSRAM_SPIQ_SD0_IO); never_reset_pin_number(PSRAM_SPID_SD1_IO); never_reset_pin_number(PSRAM_SPIWP_SD3_IO); From 010b8a2b5a15f8430f28d568443fc98f922edab4 Mon Sep 17 00:00:00 2001 From: eightycc Date: Fri, 18 Apr 2025 06:45:58 -0700 Subject: [PATCH 11/30] Update esp-idf with cherry-picked commit 793e394 to resolve missing __atomic_test_and_set. --- ports/espressif/esp-idf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/esp-idf b/ports/espressif/esp-idf index e6c5c73c5b6c..f50ec8ecdb31 160000 --- a/ports/espressif/esp-idf +++ b/ports/espressif/esp-idf @@ -1 +1 @@ -Subproject commit e6c5c73c5b6caa552c56e724facb3faa596e3022 +Subproject commit f50ec8ecdb31f681e6a778f145de95f849c1089d From c127f661a2dbec775ca247bf9961c0943dcd151e Mon Sep 17 00:00:00 2001 From: eightycc Date: Fri, 18 Apr 2025 07:21:22 -0700 Subject: [PATCH 12/30] Add ESP-IDF component esp_security for BLE-only parts. --- ports/espressif/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index 927906d5a0f2..6c320f648efb 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -609,7 +609,7 @@ ifneq ($(CIRCUITPY_BLEIO_NATIVE),0) BLE_IMPL_esp32h2 := libble BLE_IMPL = $(BLE_IMPL_$(IDF_TARGET)) - ESP_IDF_COMPONENTS_LINK += bt esp_phy + ESP_IDF_COMPONENTS_LINK += bt esp_phy esp_security ifeq ($(BLE_IMPL),esp32) # BLE will hang the ESP32 and trigger an interrupt watchdog without this undefined symbol at # link because a weak version of the interrupt that BLE uses will be linked incorrectly. From 7cc3f10f1e209b1738f2377d3735639b8d0803db Mon Sep 17 00:00:00 2001 From: eightycc Date: Fri, 18 Apr 2025 09:43:36 -0700 Subject: [PATCH 13/30] Remove CIRCUITPY_ESPCAMERA from ESP32-S2 to free up DRAM. --- ports/espressif/mpconfigport.mk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index 31522795a165..a2a2ec7894d3 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -250,6 +250,9 @@ CIRCUITPY_AUDIOIO = 1 # No BLE in hw CIRCUITPY_BLEIO_NATIVE = 0 +# Not enough DRAM for this with ESP-IDF 5.4.1 +CIRCUITPY_ESPCAMERA = 0 + # No SDMMC CIRCUITPY_SDIOIO = 0 From bdbd4af809191f2a2c5d2871adeb9dc97e81aeeb Mon Sep 17 00:00:00 2001 From: eightycc Date: Fri, 18 Apr 2025 10:24:29 -0700 Subject: [PATCH 14/30] Add ESP-IDF component esp_security to ESP32-P4. --- ports/espressif/Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index 6c320f648efb..3a07cc5438e2 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -631,6 +631,9 @@ ifneq ($(CIRCUITPY_BLEIO_NATIVE),0) endif endif endif +ifeq ($(IDF_TARGET),esp32p4) + ESP_IDF_COMPONENTS_LINK += esp_security +endif ifneq ($(CIRCUITPY_ESPULP),0) ESP_IDF_COMPONENTS_LINK += ulp endif From 06d9ff4ec9853ca608dfc3ff0226a755d931cafb Mon Sep 17 00:00:00 2001 From: eightycc Date: Fri, 18 Apr 2025 11:24:46 -0700 Subject: [PATCH 15/30] Temporarily remove ULAB from ESP32-C6 to avoid flash overflow. --- ports/espressif/mpconfigport.mk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index a2a2ec7894d3..549bf8698808 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -184,6 +184,9 @@ CIRCUITPY_TOUCHIO_USE_NATIVE = 0 CIRCUITPY_USB_DEVICE = 0 CIRCUITPY_ESP_USB_SERIAL_JTAG ?= 1 +# Remove temporarily until 10265 is merged +CIRCUITPY_ULAB = 0 + else ifeq ($(IDF_TARGET),esp32h2) # Modules CIRCUITPY_ESPCAMERA = 0 From 22519d88b8e88f28a0cd3cf8d808ed4867332407 Mon Sep 17 00:00:00 2001 From: eightycc Date: Sat, 19 Apr 2025 09:13:00 -0700 Subject: [PATCH 16/30] Restore ESP_CAMERA to ESP32-S2, resolve dram overflow by specifying CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH. --- ports/espressif/esp-idf-config/sdkconfig-esp32s2.defaults | 6 ++++++ ports/espressif/mpconfigport.mk | 3 --- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ports/espressif/esp-idf-config/sdkconfig-esp32s2.defaults b/ports/espressif/esp-idf-config/sdkconfig-esp32s2.defaults index 66e06667a1a8..5c748bd0e6f0 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-esp32s2.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-esp32s2.defaults @@ -58,6 +58,12 @@ CONFIG_ULP_COPROC_TYPE_RISCV=y # Note: enabling both ULPs simultaneously only w CONFIG_ULP_COPROC_RESERVE_MEM=8176 # end of Ultra Low Power (ULP) Co-processor +# +# FreeRTOS +# +CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y +# end of FreeRTOS + # end of Component config # end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index 549bf8698808..d7037fa5217e 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -253,9 +253,6 @@ CIRCUITPY_AUDIOIO = 1 # No BLE in hw CIRCUITPY_BLEIO_NATIVE = 0 -# Not enough DRAM for this with ESP-IDF 5.4.1 -CIRCUITPY_ESPCAMERA = 0 - # No SDMMC CIRCUITPY_SDIOIO = 0 From aeb5bacc566ead1da1b3df76cca9101e1a704b74 Mon Sep 17 00:00:00 2001 From: eightycc Date: Thu, 24 Apr 2025 09:25:07 -0700 Subject: [PATCH 17/30] Remove *.rom.newlib-time.ld from link of esp32, esp32c3, and esp32s2 to resolve newlib stat struct mismatch. --- ports/espressif/Makefile | 3 --- 1 file changed, 3 deletions(-) diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index 3a07cc5438e2..7806e6be2827 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -242,7 +242,6 @@ ifeq ($(IDF_TARGET),esp32) LDFLAGS += \ -Tesp32.rom.newlib-data.ld \ -Tesp32.rom.newlib-funcs.ld \ - -Tesp32.rom.newlib-time.ld \ -Tesp32.rom.spiflash_legacy.ld CHIP_COMPONENTS = \ @@ -265,7 +264,6 @@ CHIP_COMPONENTS = \ else ifeq ($(IDF_TARGET),esp32c3) LDFLAGS += \ -Tesp32c3.rom.newlib.ld \ - -Tesp32c3.rom.newlib-time.ld \ -Tesp32c3.rom.version.ld \ -Tesp32c3.rom.eco3.ld \ -Tesp32c3.rom.bt_funcs.ld @@ -312,7 +310,6 @@ else ifeq ($(IDF_TARGET),esp32s2) LDFLAGS += \ -Tesp32s2.rom.newlib-data.ld \ -Tesp32s2.rom.newlib-funcs.ld \ - -Tesp32s2.rom.newlib-time.ld \ -Tesp32s2.rom.spiflash_legacy.ld CHIP_COMPONENTS = \ From 1942d5ebd7641ee7e809f657b6eb6406feb326c4 Mon Sep 17 00:00:00 2001 From: eightycc Date: Thu, 24 Apr 2025 10:17:25 -0700 Subject: [PATCH 18/30] Temporarily disable CIRCUITPY_CANIO for mixgo_ce_udisk board to work around flash overflow for ru translation. --- ports/espressif/boards/mixgo_ce_udisk/mpconfigboard.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/espressif/boards/mixgo_ce_udisk/mpconfigboard.mk b/ports/espressif/boards/mixgo_ce_udisk/mpconfigboard.mk index 691da625e035..a6a8cd7fa00e 100644 --- a/ports/espressif/boards/mixgo_ce_udisk/mpconfigboard.mk +++ b/ports/espressif/boards/mixgo_ce_udisk/mpconfigboard.mk @@ -10,6 +10,7 @@ CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB CIRCUITPY_AESIO = 0 +CIRCUITPY_CANIO = 0 CIRCUITPY_CODEOP = 0 CIRCUITPY_ESPCAMERA = 0 From 62d16ce61fdd1ec8cfb0d70a6240ad877c12df21 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 25 Apr 2025 15:14:20 -0400 Subject: [PATCH 19/30] Fix TLS for v5.4.1 update Cert bundle code in lib/mbedtls_config was being used, and assumed the older ESP-IDF internal bundle format, which was changed in ESP-IDF v5.4. Added a wrapper around the ESP-IDF bundle routines, and stopped using the shared bundle code. Also fixed extraneous blank lines in mbedtls logging and removed an extraneous, unused, damaged .h. --- lib/mbedtls_config/mbedtls_config_port.h | 67 --------------------- ports/espressif/Makefile | 14 ++--- ports/espressif/common-hal/ssl/crt_bundle.c | 37 ++++++++++++ shared-module/ssl/SSLSocket.c | 2 +- 4 files changed, 45 insertions(+), 75 deletions(-) delete mode 100644 lib/mbedtls_config/mbedtls_config_port.h create mode 100644 ports/espressif/common-hal/ssl/crt_bundle.c diff --git a/lib/mbedtls_config/mbedtls_config_port.h b/lib/mbedtls_config/mbedtls_config_port.h deleted file mode 100644 index 1752d946529f..000000000000 --- a/lib/mbedtls_config/mbedtls_config_port.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018-2019 Damien P. George - * - * 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_MBEDTLS_CONFIG_H -#define MICROPY_INCLUDED_MBEDTLS_CONFIG_H - -// If you want to debug MBEDTLS uncomment the following and -// Pass 3 to mbedtls_debug_set_threshold in socket_new -// #define MBEDTLS_DEBUG_C - -// Set mbedtls configuration -#define MBEDTLS_PLATFORM_C -#define MBEDTLS_PLATFORM_MEMORY -#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS -#define MBEDTLS_DEPRECATED_REMOVED -#define MBEDTLS_ENTROPY_HARDWARE_ALT - -// Enable mbedtls modules -#define MBEDTLS_MD_C -#define MBEDTLS_MD5_C -#define MBEDTLS_SHA1_C -#define MBEDTLS_SHA256_C -#define MBEDTLS_SHA512_C -#undef MBEDTLS_HAVE_TIME_DATE - -<<<<<<<< HEAD:lib/mbedtls_config/mbedtls_config_hashlib.h -// Memory allocation hooks -#include -#include -void *m_tracked_calloc(size_t nmemb, size_t size); -void m_tracked_free(void *ptr); -#define MBEDTLS_PLATFORM_STD_CALLOC m_tracked_calloc -#define MBEDTLS_PLATFORM_STD_FREE m_tracked_free -#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf -======== -// Time hook -#include -time_t rp2_rtctime_seconds(time_t *timer); -#define MBEDTLS_PLATFORM_TIME_MACRO rp2_rtctime_seconds -#define MBEDTLS_PLATFORM_MS_TIME_ALT mbedtls_ms_time ->>>>>>>> v1.23.0:lib/mbedtls_config/mbedtls_config_port.h - -#include "mbedtls/check_config.h" - -#endif /* MICROPY_INCLUDED_MBEDTLS_CONFIG_H */ diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index 7806e6be2827..09fa76e79fbe 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -175,12 +175,12 @@ ifeq ($(DEBUG), 1) OPTIMIZATION_FLAGS ?= -Og CFLAGS += -DDEBUG endif - # You may want to enable these flags to make setting breakpoints easier. - # CFLAGS += -fno-inline -fno-ipa-sra +# You may want to enable these flags to make setting breakpoints easier. +# CFLAGS += -fno-inline -fno-ipa-sra else CFLAGS += -DNDEBUG - # RISC-V is larger than xtensa - # Use -Os for RISC-V when it overflows +# RISC-V is larger than xtensa +# Use -Os for RISC-V when it overflows ifeq ($(IDF_TARGET_ARCH),riscv) OPTIMIZATION_FLAGS ?= -Os else @@ -384,7 +384,7 @@ SRC_C += \ peripherals/$(IDF_TARGET)/pins.c ifeq ($(CIRCUITPY_SSL),1) -SRC_C += lib/mbedtls_config/crt_bundle.c +SRC_C += common-hal/ssl/crt_bundle.c endif SRC_C += $(wildcard common-hal/espidf/*.c) @@ -608,8 +608,8 @@ ifneq ($(CIRCUITPY_BLEIO_NATIVE),0) ESP_IDF_COMPONENTS_LINK += bt esp_phy esp_security ifeq ($(BLE_IMPL),esp32) - # BLE will hang the ESP32 and trigger an interrupt watchdog without this undefined symbol at - # link because a weak version of the interrupt that BLE uses will be linked incorrectly. +# BLE will hang the ESP32 and trigger an interrupt watchdog without this undefined symbol at +# link because a weak version of the interrupt that BLE uses will be linked incorrectly. REGISTRATION_FUNCTIONS += -u ld_include_hli_vectors_bt BINARY_BLOBS += esp-idf/components/bt/controller/lib_esp32/$(IDF_TARGET)/libbtdm_app.a endif diff --git a/ports/espressif/common-hal/ssl/crt_bundle.c b/ports/espressif/common-hal/ssl/crt_bundle.c new file mode 100644 index 000000000000..5fce7a42051a --- /dev/null +++ b/ports/espressif/common-hal/ssl/crt_bundle.c @@ -0,0 +1,37 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// In ESP-IDF v5.4, Espressif changed the format of the in-flash cert bundle, which +// made lib/mbedtls_config/crt_bundle.c no longer work. Rather than update that, +// just wrap those functions and use the ESP-IDF versions. + +#include "py/mperrno.h" +#include "mbedtls/x509_crt.h" +#include "lib/mbedtls_config/crt_bundle.h" +#include "esp_crt_bundle.h" + +static int convert_esp_err(esp_err_t ret) { + switch (ret) { + case ESP_OK: + return 0; + default: + // Right now esp_crt_bundle.c doesn't return very specific errors. + case ESP_ERR_INVALID_ARG: + return -MP_EINVAL; + } +} + +int crt_bundle_attach(mbedtls_ssl_config *ssl_conf) { + return convert_esp_err(esp_crt_bundle_attach(ssl_conf)); +} + +void crt_bundle_detach(mbedtls_ssl_config *conf) { + esp_crt_bundle_detach(conf); +} + +int crt_bundle_set(const uint8_t *x509_bundle, size_t bundle_size) { + return convert_esp_err(esp_crt_bundle_set(x509_bundle, bundle_size)); +} diff --git a/shared-module/ssl/SSLSocket.c b/shared-module/ssl/SSLSocket.c index 129a48d00d6e..d04ca3c4603b 100644 --- a/shared-module/ssl/SSLSocket.c +++ b/shared-module/ssl/SSLSocket.c @@ -37,7 +37,7 @@ static void mbedtls_debug(void *ctx, int level, const char *file, int line, const char *str) { (void)ctx; (void)level; - mp_printf(&mp_plat_print, "DBG:%s:%04d: %s\n", file, line, str); + mp_printf(&mp_plat_print, "DBG:%s:%04d: %s", file, line, str); } #define DEBUG_PRINT(fmt, ...) mp_printf(&mp_plat_print, "DBG:%s:%04d: " fmt "\n", __FILE__, __LINE__,##__VA_ARGS__) #else From d5f89a176009c5087b85056f3e56d9dc6ae97416 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 25 Apr 2025 16:19:48 -0400 Subject: [PATCH 20/30] pre-commit format fix --- ports/espressif/common-hal/ssl/crt_bundle.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/common-hal/ssl/crt_bundle.c b/ports/espressif/common-hal/ssl/crt_bundle.c index 5fce7a42051a..53a07f4db1b2 100644 --- a/ports/espressif/common-hal/ssl/crt_bundle.c +++ b/ports/espressif/common-hal/ssl/crt_bundle.c @@ -18,7 +18,7 @@ static int convert_esp_err(esp_err_t ret) { case ESP_OK: return 0; default: - // Right now esp_crt_bundle.c doesn't return very specific errors. + // Right now esp_crt_bundle.c doesn't return very specific errors. case ESP_ERR_INVALID_ARG: return -MP_EINVAL; } From a3ccaf9c683502eb452d40d2e754b6195d654060 Mon Sep 17 00:00:00 2001 From: eightycc Date: Tue, 29 Apr 2025 08:32:58 -0700 Subject: [PATCH 21/30] Switch to Adafruit ESP-IDF repo branch circuitpython-v5.4.1. --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index f297dae58473..315c74241693 100644 --- a/.gitmodules +++ b/.gitmodules @@ -142,7 +142,7 @@ url = https://github.com/adafruit/Adafruit_CircuitPython_RFM69.git [submodule "ports/espressif/esp-idf"] path = ports/espressif/esp-idf - url = https://github.com/eightycc/esp-idf.git + url = https://github.com/adafruit/esp-idf.git branch = circuitpython-v5.4.1 [submodule "ports/espressif/esp-protocols"] path = ports/espressif/esp-protocols From e35b1e9865a54ad2a245d7fda0e670ebeb060dc1 Mon Sep 17 00:00:00 2001 From: eightycc Date: Wed, 30 Apr 2025 18:52:05 -0700 Subject: [PATCH 22/30] Workaround Risc-V code gen problem causing Python interpreter crash. --- shared/runtime/pyexec.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/shared/runtime/pyexec.c b/shared/runtime/pyexec.c index 14e5e51a49aa..8d09a9257a6b 100644 --- a/shared/runtime/pyexec.c +++ b/shared/runtime/pyexec.c @@ -90,8 +90,9 @@ static int parse_compile_execute(const void *source, mp_parse_input_kind_t input nlr_buf_t nlr; nlr.ret_val = NULL; + // CIRCUITPY-CHANGE + mp_obj_t module_fun = mp_const_none; if (nlr_push(&nlr) == 0) { - mp_obj_t module_fun = mp_const_none; // CIRCUITPY-CHANGE #if CIRCUITPY_ATEXIT if (!(exec_flags & EXEC_FLAG_SOURCE_IS_ATEXIT)) @@ -157,6 +158,7 @@ static int parse_compile_execute(const void *source, mp_parse_input_kind_t input mp_call_function_n_kw(callback->func, callback->n_pos, callback->n_kw, callback->args); } else #endif + // CIRCUITPY-CHANGE if (module_fun != mp_const_none) { mp_call_function_0(module_fun); } From e729849fac17fb78bf902e3a6c1112d6c9fc7eff Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Thu, 1 May 2025 08:15:43 -0500 Subject: [PATCH 23/30] Initial setup of phaser effect. --- .../unix/variants/coverage/mpconfigvariant.mk | 2 + py/circuitpy_defns.mk | 1 + shared-bindings/audiofilters/Phaser.c | 287 ++++++++++++++++++ shared-bindings/audiofilters/Phaser.h | 34 +++ shared-bindings/audiofilters/__init__.c | 2 + shared-module/audiofilters/Phaser.c | 276 +++++++++++++++++ shared-module/audiofilters/Phaser.h | 46 +++ 7 files changed, 648 insertions(+) create mode 100644 shared-bindings/audiofilters/Phaser.c create mode 100644 shared-bindings/audiofilters/Phaser.h create mode 100644 shared-module/audiofilters/Phaser.c create mode 100644 shared-module/audiofilters/Phaser.h diff --git a/ports/unix/variants/coverage/mpconfigvariant.mk b/ports/unix/variants/coverage/mpconfigvariant.mk index e1924479bbf5..579e42cc05cf 100644 --- a/ports/unix/variants/coverage/mpconfigvariant.mk +++ b/ports/unix/variants/coverage/mpconfigvariant.mk @@ -40,6 +40,7 @@ SRC_BITMAP := \ shared-bindings/audiodelays/__init__.c \ shared-bindings/audiofilters/Distortion.c \ shared-bindings/audiofilters/Filter.c \ + shared-bindings/audiofilters/Phaser.c \ shared-bindings/audiofilters/__init__.c \ shared-bindings/audiofreeverb/Freeverb.c \ shared-bindings/audiofreeverb/__init__.c \ @@ -87,6 +88,7 @@ SRC_BITMAP := \ shared-module/audiodelays/__init__.c \ shared-module/audiofilters/Distortion.c \ shared-module/audiofilters/Filter.c \ + shared-module/audiofilters/Phaser.c \ shared-module/audiofilters/__init__.c \ shared-module/audiofreeverb/Freeverb.c \ shared-module/audiofreeverb/__init__.c \ diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index fa90481e648e..f73d52a6c4b1 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -674,6 +674,7 @@ SRC_SHARED_MODULE_ALL = \ audiodelays/__init__.c \ audiofilters/Distortion.c \ audiofilters/Filter.c \ + audiofilters/Phaser.c \ audiofilters/__init__.c \ audiofreeverb/__init__.c \ audiofreeverb/Freeverb.c \ diff --git a/shared-bindings/audiofilters/Phaser.c b/shared-bindings/audiofilters/Phaser.c new file mode 100644 index 000000000000..64fd01d7ab10 --- /dev/null +++ b/shared-bindings/audiofilters/Phaser.c @@ -0,0 +1,287 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Cooper Dalrymple +// +// SPDX-License-Identifier: MIT + +#include + +#include "shared-bindings/audiofilters/Phaser.h" +#include "shared-bindings/audiocore/__init__.h" +#include "shared-module/audiofilters/Phaser.h" + +#include "shared/runtime/context_manager_helpers.h" +#include "py/binary.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/util.h" +#include "shared-module/synthio/block.h" + +//| class Phaser: +//| """A Phaser effect""" +//| +//| def __init__( +//| self, +//| frequency: synthio.BlockInput = 1000.0, +//| feedback: synthio.BlockInput = 0.7, +//| mix: synthio.BlockInput = 1.0, +//| stages: int = 6, +//| buffer_size: int = 512, +//| sample_rate: int = 8000, +//| bits_per_sample: int = 16, +//| samples_signed: bool = True, +//| channel_count: int = 1, +//| ) -> None: +//| """Create a Phaser effect where the original sample is processed through a variable +//| number of all-pass filter stages. This slightly delays the signal so that it is out +//| of phase with the original signal. When the amount of phase is modulated and mixed +//| back into the original signal with the mix parameter, it creates a distinctive +//| phasing sound. +//| +//| :param synthio.BlockInput frequency: The target frequency which is affected by the effect in hz. +//| :param int stages: The number of all-pass filters which will be applied to the signal. +//| :param synthio.BlockInput feedback: The amount that the previous output of the filters is mixed back into their input along with the unprocessed signal. +//| :param synthio.BlockInput mix: The mix as a ratio of the sample (0.0) to the effect (1.0). +//| :param int buffer_size: The total size in bytes of each of the two playback buffers to use +//| :param int sample_rate: The sample rate to be used +//| :param int channel_count: The number of channels the source samples contain. 1 = mono; 2 = stereo. +//| :param int bits_per_sample: The bits per sample of the effect +//| :param bool samples_signed: Effect is signed (True) or unsigned (False) +//| +//| Playing adding a phaser to a synth:: +//| +//| import time +//| import board +//| import audiobusio +//| import synthio +//| import audiofilters +//| +//| audio = audiobusio.I2SOut(bit_clock=board.GP20, word_select=board.GP21, data=board.GP22) +//| synth = synthio.Synthesizer(channel_count=1, sample_rate=44100) +//| effect = audiofilters.Phaser(buffer_size=1024, channel_count=1, sample_rate=44100, mix=1.0) +//| effect.frequency = synthio.LFO(offset=1000.0, scale=600.0, rate=0.5) +//| effect.play(synth) +//| audio.play(effect) +//| +//| synth.press(48)""" +//| ... +//| +static mp_obj_t audiofilters_phaser_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_frequency, ARG_stages, ARG_feedback, ARG_mix, ARG_buffer_size, ARG_sample_rate, ARG_bits_per_sample, ARG_samples_signed, ARG_channel_count, }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_frequency, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_INT(1000) } }, + { MP_QSTR_feedback, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_NONE } }, + { MP_QSTR_mix, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_INT(1)} }, + { MP_QSTR_stages, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 6 } }, + { MP_QSTR_buffer_size, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 512} }, + { MP_QSTR_sample_rate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 8000} }, + { MP_QSTR_bits_per_sample, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 16} }, + { MP_QSTR_samples_signed, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, + { MP_QSTR_channel_count, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1 } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_int_t channel_count = mp_arg_validate_int_range(args[ARG_channel_count].u_int, 1, 2, MP_QSTR_channel_count); + mp_int_t sample_rate = mp_arg_validate_int_min(args[ARG_sample_rate].u_int, 1, MP_QSTR_sample_rate); + mp_int_t bits_per_sample = args[ARG_bits_per_sample].u_int; + if (bits_per_sample != 8 && bits_per_sample != 16) { + mp_raise_ValueError(MP_ERROR_TEXT("bits_per_sample must be 8 or 16")); + } + + audiofilters_phaser_obj_t *self = mp_obj_malloc(audiofilters_phaser_obj_t, &audiofilters_phaser_type); + common_hal_audiofilters_phaser_construct(self, args[ARG_frequency].u_obj, args[ARG_feedback].u_obj, args[ARG_mix].u_obj, args[ARG_stages].u_int, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate); + + return MP_OBJ_FROM_PTR(self); +} + +//| def deinit(self) -> None: +//| """Deinitialises the Phaser.""" +//| ... +//| +static mp_obj_t audiofilters_phaser_deinit(mp_obj_t self_in) { + audiofilters_phaser_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiofilters_phaser_deinit(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(audiofilters_phaser_deinit_obj, audiofilters_phaser_deinit); + +static void check_for_deinit(audiofilters_phaser_obj_t *self) { + audiosample_check_for_deinit(&self->base); +} + +//| def __enter__(self) -> Phaser: +//| """No-op used by Context Managers.""" +//| ... +//| +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Automatically deinitializes when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +// Provided by context manager helper. + + +//| frequency: synthio.BlockInput +//| """The target frequency in hertz at which the phaser is delaying the signal.""" +static mp_obj_t audiofilters_phaser_obj_get_frequency(mp_obj_t self_in) { + return common_hal_audiofilters_phaser_get_frequency(self_in); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiofilters_phaser_get_frequency_obj, audiofilters_phaser_obj_get_frequency); + +static mp_obj_t audiofilters_phaser_obj_set_frequency(mp_obj_t self_in, mp_obj_t frequency_in) { + audiofilters_phaser_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiofilters_phaser_set_frequency(self, frequency_in); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiofilters_phaser_set_frequency_obj, audiofilters_phaser_obj_set_frequency); + +MP_PROPERTY_GETSET(audiofilters_phaser_frequency_obj, + (mp_obj_t)&audiofilters_phaser_get_frequency_obj, + (mp_obj_t)&audiofilters_phaser_set_frequency_obj); + + +//| feedback: synthio.BlockInput +//| """The amount of which the incoming signal is fed back into the phasing filters from 0 to 1 where 0 is no feedback and 1 is full feedback.""" +static mp_obj_t audiofilters_phaser_obj_get_feedback(mp_obj_t self_in) { + return common_hal_audiofilters_phaser_get_feedback(self_in); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiofilters_phaser_get_feedback_obj, audiofilters_phaser_obj_get_feedback); + +static mp_obj_t audiofilters_phaser_obj_set_feedback(mp_obj_t self_in, mp_obj_t feedback_in) { + audiofilters_phaser_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiofilters_phaser_set_feedback(self, feedback_in); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiofilters_phaser_set_feedback_obj, audiofilters_phaser_obj_set_feedback); + +MP_PROPERTY_GETSET(audiofilters_phaser_feedback_obj, + (mp_obj_t)&audiofilters_phaser_get_feedback_obj, + (mp_obj_t)&audiofilters_phaser_set_feedback_obj); + + +//| mix: synthio.BlockInput +//| """The amount that the effect signal is mixed into the output between 0 and 1 where 0 is only the original sample and 1 is all effect.""" +static mp_obj_t audiofilters_phaser_obj_get_mix(mp_obj_t self_in) { + return common_hal_audiofilters_phaser_get_mix(self_in); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiofilters_phaser_get_mix_obj, audiofilters_phaser_obj_get_mix); + +static mp_obj_t audiofilters_phaser_obj_set_mix(mp_obj_t self_in, mp_obj_t mix_in) { + audiofilters_phaser_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiofilters_phaser_set_mix(self, mix_in); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiofilters_phaser_set_mix_obj, audiofilters_phaser_obj_set_mix); + +MP_PROPERTY_GETSET(audiofilters_phaser_mix_obj, + (mp_obj_t)&audiofilters_phaser_get_mix_obj, + (mp_obj_t)&audiofilters_phaser_set_mix_obj); + + +//| stages: int +//| """The number of allpass filters to pass the signal through. More stages requires more processing but produces a more pronounced effect. Requires a minimum value of 1.""" +static mp_obj_t audiofilters_phaser_obj_get_stages(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(common_hal_audiofilters_phaser_get_stages(self_in)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiofilters_phaser_get_stages_obj, audiofilters_phaser_obj_get_stages); + +static mp_obj_t audiofilters_phaser_obj_set_stages(mp_obj_t self_in, mp_obj_t stages_in) { + audiofilters_phaser_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiofilters_phaser_set_stages(self, mp_obj_get_int(stages_in)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiofilters_phaser_set_stages_obj, audiofilters_phaser_obj_set_stages); + +MP_PROPERTY_GETSET(audiofilters_phaser_stages_obj, + (mp_obj_t)&audiofilters_phaser_get_stages_obj, + (mp_obj_t)&audiofilters_phaser_set_stages_obj); + + +//| playing: bool +//| """True when the effect is playing a sample. (read-only)""" +//| +static mp_obj_t audiofilters_phaser_obj_get_playing(mp_obj_t self_in) { + audiofilters_phaser_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_audiofilters_phaser_get_playing(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiofilters_phaser_get_playing_obj, audiofilters_phaser_obj_get_playing); + +MP_PROPERTY_GETTER(audiofilters_phaser_playing_obj, + (mp_obj_t)&audiofilters_phaser_get_playing_obj); + +//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None: +//| """Plays the sample once when loop=False and continuously when loop=True. +//| Does not block. Use `playing` to block. +//| +//| The sample must match the encoding settings given in the constructor.""" +//| ... +//| +static mp_obj_t audiofilters_phaser_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_sample, ARG_loop }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED, {} }, + { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + }; + audiofilters_phaser_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + + mp_obj_t sample = args[ARG_sample].u_obj; + common_hal_audiofilters_phaser_play(self, sample, args[ARG_loop].u_bool); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(audiofilters_phaser_play_obj, 1, audiofilters_phaser_obj_play); + +//| def stop(self) -> None: +//| """Stops playback of the sample.""" +//| ... +//| +//| +static mp_obj_t audiofilters_phaser_obj_stop(mp_obj_t self_in) { + audiofilters_phaser_obj_t *self = MP_OBJ_TO_PTR(self_in); + + common_hal_audiofilters_phaser_stop(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(audiofilters_phaser_stop_obj, audiofilters_phaser_obj_stop); + +static const mp_rom_map_elem_t audiofilters_phaser_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiofilters_phaser_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audiofilters_phaser_play_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&audiofilters_phaser_stop_obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiofilters_phaser_playing_obj) }, + { MP_ROM_QSTR(MP_QSTR_frequency), MP_ROM_PTR(&audiofilters_phaser_frequency_obj) }, + { MP_ROM_QSTR(MP_QSTR_feedback), MP_ROM_PTR(&audiofilters_phaser_feedback_obj) }, + { MP_ROM_QSTR(MP_QSTR_mix), MP_ROM_PTR(&audiofilters_phaser_mix_obj) }, + { MP_ROM_QSTR(MP_QSTR_stages), MP_ROM_PTR(&audiofilters_phaser_stages_obj) }, + AUDIOSAMPLE_FIELDS, +}; +static MP_DEFINE_CONST_DICT(audiofilters_phaser_locals_dict, audiofilters_phaser_locals_dict_table); + +static const audiosample_p_t audiofilters_phaser_proto = { + MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample) + .reset_buffer = (audiosample_reset_buffer_fun)audiofilters_phaser_reset_buffer, + .get_buffer = (audiosample_get_buffer_fun)audiofilters_phaser_get_buffer, +}; + +MP_DEFINE_CONST_OBJ_TYPE( + audiofilters_phaser_type, + MP_QSTR_Phaser, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, audiofilters_phaser_make_new, + locals_dict, &audiofilters_phaser_locals_dict, + protocol, &audiofilters_phaser_proto + ); diff --git a/shared-bindings/audiofilters/Phaser.h b/shared-bindings/audiofilters/Phaser.h new file mode 100644 index 000000000000..b020ba6183cf --- /dev/null +++ b/shared-bindings/audiofilters/Phaser.h @@ -0,0 +1,34 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Cooper Dalrymple +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/audiofilters/Phaser.h" + +extern const mp_obj_type_t audiofilters_phaser_type; + +void common_hal_audiofilters_phaser_construct(audiofilters_phaser_obj_t *self, + mp_obj_t frequency, mp_obj_t feedback, mp_obj_t mix, uint8_t stages, + uint32_t buffer_size, uint8_t bits_per_sample, bool samples_signed, + uint8_t channel_count, uint32_t sample_rate); + +void common_hal_audiofilters_phaser_deinit(audiofilters_phaser_obj_t *self); + +mp_obj_t common_hal_audiofilters_phaser_get_frequency(audiofilters_phaser_obj_t *self); +void common_hal_audiofilters_phaser_set_frequency(audiofilters_phaser_obj_t *self, mp_obj_t arg); + +mp_obj_t common_hal_audiofilters_phaser_get_feedback(audiofilters_phaser_obj_t *self); +void common_hal_audiofilters_phaser_set_feedback(audiofilters_phaser_obj_t *self, mp_obj_t arg); + +mp_obj_t common_hal_audiofilters_phaser_get_mix(audiofilters_phaser_obj_t *self); +void common_hal_audiofilters_phaser_set_mix(audiofilters_phaser_obj_t *self, mp_obj_t arg); + +uint8_t common_hal_audiofilters_phaser_get_stages(audiofilters_phaser_obj_t *self); +void common_hal_audiofilters_phaser_set_stages(audiofilters_phaser_obj_t *self, mp_obj_t arg); + +bool common_hal_audiofilters_phaser_get_playing(audiofilters_phaser_obj_t *self); +void common_hal_audiofilters_phaser_play(audiofilters_phaser_obj_t *self, mp_obj_t sample, bool loop); +void common_hal_audiofilters_phaser_stop(audiofilters_phaser_obj_t *self); diff --git a/shared-bindings/audiofilters/__init__.c b/shared-bindings/audiofilters/__init__.c index 7a17ec655e62..ae43af9bfef8 100644 --- a/shared-bindings/audiofilters/__init__.c +++ b/shared-bindings/audiofilters/__init__.c @@ -12,6 +12,7 @@ #include "shared-bindings/audiofilters/__init__.h" #include "shared-bindings/audiofilters/Distortion.h" #include "shared-bindings/audiofilters/Filter.h" +#include "shared-bindings/audiofilters/Phaser.h" //| """Support for audio filter effects //| @@ -23,6 +24,7 @@ static const mp_rom_map_elem_t audiofilters_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audiofilters) }, { MP_ROM_QSTR(MP_QSTR_Filter), MP_ROM_PTR(&audiofilters_filter_type) }, { MP_ROM_QSTR(MP_QSTR_Distortion), MP_ROM_PTR(&audiofilters_distortion_type) }, + { MP_ROM_QSTR(MP_QSTR_Phaser), MP_ROM_PTR(&audiofilters_phaser_type) }, // Enum-like Classes. { MP_ROM_QSTR(MP_QSTR_DistortionMode), MP_ROM_PTR(&audiofilters_distortion_mode_type) }, diff --git a/shared-module/audiofilters/Phaser.c b/shared-module/audiofilters/Phaser.c new file mode 100644 index 000000000000..8e669dc90a01 --- /dev/null +++ b/shared-module/audiofilters/Phaser.c @@ -0,0 +1,276 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Cooper Dalrymple +// +// SPDX-License-Identifier: MIT +#include "shared-bindings/audiofilters/Phaser.h" +#include "shared-bindings/audiocore/__init__.h" + +#include +#include "py/runtime.h" + +void common_hal_audiofilters_phaser_construct(audiofilters_phaser_obj_t *self, + mp_obj_t frequency, mp_obj_t feedback, mp_obj_t mix, uint8_t stages, + uint32_t buffer_size, uint8_t bits_per_sample, + bool samples_signed, uint8_t channel_count, uint32_t sample_rate) { + + // Basic settings every effect and audio sample has + // These are the effects values, not the source sample(s) + self->base.bits_per_sample = bits_per_sample; // Most common is 16, but 8 is also supported in many places + self->base.samples_signed = samples_signed; // Are the samples we provide signed (common is true) + self->base.channel_count = channel_count; // Channels can be 1 for mono or 2 for stereo + self->base.sample_rate = sample_rate; // Sample rate for the effect, this generally needs to match all audio objects + self->base.single_buffer = false; + self->base.max_buffer_length = buffer_size; + + // To smooth things out as CircuitPython is doing other tasks most audio objects have a buffer + // A double buffer is set up here so the audio output can use DMA on buffer 1 while we + // write to and create buffer 2. + // This buffer is what is passed to the audio component that plays the effect. + // Samples are set sequentially. For stereo audio they are passed L/R/L/R/... + self->buffer_len = buffer_size; // in bytes + + self->buffer[0] = m_malloc_without_collect(self->buffer_len); + memset(self->buffer[0], 0, self->buffer_len); + + self->buffer[1] = m_malloc_without_collect(self->buffer_len); + memset(self->buffer[1], 0, self->buffer_len); + + self->last_buf_idx = 1; // Which buffer to use first, toggle between 0 and 1 + + // This buffer will be used to process samples through the biquad filter + self->filter_buffer = m_malloc_without_collect(SYNTHIO_MAX_DUR * sizeof(int32_t)); + memset(self->filter_buffer, 0, SYNTHIO_MAX_DUR * sizeof(int32_t)); + + // Initialize other values most effects will need. + self->sample = NULL; // The current playing sample + self->sample_remaining_buffer = NULL; // Pointer to the start of the sample buffer we have not played + self->sample_buffer_length = 0; // How many samples do we have left to play (these may be 16 bit!) + self->loop = false; // When the sample is done do we loop to the start again or stop (e.g. in a wav file) + self->more_data = false; // Is there still more data to read from the sample or did we finish + + // The below section sets up the effect's starting values. + + self->nyquist = (mp_float_t) self->base.sample_rate / 2; + + if (feedback == mp_const_none) { + feedback = mp_obj_new_float(MICROPY_FLOAT_CONST(0.7)); + } + + synthio_block_assign_slot(frequency, &self->frequency, MP_QSTR_frequency); + synthio_block_assign_slot(feedback, &self->feedback, MP_QSTR_feedback); + synthio_block_assign_slot(mix, &self->mix, MP_QSTR_mix); + + common_hal_audiofilters_phaser_set_stages(self, stages); +} + +void common_hal_audiofilters_phaser_deinit(audiofilters_phaser_obj_t *self) { + audiosample_mark_deinit(&self->base); + self->buffer[0] = NULL; + self->buffer[1] = NULL; +} + +mp_obj_t common_hal_audiofilters_phaser_get_frequency(audiofilters_phaser_obj_t *self) { + return self->frequency.obj; +} + +void common_hal_audiofilters_phaser_set_frequency(audiofilters_phaser_obj_t *self, mp_obj_t arg) { + synthio_block_assign_slot(arg, &self->frequency, MP_QSTR_frequency); +} + +mp_obj_t common_hal_audiofilters_phaser_get_feedback(audiofilters_phaser_obj_t *self) { + return self->feedback.obj; +} + +void common_hal_audiofilters_phaser_set_feedback(audiofilters_phaser_obj_t *self, mp_obj_t arg) { + synthio_block_assign_slot(arg, &self->feedback, MP_QSTR_feedback); +} + +mp_obj_t common_hal_audiofilters_phaser_get_mix(audiofilters_phaser_obj_t *self) { + return self->mix.obj; +} + +void common_hal_audiofilters_phaser_set_mix(audiofilters_phaser_obj_t *self, mp_obj_t arg) { + synthio_block_assign_slot(arg, &self->mix, MP_QSTR_mix); +} + +uint8_t common_hal_audiofilters_phaser_get_stages(audiofilters_phaser_obj_t *self) { + return self->stages; +} + +void common_hal_audiofilters_phaser_set_stages(audiofilters_phaser_obj_t *self, uint8_t arg) { + if (!arg) { + arg = 1; + } + // TODO: reallocate filters + self->stages = arg; +} + +void audiofilters_phaser_reset_buffer(audiofilters_phaser_obj_t *self, + bool single_channel_output, + uint8_t channel) { + + memset(self->buffer[0], 0, self->buffer_len); + memset(self->buffer[1], 0, self->buffer_len); +} + +bool common_hal_audiofilters_phaser_get_playing(audiofilters_phaser_obj_t *self) { + return self->sample != NULL; +} + +void common_hal_audiofilters_phaser_play(audiofilters_phaser_obj_t *self, mp_obj_t sample, bool loop) { + audiosample_must_match(&self->base, sample); + + self->sample = sample; + self->loop = loop; + + audiosample_reset_buffer(self->sample, false, 0); + audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); + + // Track remaining sample length in terms of bytes per sample + self->sample_buffer_length /= (self->base.bits_per_sample / 8); + // Store if we have more data in the sample to retrieve + self->more_data = result == GET_BUFFER_MORE_DATA; + + return; +} + +void common_hal_audiofilters_phaser_stop(audiofilters_phaser_obj_t *self) { + // When the sample is set to stop playing do any cleanup here + self->sample = NULL; + return; +} + +audioio_get_buffer_result_t audiofilters_phaser_get_buffer(audiofilters_phaser_obj_t *self, bool single_channel_output, uint8_t channel, + uint8_t **buffer, uint32_t *buffer_length) { + (void)channel; + + if (!single_channel_output) { + channel = 0; + } + + // Switch our buffers to the other buffer + self->last_buf_idx = !self->last_buf_idx; + + // If we are using 16 bit samples we need a 16 bit pointer, 8 bit needs an 8 bit pointer + int16_t *word_buffer = (int16_t *)self->buffer[self->last_buf_idx]; + int8_t *hword_buffer = self->buffer[self->last_buf_idx]; + uint32_t length = self->buffer_len / (self->base.bits_per_sample / 8); + + // Loop over the entire length of our buffer to fill it, this may require several calls to get data from the sample + while (length != 0) { + // Check if there is no more sample to play, we will either load more data, reset the sample if loop is on or clear the sample + if (self->sample_buffer_length == 0) { + if (!self->more_data) { // The sample has indicated it has no more data to play + if (self->loop && self->sample) { // If we are supposed to loop reset the sample to the start + audiosample_reset_buffer(self->sample, false, 0); + } else { // If we were not supposed to loop the sample, stop playing it + self->sample = NULL; + } + } + if (self->sample) { + // Load another sample buffer to play + audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); + // Track length in terms of words. + self->sample_buffer_length /= (self->base.bits_per_sample / 8); + self->more_data = result == GET_BUFFER_MORE_DATA; + } + } + + if (self->sample == NULL) { + // tick all block inputs + shared_bindings_synthio_lfo_tick(self->base.sample_rate, length / self->base.channel_count); + (void)synthio_block_slot_get(&self->frequency); + (void)synthio_block_slot_get(&self->feedback); + (void)synthio_block_slot_get(&self->mix); + + if (self->base.samples_signed) { + memset(word_buffer, 0, length * (self->base.bits_per_sample / 8)); + } else { + // For unsigned samples set to the middle which is "quiet" + if (MP_LIKELY(self->base.bits_per_sample == 16)) { + uint16_t *uword_buffer = (uint16_t *)word_buffer; + while (length--) { + *uword_buffer++ = 32768; + } + } else { + memset(hword_buffer, 128, length * (self->base.bits_per_sample / 8)); + } + } + + length = 0; + } else { + // we have a sample to play and filter + // Determine how many bytes we can process to our buffer, the less of the sample we have left and our buffer remaining + uint32_t n = MIN(MIN(self->sample_buffer_length, length), SYNTHIO_MAX_DUR * self->base.channel_count); + + int16_t *sample_src = (int16_t *)self->sample_remaining_buffer; // for 16-bit samples + int8_t *sample_hsrc = (int8_t *)self->sample_remaining_buffer; // for 8-bit samples + + // get the effect values we need from the BlockInput. These may change at run time so you need to do bounds checking if required + shared_bindings_synthio_lfo_tick(self->base.sample_rate, n / self->base.channel_count); + mp_float_t frequency = synthio_block_slot_get_limited(&self->frequency, MICROPY_FLOAT_CONST(0.0), self->nyquist); + mp_float_t feedback = synthio_block_slot_get_limited(&self->feedback, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(1.0)); + mp_float_t mix = synthio_block_slot_get_limited(&self->mix, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(1.0)); + + if (mix <= MICROPY_FLOAT_CONST(0.01)) { // if mix is zero pure sample only + for (uint32_t i = 0; i < n; i++) { + if (MP_LIKELY(self->base.bits_per_sample == 16)) { + word_buffer[i] = sample_src[i]; + } else { + hword_buffer[i] = sample_hsrc[i]; + } + } + } else { + for (uint32_t i = 0; i < n; i++) { + int32_t sample_word = 0; + if (MP_LIKELY(self->base.bits_per_sample == 16)) { + sample_word = sample_src[i]; + } else { + if (self->base.samples_signed) { + sample_word = sample_hsrc[i]; + } else { + // Be careful here changing from an 8 bit unsigned to signed into a 32-bit signed + sample_word = (int8_t)(((uint8_t)sample_hsrc[i]) ^ 0x80); + } + } + + // TODO: Process sample + int32_t word = 0; + + // Add original sample + effect + word = sample_word + (int32_t)(word * mix); + word = synthio_mix_down_sample(word, 2); + + if (MP_LIKELY(self->base.bits_per_sample == 16)) { + word_buffer[i] = word; + if (!self->base.samples_signed) { + word_buffer[i] ^= 0x8000; + } + } else { + int8_t out = word; + if (self->base.samples_signed) { + hword_buffer[i] = out; + } else { + hword_buffer[i] = (uint8_t)out ^ 0x80; + } + } + } + } + + // Update the remaining length and the buffer positions based on how much we wrote into our buffer + length -= n; + word_buffer += n; + hword_buffer += n; + self->sample_remaining_buffer += (n * (self->base.bits_per_sample / 8)); + self->sample_buffer_length -= n; + } + } + + // Finally pass our buffer and length to the calling audio function + *buffer = (uint8_t *)self->buffer[self->last_buf_idx]; + *buffer_length = self->buffer_len; + + // Phaser always returns more data but some effects may return GET_BUFFER_DONE or GET_BUFFER_ERROR (see audiocore/__init__.h) + return GET_BUFFER_MORE_DATA; +} diff --git a/shared-module/audiofilters/Phaser.h b/shared-module/audiofilters/Phaser.h new file mode 100644 index 000000000000..c2d9aeeb21de --- /dev/null +++ b/shared-module/audiofilters/Phaser.h @@ -0,0 +1,46 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Cooper Dalrymple +// +// SPDX-License-Identifier: MIT +#pragma once + +#include "py/obj.h" + +#include "shared-module/audiocore/__init__.h" +#include "shared-module/synthio/__init__.h" +#include "shared-module/synthio/block.h" + +extern const mp_obj_type_t audiofilters_phaser_type; + +typedef struct { + audiosample_base_t base; + synthio_block_slot_t frequency; + synthio_block_slot_t feedback; + synthio_block_slot_t mix; + uint8_t stages; + + mp_float_t nyquist; + + int8_t *buffer[2]; + uint8_t last_buf_idx; + uint32_t buffer_len; // max buffer in bytes + + uint8_t *sample_remaining_buffer; + uint32_t sample_buffer_length; + + bool loop; + bool more_data; + + mp_obj_t sample; +} audiofilters_phaser_obj_t; + +void audiofilters_phaser_reset_buffer(audiofilters_phaser_obj_t *self, + bool single_channel_output, + uint8_t channel); + +audioio_get_buffer_result_t audiofilters_phaser_get_buffer(audiofilters_phaser_obj_t *self, + bool single_channel_output, + uint8_t channel, + uint8_t **buffer, + uint32_t *buffer_length); // length in bytes From ba81c6b1c4c16ee190bd16e34b1217f452e68923 Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Thu, 1 May 2025 10:42:03 -0500 Subject: [PATCH 24/30] Implement allpass filters. --- shared-bindings/audiofilters/Phaser.c | 6 ++-- shared-bindings/audiofilters/Phaser.h | 2 +- shared-module/audiofilters/Phaser.c | 45 +++++++++++++++++++++------ shared-module/audiofilters/Phaser.h | 3 ++ 4 files changed, 43 insertions(+), 13 deletions(-) diff --git a/shared-bindings/audiofilters/Phaser.c b/shared-bindings/audiofilters/Phaser.c index 64fd01d7ab10..817614fa21f3 100644 --- a/shared-bindings/audiofilters/Phaser.c +++ b/shared-bindings/audiofilters/Phaser.c @@ -53,12 +53,12 @@ //| import time //| import board //| import audiobusio -//| import synthio //| import audiofilters +//| import synthio //| //| audio = audiobusio.I2SOut(bit_clock=board.GP20, word_select=board.GP21, data=board.GP22) //| synth = synthio.Synthesizer(channel_count=1, sample_rate=44100) -//| effect = audiofilters.Phaser(buffer_size=1024, channel_count=1, sample_rate=44100, mix=1.0) +//| effect = audiofilters.Phaser(channel_count=1, sample_rate=44100) //| effect.frequency = synthio.LFO(offset=1000.0, scale=600.0, rate=0.5) //| effect.play(synth) //| audio.play(effect) @@ -67,7 +67,7 @@ //| ... //| static mp_obj_t audiofilters_phaser_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - enum { ARG_frequency, ARG_stages, ARG_feedback, ARG_mix, ARG_buffer_size, ARG_sample_rate, ARG_bits_per_sample, ARG_samples_signed, ARG_channel_count, }; + enum { ARG_frequency, ARG_feedback, ARG_mix, ARG_stages, ARG_buffer_size, ARG_sample_rate, ARG_bits_per_sample, ARG_samples_signed, ARG_channel_count, }; static const mp_arg_t allowed_args[] = { { MP_QSTR_frequency, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_INT(1000) } }, { MP_QSTR_feedback, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_NONE } }, diff --git a/shared-bindings/audiofilters/Phaser.h b/shared-bindings/audiofilters/Phaser.h index b020ba6183cf..dbab22f57102 100644 --- a/shared-bindings/audiofilters/Phaser.h +++ b/shared-bindings/audiofilters/Phaser.h @@ -27,7 +27,7 @@ mp_obj_t common_hal_audiofilters_phaser_get_mix(audiofilters_phaser_obj_t *self) void common_hal_audiofilters_phaser_set_mix(audiofilters_phaser_obj_t *self, mp_obj_t arg); uint8_t common_hal_audiofilters_phaser_get_stages(audiofilters_phaser_obj_t *self); -void common_hal_audiofilters_phaser_set_stages(audiofilters_phaser_obj_t *self, mp_obj_t arg); +void common_hal_audiofilters_phaser_set_stages(audiofilters_phaser_obj_t *self, uint8_t arg); bool common_hal_audiofilters_phaser_get_playing(audiofilters_phaser_obj_t *self); void common_hal_audiofilters_phaser_play(audiofilters_phaser_obj_t *self, mp_obj_t sample, bool loop); diff --git a/shared-module/audiofilters/Phaser.c b/shared-module/audiofilters/Phaser.c index 8e669dc90a01..f31aea4caaa3 100644 --- a/shared-module/audiofilters/Phaser.c +++ b/shared-module/audiofilters/Phaser.c @@ -38,10 +38,6 @@ void common_hal_audiofilters_phaser_construct(audiofilters_phaser_obj_t *self, self->last_buf_idx = 1; // Which buffer to use first, toggle between 0 and 1 - // This buffer will be used to process samples through the biquad filter - self->filter_buffer = m_malloc_without_collect(SYNTHIO_MAX_DUR * sizeof(int32_t)); - memset(self->filter_buffer, 0, SYNTHIO_MAX_DUR * sizeof(int32_t)); - // Initialize other values most effects will need. self->sample = NULL; // The current playing sample self->sample_remaining_buffer = NULL; // Pointer to the start of the sample buffer we have not played @@ -51,7 +47,11 @@ void common_hal_audiofilters_phaser_construct(audiofilters_phaser_obj_t *self, // The below section sets up the effect's starting values. - self->nyquist = (mp_float_t) self->base.sample_rate / 2; + // Create buffer to hold the last processed word + self->word_buffer = m_malloc_without_collect(self->base.channel_count * sizeof(int32_t)); + memset(self->word_buffer, 0, self->base.channel_count * sizeof(int32_t)); + + self->nyquist = (mp_float_t)self->base.sample_rate / 2; if (feedback == mp_const_none) { feedback = mp_obj_new_float(MICROPY_FLOAT_CONST(0.7)); @@ -68,6 +68,8 @@ void common_hal_audiofilters_phaser_deinit(audiofilters_phaser_obj_t *self) { audiosample_mark_deinit(&self->base); self->buffer[0] = NULL; self->buffer[1] = NULL; + self->word_buffer = NULL; + self->allpass_buffer = NULL; } mp_obj_t common_hal_audiofilters_phaser_get_frequency(audiofilters_phaser_obj_t *self) { @@ -102,8 +104,15 @@ void common_hal_audiofilters_phaser_set_stages(audiofilters_phaser_obj_t *self, if (!arg) { arg = 1; } - // TODO: reallocate filters + + self->allpass_buffer = (int32_t *)m_realloc(self->allpass_buffer, + #if MICROPY_MALLOC_USES_ALLOCATED_SIZE + self->base.channel_count * self->stages * sizeof(int32_t), // Old size + #endif + self->base.channel_count * arg * sizeof(int32_t)); self->stages = arg; + + memset(self->allpass_buffer, 0, self->base.channel_count * self->stages * sizeof(int32_t)); } void audiofilters_phaser_reset_buffer(audiofilters_phaser_obj_t *self, @@ -112,6 +121,8 @@ void audiofilters_phaser_reset_buffer(audiofilters_phaser_obj_t *self, memset(self->buffer[0], 0, self->buffer_len); memset(self->buffer[1], 0, self->buffer_len); + memset(self->word_buffer, 0, self->base.channel_count * sizeof(int32_t)); + memset(self->allpass_buffer, 0, self->base.channel_count * self->stages * sizeof(int32_t)); } bool common_hal_audiofilters_phaser_get_playing(audiofilters_phaser_obj_t *self) { @@ -222,7 +233,15 @@ audioio_get_buffer_result_t audiofilters_phaser_get_buffer(audiofilters_phaser_o } } } else { + + // Update all-pass filter coefficient + mp_float_t allpasscoef = frequency / self->nyquist; + allpasscoef = (MICROPY_FLOAT_CONST(1.0) - allpasscoef) / (MICROPY_FLOAT_CONST(1.0) + allpasscoef); + for (uint32_t i = 0; i < n; i++) { + bool right_channel = (single_channel_output && channel == 1) || (!single_channel_output && (i % self->base.channel_count) == 1); + uint32_t allpass_buffer_offset = self->stages * right_channel; + int32_t sample_word = 0; if (MP_LIKELY(self->base.bits_per_sample == 16)) { sample_word = sample_src[i]; @@ -235,13 +254,21 @@ audioio_get_buffer_result_t audiofilters_phaser_get_buffer(audiofilters_phaser_o } } - // TODO: Process sample - int32_t word = 0; + int32_t word = sample_word + self->word_buffer[right_channel] * feedback; + int32_t allpass_word = 0; + + // Update all-pass filters + for (uint32_t j = 0; j < self->stages; j++) { + allpass_word = word * -allpasscoef + self->allpass_buffer[j + allpass_buffer_offset]; + self->allpass_buffer[j + allpass_buffer_offset] = allpass_word * allpasscoef + word; + word = allpass_word; + } + self->word_buffer[(bool)allpass_buffer_offset] = word; // Add original sample + effect word = sample_word + (int32_t)(word * mix); word = synthio_mix_down_sample(word, 2); - + if (MP_LIKELY(self->base.bits_per_sample == 16)) { word_buffer[i] = word; if (!self->base.samples_signed) { diff --git a/shared-module/audiofilters/Phaser.h b/shared-module/audiofilters/Phaser.h index c2d9aeeb21de..707a2b0f0841 100644 --- a/shared-module/audiofilters/Phaser.h +++ b/shared-module/audiofilters/Phaser.h @@ -32,6 +32,9 @@ typedef struct { bool loop; bool more_data; + int32_t *allpass_buffer; + int32_t *word_buffer; + mp_obj_t sample; } audiofilters_phaser_obj_t; From e855e3e1bae5af371826efcaf975111e9f31c1e1 Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Thu, 1 May 2025 10:54:10 -0500 Subject: [PATCH 25/30] Limit feedback range to 0.1 - 0.9 --- shared-bindings/audiofilters/Phaser.c | 2 +- shared-module/audiofilters/Phaser.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/shared-bindings/audiofilters/Phaser.c b/shared-bindings/audiofilters/Phaser.c index 817614fa21f3..e7ddd986176b 100644 --- a/shared-bindings/audiofilters/Phaser.c +++ b/shared-bindings/audiofilters/Phaser.c @@ -145,7 +145,7 @@ MP_PROPERTY_GETSET(audiofilters_phaser_frequency_obj, //| feedback: synthio.BlockInput -//| """The amount of which the incoming signal is fed back into the phasing filters from 0 to 1 where 0 is no feedback and 1 is full feedback.""" +//| """The amount of which the incoming signal is fed back into the phasing filters from 0.1 to 0.9.""" static mp_obj_t audiofilters_phaser_obj_get_feedback(mp_obj_t self_in) { return common_hal_audiofilters_phaser_get_feedback(self_in); } diff --git a/shared-module/audiofilters/Phaser.c b/shared-module/audiofilters/Phaser.c index f31aea4caaa3..3a426ff2c302 100644 --- a/shared-module/audiofilters/Phaser.c +++ b/shared-module/audiofilters/Phaser.c @@ -221,7 +221,7 @@ audioio_get_buffer_result_t audiofilters_phaser_get_buffer(audiofilters_phaser_o // get the effect values we need from the BlockInput. These may change at run time so you need to do bounds checking if required shared_bindings_synthio_lfo_tick(self->base.sample_rate, n / self->base.channel_count); mp_float_t frequency = synthio_block_slot_get_limited(&self->frequency, MICROPY_FLOAT_CONST(0.0), self->nyquist); - mp_float_t feedback = synthio_block_slot_get_limited(&self->feedback, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(1.0)); + mp_float_t feedback = synthio_block_slot_get_limited(&self->feedback, MICROPY_FLOAT_CONST(0.1), MICROPY_FLOAT_CONST(0.9)); mp_float_t mix = synthio_block_slot_get_limited(&self->mix, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(1.0)); if (mix <= MICROPY_FLOAT_CONST(0.01)) { // if mix is zero pure sample only From 8a9d78ada4d008dec2930d620d2443d10df6a8e3 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 1 May 2025 14:57:36 -0500 Subject: [PATCH 26/30] use m_malloc for outter mappings pointers --- shared-module/tilepalettemapper/TilePaletteMapper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-module/tilepalettemapper/TilePaletteMapper.c b/shared-module/tilepalettemapper/TilePaletteMapper.c index f46810b6a351..fb784fd441b9 100644 --- a/shared-module/tilepalettemapper/TilePaletteMapper.c +++ b/shared-module/tilepalettemapper/TilePaletteMapper.c @@ -18,7 +18,7 @@ void common_hal_tilepalettemapper_tilepalettemapper_construct(tilepalettemapper_ self->input_color_count = input_color_count; self->needs_refresh = false; int mappings_len = width * height; - self->tile_mappings = (uint32_t **)m_malloc_without_collect(mappings_len * sizeof(uint32_t *)); + self->tile_mappings = (uint32_t **)m_malloc(mappings_len * sizeof(uint32_t *)); for (int i = 0; i < mappings_len; i++) { self->tile_mappings[i] = (uint32_t *)m_malloc_without_collect(input_color_count * sizeof(uint32_t)); if (mp_obj_is_type(self->pixel_shader, &displayio_palette_type)) { From 421521516c221629ff6c15fd066a1be3fc6a95f3 Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Thu, 1 May 2025 15:27:23 -0500 Subject: [PATCH 27/30] Convert floating point operations to fixed point and use `synthio_sat16`. --- shared-module/audiofilters/Phaser.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/shared-module/audiofilters/Phaser.c b/shared-module/audiofilters/Phaser.c index 3a426ff2c302..73a2a8d54a59 100644 --- a/shared-module/audiofilters/Phaser.c +++ b/shared-module/audiofilters/Phaser.c @@ -221,10 +221,10 @@ audioio_get_buffer_result_t audiofilters_phaser_get_buffer(audiofilters_phaser_o // get the effect values we need from the BlockInput. These may change at run time so you need to do bounds checking if required shared_bindings_synthio_lfo_tick(self->base.sample_rate, n / self->base.channel_count); mp_float_t frequency = synthio_block_slot_get_limited(&self->frequency, MICROPY_FLOAT_CONST(0.0), self->nyquist); - mp_float_t feedback = synthio_block_slot_get_limited(&self->feedback, MICROPY_FLOAT_CONST(0.1), MICROPY_FLOAT_CONST(0.9)); - mp_float_t mix = synthio_block_slot_get_limited(&self->mix, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(1.0)); + int16_t feedback = (int16_t)(synthio_block_slot_get_limited(&self->feedback, MICROPY_FLOAT_CONST(0.1), MICROPY_FLOAT_CONST(0.9)) * 32767); + int16_t mix = (int16_t)(synthio_block_slot_get_limited(&self->mix, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(1.0)) * 32767); - if (mix <= MICROPY_FLOAT_CONST(0.01)) { // if mix is zero pure sample only + if (mix <= 328) { // if mix is zero (0.01 in fixed point), pure sample only for (uint32_t i = 0; i < n; i++) { if (MP_LIKELY(self->base.bits_per_sample == 16)) { word_buffer[i] = sample_src[i]; @@ -233,10 +233,9 @@ audioio_get_buffer_result_t audiofilters_phaser_get_buffer(audiofilters_phaser_o } } } else { - // Update all-pass filter coefficient - mp_float_t allpasscoef = frequency / self->nyquist; - allpasscoef = (MICROPY_FLOAT_CONST(1.0) - allpasscoef) / (MICROPY_FLOAT_CONST(1.0) + allpasscoef); + frequency /= self->nyquist; // scale relative to frequency range + int16_t allpasscoef = (int16_t)((MICROPY_FLOAT_CONST(1.0) - frequency) / (MICROPY_FLOAT_CONST(1.0) + frequency) * 32767); for (uint32_t i = 0; i < n; i++) { bool right_channel = (single_channel_output && channel == 1) || (!single_channel_output && (i % self->base.channel_count) == 1); @@ -254,19 +253,19 @@ audioio_get_buffer_result_t audiofilters_phaser_get_buffer(audiofilters_phaser_o } } - int32_t word = sample_word + self->word_buffer[right_channel] * feedback; + int32_t word = synthio_sat16(sample_word + synthio_sat16(self->word_buffer[right_channel] * feedback, 15), 0); int32_t allpass_word = 0; // Update all-pass filters for (uint32_t j = 0; j < self->stages; j++) { - allpass_word = word * -allpasscoef + self->allpass_buffer[j + allpass_buffer_offset]; - self->allpass_buffer[j + allpass_buffer_offset] = allpass_word * allpasscoef + word; + allpass_word = synthio_sat16(synthio_sat16(word * -allpasscoef, 15) + self->allpass_buffer[j + allpass_buffer_offset], 0); + self->allpass_buffer[j + allpass_buffer_offset] = synthio_sat16(synthio_sat16(allpass_word * allpasscoef, 15) + word, 0); word = allpass_word; } self->word_buffer[(bool)allpass_buffer_offset] = word; // Add original sample + effect - word = sample_word + (int32_t)(word * mix); + word = sample_word + (int32_t)(synthio_sat16(word * mix, 15)); word = synthio_mix_down_sample(word, 2); if (MP_LIKELY(self->base.bits_per_sample == 16)) { From 02382401c6060154d8283c8871fa6d7a5887cc6f Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Fri, 2 May 2025 09:08:19 -0500 Subject: [PATCH 28/30] Reduce data size of internal buffers. --- shared-module/audiofilters/Phaser.c | 20 ++++++++++---------- shared-module/audiofilters/Phaser.h | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/shared-module/audiofilters/Phaser.c b/shared-module/audiofilters/Phaser.c index 73a2a8d54a59..81d9c0bea308 100644 --- a/shared-module/audiofilters/Phaser.c +++ b/shared-module/audiofilters/Phaser.c @@ -48,8 +48,8 @@ void common_hal_audiofilters_phaser_construct(audiofilters_phaser_obj_t *self, // The below section sets up the effect's starting values. // Create buffer to hold the last processed word - self->word_buffer = m_malloc_without_collect(self->base.channel_count * sizeof(int32_t)); - memset(self->word_buffer, 0, self->base.channel_count * sizeof(int32_t)); + self->word_buffer = m_malloc_without_collect(self->base.channel_count * sizeof(int16_t)); + memset(self->word_buffer, 0, self->base.channel_count * sizeof(int16_t)); self->nyquist = (mp_float_t)self->base.sample_rate / 2; @@ -105,14 +105,14 @@ void common_hal_audiofilters_phaser_set_stages(audiofilters_phaser_obj_t *self, arg = 1; } - self->allpass_buffer = (int32_t *)m_realloc(self->allpass_buffer, + self->allpass_buffer = (int16_t *)m_realloc(self->allpass_buffer, #if MICROPY_MALLOC_USES_ALLOCATED_SIZE - self->base.channel_count * self->stages * sizeof(int32_t), // Old size + self->base.channel_count * self->stages * sizeof(int16_t), // Old size #endif - self->base.channel_count * arg * sizeof(int32_t)); + self->base.channel_count * arg * sizeof(int16_t)); self->stages = arg; - memset(self->allpass_buffer, 0, self->base.channel_count * self->stages * sizeof(int32_t)); + memset(self->allpass_buffer, 0, self->base.channel_count * self->stages * sizeof(int16_t)); } void audiofilters_phaser_reset_buffer(audiofilters_phaser_obj_t *self, @@ -121,8 +121,8 @@ void audiofilters_phaser_reset_buffer(audiofilters_phaser_obj_t *self, memset(self->buffer[0], 0, self->buffer_len); memset(self->buffer[1], 0, self->buffer_len); - memset(self->word_buffer, 0, self->base.channel_count * sizeof(int32_t)); - memset(self->allpass_buffer, 0, self->base.channel_count * self->stages * sizeof(int32_t)); + memset(self->word_buffer, 0, self->base.channel_count * sizeof(int16_t)); + memset(self->allpass_buffer, 0, self->base.channel_count * self->stages * sizeof(int16_t)); } bool common_hal_audiofilters_phaser_get_playing(audiofilters_phaser_obj_t *self) { @@ -253,7 +253,7 @@ audioio_get_buffer_result_t audiofilters_phaser_get_buffer(audiofilters_phaser_o } } - int32_t word = synthio_sat16(sample_word + synthio_sat16(self->word_buffer[right_channel] * feedback, 15), 0); + int32_t word = synthio_sat16(sample_word + synthio_sat16((int32_t)self->word_buffer[right_channel] * feedback, 15), 0); int32_t allpass_word = 0; // Update all-pass filters @@ -262,7 +262,7 @@ audioio_get_buffer_result_t audiofilters_phaser_get_buffer(audiofilters_phaser_o self->allpass_buffer[j + allpass_buffer_offset] = synthio_sat16(synthio_sat16(allpass_word * allpasscoef, 15) + word, 0); word = allpass_word; } - self->word_buffer[(bool)allpass_buffer_offset] = word; + self->word_buffer[(bool)allpass_buffer_offset] = (int16_t)word; // Add original sample + effect word = sample_word + (int32_t)(synthio_sat16(word * mix, 15)); diff --git a/shared-module/audiofilters/Phaser.h b/shared-module/audiofilters/Phaser.h index 707a2b0f0841..f627b147014a 100644 --- a/shared-module/audiofilters/Phaser.h +++ b/shared-module/audiofilters/Phaser.h @@ -32,8 +32,8 @@ typedef struct { bool loop; bool more_data; - int32_t *allpass_buffer; - int32_t *word_buffer; + int16_t *allpass_buffer; + int16_t *word_buffer; mp_obj_t sample; } audiofilters_phaser_obj_t; From fba4e681e1a4a0f5b352d356b97d7fc50564c287 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 2 May 2025 22:49:12 -0700 Subject: [PATCH 29/30] Fix finaliser in malloc helper --- py/malloc.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/py/malloc.c b/py/malloc.c index c83dd4bd6c7d..fcf930ecfaa8 100644 --- a/py/malloc.c +++ b/py/malloc.c @@ -55,18 +55,8 @@ // example. On the other hand, some (e.g. bare-metal) ports may use GC // heap as system heap, so, to avoid warnings, we do undef's first. // CIRCUITPY-CHANGE: Add selective collect support to malloc to optimize GC for large buffers -#undef malloc #undef free #undef realloc -#if MICROPY_ENABLE_SELECTIVE_COLLECT -#define malloc(b) gc_alloc((b), GC_ALLOC_FLAG_DO_NOT_COLLECT) -#define malloc_with_collect(b) gc_alloc((b), 0) -#define malloc_without_collect(b) gc_alloc((b), GC_ALLOC_FLAG_DO_NOT_COLLECT) -#else -#define malloc(b) gc_alloc((b), 0) -#define malloc_with_collect(b) gc_alloc((b), 0) -#endif -#define malloc_with_finaliser(b) gc_alloc((b), GC_ALLOC_FLAG_HAS_FINALISER) #define free gc_free #define realloc(ptr, n) gc_realloc(ptr, n, true) #define realloc_ext(ptr, n, mv) gc_realloc(ptr, n, mv) @@ -99,15 +89,18 @@ static void *realloc_ext(void *ptr, size_t n_bytes, bool allow_move) { void *m_malloc_helper(size_t num_bytes, uint8_t flags) { void *ptr; #if MICROPY_ENABLE_GC + uint8_t gc_flags = 0; #if MICROPY_ENABLE_SELECTIVE_COLLECT if ((flags & M_MALLOC_COLLECT) == 0) { - ptr = malloc_without_collect(num_bytes); - } else { - ptr = malloc_with_collect(num_bytes); + gc_flags |= GC_ALLOC_FLAG_DO_NOT_COLLECT; + } + #endif + #if MICROPY_ENABLE_FINALISER + if ((flags & M_MALLOC_WITH_FINALISER) != 0) { + gc_flags |= GC_ALLOC_FLAG_HAS_FINALISER; } - #else - ptr = malloc_with_collect(num_bytes); #endif + ptr = gc_alloc(num_bytes, gc_flags); #else ptr = malloc(num_bytes); #endif From 1f5ce9613980d2c7ba57b128644869de80cbfaad Mon Sep 17 00:00:00 2001 From: eightycc Date: Fri, 2 May 2025 22:58:32 -0700 Subject: [PATCH 30/30] Durable fix for RISC-V interpreter crash. --- shared/runtime/pyexec.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/shared/runtime/pyexec.c b/shared/runtime/pyexec.c index 8d09a9257a6b..df2b60e207c9 100644 --- a/shared/runtime/pyexec.c +++ b/shared/runtime/pyexec.c @@ -90,9 +90,10 @@ static int parse_compile_execute(const void *source, mp_parse_input_kind_t input nlr_buf_t nlr; nlr.ret_val = NULL; - // CIRCUITPY-CHANGE - mp_obj_t module_fun = mp_const_none; if (nlr_push(&nlr) == 0) { + // CIRCUITPY-CHANGE: Made volatile to prevent gcc from re-ordering store of function pointer into stack frame + // after call to gc_collect. For RISC-V this was causing free of the compiled function before execution. + volatile mp_obj_t module_fun = mp_const_none; // CIRCUITPY-CHANGE #if CIRCUITPY_ATEXIT if (!(exec_flags & EXEC_FLAG_SOURCE_IS_ATEXIT))