You can watch a video of this in action here.
ESP32-S3 USB serial experiments and host-side tests:
- Echo firmware (Arduino): uppercase-echo any received bytes via USB-CDC
- Echo firmware (ESP-IDF): uppercase-echo using
usb_serial_jtag
- Bandwidth TX firmware (Arduino): stream 4 MiB payload over USB-CDC on BOOT press
- Bandwidth TX firmware (ESP-IDF): stream 4 MiB payload via TinyUSB CDC ACM on BOOT press
- Python echo test: iterate common host baud rates and verify echo
- Python throughput receiver: receive payload, verify CRC32, report throughput
- PlatformIO (VS Code extension or
pio
CLI) uv
for Python package/runtime management (curl -LsSf https://astral.sh/uv/install.sh | sh
)- Python 3.10+
Folder: echo-firmware-arduino/
targeting esp32-s3-devkitc-1
with Arduino USB-CDC enabled.
Build and upload:
cd echo-firmware-arduino
pio run -t upload
Behavior: configures Serial
at 115200; echoes incoming bytes back in uppercase.
Folder: echo-firmware-idf/
using the ESP-IDF usb_serial_jtag
driver.
Build and upload:
cd echo-firmware-idf
pio run -t upload
Behavior: prints a ready line and uppercase-echoes any incoming data.
Folder: bandwidth-tx-firmware-arduino/
.
Sends a 4 MiB payload when the BOOT button (GPIO0) is pressed.
Data format:
- 4 bytes magic:
TXT1
- 4 bytes little-endian payload length
- payload bytes (repeating 0..255 pattern)
- 4 bytes little-endian CRC32 (IEEE/ZIP, poly 0xEDB88320)
Build and upload:
cd bandwidth-tx-firmware-arduino
pio run -t upload
Press BOOT once to start a transfer.
Folder: bandwidth-tx-firmware-idf/
using TinyUSB CDC ACM.
Build and upload:
cd bandwidth-tx-firmware-idf
pio run -t upload
Device prints a ready message. Press BOOT to start a 4 MiB transfer with the same header/payload/CRC format as above.
Path: test-scripts/echo_baud_test.py
. Dependencies are declared in test-scripts/pyproject.toml
and will be resolved automatically by uv
.
Run (auto-detects an Espressif device when possible):
cd test-scripts
uv run echo_baud_test.py
Specify a port explicitly if auto-detection fails (macOS example):
uv run echo_baud_test.py --port /dev/cu.usbmodemXXXX
Customize the message or baud rates:
uv run echo_baud_test.py --message "hello world\n" --baud-rates 9600 115200 230400 460800 921600
Notes:
- The device echoes bytes in uppercase; the script compares case-insensitively by uppercasing both sent/received data.
- Exit code is non-zero if any baud rate fails the echo check.
Path: test-scripts/throughput_read_test.py
.
Receive and measure the transfer from either TX firmware (auto-detects port when possible):
cd test-scripts
uv run throughput_read_test.py
Explicit port:
uv run throughput_read_test.py --port /dev/cu.usbmodemXXXX
Options:
--baud
: host setting (CDC ignores it), default 115200--timeout
: overall timeout for a single transfer (seconds), default 60
Example output:
Received 4194304 bytes in 0.832s => 40.32 Mbit/s
Both scripts prefer devices with USB VID 0x303A
(Espressif). If none are found, they fall back to common /dev/cu.*
or /dev/tty.*
candidates. You can always override with --port
.