Hardware: XIAO ESP32-S3 + Wio-WM6180 (MM6108/FGH100M-H), SPI at 40 MHz (confirmed), morsemicro/halow 2.11.2-esp32-2, ESP-ID 5.4.4. AP: Raspberry Pi 4 on Morse OpenWrt 3.0.2, 8 MHz channel, US, MCS 7 both ways at −25 dBm.
TCP tops out at about 4 Mbit/s against an air rate of 32.5 Mbit/s. Your iperf example measures the same on this hardware, so it isn’t application code. The AP is idle (95%+), and TCP window size makes almost no difference (16 KB vs 32 KB vs 50 KB), while
CPU clock does (160 → 240 MHz gave +34%), so it looked CPU/latency-bound. Profiling during a 5 MB TCP upload (about 3,600 packets):
- drv task: 56% of one core; lwIP tiT: 6%; over a core idle.
- SPI accounts for 88% of transfer wall time.
- Per packet: 89.9 calls to mmhal_wlan_spi_rw (one byte each), about 10 writes of 2–64 bytes, and 3 block writes of 512 bytes (the payload).
- Each ESP-IDF SPI transaction costs 18–22 µs regardless of size (about 4,500 cycles at 240 MHz); a byte on the wire takes 0.2µs. So roughly 93% of SPI time is protocol chatter, not payload.
- sdio_spi.c sends CMD53 command bytes individually and polls for response tokens one byte per transaction via morse_receive_spi().
Two findings that may help others on ESP-IDF hosts:
- Calling spi_device_acquire_bus() once and holding it (nothing else is on the bus) cut per-byte cost from 20.9 to 17.5 µs, about +10% throughput. Could the shim do this by default?
- The remaining cost is ESP-IDF’s per-transaction overhead, so batching would help most: could the token-polling loop read 8–16 bytes at a time and scan the result, and could command bytes go out in one transfer?
Questions: is about 4 Mbit/s expected for the ESP32-S3 SPI port? Is a batched SPI path planned or available? Is SDIO supported on ESP32-S3 hosts as an alternative?
Yes AI written but seems to really be a problem in the driver. Thanks!