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 suspends TempTask, cutting idle current well below full-speed operation. By default WiFi is also turned off entirely; with the WiFi Standby (Keep Reachable) setting enabled (Client mode only) the radio instead stays associated in modem-sleep so the dashboard remains reachable at anchor for about 1 mA more than fully-off. Measured figures and the full state machine are in Operating Modes & Power.
-
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 | Unused — routed only to the unpopulated J3 debug header | — |
| IO13 | 21 | TEMP_DQ — DS18B20 OneWire data (via 100 Ω series + 1 nF filter) | bidir |
| 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 Also¶
- Switching Power Supply — the 3.3 V rail that powers the module
- USB-C — programming interface
- Data Cables & Pinout — off-board pinout for each GPIO function
- Digital Inputs — opto and ground-style input circuits behind IGNITION_ISO, BMSLogic_ISO, etc.