fix(espidf): compile ESP32-S3 for the esp32s3 target (not esp32)

_idf_target had no S3 case, so every S3 FQBN (esp32s3 / XIAO_ESP32S3 /
nano_nora) compiled as plain esp32 (LX6) and could not boot the S3 QEMU
machine. Add _is_esp32s3 (covers all three FQBNs; nano_nora has no 's3'
token) + return 'esp32s3'; add the xtensa-esp32s3-elf toolchain to the
build PATH; place the S3 second-stage bootloader at flash offset 0x0
(like C3) instead of 0x1000 via 'is_c3 or idf_target==esp32s3' at the merge.

Requires the xtensa-esp32s3-elf toolchain in the image
(install.sh esp32,esp32c3,esp32s3) and a libqemu-xtensa with an
esp32s3(-picsimlab) machine.
This commit is contained in:
David Montero Crespo 2026-07-11 01:51:02 +02:00
parent 8958fe7c88
commit 4a158fc40b
1 changed files with 18 additions and 3 deletions

View File

@ -316,11 +316,23 @@ class ESPIDFCompiler:
"""Return True if FQBN targets ESP32-C3 (RISC-V)."""
return 'esp32c3' in board_fqbn or 'esp32-c3' in board_fqbn
def _is_esp32s3(self, board_fqbn: str) -> bool:
"""Return True if FQBN targets an ESP32-S3 (Xtensa LX7).
Covers all three S3 board FQBNs the frontend emits: esp32s3,
XIAO_ESP32S3 (uppercase) and nano_nora (Arduino Nano ESP32 -- carries
no 's3' token), so a bare substring test is insufficient.
"""
fq = board_fqbn.lower()
return 'esp32s3' in fq or 'nano_nora' in fq
def _idf_target(self, board_fqbn: str) -> str:
"""Map FQBN to IDF_TARGET."""
if self._is_esp32c3(board_fqbn):
return 'esp32c3'
# Default to esp32 (Xtensa) for all other ESP32 variants
if self._is_esp32s3(board_fqbn):
return 'esp32s3'
# Default to esp32 (Xtensa LX6) for the original ESP32 / ESP32-S2
return 'esp32'
def _detect_wifi_usage(self, code: str) -> bool:
@ -1242,9 +1254,12 @@ class ESPIDFCompiler:
env['IDF_TOOLS_PATH'] = tools_path
if os.path.isdir(tools_path):
extra_paths: list[str] = []
# Xtensa toolchain (ESP32, ESP32-S3)
# Xtensa toolchain: ESP32/S2 -> xtensa-esp32-elf,
# ESP32-S3 -> xtensa-esp32s3-elf (IDF 4.4), unified on 5.x.
for tc_dir in Path(tools_path).glob('tools/xtensa-esp32-elf/*/xtensa-esp32-elf/bin'):
extra_paths.append(str(tc_dir))
for tc_dir in Path(tools_path).glob('tools/xtensa-esp32s3-elf/*/xtensa-esp32s3-elf/bin'):
extra_paths.append(str(tc_dir))
for tc_dir in Path(tools_path).glob('tools/xtensa-esp-elf/*/xtensa-esp-elf/bin'):
extra_paths.append(str(tc_dir))
# RISC-V toolchain (ESP32-C3)
@ -2252,7 +2267,7 @@ class ESPIDFCompiler:
# Step 4: Merge binaries into flash image
try:
merged_path = self._merge_flash_image(
build_dir, is_c3,
build_dir, is_c3 or idf_target == 'esp32s3', # S3 bootloader at 0x0 like C3
flash_size_bytes=flash_size_bytes,
spiffs_bin=spiffs_bin,
spiffs_offset=spiffs_offset,