Adding a New SoC
This guide describes every file that must be created or modified to add support for a new Espressif
SoC to the Arduino ESP32 core and the esp32-arduino-lib-builder.
Conventions
{soc}– lowercase IDF target name (e.g.esp32c5,esp32p4).{SOC}– uppercase variant used in C preprocessor macros (e.g.ESP32C5,ESP32P4).All ESP-IDF paths are relative to the lib-builder’s bundled ESP-IDF (
esp32-arduino-lib-builder/esp-idf/). Always verify against that copy, not a local installation on a different branch.The most recent completed SoC additions (ESP32-C61 for component-only, ESP32-C5 for full support) serve as practical reference diffs.
Support Levels
There are two levels of SoC support. Full support is a strict superset of component support – you cannot add core support without first completing component support.
Component Support
This is the minimum level of component support. The SoC can be used when Arduino is included as an ESP-IDF component
(idf.py build with Arduino in the component list). It involves:
Handling all
#errorguards in core source files so the code compiles for the new target.Adding the target to
idf_component.yml.Basic lib-builder configuration with
"skip": 1inbuilds.json(libraries build in CI for validation but are not deployed).The SoC goes into
ALL_SOCS,SKIP_LIB_BUILD_SOCS, and the appropriateIDF_V*_TARGETSarrays insocs_config.sh.
Full Support (Component + Core)
This level includes everything from component support, plus:
Prebuilt static libraries ship with the Arduino core package.
The board appears in Arduino IDE / CLI and can compile and upload sketches directly.
The SoC is removed from
SKIP_LIB_BUILD_SOCSand added toCORE_VARIANTS.Added to CI test targets, package index, PlatformIO build script, etc.
Throughout this guide, each step is marked [component] (required for both levels) or [core] (only required for full support).
Prerequisites
Before starting, ensure you have access to:
The lib-builder’s bundled ESP-IDF with the new SoC already supported by IDF (the target must exist in
components/soc/{soc}/).The DevKit schematic for the new SoC (from the Espressif DevKits page).
Confirmation that
esptoolsupports the new chip (check esptool releases for the ROM class atesptool/targets/{soc}.py).The
openocd-esp32package includes a debug config (board/{soc}-builtin.cfg) if debugging support is needed at launch.
Step 1: Gather SoC Information from ESP-IDF [component]
Collect hardware parameters from the lib-builder’s bundled ESP-IDF. The table below lists what
you need and where to find it. All paths use the convention components/soc/{soc}/... unless
stated otherwise.
Information |
ESP-IDF Path |
Key Symbols / Notes |
|---|---|---|
Peripheral capabilities |
|
|
CPU / XTAL frequencies |
|
|
UART default pins |
|
|
Boot strapping GPIO |
|
Not all SoCs have |
Bootloader flash offset |
|
|
Flash frequency options |
|
|
Flash frequency encoding |
|
Maps Kconfig choices to esptool strings. Also check
|
eFuse registers (MAC address) |
|
Register naming varies by SoC (e.g. |
eFuse registers (package version) |
|
|
GPIO device structure |
|
Check if pin access is |
SPI peripheral base address |
|
|
USB Serial/JTAG registers |
|
Only if |
USB D+/D- pins |
|
Only for SoCs with routable USB PHY ( |
ADC channel to GPIO mapping |
|
|
Touch pad to GPIO mapping |
|
Only if |
SPI default IOMUX pins |
|
|
Chip model / ID |
|
|
OpenOCD debug config |
External: |
Config files under |
DevKit schematics |
Pin assignments, LED GPIOs, USB connector wiring, BOOT/RESET button GPIOs. |
Note
For SoCs with hardware versioning (e.g. ESP32-P4 with hw_ver1/hw_ver3), register
headers may be under components/soc/{soc}/register/hw_ver*/soc/ instead of the usual
components/soc/{soc}/register/soc/.
Step 2: Lib-Builder Changes
The esp32-arduino-lib-builder builds the precompiled static libraries that ship with the
Arduino core. These changes should be done first because the Arduino core depends on the
libraries the builder produces.
2.1 Build Target Definition [component]
File: configs/builds.json
Add a new object to the targets array. For component-only support, include "skip": 1
so the target is excluded from production deploys but still built in CI for validation.
Each value in features, idf_libs, bootloaders, and mem_variants corresponds
to a defconfig fragment filename under configs/ (e.g. "80m" means
configs/defconfig.80m).
{
"target": "{soc}",
"skip": 1,
"features": [],
"idf_libs": ["qio", "80m"],
"bootloaders": [
["qio", "80m"],
["dio", "80m"],
["qio", "40m"],
["dio", "40m"]
],
"mem_variants": [
["dio", "80m"]
]
}
Field |
Description |
|---|---|
|
The IDF target name (passed to |
|
Optional. Output directory name when it differs from |
|
Set to |
|
Defconfig fragments applied to all builds. Maps to |
|
Defconfig fragments for the main static library build (typically flash mode + freq). |
|
List of |
|
List of |
Also add the new SoC to the mem_variants_files section at the top of the file – at minimum
to the libspi_flash.a entry’s targets array.
To promote to full support [core]: Remove "skip": 1 from the target entry.
2.2 SoC Defconfig [component]
File: configs/defconfig.{soc}
Create a per-SoC Kconfig fragment. The build system chains configs as:
defconfig.common + defconfig.{soc} + feature/mode/freq fragments.
Use the closest existing SoC as a template. Common options to set:
Bluetooth stack (
CONFIG_BT_NIMBLE_ENABLED,CONFIG_BT_BLUEDROID_ENABLED)PSRAM (
CONFIG_SPIRAM=y) if supportedOpenThread / IEEE 802.15.4 settings if
SOC_IEEE802154_SUPPORTEDWi-Fi settings if
SOC_WIFI_SUPPORTEDZigbee: set
CONFIG_ZB_ENABLED=nif prebuilt Zigbee libraries are not available yetTinyUSB / USB settings if
SOC_USB_OTG_SUPPORTEDCPU frequency default
2.3 Flash Frequency Fragments [component]
Files: configs/defconfig.{freq} and main/Kconfig.projbuild
If the SoC introduces flash frequencies not already covered by existing fragments, create
new files (e.g. configs/defconfig.48m):
CONFIG_ESPTOOLPY_FLASHFREQ_{FREQ}M=y
And add the mapping in main/Kconfig.projbuild under LIB_BUILDER_FLASHFREQ:
default "{freq}m" if ESPTOOLPY_FLASHFREQ_{FREQ}M
The frequency values in builds.json must match an available ESPTOOLPY_FLASHFREQ_*
Kconfig choice in the lib-builder’s bundled IDF. If they don’t match, the option is silently
ignored and the build produces files with unexpected names.
2.4 TinyUSB Component [component, if applicable]
Files: components/arduino_tinyusb/CMakeLists.txt,
components/arduino_tinyusb/Kconfig.projbuild
Only if SOC_USB_OTG_SUPPORTED:
Add an
IDF_TARGETbranch with the correctOPT_MCU_ESP32*define.Add
depends on IDF_TARGET_{SOC}to the Kconfig.
2.5 Arduino Component CMakeLists [component]
During the lib-builder build, the Arduino core is cloned/linked into
components/arduino/ (this directory is gitignored). The CMakeLists.txt used is the
same file as the Arduino core’s root CMakeLists.txt (see Step 3.8). No separate
file exists in the lib-builder repo – just ensure the core’s CMakeLists.txt has correct
IDF_TARGET conditionals before building.
2.6 Managed Component Dependencies [component]
File: main/idf_component.yml
Update dependency rules: to include or exclude the new SoC for components like
esp32-camera, esp-tflite-micro, esp-sr, esp_matter, etc., based on the
SoC’s capabilities.
2.7 Copy-Libs Script [component, if applicable]
File: tools/copy-libs.sh
If the new SoC depends on headers from another SoC’s Bluetooth or other component at build time (e.g. ESP32-C61 shares BT headers with ESP32-C6), add the appropriate cross-SoC copy logic.
2.8 Toolchain Configuration [component]
File: tools/get_projbuild_gitconfig.py
This file has a hardcoded if-chain for architecture detection. If the new SoC uses RISC-V,
add it to the condition that sets arch_target = "riscv32-esp". If Xtensa, add it to the
Xtensa branch.
2.9 CI Build Workflow [component]
File: .github/workflows/push.yml
Add the new SoC (using chip_variant if applicable) to the matrix.target array.
This ensures the target is built in CI for every push, even with "skip": 1.
2.10 CI Deploy Workflow [core]
File: .github/workflows/cron.yml
Add the SoC to the targets: string in the active matrix entry. This enables automatic
deployment of prebuilt libraries.
2.11 PlatformIO Template [core, if applicable]
File: configs/pioarduino_start.txt
If the SoC supports Zigbee (SOC_IEEE802154_SUPPORTED), add it to the appropriate
build_mcu in [...] list for native 802.15.4 Zigbee library selection.
Step 3: Arduino Core Changes
3.1 SoC Configuration Script [component]
File: .github/scripts/socs_config.sh
This is the central SoC registry. Add the new SoC to:
ALL_SOCS: always.SKIP_LIB_BUILD_SOCS: for component-only support.IDF_V*_TARGETS: add to every IDF version array that supports this chip.
If the SoC uses Xtensa, add it to the explicit case in get_arch(). RISC-V SoCs are
handled by the default case.
To promote to full support [core]:
Remove from
SKIP_LIB_BUILD_SOCS.Add to
CORE_VARIANTS.Add to
HW_TEST_TARGETSwhen hardware CI runners are available.Add to
WOKWI_TEST_TARGETSwhen Wokwi simulation support exists.Add to
QEMU_TEST_TARGETSwhen QEMU support exists.
3.2 Board Definition [component]
File: boards.txt
Add a Dev Module entry block. Use an existing similar SoC as a template (e.g. a RISC-V chip
with similar peripherals). The board entry is required even for component-only support because
the IDF component build uses ARDUINO_VARIANT to locate pin definitions.
Key properties to set (source of truth noted for each):
Property |
Source |
|---|---|
|
|
|
The IDF target name |
|
Directory name under |
|
Max CPU frequency in Hz (from |
|
From |
|
Default flash frequency string (from |
|
Frequency written to image header. This may differ from |
|
|
|
Flash size minus overhead (from default partition table) |
|
SRAM size (from datasheet or |
Menu entries to add as applicable (based on soc_caps.h):
CPUFreq,FlashFreq,FlashMode,FlashSize,PartitionSchemeUploadSpeed,DebugLevel,EraseFlash,JTAGAdapterUSBMode(ifSOC_USB_OTG_SUPPORTED)CDCOnBoot(ifSOC_USB_SERIAL_JTAG_SUPPORTEDorSOC_USB_OTG_SUPPORTED)ZigbeeMode(ifSOC_IEEE802154_SUPPORTED)PSRAM(ifSOC_SPIRAM_SUPPORTED)
For component-only support, the board entry still exists but is not usable from the Arduino IDE without prebuilt libraries.
3.3 Variant [component]
Directory: variants/{soc}/
Create variants/{soc}/pins_arduino.h with default pin definitions:
TX/RX: Default UART0 pins (fromuart_pins.h)SDA/SCL: Default I2C pins (from DevKit schematic)SS/MOSI/MISO/SCK: Default SPI pins (fromspi_pins.h)LED_BUILTIN: Onboard LED GPIO (from DevKit schematic)Analog pin macros (
A0,A1, …): ADC GPIO mappings (fromadc_channel.h)
3.4 Platform Configuration [component]
File: platform.txt
Add:
Build extra flags (in the target-dependent section):
build.extra_flags.{soc}=...The flags depend on USB capabilities:
No USB at all:
-DARDUINO_USB_CDC_ON_BOOT=0USB Serial/JTAG only:
-DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT={build.cdc_on_boot}USB-OTG + Serial/JTAG:
-DARDUINO_USB_MODE={build.usb_mode} -DARDUINO_USB_CDC_ON_BOOT={build.cdc_on_boot} -DARDUINO_USB_MSC_ON_BOOT={build.msc_on_boot} -DARDUINO_USB_DFU_ON_BOOT={build.dfu_on_boot}
Debug configuration (in the debugger section):
debug_script.{soc}={soc}-builtin.cfg debug_config.{soc}=Newer SoCs use this minimal form. Older SoCs (ESP32, S2, S3, C3) have full
cortex-debug.custom.*blocks – use those as a reference only if the OpenOCD config requires special attach/restart commands.
3.5 Core Source Files with #error Guards [component]
These files contain #error directives and will not compile without adding a branch
for the new SoC:
File |
What to add |
|---|---|
|
|
|
ROM RTC header include and clock source names array |
|
ROM RTC header include |
|
GPIO signal count include |
|
SPI bus array with base address ( |
|
PSRAM type include. Only if |
|
|
3.6 Core Source Files That Need Review [component]
These files may compile without changes but can produce incorrect behavior if the new SoC has different peripheral layouts:
File |
What to check |
|---|---|
|
UART port count and default pins (from |
|
|
|
UART clock sources and hardware limits |
|
I2C slave driver port count and config |
|
LEDC timer/channel count, clock sources |
|
CPU frequency table and validation |
|
Package version eFuse register (from |
|
eFuse MAC register names. Only if |
|
USB Serial/JTAG PHY configuration. Only if |
|
ADC channel count and configuration |
|
Only if |
|
Only if |
3.7 Library Source Files [component]
``libraries/SPI/src/SPI.cpp``: Almost always needs updating for SPI pin/bus configuration differences.
Library ``ci.yml`` files: Update target lists or requirement conditions in example directories to include or exclude the new SoC based on capabilities.
3.8 CMakeLists.txt (IDF Component) [component]
File: CMakeLists.txt (repository root)
Review and update IDF_TARGET conditionals:
OpenThread: Add to the
requires openthreadcondition ifSOC_IEEE802154_SUPPORTED.Touch sensor: Add to the
requires esp_driver_touch_senscondition ifSOC_TOUCH_SENSOR_SUPPORTED.TinyUSB: Add to the
IDF_TARGET MATCHEScondition forarduino_tinyusbifSOC_USB_OTG_SUPPORTED.
3.9 IDF Component Metadata [component]
File: idf_component.yml
Add the new SoC to the
targets:list.Add
variants/{soc}/**/*to thefiles.includesection.Update dependency
rules:conditions (e.g.esp_matter,esp32-camera,esp-sr) to include or exclude the new SoC based on capabilities.
3.10 PlatformIO Build Script [core]
File: tools/pioarduino-build.py
Add the new SoC to the correct bootloader offset group. The offset comes from
CONFIG_BOOTLOADER_OFFSET_IN_FLASH in ESP-IDF’s components/bootloader/Kconfig.projbuild.
Note
There is also a per-SoC pioarduino-build.py inside
tools/esp32-arduino-libs/{soc}/. That file is auto-generated by the lib-builder’s
tools/copy-libs.sh from configs/pioarduino_start.txt + build output +
configs/pioarduino_end.txt. No manual action is needed for that file.
3.11 Debug SVD File [core]
File: tools/ide-debug/svd/{soc}.svd
Add the SVD (System View Description) file if available from Espressif. This enables register-level debugging in IDEs. Not all SoCs have SVD files available at launch.
3.12 Package Index [core]
File: package/package_esp32_index.template.json
Add a board entry (e.g. "name": "ESP32-XX Dev Board"). Also verify that the pinned
esptool_py and openocd-esp32 versions support the new SoC:
esptool: Must include the chip’s ROM class (
esptool/targets/{soc}.py). If the pinned version is too old, update the version and all per-platform URLs/checksums.OpenOCD: Must include
board/{soc}-builtin.cfg.Toolchains: Auto-updated by
gen_tools_json.pyin the lib-builder from IDF’stools/tools.json– typically no manual changes needed.
3.13 CI Defaults [core]
File: .github/scripts/sketch_utils.sh
Add default FQBN options for the new SoC in the default_fqbn_for_target() function.
Define a {soc}_opts variable with appropriate defaults (e.g. PSRAM enabled, USB mode).
3.14 Example Gating [component]
Examples that don’t work on the new SoC (e.g. Wi-Fi examples on a chip without Wi-Fi) need to be
excluded. The modern approach uses ci.yml files in example directories
with explicit targets or requires fields.
Check existing examples and add exclusions where the SoC lacks required capabilities.
3.15 Test Pin Configuration [core]
File: tests/validation/adc_pwm/pins_config.h (and similar test files)
Add a #elif CONFIG_IDF_TARGET_{SOC} block with appropriate test GPIO assignments.
Files with #error "add pins for this target" guards will indicate where this is needed.
3.16 CI Workflows [component/core]
[component]:
.github/workflows/build_component.yml: Ensure the IDF version matrix covers the new target (driven bysocs_config.sh’sIDF_V*_TARGETS).
[core]:
Test workflows (
tests.yml,tests_hw_wokwi.yml): Driven bysocs_config.shtest target arrays.Release workflow (
.github/workflows/release.yml): May reference target lists for packaging.
3.17 Documentation [component]
Several documentation files reference SoC-specific information and should be updated:
``docs/en/boards/boards.rst``: Add the new SoC to the family list with its key features (connectivity, architecture). For component-only SoCs, add a footnote indicating that rebuilding static libraries or using Arduino as an IDF component is required.
``docs/en/libraries.rst``: Update the peripheral support matrix table. Add a column for the new SoC with
|yes|,|no|, or|n/a|for each feature based onsoc_caps.h.``docs/en/contributing.rst``: Update the default FQBN list if the SoC has full support (this list mirrors what
sketch_utils.shdefines).``.github/CI_README.md``:
The “Adding a New SoC” section documents the CI-specific steps (updating
socs_config.sh). Verify it is still accurate after your changes.The “DevKit GPIO Reference” section: Add a GPIO reference table for the new SoC’s DevKit board, documenting broken-out pins, strapping pins, peripheral assignments, and safe pin categories.
Board-specific RST (optional): If a dedicated documentation page is needed for the DevKit, add a file under
docs/en/boards/and include it in theboards.rsttoctree.
3.18 Validation Tests [core]
The tests/validation/ directory contains hardware validation tests. For full support,
ensure the new SoC can run the relevant validation tests:
Tests with
pins_config.hfiles that have#errorguards must have pin assignments added (see Step 3.15).Tests with
ci.ymlfiles that specifytargets:lists should include the new SoC where applicable.At minimum, verify that these validation test categories pass on hardware:
gpio,uart,spi,i2c_master,adc_pwm,timer,periman.For SoCs with specific capabilities, also run:
ble,wifi,touch,psram,openthread,zigbee,ethernet, as applicable.
Step 4: Verification
Component Support Checklist
[ ] configs/builds.json has the target entry (with "skip": 1)
[ ] configs/defconfig.{soc} exists with appropriate options
[ ] ./build.sh -t {soc} completes successfully in the lib-builder
[ ] All #error guards in cores/esp32/ are resolved
[ ] idf_component.yml includes the SoC in targets list
[ ] CMakeLists.txt conditionals are updated
[ ] boards.txt has a Dev Module entry
[ ] variants/{soc}/pins_arduino.h exists
[ ] platform.txt has build.extra_flags.{soc} and debug_script.{soc}
[ ] socs_config.sh has the SoC in ALL_SOCS, SKIP_LIB_BUILD_SOCS, and IDF_V*_TARGETS
[ ] Lib-builder push.yml includes the target in CI matrix
[ ] Arduino build_component.yml covers the SoC
[ ] docs/en/boards/boards.rst updated with new SoC family entry
[ ] docs/en/libraries.rst support matrix updated
[ ] A basic sketch (Blink) compiles when using Arduino as IDF component
[ ] CI passes on both repositories
Full Support Checklist (in addition to above)
[ ] builds.json: "skip" removed
[ ] cron.yml: target added to deploy matrix
[ ] socs_config.sh: SoC in CORE_VARIANTS, removed from SKIP_LIB_BUILD_SOCS
[ ] sketch_utils.sh: default FQBN options defined
[ ] pioarduino-build.py: bootloader offset group updated
[ ] package_esp32_index.template.json: board entry added, tool versions verified
[ ] Bootloader ELF files generated with correct names
[ ] Libraries built in <lib-builder>/out/tools/esp32-arduino-libs/{soc}/ and copied to <arduino-repo>/tools/esp32-arduino-libs/{soc}/
[ ] .github/CI_README.md: DevKit GPIO reference table added
[ ] Sketch compiles and uploads via Arduino IDE/CLI
[ ] USB Serial/JTAG (if applicable) works for upload and monitor
[ ] Validation tests pass: gpio, uart, spi, i2c_master, adc_pwm, timer, periman
[ ] Capability-specific tests pass (ble, wifi, touch, psram, etc. as applicable)
[ ] CI passes on both repositories
Appendix A: Flash Frequency Reference
Flash frequency configuration is error-prone due to indirection between Kconfig names, esptool encoding values, and actual flash speeds.
For SoCs with a 40 MHz XTAL, the Kconfig option names match the actual flash speeds
and flash_freq / img_freq / boot_freq are all the same (e.g. 80m everywhere).
For SoCs with a 32 MHz XTAL (or other non-40 MHz crystals), there is additional indirection:
Kconfig option name (e.g.
ESPTOOLPY_FLASHFREQ_64M): The label defined inspi_flash/{soc}/Kconfig.flash_freq.esptool string (e.g.
48m): The value ofCONFIG_ESPTOOLPY_FLASHFREQafter Kconfig resolution (defined inesptool_py/Kconfig.projbuild). Passed to esptool’s--flash-freqargument.esptool encoding (e.g.
0xF): The byte value written to the flash image header. Defined inesptool/targets/{soc}.pyin theFLASH_FREQUENCYdictionary.Bootloader filename:
bootloader_{boot}_{boot_freq}.elfwhereboot_freqdefaults toflash_freq(fromplatform.txt).Lib-builder filename: Determined by
LIB_BUILDER_FLASHFREQinmain/Kconfig.projbuild, which maps the Kconfig choice to the output directory string.
The critical rule: the frequency names in builds.json must match an available
ESPTOOLPY_FLASHFREQ_* Kconfig choice in the lib-builder’s bundled IDF. If they don’t,
the defconfig option is silently ignored, the build falls through to the Kconfig default,
and bootloader files end up with unexpected names.
Appendix B: File Reference Summary
Arduino Core File |
Level |
Purpose |
|---|---|---|
|
component |
Central SoC registry |
|
core |
Default FQBN options per target |
|
component |
Board definitions and menu options |
|
component |
Build flags, debug config |
|
component |
Default pin assignments |
|
component |
IDF component dependencies |
|
component |
IDF component metadata and target list |
|
component |
|
|
component |
Clock source names, ROM header |
|
component |
ROM header include |
|
component |
GPIO signal count |
|
component |
SPI bus base addresses |
|
component |
PSRAM type detection |
|
component |
Flash image base, chip model strings |
|
component |
UART port/pin definitions |
|
component |
GPIO HAL pin structure access |
|
component |
I2C slave driver config |
|
component |
Package version eFuse |
|
component |
TinyUSB MAC address (if USB-OTG) |
|
component |
USB Serial/JTAG PHY (if applicable) |
|
component |
SPI pin/bus configuration |
|
core |
PlatformIO bootloader offset |
|
core |
Debug SVD file |
|
core |
Board Manager package index |
|
core |
Test pin assignments |
|
component |
SoC family list and descriptions |
|
component |
Peripheral support matrix per SoC |
|
core |
Default FQBN list for CI |
|
core |
DevKit GPIO reference tables, CI SoC guide |
Lib-Builder File |
Level |
Purpose |
|---|---|---|
|
component |
Build target matrix |
|
component |
SoC-specific Kconfig fragment |
|
– |
Shared base config (rarely needs changes) |
|
component |
Flash frequency Kconfig fragment |
|
component |
Flash mode/frequency string mappings |
|
component |
Managed component dependencies |
|
component |
TinyUSB component (if USB-OTG) |
|
component |
Library copy logic (cross-SoC headers) |
|
component |
Toolchain arch detection |
|
core |
PlatformIO Zigbee library template |
|
component |
CI build matrix |
|
core |
Deploy targets |