← micropython-hardware docs

Firmware Detect — hardware fixture campaign

Raw data captured while designing the Firmware Detect feature.

These are verbatim field notes; some boards were re-probed multiple times (same model, distinct unique_id/MAC) to harden family/variant matching.


Fixture 1 — ESP32-P4 (COM4)

esptool (authoritative — works without MicroPython):

MicroPython (optional enrichment — this board happened to have it):

Autoset: board ESP32_GENERIC_P4; variant from MP _build = C6_WIFI (without MP, leave variant unset and offer C5/C6); flash 32 MB.

Fixture 2 — ESP32-S3 (COM5 → COM6 in bootloader)

esptool (after machine.bootloader(); native USB remapped COM5→COM6):

MicroPython: Generic ESP32S3 module with ESP32S3, MP 1.24.0, freq 160 MHz, esp.flash_size() 8 MB, gc.mem_free() ~214 KB → no SPIRAM. Partitions: factory ~2 MB, df ~6 MB.

Autoset: ESP32_GENERIC_S3, default variant, 8 MB. UX note: native USB-Serial/JTAG chips can change COM port on bootloader entry — re-enumerate by MAC/serial before reconnecting.

Fixture 3 — ESP32-S3 Octal-SPIRAM (COM8)

MicroPython (primary; esptool failed while MP held the port):

Autoset: ESP32_GENERIC_S3, variant SPIRAM_OCT (machine string says Octal-SPIRAM), 8 MB.

Fixture 4 — ESP32-S3 with SPIRAM, machine string silent (COM10)

Autoset: ESP32_GENERIC_S3, variant SPIRAM (not OCT — string omits "Octal"; heap proves external RAM), 8 MB. esptool failed after disconnect and bootloader (native-USB hazard).

Fixture 5 — Adafruit Metro M7 (MIMXRT1011) — non-ESP (COM12)

Not Espressif. esptool correctly fails ("No serial data").

Autoset: port mimxrt; no ESP partition/flash/security UI.

Fixture 6 — ESP32-S3 Arduino firmware, no MicroPython (COM13)

Bare / non-MP path — Detect succeeds with esptool only.

Autoset (no MP): ESP32_GENERIC_S3, variant SPIRAM (esptool reports Embedded PSRAM — no heap needed), 8 MB. Status: No MicroPython (Arduino/other).

Fixture 7 — Adafruit Feather RP2040 — non-ESP (COM14)

Autoset: port rp2; UF2 flash; no ESP UI.

Fixture 8 — ESP32-S3 CircuitPython (Qualia) — not MicroPython (COM16)

CircuitPython 9.0.5.

Autoset: ESP32_GENERIC_S3 (or Qualia), variant SPIRAM, flash unknown until esptool. Status: CircuitPython running (not MicroPython).

Fixture 9 — ESP32-S3 + Embedded PSRAM via CH343, no MicroPython (COM17)

esptool succeeded first try (external USB-UART, not native USB).

Autoset: ESP32_GENERIC_S3 / SPIRAM / 8 MB.

Fixture 10 — ESP32-S3 + Embedded PSRAM via CH343, no MicroPython (COM18)

Same profile as fixture 9. Distinct MAC dc:da:0c:48:ac:0c. Confirms Detect should key identity on MAC, not adapter serial (5837055051). Autoset: ESP32_GENERIC_S3 / SPIRAM / 8 MB.

Fixture 11 — Waveshare RP2040-Plus 4MB (CircuitPython) — non-ESP (COM19)

Autoset: port rp2; UF2 flash. Status: CircuitPython.

Fixture 12 — ESP32-S3 no SPIRAM (MicroPython) (COM10)

MP 1.21.0 on native USB. machine Generic ESP32S3 module with ESP32S3; unique_id 3485186bfcac (USB serial bogus 123456); freq 160 MHz; flash 8 MB; mem_free ~170 KBno SPIRAM. Autoset: ESP32_GENERIC_S3 / default / 8 MB. Contrast: fixture 4 had same string + MP + bogus serial but ~8 MB heap → SPIRAM. Heap (or esptool PSRAM feature) drives the variant, not the string.

Fixture 13 — Adafruit FunHouse (ESP32-S2, CircuitPython) (COM20)

First S2 fixture. CircuitPython 8.2.0.

Autoset: ESP32_GENERIC_S2 (or FunHouse), variant SPIRAM if present. Family mapper must accept uname ESP32S2 / CP Espressif → S2.

Fixture 14 — ESP32-S3 no SPIRAM (MicroPython) (COM10)

Same profile as fixture 12. Distinct unique_id 3485188d5428. Autoset: ESP32_GENERIC_S3 / default / 8 MB.

Fixture 15 — ESP32-S3 no SPIRAM (MicroPython) (COM10)

Same cohort as 12/14. unique_id c04e3003f630. Autoset: default / 8 MB.

Fixture 16 — Raspberry Pi Pico (MicroPython) — non-ESP (COM21)

Autoset: port rp2; UF2 flash.

Fixture 17 — classic ESP32-PICO-V3-02 + Embedded PSRAM, no MicroPython (COM22)

First classic ESP32 (not S2/S3/P4). CH9102 UART (VID 6790 / PID 21972).

Autoset: ESP32_GENERIC, variant SPIRAM, 8 MB.

Fixture 18 — Adafruit QT Py M0 (SAMD21) — UF2 bootloader (COM24 / was COM23)

Not ESP. In UF2 bootloader after replug.

Autoset: port samd; UF2 flash. Detect via UF2 volume label + INFO_UF2.TXT Board-ID.

Fixture 19 — Seeed XIAO nRF52840 Sense (CircuitPython) (COM26)

First nRF52 fixture. VID 10374 (0x2886 Seeed).

Autoset: port nrf; UF2/nrfutil flash — not esptool. Status: CircuitPython.

Fixture 20 — classic ESP32-PICO-V3-02 + Embedded PSRAM, no MicroPython (COM28)

Same chip profile as fixture 17. CH9102. Distinct MAC 4c:75:25:ee:d7:08. Crystal warning once (41.01 vs 40 MHz normalized). Autoset: ESP32_GENERIC / SPIRAM / 8 MB.

Fixture 21 — Adafruit Feather RP2040 DVI (CircuitPython) (COM29)

Autoset: port rp2 / ADAFRUIT_FEATHER_RP2040; UF2 flash. RP2 detect tool: picotool (BOOTSEL → RPI-RP2 volume, INFO_UF2.TXT Board-ID RPI-RP2); picotool info needs WinUSB via Zadig on Windows (mass-storage works without it).

Fixture 22 — ESP32-S3 no SPIRAM (MicroPython) (COM10)

Same profile as 12/14/15. Distinct unique_id ecda3b9956dc. Autoset: default / 8 MB.

Fixture 23 — Teensy 4.1 (IMXRT1062) CircuitPython (COM30)

First Teensy / high-end mimxrt. VID 9114 (Adafruit CDC on PJRC board).

Autoset: port mimxrt, board TEENSY41. Flashed → MP 1.29.0-preview via teensy_loader_cli (HalfKay HID — not esptool; Win32 HID build preferred over libusb on Windows). After flash: COM remaps (COM30→COM31), VID 0xF055.

Fixture 24 — SparkFun Thing Plus SAMD51 (CircuitPython) (COM32)

First SAMD51 fixture. VID 6991 (0x1B4F SparkFun).

Autoset: port samd, board SPARKFUN_SAMD51_THING_PLUS (exact match). UF2 flash.

Fixture 25 — STM32 NUCLEO-H743ZI2 (MicroPython) (COM33)

First stm32 fixture. VID 1155 (0x0483 STMicroelectronics).

Autoset: port stm32, board NUCLEO_H743ZI2. Flash via ST-Link MSD drag-drop of firmware.bin — not esptool. Flashed → MP 1.29.0-preview.

Fixture 26 — Adafruit PyRuler (SAMD21) CircuitPython (COM34)

Autoset: port samd; no PYRULER in MP tree — closest ADAFRUIT_TRINKET_M0 / ADAFRUIT_QTPY_SAMD21. UF2 flash. Flash note: bootloader updated Trinket M0 v2→v4.0.0; official CP UF2 returned to TRINKETBOOT — app image not sticking. Left for later (out of scope).

Fixture 27 — Adafruit PyGamer (SAMD51) CircuitPython (COM36)

Autoset: port samd; no PYGAMER in MP tree — closest SAMD_GENERIC_D51X19 (samd51j19; contrast fixture 24 samd51j20). UF2 flash.

Fixture 28 — classic ESP32-PICO-V3-02 + Embedded PSRAM (COM37)

Same chip profile as 17/20. CH9102 (54B0007563). Distinct MAC 4c:75:25:ee:d8:b4. Autoset: ESP32_GENERIC / SPIRAM / 8 MB. Flashed → MP 1.29.0-preview ESP32_GENERIC-SPIRAM (needed erase-flash first — partial write left a corrupted VFS). mem_free ~2.0 MB.

Fixture 29 — Adafruit Feather nRF52840 Express (CircuitPython) (COM38)

Second nRF52 fixture. VID 9114 Adafruit.

Autoset: port nrf. MP tree has FEATHER52 (nRF52832) — not a 52840 match; closest Adafruit-bootloader build SEEED_XIAO_NRF52 UF2 family 0xADA52840. Flash note: FTHR840BOOT SoftDevice S140 6.1.1 — must build SEEED_XIAO_NRF52 with SOFTDEV_VERSION=6.1.1 (UF2 start 0x26000); default 7.3.0 UF2 fails. Flashed → MP 1.29.0-preview (USB VID becomes Seeed 0x2886).

Fixture 30 — Adafruit Trinket M0 (SAMD21) CircuitPython (COM41)

True Trinket M0 (contrast fixture 26 PyRuler clone). VID 9114.

Autoset: port samd, board ADAFRUIT_TRINKET_M0 (exact match). UF2 via TRINKETBOOT (double-reset).


Autoset rules distilled from these fixtures

Signal Autoset
Chip family from esptool ESP32_GENERIC, _S2, _S3, _C3, _C6, _H2, _P4, …
Single-core feature UNICORE if that variant exists
PSRAM esptool Embedded PSRAMSPIRAM; machine Octal-SPIRAMSPIRAM_OCT; else MP large heap → SPIRAM
Physical flash CONFIG_ESPTOOLPY_FLASHSIZE_* + layout base
ESP32-P4 Wi-Fi C5_WIFI / C6_WIFI only from MP _build/machine or explicit user pick
Identity key MAC (esptool) — never the USB adapter serial (often bogus, e.g. 123456)

Confidence: matched / family-only / unknown. Non-Espressif → suggested firmware port only, never a forced ESP32_GENERIC_*.