Files
ESP32_Serial_Swiss_Army_Knife/wiring.md
T

281 lines
15 KiB
Markdown

# Hardware wiring
This document records hardware-specific pin assignments. Keeping each assignment tied to a named board combination allows additional wiring profiles to be added later without treating one GPIO map as universal.
## Profile: ESP32-S3-DevKitC-1 N16R8 with Adafruit MAX3243
This initial profile is for:
- An ESP32-S3-DevKitC-1-compatible development board with an ESP32-S3-WROOM-1-N16R8 module, 16 MB flash, 8 MB octal PSRAM, two USB-C ports, and its onboard RGB LED on GPIO48.
- The [Adafruit RS-232 Full Pinout Level-Shifter Breakout, product 5988](https://www.adafruit.com/product/5988), using a MAX3243 and a DE-9 female connector.
The Adafruit board provides three logic-to-RS-232 drivers (`TX`, `RTS`, and `DTR`), five RS-232-to-logic receivers (`RX`, `CTS`, `DSR`, `DCD`, and `RI`), valid-signal detection, and shutdown control. It is a level shifter, not a galvanic isolator.
### Wiring table
| Adafruit breakout pin | Direction at ESP32 | ESP32-S3 connection | DevKit header | Purpose |
|---|---:|---:|---:|---|
| `Vin` | Power | `3V3` | J1-1 or J1-2 | Power the MAX3243 with 3.3 V logic levels |
| `GND` | Power | `GND` | J1-22 | Common logic and RS-232 signal ground |
| `TX` | ESP32 → breakout | GPIO17 | J1-10 | UART1 transmit |
| `RX` | Breakout → ESP32 | GPIO18 | J1-11 | UART1 receive |
| `RTS` | ESP32 → breakout | GPIO15 | J1-8 | UART1 hardware receive-flow-control output |
| `CTS` | Breakout → ESP32 | GPIO16 | J1-9 | UART1 hardware transmit-flow-control input |
| `DTR` | ESP32 → breakout | GPIO7 | J1-7 | Software-controlled data-terminal-ready output |
| `DSR` | Breakout → ESP32 | GPIO5 | J1-5 | Data-set-ready input |
| `DCD` | Breakout → ESP32 | GPIO4 | J1-4 | Carrier/connect-state input |
| `RI` | Breakout → ESP32 | GPIO6 | J1-6 | Ring-indicator input |
| `VLD` | Breakout → ESP32 | GPIO8 | J1-12 | Valid RS-232 voltage indication |
| `OFF` | ESP32 → breakout | GPIO9 | J1-15 | Optional active-low transceiver shutdown |
Use the GPIO labels printed on the development board when wiring a compatible clone; its physical header numbering may differ from the official DevKitC-1 documentation.
### Wiring diagram
The arrows show signal direction at the breakout's 3.3 V logic header.
```text
ESP32-S3-DevKitC-1 N16R8 Adafruit MAX3243 breakout
──────────────────────── ──────────────────────────
3V3 ────────────> Vin
GND ────────────> GND
GPIO17 / U1TXD ────────────> TX
GPIO18 / U1RXD <──────────── RX
GPIO15 / U1RTS ────────────> RTS
GPIO16 / U1CTS <──────────── CTS
GPIO7 ────────────> DTR
GPIO5 <──────────── DSR
GPIO4 <──────────── DCD
GPIO6 <──────────── RI
GPIO8 <──────────── VLD
GPIO9 ────────────> OFF
```
### UART and flow-control pins
UART1 is used for the external RS-232 data path. GPIO17 and GPIO18 are the ESP32-S3's conventional `U1TXD` and `U1RXD` pins. GPIO15 and GPIO16 are physically adjacent to them on header J1 and are routed to UART1 RTS and CTS through the ESP32-S3 GPIO matrix.
The GPIO matrix means GPIO15 and GPIO16 can serve UART1 even though their fixed-function labels mention UART0 RTS and CTS. UART0 logging remains on GPIO43 and GPIO44 through the board's USB-to-UART bridge. GPIO19 and GPIO20 remain free for future native USB CDC-ACM support.
RTS/CTS flow control will be configurable. When enabled, the UART peripheral can handle it in hardware so backpressure does not depend on application-task scheduling. When disabled, firmware must place the output signals in compatible idle states.
### Modem-control signals
GPIO4 through GPIO7 form a compact group for the remaining modem-control lines:
- GPIO4 reads `DCD`.
- GPIO5 reads `DSR`.
- GPIO6 reads `RI`.
- GPIO7 drives `DTR`.
DCD, DSR, and RI are ordinary GPIO inputs rather than hardware-managed UART signals. Firmware will monitor them and make their state available to the serial session broker and user interfaces. DTR is a software-controlled GPIO output.
`VLD` on GPIO8 reports whether the MAX3243 detects a valid RS-232 voltage on at least one receiver. It is a useful connection hint but does not prove that the cable, signal direction, or serial parameters are correct.
The breakout's `OFF` pin is connected to the MAX3243 active-low `!FORCEOFF` input. High or unconnected keeps the transceiver enabled; low forces shutdown. Its onboard pull-up makes it safe to leave unconnected during initial testing. If firmware uses GPIO9 later, it should preferably configure it as an open-drain output that is released to enable the transceiver and driven low to disable it.
### Power and cable notes
- Connect breakout `Vin` to `3V3`, not `5V`. ESP32-S3 GPIOs are not 5 V tolerant.
- The MAX3243 generates the positive and negative RS-232 voltages required on the DE-9 side.
- The breakout is not isolated: ESP32 ground, breakout ground, USB ground, and DE-9 pin 5 are electrically connected.
- The breakout is electrically DTE-style: `TX`, `RTS`, and `DTR` drive the DE-9, while `RX`, `CTS`, `DSR`, `DCD`, and `RI` receive from it.
- A straight-through male-to-male gender changer changes connector gender only. Use a straight-through cable for a DCE peer and an appropriate null-modem cable for another DTE peer.
GPIO8 and GPIO9 are not adjacent on the official J1 header. GPIO3 and GPIO46 lie between them and are boot-strapping pins, so follow the printed GPIO labels instead of counting header positions.
## Phase 0 loopback tests
The hardware-characterization firmware never starts a test automatically. Wire exactly one configuration below while the board is powered down, inspect the connections, power it again, and then invoke the corresponding console command.
> **Important:** DE-9 pins 3 (`TX`), 4 (`DTR`), and 7 (`RTS`) are all driven outputs. Never connect any of these three pins to another one of these output pins. Connect each output only to the receiver input specified by the selected test.
The temporary Dupont-wire breakout is mechanically fragile. Keep wires short, make all changes with power removed, and prevent loose conductors from touching neighboring pins.
### Configuration A: primary data and handshake pairs
Connect:
| From driven output | To receiver input | Expected ESP32 logic |
|---|---|---|
| DE-9 pin 3, `TX` | DE-9 pin 2, `RX` | `RX == TX` |
| DE-9 pin 4, `DTR` | DE-9 pin 6, `DSR` | `DSR == DTR` |
| DE-9 pin 7, `RTS` | DE-9 pin 8, `CTS` | `CTS == RTS` |
```text
DE-9 pin 3 TX ─────> pin 2 RX
DE-9 pin 4 DTR ─────> pin 6 DSR
DE-9 pin 7 RTS ─────> pin 8 CTS
```
Run `loopback-a`. The firmware cycles all eight TX/DTR/RTS logic combinations, waits for the MAX3243 outputs and receivers to settle, and verifies all three receiver states plus `VLD`. Two inversions occur—once in the driver and once in the receiver—so the final ESP32 logic levels must match.
Configuration A can also be used for:
- `valid-test`, with no external RS-232 peer connected.
- `uart-loopback <baud> [format] [bytes]`, although only the pin 3 to pin 2 link is needed by that command.
- `uart-suite`, again using only the pin 3 to pin 2 data link.
### Configuration B: remaining receivers
Remove all configuration A jumpers, then connect:
| From driven output | To receiver input | Expected ESP32 logic |
|---|---|---|
| DE-9 pin 3, `TX` | DE-9 pin 1, `DCD` | `DCD == TX` |
| DE-9 pin 4, `DTR` | DE-9 pin 9, `RI` | `RI == DTR` |
| DE-9 pin 7, `RTS` | DE-9 pin 2, `RX` | `RX == RTS` |
```text
DE-9 pin 3 TX ─────> pin 1 DCD
DE-9 pin 4 DTR ─────> pin 9 RI
DE-9 pin 7 RTS ─────> pin 2 RX
```
Run `loopback-b`. Together, configurations A and B exercise all three MAX3243 drivers and all five receivers.
### Configuration C: CTS transmit gating
Disconnect every external DE-9 cable or peer, power the ESP32 and breakout down, and remove every previous jumper. Confirm that the two jumpers below are the only connections to these RS-232 pins before powering up again.
| From driven output | To receiver input | Test purpose |
|---|---|---|
| DE-9 pin 3, `TX` | DE-9 pin 2, `RX` | Return UART1 transmitted data for exact comparison |
| DE-9 pin 4, `DTR` | DE-9 pin 8, `CTS` | Let software-controlled DTR present inactive and active CTS states |
```text
DE-9 pin 3 TX ─────> pin 2 RX
DE-9 pin 4 DTR ─────> pin 8 CTS
```
Run `cts-flow-test`. The test operates UART1 at 115200 baud with hardware CTS enabled and performs two phases:
1. DTR logic 1 produces CTS logic 1, the inactive/high state. The firmware queues 512 bytes and verifies that transmission does not complete and no byte reaches RX during a 250 ms observation period.
2. DTR changes to logic 0, producing active/low CTS. The queued transmission must resume automatically, and all 512 bytes must return through RX without missing, extra, or corrupted data and without UART errors.
A buffered UART transmitter is used so the console command itself cannot deadlock while CTS is blocking transmission. The firmware does not manipulate the UART transmit queue between the blocked and resumed phases.
### Configuration D: RTS receive backpressure
Disconnect every external DE-9 cable or peer, power the ESP32 and breakout down, and remove every previous jumper. Confirm that the two jumpers below are the only connections to these RS-232 pins before powering up again.
| From driven output | To receiver input | Test purpose |
|---|---|---|
| DE-9 pin 4, `DTR` | DE-9 pin 2, `RX` | Carry UART2-generated test data into UART1 RX |
| DE-9 pin 7, `RTS` | DE-9 pin 1, `DCD` | Return UART1 RTS through DCD to UART2 CTS |
```text
UART2 TX / DE-9 pin 4 DTR ─────> pin 2 RX / UART1 RX
UART1 RTS / DE-9 pin 7 RTS ─────> pin 1 DCD / UART2 CTS
```
Run `rts-flow-test`. GPIO7 is temporarily routed from UART2 TX through the MAX3243 DTR driver. GPIO4 receives UART1 RTS through the DCD receiver and is simultaneously routed to UART2 CTS. This creates a complete hardware-controlled flow loop without an external serial peer.
The test queues 4096 bytes from UART2 but initially does not read UART1. UART1's receive ring eventually fills, its hardware FIFO crosses the configured threshold, and UART1 automatically deasserts RTS. That state passes through the physical pin 7 to pin 1 jumper and blocks UART2 through CTS. The firmware then drains UART1, which must automatically reassert RTS and allow UART2 to finish.
`UART_BUFFER_FULL` is expected during this deliberate pressure test. It means the UART ISR could not fit its current received-data batch into the software RX ring, confirming receive-side resource pressure. The driver preserves that batch while hardware RTS stops the sender. `UART_FIFO_OVF`, framing errors, parity errors, breaks, missing bytes, extra bytes, or data mismatches are failures.
### Manual voltage and polarity checks
With no DE-9 loopback jumpers installed, use the static `drivers` command and measure each driven output relative to DE-9 pin 5 (`GND`):
```text
drivers 0 0 0
```
Each of pins 3, 4, and 7 should be at a positive RS-232 voltage. Then run:
```text
drivers 1 1 1
```
Each output should be at a negative RS-232 voltage. Exact values vary with supply, load, meter, and charge-pump behavior; polarity is the primary check. The firmware leaves all outputs at logic 1 after automated tests.
### Recommended test order
1. Start with no DE-9 jumpers and run `status`.
2. Use `drivers 0 0 0` and `drivers 1 1 1` for the three output-polarity measurements.
3. Power down, install configuration A, power up, and run `loopback-a`.
4. With configuration A still installed and no external peer, run `valid-test`.
5. Keep only the pin 3 to pin 2 jumper and run a basic test such as `uart-loopback 9600 8N1 256`.
6. If that passes, run `uart-suite`.
7. Power down, replace the jumpers with configuration B, power up, and run `loopback-b`.
8. Power down, install configuration C, power up, and run `cts-flow-test`.
9. Power down, install configuration D, power up, and run `rts-flow-test`.
RTS and CTS remain ordinary GPIO signals during static and basic UART loopback tests. Only the two dedicated flow-control commands hand them to UART peripherals. Every test shuts the MAX3243 down while changing GPIO-matrix routing and restores all outputs to static logic 1 afterward.
## Phase 2 broker loopback
The Phase 2 broker can be checked independently of the Phase 0 UART test implementation. Disconnect external peers, power down, remove all previous jumpers, and connect only:
```text
DE-9 pin 3 TX -> pin 2 RX
```
Power up and use the default 115200 8N1 configuration:
```text
serial status
serial start
broker connect writer
broker connect observer
broker clients
```
On a fresh boot the returned IDs are normally 8 and 9, but always use the IDs printed by your device. In the commands below, substitute those values if they differ:
```text
broker request-writer 8
broker send-hex 8 0055aaff1b5b33316d
broker read 8 64
broker read 9 64
```
Both clients are observers, including the active writer, so both reads should return the exact nine bytes:
```text
Client 8 read 9 bytes: 0055aaff1b5b33316d
Client 9 read 9 bytes: 0055aaff1b5b33316d
```
If a read occurs before UART1 has returned the bytes, it may report zero; run it again. Next verify writer exclusion and forced reassignment:
```text
broker request-writer 9
broker send-hex 9 dead
broker force-writer 9
broker send-hex 9 112233
broker read 8 64
broker read 9 64
broker events 8
broker events 9
broker counters
```
The competing writer request and pre-reassignment send are expected to fail. After forced reassignment, both clients must receive `112233`. Events should describe the denied request, revocation of client 8, and grant to client 9, with the forced-change events reporting final writer 9.
Clean up in this order:
```text
broker disconnect 9
broker events 8
broker disconnect 8
broker status
serial counters
serial stop
serial status
```
Disconnecting client 9 automatically releases its writer lease. Client 8 receives the corresponding release and disconnect events; draining them before its own disconnect avoids intentionally counting them as discarded events. After the final disconnect, the broker should report zero clients and writer 0. `serial stop` must return the RS-232 port owner to `idle`, after which Phase 0 commands are available again.
Remove the loopback jumper with power off before connecting an external serial peer.
## Future hardware profiles
Alternative boards—such as the LILYGO T-Display-S3—or different RS-232 transceivers will receive separate profiles here. GPIO assignments must be reviewed for each board's display, buttons, USB connection, flash/PSRAM wiring, boot-strapping pins, and onboard peripherals.