ESP32-S3 Reasoning¶
Overview¶
The ESP32-S3 is well-suited for this application, offering the right balance of performance, I/O, and wireless capabilities. The specific part used is ESP32-S3-WROOM-1-N16R8 (LCSC C2913202) — 16 MB QSPI flash + 8 MB OPI (octal) PSRAM, integrated PCB antenna. The PCB footprint is the dual-compatible WROOM-1U outline (which accepts either the WROOM-1 PCB-antenna or WROOM-1U u.FL-connector variant); the V9 build assembles the PCB-antenna part. The -N16R8 suffix encodes the flash/PSRAM configuration.
Key Strengths¶
-
USB Native Support: Simplifies firmware upload and eliminates USB-serial converter requirements. Full-speed support with ESD protection and proper impedance control in the hardware.
-
Sufficient GPIO: Easily accommodates ADS1115, INA228, BMP388, LSM6DSOX IMU, opto-isolated UARTs, CAN transceiver, field driver PWM, and digital I/O without pin conflicts.
-
Ample RAM & Flash: 16 MB flash split across two app slots (factory + ota_0) and two web slots (factory_fs + prod_fs) plus a 3.8 MB userdata partition handles OTA updates, web file system, and buffered sensor data. The 8 MB PSRAM hosts every large buffer (sensor history ring, payload buffers, console queue, PID/CV/thermal logs, IMU ring, efficiency matrix). Internal RAM is reserved for FreeRTOS stacks and TLS handshakes.
-
WiFi Reliability: Supports AP and client mode with watchdog, reconnection logic, and captive portal setup. GPIO-pin overrides on GPIO45 (config), GPIO46 (AP), GPIO41 (factory partition) let users recover from a stuck/lost-password state without re-flashing.
-
Low Power Sleep Modes: When ignition is off and uploads are complete, the firmware drops the CPU from 240 MHz to 80 MHz and turns WiFi off. With WiFi off and TempTask suspended, idle current is dramatically lower than full-speed operation.
-
Adequate Processing Power: Dual-core Xtensa LX7 @ 240 MHz handles:
- Real-time control loop firing on every fresh CH1 ADC sample (~4.7 ms / 213 Hz)
- 100 ms voltage CV loop
- 5 s temperature PID
- NMEA 2000 CAN parsing
- Field PWM generation
- Web server, SSE dispatch, real-time plots
- Core 0 hosts a dedicated TempTask (DS18B20) and httpsTask (all TLS uploads, OTA, weather), leaving Core 1 free for the control loop. Watchdog timeout is 16 s on Core 1.
Hardware: Power Pins and Decoupling¶
| Pin | Net | Notes |
|---|---|---|
| 2 (3V3) | 3V3 | Single supply, 3.3 V from TLV62569 — see Switching Power Supply |
| 1, 40, 41 (GND) | GND | Multiple ground pins all bonded to main GND plane |
| 3 (EN) | Net-(U19-EN) | Pulled through R98 (330 Ω) to the RESET wire (RJ3 cable 4 pin 13) for manual reset |
The S3 has only one external supply rail (3.3 V) and no separate analog supply. Module-level decoupling is handled inside the WROOM-1; the only external bypass caps are the standard 0.1 µF caps near the 3V3 pin.
Hardware: GPIO Allocation (V9 build)¶
| GPIO | Module pin | Function | Direction |
|---|---|---|---|
| IO1 | 39 | IGNITION_ISO (engine ignition wake input via VO615A opto) | IN |
| IO2 | 38 | Status LED (GPIO2 net, drives an indicator LED) | OUT |
| IO4 | 4 | GPIO4 — uncommitted, broken out at connector | — |
| IO5 | 5 | WakeFromDeepSleep (active-low to GND via switch panel) | IN |
| IO6 | 6 | UART_RX2_ISOL — NMEA0183 RX (via HCPL2531 ch 2) | IN |
| IO7 | 7 | UART_RX1_ISOL — Victron VE.Direct RX (via HCPL2531 ch 1) | IN |
| IO8 | 12 | EXTRA_OPTICAL_GPIO1_ISOL (spare opto input via VO615A) | IN |
| IO9 | 17 | I2C_SDA — shared bus to INA228, BMP388, LSM6DSOX | bidir |
| IO10 | 18 | I2C_SCL — same bus | OUT |
| IO11 | 19 | ESP_TACHOUT (tachometer signal to dashboard) | OUT |
| IO13 | 21 | GPIO13 — uncommitted | — |
| IO14 | 22 | OUT_PWM — alternator field PWM to LM5109A HI input | OUT |
| IO16 | 9 | GPIO16 — CAN RX from ISO1050 | IN |
| IO17 | 10 | GPIO17 — CAN TX to ISO1050 | OUT |
| (USB D-) | 13 | ESP32_D- → USB-C via 22 Ω + USBLC6 | bidir |
| (USB D+) | 14 | ESP32_D+ → USB-C via 22 Ω + USBLC6 | bidir |
| IO21 | 23 | BuzzerControl — to BC847 base via R38 | OUT |
| IO39 | 32 | HIGH/LOW_ISO (mode-select opto input) | IN |
| IO40 | 33 | FORCEFLOAT_ISO (mode-select opto input) | IN |
| IO42 | 35 | BMSLogic_ISO (BMS enable opto input) | IN |
| IO3, IO12, IO15, IO18, IO38 | 15, 20, 8, 11, 31 | EXTRA_3 / EXTRA_4 / EXTRA_5 / EXTRA_6 / EXTRA_7 (uncommitted, broken out via 330 Ω) | — |
| IO41 | 34 | FactoryReset (active-low GND-style switch via 330 Ω) | IN |
| IO45 | 26 | WifiReset (active-low GND-style switch via 330 Ω) | IN |
| IO46 | 16 | AP/ClientMode (active-low GND-style switch via 330 Ω) | IN |
| IO0 | 27 | Boot mode select — broken out via 330 Ω to RJ3 cable 3 pin 8 for programming | IN |
| RXD0 / TXD0 | 36 / 37 | UART0 — Arduino serial monitor over USB-CDC | bidir |
| IO35, IO36, IO37, IO47, IO48 | 28, 29, 30, 24, 25 | Reserved by module — octal SPI PSRAM lines, must not be routed | — |
Why every off-board GPIO has a 330 Ω series resistor: R56, R58, R71, R98, R100–R107 are all 330 Ω 0402 series resistors between the ESP32 pin and the connector. They limit fault current to ~10 mA if a user shorts an output to GND or applies 3.3 V to an unprotected input. This protects the ESP32 internal ESD clamps and is a routine practice for any GPIO exposed at a field connector.
Why IO35/36/37/47/48 are unconnected: On the N16R8 module these pins are bonded internally to the octal SPI interface that connects the ESP32 to the on-package PSRAM. They are not available for user use, even though some package diagrams show them. Attempting to use them will corrupt PSRAM access and crash the chip immediately.
Hardware: Reset and Boot¶
| Function | Mechanism |
|---|---|
| Power-on reset | Internal POR — no external supervisor IC |
| Manual reset | Ground the RJ3 cable 4 RESET wire, which pulls the EN pin through R98 |
| Programming mode (DFU) | Ground IO0 before reset (RJ3 cable 3 pin 8). Release IO0 after release of RESET. |
In normal operation IO0 is left floating — the WROOM module pulls it high internally to select boot from SPI flash. The board does not auto-toggle IO0/RESET because the USB-CDC native programming path doesn't require it (the S3 enters DFU on host command). The manual override exists as a fallback for the rare case where firmware has locked up and can't enter DFU on USB request.
Hardware: RF Layout¶
- Antenna is the integrated PCB trace on the WROOM-1 module substrate.
- Module is placed at a board edge with the antenna pointing outward; the 5 mm copper-keep-out band on all sides of the antenna pattern is honored on the V9 layout.
- WiFi performance through the wooden enclosure is excellent — wood is nearly transparent to 2.4 GHz, unlike a metal box. This was an explicit selection criterion (see Enclosure Design Summary).
See Also¶
- Switching Power Supply — the 3.3 V rail that powers the module
- USB-C — programming interface
- Connectors & Wiring — off-board pinout for each GPIO function
- Digital Inputs — opto and ground-style input circuits behind IGNITION_ISO, BMSLogic_ISO, etc.