From 1727222d93718184287b7a10f949a19abd5faba2 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Tue, 1 Sep 2026 19:53:10 -0700 Subject: [PATCH 1/4] espressif: add esp32c5 target support C5 is the first dual-band ESP32. It differs from c6 in ways that build cleanly but fail at run time: - bootloader flash offset is 0x2000, not 0x0 - ADC1 channels start at GPIO1, not GPIO0 - efuse MAC registers are named like c61, not c6 - libphy.a references _rom_eco_version, so rom.version.ld must link - USB-Serial-JTAG pads (GPIO13/14) are cleared by gpio_ll_func_sel(), so reset_all_pins() must skip them along with the flash/PSRAM MSPI pins and VDD_SPI - boot button is GPIO28, not GPIO9 or GPIO0 - the 48MHz crystal leaves only 40/80/160/240MHz CPU valid - TWAI is the newer TWAI-FD, so canio is off pending a backend --- ports/espressif/Makefile | 28 ++++++++ .../common-hal/analogbufio/BufferedIn.c | 2 +- .../espressif/common-hal/analogio/AnalogIn.c | 2 + ports/espressif/common-hal/espidf/__init__.c | 3 +- .../common-hal/microcontroller/Pin.c | 26 +++++++ .../common-hal/microcontroller/Processor.c | 8 ++- .../common-hal/microcontroller/__init__.c | 5 +- .../esp-idf-config/sdkconfig-esp32c5.defaults | 54 ++++++++++++++ ports/espressif/mpconfigport.h | 2 + ports/espressif/mpconfigport.mk | 38 ++++++++++ ports/espressif/peripherals/esp32c5/pins.c | 37 ++++++++++ ports/espressif/peripherals/esp32c5/pins.h | 70 +++++++++++++++++++ ports/espressif/peripherals/pins.h | 2 + ports/espressif/tools/build_memory_info.py | 5 ++ 14 files changed, 277 insertions(+), 5 deletions(-) create mode 100644 ports/espressif/esp-idf-config/sdkconfig-esp32c5.defaults create mode 100644 ports/espressif/peripherals/esp32c5/pins.c create mode 100644 ports/espressif/peripherals/esp32c5/pins.h diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index ca70127565f..b772e384410 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -402,6 +402,29 @@ CHIP_COMPONENTS = \ esp_hal_twai \ esp_hal_usb +else ifeq ($(IDF_TARGET),esp32c5) +LDFLAGS += \ + -Tesp32c5.rom.phy.ld \ + -Tesp32c5.rom.pp.ld \ + -Tesp32c5.rom.net80211.ld \ + -Tesp32c5.rom.libc.ld \ + -Tesp32c5.rom.version.ld \ + -Tesp32c5.rom.coexist.ld \ + -Tesp32c5.rom.heap.ld \ + -Tesp32c5.rom.systimer.ld \ + -Trom.wdt.ld + +CHIP_COMPONENTS = \ + esp_driver_tsens \ + esp_driver_usb_serial_jtag \ + esp_hal_dma \ + esp_hal_i2s \ + esp_hal_pcnt \ + esp_hal_pmu \ + esp_hal_rmt \ + esp_hal_twai \ + esp_hal_usb + else ifeq ($(IDF_TARGET),esp32c6) LDFLAGS += \ -Tesp32c6.rom.phy.ld \ @@ -565,6 +588,8 @@ else ifeq ($(IDF_TARGET),esp32c2) CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_ESP32C2 else ifeq ($(IDF_TARGET),esp32c3) CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_ESP32C3 +else ifeq ($(IDF_TARGET),esp32c5) +CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_ESP32C5 else ifeq ($(IDF_TARGET),esp32c6) CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_ESP32C6 else ifeq ($(IDF_TARGET),esp32c61) @@ -912,6 +937,7 @@ ifneq ($(CIRCUITPY_BLEIO_NATIVE),0) BLE_IMPL_esp32s3 := esp32c3 BLE_IMPL_esp32c2 := libble BLE_IMPL_esp32c3 := esp32c3 + BLE_IMPL_esp32c5 := libble BLE_IMPL_esp32c6 := libble BLE_IMPL_esp32c61 := libble BLE_IMPL_esp32h2 := libble @@ -1006,6 +1032,8 @@ else ifeq ($(IDF_TARGET),esp32c2) BOOTLOADER_OFFSET = 0x0 else ifeq ($(IDF_TARGET),esp32c3) BOOTLOADER_OFFSET = 0x0 +else ifeq ($(IDF_TARGET),esp32c5) +BOOTLOADER_OFFSET = 0x2000 else ifeq ($(IDF_TARGET),esp32c6) BOOTLOADER_OFFSET = 0x0 else ifeq ($(IDF_TARGET),esp32c61) diff --git a/ports/espressif/common-hal/analogbufio/BufferedIn.c b/ports/espressif/common-hal/analogbufio/BufferedIn.c index 747d7d53878..e91c8aafca8 100644 --- a/ports/espressif/common-hal/analogbufio/BufferedIn.c +++ b/ports/espressif/common-hal/analogbufio/BufferedIn.c @@ -33,7 +33,7 @@ #elif defined(CONFIG_IDF_TARGET_ESP32S2) #define ADC_RESULT_BYTE 2 #define ADC_CONV_LIMIT_EN 0 -#elif defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32H2) || defined(CONFIG_IDF_TARGET_ESP32P4) || defined(CONFIG_IDF_TARGET_ESP32C61) +#elif defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32H2) || defined(CONFIG_IDF_TARGET_ESP32P4) || defined(CONFIG_IDF_TARGET_ESP32C61) #define ADC_RESULT_BYTE 4 #define ADC_CONV_LIMIT_EN 0 #elif defined(CONFIG_IDF_TARGET_ESP32S3) diff --git a/ports/espressif/common-hal/analogio/AnalogIn.c b/ports/espressif/common-hal/analogio/AnalogIn.c index 9809962b394..974cba8c5c9 100644 --- a/ports/espressif/common-hal/analogio/AnalogIn.c +++ b/ports/espressif/common-hal/analogio/AnalogIn.c @@ -30,6 +30,8 @@ #define DATA_WIDTH ADC_BITWIDTH_12 #elif defined(CONFIG_IDF_TARGET_ESP32C3) #define DATA_WIDTH ADC_BITWIDTH_12 +#elif defined(CONFIG_IDF_TARGET_ESP32C5) +#define DATA_WIDTH ADC_BITWIDTH_12 #elif defined(CONFIG_IDF_TARGET_ESP32C6) #define DATA_WIDTH ADC_BITWIDTH_12 #elif defined(CONFIG_IDF_TARGET_ESP32C61) diff --git a/ports/espressif/common-hal/espidf/__init__.c b/ports/espressif/common-hal/espidf/__init__.c index 83e30657750..bfb50a04ec7 100644 --- a/ports/espressif/common-hal/espidf/__init__.c +++ b/ports/espressif/common-hal/espidf/__init__.c @@ -27,7 +27,8 @@ static size_t psram_size_usable(void) { #ifdef CONFIG_SPIRAM /* PSRAM chip may be larger than the size we can map into address space */ - #ifdef CONFIG_IDF_TARGET_ESP32P4 + #if defined(CONFIG_IDF_TARGET_ESP32P4) || defined(CONFIG_IDF_TARGET_ESP32C5) + // These targets don't define SOC_EXTRAM_DATA_SIZE. size_t s = esp_psram_get_size(); #else size_t s = MIN(esp_psram_get_size(), SOC_EXTRAM_DATA_SIZE); diff --git a/ports/espressif/common-hal/microcontroller/Pin.c b/ports/espressif/common-hal/microcontroller/Pin.c index 34b9578d580..0c49318f4bc 100644 --- a/ports/espressif/common-hal/microcontroller/Pin.c +++ b/ports/espressif/common-hal/microcontroller/Pin.c @@ -136,6 +136,32 @@ static const uint64_t pin_mask_reset_forbidden = #endif #endif // ESP32C3 + #if defined(CONFIG_IDF_TARGET_ESP32C5) + // Never ever reset pins used to communicate with SPI flash. + // ports/espressif/esp-idf/components/esp_hal_gpspi/esp32c5/include/soc/spi_pins.h + GPIO_SEL_16 | // MSPI_IOMUX_PIN_NUM_CS0 (flash) + GPIO_SEL_17 | // MSPI_IOMUX_PIN_NUM_MISO + GPIO_SEL_18 | // MSPI_IOMUX_PIN_NUM_WP + GPIO_SEL_19 | // VDD_SPI (powers the in-module flash) + GPIO_SEL_20 | // MSPI_IOMUX_PIN_NUM_HD + GPIO_SEL_21 | // MSPI_IOMUX_PIN_NUM_CLK + GPIO_SEL_22 | // MSPI_IOMUX_PIN_NUM_MOSI + #if CIRCUITPY_ESP_USB_SERIAL_JTAG + // Never ever reset serial/JTAG communication pins. On C5, gpio_ll_func_sel() + // on either clears USB_SERIAL_JTAG.conf0.usb_pad_enable, killing the USB pads. + GPIO_SEL_13 | // USB D- (USB_INT_PHY0_DM_GPIO_NUM) + GPIO_SEL_14 | // USB D+ (USB_INT_PHY0_DP_GPIO_NUM) + #endif + #if defined(CONFIG_SPIRAM) + GPIO_SEL_15 | // MSPI_IOMUX_PIN_NUM_CS1 (PSRAM); keep if PSRAM in use + #endif + #if defined(CONFIG_ESP_CONSOLE_UART_DEFAULT) && CONFIG_ESP_CONSOLE_UART_DEFAULT && CONFIG_ESP_CONSOLE_UART_NUM == 0 + // Never reset debug UART/console pins. + GPIO_SEL_11 | + GPIO_SEL_12 | + #endif + #endif // ESP32C5 + #if defined(CONFIG_IDF_TARGET_ESP32C6) // Never ever reset pins used to communicate with SPI flash. GPIO_SEL_24 | // SPICS0 diff --git a/ports/espressif/common-hal/microcontroller/Processor.c b/ports/espressif/common-hal/microcontroller/Processor.c index 72c9845241c..26cec5eb467 100644 --- a/ports/espressif/common-hal/microcontroller/Processor.c +++ b/ports/espressif/common-hal/microcontroller/Processor.c @@ -65,6 +65,10 @@ static uint32_t get_valid_cpu_frequency(uint32_t requested_freq_mhz) { uint32_t valid_cpu_frequencies[] = {20, 40, 80, 120}; #elif defined(CONFIG_IDF_TARGET_ESP32H2) uint32_t valid_cpu_frequencies[] = {32, 48, 64, 96}; + #elif defined(CONFIG_IDF_TARGET_ESP32C5) + // C5's 48 MHz crystal does not divide evenly to 20 or 24 MHz, both of + // which esp_pm_configure() rejects. + uint32_t valid_cpu_frequencies[] = {40, 80, 160, 240}; #else uint32_t valid_cpu_frequencies[] = {20, 40, 80, 160, 240}; #endif @@ -126,7 +130,7 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { uint32_t mac_address_part = REG_READ(EFUSE_RD_MAC_SYS_0_REG); #elif defined(CONFIG_IDF_TARGET_ESP32C2) uint32_t mac_address_part = REG_READ(EFUSE_RD_BLK2_DATA0_REG); - #elif defined(CONFIG_IDF_TARGET_ESP32C61) + #elif defined(CONFIG_IDF_TARGET_ESP32C61) || defined(CONFIG_IDF_TARGET_ESP32C5) uint32_t mac_address_part = REG_READ(EFUSE_RD_MAC_SYS0_REG); #else uint32_t mac_address_part = REG_READ(EFUSE_RD_MAC_SPI_SYS_0_REG); @@ -147,7 +151,7 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { mac_address_part = REG_READ(EFUSE_RD_MAC_SYS_1_REG); #elif defined(CONFIG_IDF_TARGET_ESP32C2) mac_address_part = REG_READ(EFUSE_RD_BLK2_DATA1_REG); - #elif defined(CONFIG_IDF_TARGET_ESP32C61) + #elif defined(CONFIG_IDF_TARGET_ESP32C61) || defined(CONFIG_IDF_TARGET_ESP32C5) mac_address_part = REG_READ(EFUSE_RD_MAC_SYS1_REG); #else mac_address_part = REG_READ(EFUSE_RD_MAC_SPI_SYS_1_REG); diff --git a/ports/espressif/common-hal/microcontroller/__init__.c b/ports/espressif/common-hal/microcontroller/__init__.c index 9b50cd7b5d2..2da2d09f22d 100644 --- a/ports/espressif/common-hal/microcontroller/__init__.c +++ b/ports/espressif/common-hal/microcontroller/__init__.c @@ -33,6 +33,9 @@ #elif defined(CONFIG_IDF_TARGET_ESP32C3) #include "soc/rtc_cntl_reg.h" #include "esp32c3/rom/rtc.h" +#elif defined(CONFIG_IDF_TARGET_ESP32C5) +#include "soc/lp_aon_reg.h" +#include "esp32c5/rom/rtc.h" #elif defined(CONFIG_IDF_TARGET_ESP32C6) #include "soc/lp_aon_reg.h" #include "esp32c6/rom/rtc.h" @@ -86,7 +89,7 @@ void common_hal_mcu_enable_interrupts(void) { void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) { switch (runmode) { case RUNMODE_UF2: - #if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32C61) + #if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32C61) mp_arg_error_invalid(MP_QSTR_run_mode); #else // 0x11F2 is APP_REQUEST_UF2_RESET_HINT & is defined by TinyUF2 diff --git a/ports/espressif/esp-idf-config/sdkconfig-esp32c5.defaults b/ports/espressif/esp-idf-config/sdkconfig-esp32c5.defaults new file mode 100644 index 00000000000..eb6f64cbb78 --- /dev/null +++ b/ports/espressif/esp-idf-config/sdkconfig-esp32c5.defaults @@ -0,0 +1,54 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# Bluetooth +# +CONFIG_BT_ENABLED=y +CONFIG_BT_NIMBLE_ENABLED=y +# +# NimBLE Options +# +CONFIG_BT_NIMBLE_LOG_LEVEL_NONE=y +CONFIG_BT_NIMBLE_NVS_PERSIST=y +# +# Memory Settings +# +CONFIG_BT_NIMBLE_TRANSPORT_ACL_FROM_LL_COUNT=20 +CONFIG_BT_NIMBLE_TRANSPORT_EVT_SIZE=70 +# end of Memory Settings + +CONFIG_BT_NIMBLE_EXT_ADV=y +# end of NimBLE Options + +# end of Bluetooth + +# +# Driver Configurations +# +# +# PCNT Configuration +# +CONFIG_PCNT_CTRL_FUNC_IN_IRAM=y +# end of PCNT Configuration + +# end of Driver Configurations + +# +# Wi-Fi +# +CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=4 +# end of Wi-Fi + +# +# mbedTLS +# +# CONFIG_MBEDTLS_HARDWARE_SHA is not set +# end of mbedTLS + +# end of Component config + +# end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/mpconfigport.h b/ports/espressif/mpconfigport.h index 7f1a581571e..f0106f26b2c 100644 --- a/ports/espressif/mpconfigport.h +++ b/ports/espressif/mpconfigport.h @@ -29,6 +29,8 @@ #ifndef CIRCUITPY_BOOT_BUTTON #if defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32H2) || defined(CONFIG_IDF_TARGET_ESP32C61) #define CIRCUITPY_BOOT_BUTTON (&pin_GPIO9) + #elif defined(CONFIG_IDF_TARGET_ESP32C5) + #define CIRCUITPY_BOOT_BUTTON (&pin_GPIO28) #elif !defined(CONFIG_IDF_TARGET_ESP32) #define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0) #endif diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index 98fe3224a49..58c6835fc09 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -11,6 +11,9 @@ CROSS_COMPILE = riscv32-esp-elf- else ifeq ($(IDF_TARGET),esp32c3) IDF_TARGET_ARCH = riscv CROSS_COMPILE = riscv32-esp-elf- +else ifeq ($(IDF_TARGET),esp32c5) +IDF_TARGET_ARCH = riscv +CROSS_COMPILE = riscv32-esp-elf- else ifeq ($(IDF_TARGET),esp32p4) IDF_TARGET_ARCH = riscv CROSS_COMPILE = riscv32-esp-elf- @@ -188,6 +191,41 @@ CIRCUITPY_SDIOIO = 0 CIRCUITPY_USB_DEVICE = 0 CIRCUITPY_ESP_USB_SERIAL_JTAG ?= 1 +#### esp32c5 ########################################################## +else ifeq ($(IDF_TARGET),esp32c5) +# Modules +CIRCUITPY_ESPCAMERA = 0 +CIRCUITPY_ESPULP = 0 +CIRCUITPY_MEMORYMAP = 0 +CIRCUITPY_RGBMATRIX = 0 + +# TWAI-FD generation, needs a new canio backend +CIRCUITPY_CANIO = 0 + +# No capacitive touch peripheral +CIRCUITPY_ALARM_TOUCH = 0 +CIRCUITPY_TOUCHIO_USE_NATIVE = 0 + +# No DAC +CIRCUITPY_AUDIOIO = 0 + +# No I2S peripheral PDM-to-PCM hardware support +CIRCUITPY_AUDIOBUSIO_PDMIN = 0 + +# No space for this +CIRCUITPY_AUDIOBUSIO = 0 +CIRCUITPY_AUDIOI2SIN = 0 + +# No LCD_CAM peripheral, so no esp_lcd_new_i80_bus() +CIRCUITPY_PARALLELDISPLAYBUS = 0 + +# No SDMMC +CIRCUITPY_SDIOIO = 0 + +# Features +CIRCUITPY_USB_DEVICE = 0 +CIRCUITPY_ESP_USB_SERIAL_JTAG ?= 1 + #### esp32c6 ########################################################## else ifeq ($(IDF_TARGET),esp32c6) # Modules diff --git a/ports/espressif/peripherals/esp32c5/pins.c b/ports/espressif/peripherals/esp32c5/pins.c new file mode 100644 index 00000000000..2abf905e18f --- /dev/null +++ b/ports/espressif/peripherals/esp32c5/pins.c @@ -0,0 +1,37 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 microDev +// +// SPDX-License-Identifier: MIT + +#include "peripherals/pins.h" + +const mcu_pin_obj_t pin_GPIO0 = PIN(0, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO1 = PIN(1, ADC_UNIT_1, ADC_CHANNEL_0, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO2 = PIN(2, ADC_UNIT_1, ADC_CHANNEL_1, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO3 = PIN(3, ADC_UNIT_1, ADC_CHANNEL_2, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO4 = PIN(4, ADC_UNIT_1, ADC_CHANNEL_3, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO5 = PIN(5, ADC_UNIT_1, ADC_CHANNEL_4, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO6 = PIN(6, ADC_UNIT_1, ADC_CHANNEL_5, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO7 = PIN(7, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO8 = PIN(8, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO9 = PIN(9, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO10 = PIN(10, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO11 = PIN(11, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO12 = PIN(12, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO13 = PIN(13, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO14 = PIN(14, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO15 = PIN(15, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO16 = PIN(16, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO17 = PIN(17, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO18 = PIN(18, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO19 = PIN(19, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO20 = PIN(20, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO21 = PIN(21, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO22 = PIN(22, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO23 = PIN(23, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO24 = PIN(24, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO25 = PIN(25, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO26 = PIN(26, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO27 = PIN(27, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO28 = PIN(28, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); diff --git a/ports/espressif/peripherals/esp32c5/pins.h b/ports/espressif/peripherals/esp32c5/pins.h new file mode 100644 index 00000000000..90c28621791 --- /dev/null +++ b/ports/espressif/peripherals/esp32c5/pins.h @@ -0,0 +1,70 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2023 Scott Shawcroft for Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +// DO NOT include this file directly. +// Use shared-bindings/microcontroller/Pin.h instead. +// This ensures that all necessary includes are already included. + +#pragma once + +#define GPIO0_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO0; +#define GPIO1_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO1; +#define GPIO2_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO2; +#define GPIO3_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO3; +#define GPIO4_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO4; +#define GPIO5_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO5; +#define GPIO6_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO6; +#define GPIO7_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO7; +#define GPIO8_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO8; +#define GPIO9_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO9; +#define GPIO10_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO10; +#define GPIO11_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO11; +#define GPIO12_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO12; +#define GPIO13_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO13; +#define GPIO14_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO14; +#define GPIO15_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO15; +#define GPIO16_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO16; +#define GPIO17_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO17; +#define GPIO18_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO18; +#define GPIO19_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO19; +#define GPIO20_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO20; +#define GPIO21_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO21; +#define GPIO22_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO22; +#define GPIO23_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO23; +#define GPIO24_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO24; +#define GPIO25_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO25; +#define GPIO26_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO26; +#define GPIO27_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO27; +#define GPIO28_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO28; diff --git a/ports/espressif/peripherals/pins.h b/ports/espressif/peripherals/pins.h index 431a136545a..ada17075e50 100644 --- a/ports/espressif/peripherals/pins.h +++ b/ports/espressif/peripherals/pins.h @@ -49,6 +49,8 @@ extern const mp_obj_type_t mcu_pin_type; #include "esp32c2/pins.h" #elif defined(CONFIG_IDF_TARGET_ESP32C3) #include "esp32c3/pins.h" +#elif defined(CONFIG_IDF_TARGET_ESP32C5) +#include "esp32c5/pins.h" #elif defined(CONFIG_IDF_TARGET_ESP32C6) #include "esp32c6/pins.h" #elif defined(CONFIG_IDF_TARGET_ESP32C61) diff --git a/ports/espressif/tools/build_memory_info.py b/ports/espressif/tools/build_memory_info.py index 0cf609c4d63..27ad13b29e6 100644 --- a/ports/espressif/tools/build_memory_info.py +++ b/ports/espressif/tools/build_memory_info.py @@ -56,6 +56,11 @@ ("Internal SRAM 0", (0x4037_C000,), 16 * 1024), ("Internal SRAM 1", (0x3FC8_0000, 0x4038_0000), 384 * 1024), ], + "esp32c5": [ + # Name, Start, Length + ("LP SRAM", (0x5000_0000,), 16 * 1024), + ("HP SRAM", (0x4080_0000,), 384 * 1024), + ], "esp32c6": [ # Name, Start, Length ("LP SRAM", (0x5000_0000,), 16 * 1024), From 372420c2b75449252d03d2d826f66a15a8609c42 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Tue, 1 Sep 2026 19:53:20 -0700 Subject: [PATCH 2/4] espressif: add ESP32-C5-DevKitC-1-N8R8 board 8MB flash, 8MB quad PSRAM, WS2812B on GPIO27, UART0 on GPIO11/12. Flash mode is dio: qio locks the CPU during bootloader startup on this board. PSRAM stays qio, which is the only mode C5 offers. --- .../espressif_esp32c5_devkitc_1_n8r8/board.c | 9 +++++ .../mpconfigboard.h | 17 ++++++++ .../mpconfigboard.mk | 12 ++++++ .../espressif_esp32c5_devkitc_1_n8r8/pins.c | 40 +++++++++++++++++++ .../sdkconfig | 14 +++++++ 5 files changed, 92 insertions(+) create mode 100644 ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/board.c create mode 100644 ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/mpconfigboard.h create mode 100644 ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/mpconfigboard.mk create mode 100644 ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/pins.c create mode 100644 ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/sdkconfig diff --git a/ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/board.c b/ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/board.c new file mode 100644 index 00000000000..a3a9eec0471 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 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/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/mpconfigboard.h b/ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/mpconfigboard.h new file mode 100644 index 00000000000..ca05bf78b6a --- /dev/null +++ b/ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/mpconfigboard.h @@ -0,0 +1,17 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "ESP32-C5-DevKitC-1-N8R8" +#define MICROPY_HW_MCU_NAME "ESP32C5" + +#define MICROPY_HW_NEOPIXEL (&pin_GPIO27) + +#define DEFAULT_UART_BUS_RX (&pin_GPIO12) +#define DEFAULT_UART_BUS_TX (&pin_GPIO11) diff --git a/ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/mpconfigboard.mk b/ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/mpconfigboard.mk new file mode 100644 index 00000000000..0da008596e3 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/mpconfigboard.mk @@ -0,0 +1,12 @@ +CIRCUITPY_CREATOR_ID = 0x000C303A +CIRCUITPY_CREATION_ID = 0x00C50001 + +IDF_TARGET = esp32c5 + +CIRCUITPY_ESP_FLASH_MODE = dio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 8MB + +CIRCUITPY_ESP_PSRAM_SIZE = 8MB +CIRCUITPY_ESP_PSRAM_MODE = qio +CIRCUITPY_ESP_PSRAM_FREQ = 40m diff --git a/ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/pins.c b/ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/pins.c new file mode 100644 index 00000000000..dc4a478a592 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/pins.c @@ -0,0 +1,40 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 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_IO0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_IO10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_IO13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_IO14), MP_ROM_PTR(&pin_GPIO14) }, + + { MP_ROM_QSTR(MP_QSTR_IO23), MP_ROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_IO24), MP_ROM_PTR(&pin_GPIO24) }, + { MP_ROM_QSTR(MP_QSTR_IO25), MP_ROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_IO26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_IO27), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_IO28), MP_ROM_PTR(&pin_GPIO28) }, + + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO27) }, + + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO12) }, + + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/sdkconfig b/ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/sdkconfig new file mode 100644 index 00000000000..e9628662160 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32c5_devkitc_1_n8r8/sdkconfig @@ -0,0 +1,14 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +# end of LWIP + +# end of Component config + +# end of Espressif IoT Development Framework Configuration From e66da0424e6ea0e9a99f6a5e2bc854f801768e56 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Fri, 4 Sep 2026 09:50:01 -0700 Subject: [PATCH 3/4] espressif: name the real limit on esp32c5 audio modules The comment was copied from the c6 block. The 8MB flash has a 2048K app partition, and enabling both leaves 42 KB free. --- ports/espressif/mpconfigport.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index 58c6835fc09..ca9d3c5fb09 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -212,7 +212,7 @@ CIRCUITPY_AUDIOIO = 0 # No I2S peripheral PDM-to-PCM hardware support CIRCUITPY_AUDIOBUSIO_PDMIN = 0 -# No space for this +# 2048K app partition, only 42 KB free with these on CIRCUITPY_AUDIOBUSIO = 0 CIRCUITPY_AUDIOI2SIN = 0 From ccf27daafc3d24c37877dce60b4a2e583cf021cc Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Fri, 4 Sep 2026 11:10:28 -0700 Subject: [PATCH 4/4] espressif: enable audiobusio and audioi2sin on esp32c5 The C5 has an I2S peripheral and the DevKitC breaks out 19 GPIOs, so external I2S hardware works the same as on the S3 DevKitC, which ships with these on and has no onboard audio either. Costs 78160 bytes, leaving 42928 free in the 2048K app partition. --- ports/espressif/mpconfigport.mk | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index ca9d3c5fb09..ee28bba9918 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -212,10 +212,6 @@ CIRCUITPY_AUDIOIO = 0 # No I2S peripheral PDM-to-PCM hardware support CIRCUITPY_AUDIOBUSIO_PDMIN = 0 -# 2048K app partition, only 42 KB free with these on -CIRCUITPY_AUDIOBUSIO = 0 -CIRCUITPY_AUDIOI2SIN = 0 - # No LCD_CAM peripheral, so no esp_lcd_new_i80_bus() CIRCUITPY_PARALLELDISPLAYBUS = 0