ESP32-WROOM-32 devkit — 38-pin
The reference form factor: Espressif's ESP32-DevKitC V4 and the clones that copy its
J2/J3 header pin for pin. Nineteen pins a side, and every pad of the module is broken out —
including six that will hang the chip and one that will stop it booting.
That completeness is the whole story of this board. The 30-pin version protects you by
omission; this one hands you the flash bus and GPIO0 and expects you to know better.
Read reference/board-hardware.md before choosing pins.
reference/board-hardware.md — the board: the Espressif J2/J3 header table with every
pin's alternate functions, the six flash pins, the IO0 hazard, the D2-means-GPIO9
silkscreen trap, the WROVER GPIO16/17 difference, the USB bridge and auto-reset circuit,
power tree, flash partitions — plus a development guide (§10 toolchain, §11
sdkconfig, §12 flashing and recovery, §13 peripheral cookbook, §14 symptom → cause → fix
table).
reference/esp32-soc.md — the silicon: pins that do not exist, strapping semantics and
the GPIO_STRAP_REG bit order, ADC/DAC/touch maps and accuracy, IO_MUX vs GPIO Matrix
and the SPI speed rule, power modes, memory map, deep-sleep wake pins.
reference/esp32-family.md — the rest of the family, for "should this be a different
ESP32?" questions: what does and does not port between chips, radio and USB capability
per chip, the RMT generation table (WS2812 under Wi-Fi load), deep-sleep memory and
ULP/LP-core availability, and a chip-selection table.
reference/recipes.md — code that compiles: platformio.ini, sdkconfig.defaults,
ADC1 with calibration, LEDC LED and servo, debounced input, the new I2C master driver,
80 MHz SPI, UART2, Wi-Fi scan and station connect, NVS, deep sleep, RMT WS2812.
template/ — a project that builds clean, in two variants, plus a scaffold script.
See template/README.md.
Confirm the board first
The 30-, 36- and 38-pin ESP32 devkits share silicon but not a header, and the pin map is
what this skill is for. Count the pins on one side:
| Pins per side |
Flash pins on the header |
IO0/D0 pin |
GND pins |
Skill |
| 15 |
no |
no |
2 |
esp32-wroom-30pin |
| 18 |
yes (SD2 SD3 CMD / SD1 SD0 CLK) |
no |
2 |
esp32-wroom-36pin |
| 19 |
yes (D2 D3 CMD / D1 D0 CLK) |
yes |
3 |
this one |
If the count does not match, switch skills. reference/board-hardware.md §1 has the detail,
including the silkscreen trap where D2 means GPIO9.
Orientation
|
|
| Module |
ESP32-WROOM-32/-32D/-32E/-32U, ESP-WROOM-32S, or ESP32-WROVER — check the can. ESP32-D0WDQ6 or D0WD-V3, Xtensa LX6 dual-core @ 240 MHz |
| Memory |
4 MB in-package flash, 520 KB SRAM (~320 KB linkable), 8 KB RTC FAST + 8 KB RTC SLOW. PSRAM only on a WROVER |
| Header |
38 pins, 19 per side (Espressif J2 / J3). 32 GPIOs — all module pads, EN, 3V3, 5V, 3× GND |
| USB |
No USB peripheral in the chip. A CP2102N (DevKitC) or CH340G (clones) bridge on UART0 (GPIO1/GPIO3), with DTR/RTS auto-reset |
| Console |
UART0 @ 115200 only. There is no USB-Serial-JTAG and no debug header |
| LED |
none on the Espressif DevKitC V4. GPIO2, active high, on NodeMCU-32S and clones |
| Buttons |
BOOT = GPIO0, pressed low, and GPIO0 is also a header pin · EN/RST acts on CHIP_PU, not readable |
| Free pins |
4, 13, 14, 16, 17, 18, 19, 21, 22, 23, 25, 26, 27, 32, 33 |
| Input-only |
34, 35, 36 (VP), 39 (VN) — no output driver, no internal pulls |
| Strapping |
0, 2, 5, 12 (MTDI), 15 (MTDO) |
| Never use |
6, 7, 8, 9, 10, 11 — the in-package flash bus, six pins by the USB connector |
| Analog |
ADC1 on 32–36, 39 · ADC2 on 0, 2, 4, 12–15, 25–27 · DAC on 25 and 26 |
| Radio |
Wi-Fi b/g/n + Bluetooth 4.2 BR/EDR + BLE, PCB antenna (or u.FL on -U/-IE modules) |
| Power |
3V3 out (~600 mA budget) · 5V in/out. Three mutually exclusive supply routes |
| Toolchain |
PlatformIO 6.1.19 + platform-espressif32 7.0.1 + ESP-IDF 6.0.1, board = esp32dev |
Rules that prevent the expensive mistakes
Each of these produces a failure that looks like something else.
GPIO6–11 are the flash bus. Wire nothing to them, ever. The six pins nearest the
USB connector — D2 D3 CMD on one side, D1 D0 CLK on the other — go to the module's
internal 4 MB flash die, which the CPU is executing out of. A pull-up, an LED, or even
a scope probe with too much capacitance gives you one of: a hang just after the
bootloader banner, a boot loop with invalid header, or — worst — a board that runs
and corrupts flash sectors under load. Espressif's own footnote says "avoid"; treat
that end of the header as mechanical support.
D2 on an Espressif silkscreen means GPIO9, not GPIO2. DOIT-style boards use D2
for GPIO2 and D4 for GPIO4; Espressif uses D0–D3 for the flash pins GPIO7–GPIO10.
The same two characters mean different pins on different boards, and following a
tutorial written for the other one puts your signal on the flash bus (rule 1). Resolve
every silkscreen label to a GPIO number via board-hardware.md §2 before writing code.
GPIO0 is on this header, and three things already own it: the boot strap (low at
reset ⇒ serial download mode), the BOOT button, and the bridge chip's auto-reset
circuit. An LED to ground on IO0 is enough to drop the board into download mode on
every reset — which presents as "my firmware stopped running", not as a pin problem —
and a pull-up breaks pio run -t upload. If uploads started failing after you wired
something, unplug IO0 first.
CONFIG_ESP_CONSOLE_UART_DEFAULT=y, never ..._USB_SERIAL_JTAG. The original
ESP32 has no USB peripheral at all — every byte comes out of UART0 through a
separate bridge chip. Configuration copied from an ESP32-C3/C6/S3 project produces a
firmware that runs perfectly and says nothing.
GPIO12 must be LOW at reset. It is MTDI, and high at reset straps VDD_SDIO to
1.8 V while the flash is a 3.3 V part. The board boots intermittently and the symptom
looks like flash corruption. A pull-up, an LED to 3V3, or a peripheral idling a line
high all do it. Fine after boot; add a 10 kΩ pull-down if you need the pin.
Check whether the module is a WROVER before touching GPIO16/17. On WROVER modules
those two are the 8 MB PSRAM's CS and CLK and are unusable — which also removes UART2's
default pins. Espressif's footnote: available "only on the boards with the modules
ESP32-WROOM and ESP32-SOLO-1". Read the can: WROOM ⇒ free, WROVER ⇒ taken. The same
distinction decides whether CONFIG_SPIRAM=y is correct or fatal.
ADC2 is dead while Wi-Fi is running. The Wi-Fi PHY arbitrates for the same
hardware and wins: adc_oneshot_read() on any ADC2 channel returns ESP_ERR_TIMEOUT
until esp_wifi_stop(). That leaves ADC1 — GPIO32, 33, 34, 35, 36, 39 — as the
entire analog budget of a connected application. Plan the pinout around it.
SPI3_HOST on GPIO18/19/23/5, or you get 26.67 MHz. Those four are SPI3's IO_MUX
pads and bypass the GPIO Matrix. Any other pin set — or the same pins on SPI2_HOST —
is matrix-routed and the driver silently clamps full-duplex transfers to 80 MHz / 3.
No error is reported; spi_device_get_actual_freq() is how you find out.
GPIO34/35/36/39 are input-only and have no internal pull-up or pull-down.
gpio_config() accepts GPIO_PULLUP_ENABLE on them and returns ESP_OK. Nothing
happens. A button there needs a physical 10 kΩ resistor.
A reset the moment Wi-Fi starts is the power supply, not your code. The TX burst
pulls ~300 mA against a datasheet requirement of a 500 mA source.
esp_reset_reason() returns ESP_RST_BROWNOUT; say so rather than reading the stack
trace.
Exactly one power route at a time. USB, or the 5V pin, or the 3V3 pin — never two.
Espressif warns that more than one "can damage the board and/or the power supply", and
no ORing diode is fitted on the clones either.
UART1's default pins are GPIO9 and GPIO10 — flash pins again (rule 1). Use
UART2 on GPIO17/GPIO16 (WROOM only, rule 6), and call uart_set_pin() before
uart_driver_install(); the reverse order compiles, runs, and leaves the peripheral on
its defaults.
Only RTC GPIOs wake the chip from deep sleep: 0, 2, 4, 12–15, 25–27, 32–36, 39.
GPIO5, 16, 17, 18, 19, 21, 22, 23 cannot, however you configure the interrupt. The wake
pin's pull must be set with rtc_gpio_pullup_en(), not gpio_set_pull_mode().
Deep sleep on this board is 8–20 mA, not 10 µA. LDO quiescent + USB bridge + power
LED. The datasheet's 10 µA is the bare chip; never quote it for a devkit.
CONFIG_ESP32_XTAL_FREQ_40=y. The module's crystal is 40 MHz; the 26 MHz setting
garbles the console at every baud rate, which reads as a broken cable.
Do not assume there is a user LED. The genuine Espressif DevKitC V4 has none — only
a power LED. BOARD_HAS_USER_LED in include/board.h defaults to 1 for the clones;
if the minimal variant prints ticks and nothing lights up, set it to 0 rather than
debugging the GPIO.
When the task is choosing pins
The 38-pin board has 32 pads on the header but the same 25 usable GPIOs as the 30-pin
board, because six are flash and GPIO0 is spoken for. Work outward:
- Analog first. With Wi-Fi in the design, every analog input must land on GPIO32, 33,
34, 35, 36 or 39 (rule 7).
- Then the fast bus. SPI above 26 MHz claims GPIO18/19/23/5 (rule 8).
- Then outputs that must be quiet at boot. GPIO2 is driven briefly by the bootloader;
GPIO1 emits the ROM log; GPIO0 is driven by the auto-reset circuit on every upload.
- Everything else goes on 4, 13, 14, 16, 17, 19, 21, 22, 23, 25, 26, 27.
If you run out, the extra pins on this board over the 30-pin one are not the answer —
five of the seven are unusable and the sixth is GPIO0. Reach for an I2C GPIO expander.
When the task is "the board does not work"
Diagnose in this order — each stage only depends on the ones before it:
- Is anything wired to the six pins by the USB connector, or to IO0? Unplug them
first. Rules 1 and 3 account for most mysteries on this board specifically.
- Does the port enumerate? No port ⇒ cable (try a known data cable) or bridge driver.
- Does anything print at 115200? The ROM bootloader's
rst:0x1 (POWERON_RESET)
banner comes out before any of your configuration applies.
- Does it print but say nothing after? Rule 4 — the console is misconfigured, or
MTDO/GPIO15 is strapped low.
- Does it boot-loop? Read
rst:. ESP_RST_BROWNOUT ⇒ rule 10. RTCWDT_RTC_RESET or
invalid header ⇒ esptool.py erase_flash and reflash the minimal variant.
- Does it land in download mode by itself? Something is holding GPIO0 low (rule 3).
On a genuine early DevKitC V4, it may instead be the C15 capacitor Espressif
documents — see
board-hardware.md §3.
- Does it reach
app_main() and then misbehave? Flash --minimal for a baseline,
then add one subsystem at a time.
template/src/board_report.c prints the strapping latches (including the GPIO0 one),
the reset reason, the flash size and the partition table, which answers most of steps 4–7.
Starting a new project
Do not hand-assemble one. template/ builds clean; scaffold from it:
~/.claude/skills/esp32-wroom-38pin/template/variants/new-project.sh <target-dir> [--full|--minimal]
cd <target-dir> && pio run
--minimal — LED blink on GPIO2 + console heartbeat. 144,493 B flash, 13,380 B RAM.
Flash this first on a board you have not used before: it touches only the toolchain, the
flashing route, UART0 and one GPIO, and its two outputs fail independently — LED but no
console means the serial side, console but no LED means your board is a DevKitC V4 with
no user LED (rule 16).
--full (default) — board self-test: chip/reset/strapping report, partition dump, ADC1
with calibration, Wi-Fi scan, LEDC heartbeat, BOOT button to re-run. 784,417 B flash,
37,036 B RAM. The jump is the Wi-Fi stack.
Both build as-is with ESP-IDF 6.0.1 (verified, zero warnings). Nothing is generated and no
paths are embedded, so copying template/ by hand works identically.
template/README.md maps files to subsystems so a --full scaffold can be stripped back.
When the user already has a project, prefer bringing it in line with the template's
platformio.ini, sdkconfig.defaults and include/board.h over rewriting their code.
Arduino (framework = arduino) is a reasonable choice for this board and every pin rule
above applies unchanged — but the Arduino core's analogRead() hides the ADC2/Wi-Fi
conflict of rule 7 instead of reporting it.
Flashing
pio run -t upload -t monitor
The bridge chip's DTR/RTS drive EN and GPIO0 through the two-transistor auto-reset circuit,
so esptool handles the whole cycle with no buttons. The board appears as
/dev/cu.usbserial-* or /dev/cu.SLAB_USBtoUART (macOS), /dev/ttyUSB0 (Linux, needs
dialout membership), or a COM port (Windows, WCH or Silicon Labs driver).
When it fails with Wrong boot mode detected or No serial data received, check IO0
before the cable (rule 3). Then the manual sequence: hold BOOT → tap EN → keep BOOT a
second longer → release BOOT → upload. Some clones need BOOT held for the whole upload.
If 921600 baud is unreliable, drop upload_speed to 460800.
Bad firmware cannot brick this board. The ROM bootloader is in mask ROM and always
answers that sequence:
esptool.py --chip esp32 -p <port> erase_flash # ~10 s for 4 MB
There is no debug header and no USB-JTAG. External JTAG means wiring a probe to
GPIO12/13/14/15 — and a probe that idles MTDI (GPIO12) high stops the board booting
(rule 5). In practice you debug this board over UART0.
Reporting
Say what is verified and what is derived.
Primary-source, high confidence: the header pin map in reference/board-hardware.md
§2 is transcribed from Espressif's ESP32-DevKitC V4 J2/J3 tables and cross-checked against
Ai-Thinker's NodeMCU-32S datasheet, which agree pin for pin. This is the best-documented
of the three board sizes. The flash-pin warning, the GPIO16/17 WROVER note and the C15
issue are Espressif's own text.
Verified on this machine: both template variants build clean with PlatformIO 6.1.19 /
platform-espressif32 7.0.1 / ESP-IDF 6.0.1, zero warnings, at the flash and RAM figures
quoted above. Every recipe in reference/recipes.md was compiled in the same project. The
26.67 MHz SPI figure is computed from _GPIO_MATRIX_DELAY_NS in the IDF HAL.
Not verified on hardware: none of this was run on a physical board in this session.
Details that vary by vendor — whether a user LED is fitted, which bridge chip, whether the
auto-reset transistors are present — should be confirmed with the --minimal variant on
the user's actual board. Say so rather than presenting them as certain.
1---2name: esp32-wroom-38pin3description: ESP32-WROOM-32 devkit — 38-pin4---56# ESP32-WROOM-32 devkit — 38-pin78The reference form factor: Espressif's **ESP32-DevKitC V4** and the clones that copy its9J2/J3 header pin for pin. Nineteen pins a side, and every pad of the module is broken out —10including six that will hang the chip and one that will stop it booting.1112That completeness is the whole story of this board. The 30-pin version protects you by13omission; this one hands you the flash bus and GPIO0 and expects you to know better.14Read `reference/board-hardware.md` before choosing pins.1516- `reference/board-hardware.md` — the board: the Espressif J2/J3 header table with every17 pin's alternate functions, the six flash pins, the IO0 hazard, the `D2`-means-GPIO918 silkscreen trap, the WROVER GPIO16/17 difference, the USB bridge and auto-reset circuit,19 power tree, flash partitions — **plus** a development guide (§10 toolchain, §1120 sdkconfig, §12 flashing and recovery, §13 peripheral cookbook, §14 symptom → cause → fix21 table).22- `reference/esp32-soc.md` — the silicon: pins that do not exist, strapping semantics and23 the `GPIO_STRAP_REG` bit order, ADC/DAC/touch maps and accuracy, IO_MUX vs GPIO Matrix24 and the SPI speed rule, power modes, memory map, deep-sleep wake pins.25- `reference/esp32-family.md` — the rest of the family, for "should this be a different26 ESP32?" questions: what does and does not port between chips, radio and USB capability27 per chip, the RMT generation table (WS2812 under Wi-Fi load), deep-sleep memory and28 ULP/LP-core availability, and a chip-selection table.29- `reference/recipes.md` — code that compiles: `platformio.ini`, `sdkconfig.defaults`,30 ADC1 with calibration, LEDC LED and servo, debounced input, the new I2C master driver,31 80 MHz SPI, UART2, Wi-Fi scan and station connect, NVS, deep sleep, RMT WS2812.32- `template/` — a **project that builds clean**, in two variants, plus a scaffold script.33 See `template/README.md`.3435## Confirm the board first3637The 30-, 36- and 38-pin ESP32 devkits share silicon but not a header, and the pin map is38what this skill is for. Count the pins on one side:3940| Pins per side | Flash pins on the header | `IO0`/`D0` pin | GND pins | Skill |41|---|---|---|---|---|42| 15 | no | no | 2 | `esp32-wroom-30pin` |43| 18 | yes (`SD2 SD3 CMD` / `SD1 SD0 CLK`) | no | 2 | `esp32-wroom-36pin` |44| **19** | **yes** (`D2 D3 CMD` / `D1 D0 CLK`) | **yes** | **3** | **this one** |4546If the count does not match, switch skills. `reference/board-hardware.md` §1 has the detail,47including the silkscreen trap where `D2` means GPIO9.4849## Orientation5051| | |52|---|---|53| Module | ESP32-WROOM-32/-32D/-32E/-32U, ESP-WROOM-32S, or **ESP32-WROVER** — check the can. ESP32-D0WDQ6 or D0WD-V3, **Xtensa LX6 dual-core** @ 240 MHz |54| Memory | 4 MB in-package flash, 520 KB SRAM (**~320 KB linkable**), 8 KB RTC FAST + 8 KB RTC SLOW. **PSRAM only on a WROVER** |55| Header | 38 pins, 19 per side (Espressif J2 / J3). **32 GPIOs — all module pads**, EN, 3V3, 5V, 3× GND |56| USB | **No USB peripheral in the chip.** A CP2102N (DevKitC) or CH340G (clones) bridge on UART0 (GPIO1/GPIO3), with DTR/RTS auto-reset |57| Console | UART0 @ 115200 only. There is no USB-Serial-JTAG and no debug header |58| LED | **none on the Espressif DevKitC V4.** GPIO2, active high, on NodeMCU-32S and clones |59| Buttons | **BOOT** = GPIO0, pressed low, and **GPIO0 is also a header pin** · **EN/RST** acts on CHIP_PU, not readable |60| Free pins | 4, 13, 14, 16, 17, 18, 19, 21, 22, 23, 25, 26, 27, 32, 33 |61| Input-only | 34, 35, 36 (VP), 39 (VN) — no output driver, **no internal pulls** |62| Strapping | 0, 2, 5, 12 (MTDI), 15 (MTDO) |63| **Never use** | **6, 7, 8, 9, 10, 11** — the in-package flash bus, six pins by the USB connector |64| Analog | ADC1 on 32–36, 39 · ADC2 on 0, 2, 4, 12–15, 25–27 · DAC on **25 and 26** |65| Radio | Wi-Fi b/g/n + Bluetooth 4.2 BR/EDR + BLE, PCB antenna (or u.FL on `-U`/`-IE` modules) |66| Power | 3V3 out (~600 mA budget) · 5V in/out. **Three mutually exclusive supply routes** |67| Toolchain | PlatformIO 6.1.19 + `platform-espressif32` 7.0.1 + ESP-IDF 6.0.1, `board = esp32dev` |6869## Rules that prevent the expensive mistakes7071Each of these produces a failure that looks like something else.72731. **GPIO6–11 are the flash bus. Wire nothing to them, ever.** The six pins nearest the74 USB connector — `D2 D3 CMD` on one side, `D1 D0 CLK` on the other — go to the module's75 internal 4 MB flash die, which the CPU is executing out of. A pull-up, an LED, or even76 a scope probe with too much capacitance gives you one of: a hang just after the77 bootloader banner, a boot loop with `invalid header`, or — worst — a board that runs78 and corrupts flash sectors under load. Espressif's own footnote says "avoid"; treat79 that end of the header as mechanical support.80812. **`D2` on an Espressif silkscreen means GPIO9, not GPIO2.** DOIT-style boards use `D2`82 for GPIO2 and `D4` for GPIO4; Espressif uses `D0`–`D3` for the flash pins GPIO7–GPIO10.83 The same two characters mean different pins on different boards, and following a84 tutorial written for the other one puts your signal on the flash bus (rule 1). Resolve85 every silkscreen label to a GPIO number via `board-hardware.md` §2 before writing code.86873. **GPIO0 is on this header, and three things already own it**: the boot strap (low at88 reset ⇒ serial download mode), the BOOT button, and the bridge chip's auto-reset89 circuit. An LED to ground on IO0 is enough to drop the board into download mode on90 every reset — which presents as "my firmware stopped running", not as a pin problem —91 and a pull-up breaks `pio run -t upload`. If uploads started failing after you wired92 something, unplug IO0 first.93944. **`CONFIG_ESP_CONSOLE_UART_DEFAULT=y`, never `..._USB_SERIAL_JTAG`.** The original95 ESP32 has **no USB peripheral at all** — every byte comes out of UART0 through a96 separate bridge chip. Configuration copied from an ESP32-C3/C6/S3 project produces a97 firmware that runs perfectly and says nothing.98995. **GPIO12 must be LOW at reset.** It is MTDI, and high at reset straps VDD_SDIO to100 1.8 V while the flash is a 3.3 V part. The board boots intermittently and the symptom101 looks like *flash corruption*. A pull-up, an LED to 3V3, or a peripheral idling a line102 high all do it. Fine after boot; add a 10 kΩ pull-down if you need the pin.1031046. **Check whether the module is a WROVER before touching GPIO16/17.** On WROVER modules105 those two are the 8 MB PSRAM's CS and CLK and are unusable — which also removes UART2's106 default pins. Espressif's footnote: available "only on the boards with the modules107 ESP32-WROOM and ESP32-SOLO-1". Read the can: `WROOM` ⇒ free, `WROVER` ⇒ taken. The same108 distinction decides whether `CONFIG_SPIRAM=y` is correct or fatal.1091107. **ADC2 is dead while Wi-Fi is running.** The Wi-Fi PHY arbitrates for the same111 hardware and wins: `adc_oneshot_read()` on any ADC2 channel returns `ESP_ERR_TIMEOUT`112 until `esp_wifi_stop()`. That leaves **ADC1 — GPIO32, 33, 34, 35, 36, 39** — as the113 entire analog budget of a connected application. Plan the pinout around it.1141158. **`SPI3_HOST` on GPIO18/19/23/5, or you get 26.67 MHz.** Those four are SPI3's IO_MUX116 pads and bypass the GPIO Matrix. Any other pin set — or the same pins on `SPI2_HOST` —117 is matrix-routed and the driver silently clamps full-duplex transfers to 80 MHz / 3.118 No error is reported; `spi_device_get_actual_freq()` is how you find out.1191209. **GPIO34/35/36/39 are input-only and have no internal pull-up or pull-down.**121 `gpio_config()` accepts `GPIO_PULLUP_ENABLE` on them and returns `ESP_OK`. Nothing122 happens. A button there needs a physical 10 kΩ resistor.12312410. **A reset the moment Wi-Fi starts is the power supply, not your code.** The TX burst125 pulls ~300 mA against a datasheet requirement of a 500 mA source.126 `esp_reset_reason()` returns `ESP_RST_BROWNOUT`; say so rather than reading the stack127 trace.12812911. **Exactly one power route at a time.** USB, or the 5V pin, or the 3V3 pin — never two.130 Espressif warns that more than one "can damage the board and/or the power supply", and131 no ORing diode is fitted on the clones either.13213312. **UART1's default pins are GPIO9 and GPIO10** — flash pins again (rule 1). Use134 **UART2 on GPIO17/GPIO16** (WROOM only, rule 6), and call `uart_set_pin()` *before*135 `uart_driver_install()`; the reverse order compiles, runs, and leaves the peripheral on136 its defaults.13713813. **Only RTC GPIOs wake the chip from deep sleep**: 0, 2, 4, 12–15, 25–27, 32–36, 39.139 GPIO5, 16, 17, 18, 19, 21, 22, 23 cannot, however you configure the interrupt. The wake140 pin's pull must be set with `rtc_gpio_pullup_en()`, not `gpio_set_pull_mode()`.14114214. **Deep sleep on this board is 8–20 mA, not 10 µA.** LDO quiescent + USB bridge + power143 LED. The datasheet's 10 µA is the bare chip; never quote it for a devkit.14414515. **`CONFIG_ESP32_XTAL_FREQ_40=y`.** The module's crystal is 40 MHz; the 26 MHz setting146 garbles the console at *every* baud rate, which reads as a broken cable.14714816. **Do not assume there is a user LED.** The genuine Espressif DevKitC V4 has none — only149 a power LED. `BOARD_HAS_USER_LED` in `include/board.h` defaults to 1 for the clones;150 if the minimal variant prints ticks and nothing lights up, set it to 0 rather than151 debugging the GPIO.152153## When the task is choosing pins154155The 38-pin board has 32 pads on the header but the same **25 usable GPIOs** as the 30-pin156board, because six are flash and GPIO0 is spoken for. Work outward:1571581. **Analog first.** With Wi-Fi in the design, every analog input must land on GPIO32, 33,159 34, 35, 36 or 39 (rule 7).1602. **Then the fast bus.** SPI above 26 MHz claims GPIO18/19/23/5 (rule 8).1613. **Then outputs that must be quiet at boot.** GPIO2 is driven briefly by the bootloader;162 GPIO1 emits the ROM log; GPIO0 is driven by the auto-reset circuit on every upload.1634. **Everything else** goes on 4, 13, 14, 16, 17, 19, 21, 22, 23, 25, 26, 27.164165If you run out, the extra pins on this board over the 30-pin one are **not** the answer —166five of the seven are unusable and the sixth is GPIO0. Reach for an I2C GPIO expander.167168## When the task is "the board does not work"169170Diagnose in this order — each stage only depends on the ones before it:1711721. **Is anything wired to the six pins by the USB connector, or to IO0?** Unplug them173 first. Rules 1 and 3 account for most mysteries on this board specifically.1742. **Does the port enumerate?** No port ⇒ cable (try a known data cable) or bridge driver.1753. **Does anything print at 115200?** The ROM bootloader's `rst:0x1 (POWERON_RESET)`176 banner comes out before any of your configuration applies.1774. **Does it print but say nothing after?** Rule 4 — the console is misconfigured, or178 MTDO/GPIO15 is strapped low.1795. **Does it boot-loop?** Read `rst:`. `ESP_RST_BROWNOUT` ⇒ rule 10. `RTCWDT_RTC_RESET` or180 `invalid header` ⇒ `esptool.py erase_flash` and reflash the minimal variant.1816. **Does it land in download mode by itself?** Something is holding GPIO0 low (rule 3).182 On a genuine early DevKitC V4, it may instead be the **C15** capacitor Espressif183 documents — see `board-hardware.md` §3.1847. **Does it reach `app_main()` and then misbehave?** Flash `--minimal` for a baseline,185 then add one subsystem at a time.186187`template/src/board_report.c` prints the strapping latches (including the GPIO0 one),188the reset reason, the flash size and the partition table, which answers most of steps 4–7.189190## Starting a new project191192Do not hand-assemble one. `template/` builds clean; scaffold from it:193194```sh195~/.claude/skills/esp32-wroom-38pin/template/variants/new-project.sh <target-dir> [--full|--minimal]196cd <target-dir> && pio run197```198199- `--minimal` — LED blink on GPIO2 + console heartbeat. **144,493 B flash, 13,380 B RAM.**200 Flash this first on a board you have not used before: it touches only the toolchain, the201 flashing route, UART0 and one GPIO, and its two outputs fail independently — LED but no202 console means the serial side, console but no LED means your board is a DevKitC V4 with203 no user LED (rule 16).204- `--full` (default) — board self-test: chip/reset/strapping report, partition dump, ADC1205 with calibration, Wi-Fi scan, LEDC heartbeat, BOOT button to re-run. **784,417 B flash,206 37,036 B RAM.** The jump is the Wi-Fi stack.207208Both build as-is with ESP-IDF 6.0.1 (verified, zero warnings). Nothing is generated and no209paths are embedded, so copying `template/` by hand works identically.210`template/README.md` maps files to subsystems so a `--full` scaffold can be stripped back.211212When the user already has a project, prefer bringing it in line with the template's213`platformio.ini`, `sdkconfig.defaults` and `include/board.h` over rewriting their code.214215Arduino (`framework = arduino`) is a reasonable choice for this board and every pin rule216above applies unchanged — but the Arduino core's `analogRead()` hides the ADC2/Wi-Fi217conflict of rule 7 instead of reporting it.218219## Flashing220221```sh222pio run -t upload -t monitor223```224225The bridge chip's DTR/RTS drive EN and GPIO0 through the two-transistor auto-reset circuit,226so esptool handles the whole cycle with no buttons. The board appears as227`/dev/cu.usbserial-*` or `/dev/cu.SLAB_USBtoUART` (macOS), `/dev/ttyUSB0` (Linux, needs228`dialout` membership), or a `COM` port (Windows, WCH or Silicon Labs driver).229230When it fails with `Wrong boot mode detected` or `No serial data received`, **check IO0231before the cable** (rule 3). Then the manual sequence: **hold BOOT → tap EN → keep BOOT a232second longer → release BOOT → upload.** Some clones need BOOT held for the whole upload.233If 921600 baud is unreliable, drop `upload_speed` to 460800.234235**Bad firmware cannot brick this board.** The ROM bootloader is in mask ROM and always236answers that sequence:237238```sh239esptool.py --chip esp32 -p <port> erase_flash # ~10 s for 4 MB240```241242There is no debug header and no USB-JTAG. External JTAG means wiring a probe to243GPIO12/13/14/15 — and a probe that idles MTDI (GPIO12) high stops the board booting244(rule 5). In practice you debug this board over UART0.245246## Reporting247248Say what is verified and what is derived.249250**Primary-source, high confidence:** the header pin map in `reference/board-hardware.md`251§2 is transcribed from Espressif's ESP32-DevKitC V4 J2/J3 tables and cross-checked against252Ai-Thinker's NodeMCU-32S datasheet, which agree pin for pin. This is the best-documented253of the three board sizes. The flash-pin warning, the GPIO16/17 WROVER note and the C15254issue are Espressif's own text.255256**Verified on this machine:** both template variants build clean with PlatformIO 6.1.19 /257platform-espressif32 7.0.1 / ESP-IDF 6.0.1, zero warnings, at the flash and RAM figures258quoted above. Every recipe in `reference/recipes.md` was compiled in the same project. The25926.67 MHz SPI figure is computed from `_GPIO_MATRIX_DELAY_NS` in the IDF HAL.260261**Not verified on hardware:** none of this was run on a physical board in this session.262Details that vary by vendor — whether a user LED is fitted, which bridge chip, whether the263auto-reset transistors are present — should be confirmed with the `--minimal` variant on264the user's actual board. Say so rather than presenting them as certain.