Files
desklock/firmware/components/esp_hosted/docs/performance_optimization.md
T
jpmschweitzerandClaude Fable 5 cb5826e02b
Test, Build and Push / test-gateway (push) Successful in 12s
Test, Build and Push / release (push) Skipped
Test, Build and Push / build-gateway (push) Skipped
Fork fix: the SDIO wedge is FIXED (esp-hosted-mcu #167)
Root cause (verified against our exact IDF tree, not the community guess):
the "258" in "sdio_write_task: Failed to send data: 258" is NOT a timeout
(that is 263). 258 = 0x102 = ESP_ERR_INVALID_ARG. On the ESP32-P4, block-
mode CMD53 writes require the SOURCE buffer to be 64-byte (cache-line)
aligned; the IDF sdmmc driver rejects a misaligned source with INVALID_ARG
BEFORE any bus activity. esp_hosts write loop then declares "Unrecoverable
host sdio state" and reboots the whole P4. The audio TX payload is not
64-aligned, so streaming mic audio wedged on the very FIRST frame (which is
exactly what we saw: listening -> instant Failed to send -> reboot).

This also explains why buffer/queue/clock/retry tuning all did nothing: the
write never reached the bus. And why our symptom was instant, not after
~100 writes (the community block-mode-desync theory) — it is the first
misaligned buffer, every time.

Fix: vendored esp_hosted 2.12.11 as an editable local component (overrides
the registry copy) and bounce a misaligned TX payload through one aligned
DMA scratch buffer in hosted_sdio_write_block (port_esp_hosted_host_sdio.c).
TX is serialized by the bus lock so a single static bounce buffer is safe;
freed in hosted_sdio_deinit. Host-only change — no C6 reflash.

VERIFIED ON HARDWARE (autonomous self-test): 40s of continuous mic-audio
upstream streaming — the traffic that previously wedged on the first frame
— ran clean, zero timeouts, zero reboots. A guarded SDIO_TX_SELFTEST harness
is kept (compiled out) for future SDIO stress testing.

Credit: root cause + patch designed via multi-agent investigation; the
precise 258=INVALID_ARG decode (correcting the upstream community timeout
assumption) came from checking our actual esp_err.h.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 09:50:27 +02:00

13 KiB

ESP-Hosted Performance Optimization Guide

Quick reference for optimizing ESP-Hosted performance across co-processors and different transport interfaces.

Table of Contents
  1. Quick Start - High Performance Config

    1.1 ESP32-C6 as Co-Procesor

    1.2 ESP32-C5 as Co-Processor

    1.3 ESP32-C61 as Co-Processor

    1.4 ESP32-C2 as Co-Processor

    1.5 ESP32-S2 as Co-Processor

    1.6 ESP32-C3 as Co-Processor

  2. Transport Optimization

    2.1 SDIO (Highest Performance)

    2.2 SPI Full-Duplex

    2.3 2.3 SPI Half-Duplex

    2.4 UART (Lowest Performance)

  3. Memory Optimization

  4. Hardware Guidelines

    4.1 Critical Requirements

    4.2 PCB Design Checklist

    4.3 Development Workflow

1 Quick Start - High Performance Config

For immediate performance gains, add these to your host's sdkconfig.defaults.esp32XX file based on the co-processor you are using.

Note

Adjust the values based on your MCU host's and co-processor memory capacity. These values may change when more testing shows better performance figures.

Test conditions for throughput numbers using the performance settings:

  • raw: data transferred from sender to receiver over transport
  • iPerf used to measure TCP and UDP throughput

A diagram showing the setup used to get the throughput numbers.

flowchart TB
    %% floating IP labels — above their boxes, faint leader line
    ipAP["192.168.1.1"]:::ip
    ipP4["192.168.1.2"]:::ip
    ipHost["192.168.1.88 · test<br/>10.0.0.1 · control"]:::ip
    ipDev["10.0.0.2"]:::ip

    subgraph SB["Shield Box"]
        AP["📶 AP / Router"]

        subgraph EVB["ESP32-P4-Function-EV-Board 1.2+"]
            direction LR
            C6["ESP32-C6<br/>Wi-Fi slave"]
            P4["ESP32-P4<br/>iperf app"]
            C6 ---|"SDIO"| P4
        end

        AP -.-|"Wi-Fi"| C6
        HOST["AP-backend<br/>iperf host"]
        AP ===|"LAN cable"| HOST
        P4 ---|"USB / UART"| HOST
    end

    DEV["Dev machine"]
    HOST ---|"control"| DEV

    %% faint leaders from IP labels to devices
    ipAP -.- AP
    ipP4 -.- P4
    ipHost -.- HOST
    ipDev -.- DEV

    style SB fill:#fff7ec,stroke:#e8a33d,color:#333
    style EVB fill:#efeaf8,stroke:#8a7bbd,color:#333
    classDef node fill:#ffffff,stroke:#99aabb,color:#111
    classDef ip fill:none,stroke:none,color:#555
    class AP,C6,P4,HOST,DEV node

    linkStyle 0 stroke:#e8762d,stroke-width:2.5px
    linkStyle 1 stroke:#e8762d,stroke-width:2.5px
    linkStyle 2 stroke:#e8762d,stroke-width:2.5px
    linkStyle 3 stroke:#888888,stroke-width:1.5px,stroke-dasharray:5
    linkStyle 4 stroke:#0e9488,stroke-width:2px
    linkStyle 5 stroke:#cccccc,stroke-width:1px,stroke-dasharray:2 2
    linkStyle 6 stroke:#cccccc,stroke-width:1px,stroke-dasharray:2 2
    linkStyle 7 stroke:#cccccc,stroke-width:1px,stroke-dasharray:2 2
    linkStyle 8 stroke:#cccccc,stroke-width:1px,stroke-dasharray:2 2

Note

The diagram shows the router and ESP board in a shield box. The performance numbers here were obtained from an 'Open Air' configuration, without using a shield box.

1.1 ESP32-C6 as Co-Procesor

### sdkconfig for ESP32-P4 + C6 as co-processor

# Let P4 know, C6 is attached as slave
CONFIG_SLAVE_IDF_TARGET_ESP32C6=y
CONFIG_ESP_HOSTED_CP_TARGET_ESP32C6=y

# Wi-Fi Performance
CONFIG_WIFI_RMT_STATIC_RX_BUFFER_NUM=16
CONFIG_WIFI_RMT_DYNAMIC_RX_BUFFER_NUM=64
CONFIG_WIFI_RMT_DYNAMIC_TX_BUFFER_NUM=64
CONFIG_WIFI_RMT_AMPDU_TX_ENABLED=y
CONFIG_WIFI_RMT_TX_BA_WIN=32
CONFIG_WIFI_RMT_AMPDU_RX_ENABLED=y
CONFIG_WIFI_RMT_RX_BA_WIN=32

# TCP/IP Performance
CONFIG_LWIP_TCP_SND_BUF_DEFAULT=65534
CONFIG_LWIP_TCP_WND_DEFAULT=65534
CONFIG_LWIP_TCP_RECVMBOX_SIZE=64
CONFIG_LWIP_UDP_RECVMBOX_SIZE=64
CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=64
CONFIG_LWIP_TCP_SACK_OUT=y

Throughput using the settings.

Using SDIO Transport, 4-bits, running at 40MHz, connected to a 2.4GHz network over the air

Type Direction MBits/s
Raw P4 to C6 72
Raw C6 to P4 80
iPerf, TCP P4 to Test PC 32
iPerf, UDP P4 to Test PC 50
iPerf, TCP Test PC to P4 30
iPerf, UDP Test PC to P4 49

1.2 ESP32-C5 as Co-Processor

### sdkconfig for ESP32-P4 + C5 as co-processor

# Let P4 know, C5 is attached as slave
CONFIG_SLAVE_IDF_TARGET_ESP32C5=y
CONFIG_ESP_HOSTED_CP_TARGET_ESP32C5=y

# Optional PCB selection: Uncomment if you are using Pre designed PCB P4_C5_CORE_BOARD (to use correct GPIOs on that PCB)
# CONFIG_ESP_HOSTED_P4_C5_CORE_BOARD=y

# Wi-Fi Performance
CONFIG_WIFI_RMT_STATIC_RX_BUFFER_NUM=10
CONFIG_WIFI_RMT_DYNAMIC_RX_BUFFER_NUM=32
CONFIG_WIFI_RMT_DYNAMIC_TX_BUFFER_NUM=32
CONFIG_WIFI_RMT_AMPDU_TX_ENABLED=y
CONFIG_WIFI_RMT_TX_BA_WIN=32
CONFIG_WIFI_RMT_AMPDU_RX_ENABLED=y
CONFIG_WIFI_RMT_RX_BA_WIN=16

# TCP/IP Performance
CONFIG_LWIP_TCP_SND_BUF_DEFAULT=11520
CONFIG_LWIP_TCP_WND_DEFAULT=32768
CONFIG_LWIP_TCP_RECVMBOX_SIZE=48
CONFIG_LWIP_UDP_RECVMBOX_SIZE=48
CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=48

CONFIG_LWIP_TCP_SACK_OUT=y

Throughput using the settings.

Using SDIO Transport, 4-bits, running at 40MHz, connected to a 5GHz network over the air

Type Direction MBits/s
Raw P4 to C5 72
Raw C5 to P4 81
iPerf, TCP P4 to Test PC 23
iPerf, UDP P4 to Test PC 67
iPerf, TCP Test PC to P4 32
iPerf, UDP Test PC to P4 68

1.3 ESP32-C61 as Co-Processor

### sdkconfig for ESP32-P4 + C61 as co-processor

# Let P4 know, C61 is attached as slave
CONFIG_SLAVE_IDF_TARGET_ESP32C61=y
CONFIG_ESP_HOSTED_CP_TARGET_ESP32C61=y

# Optional PCB selection: Uncomment if you are using Pre designed PCB P4_C61_CORE_BOARD (to use correct GPIOs on that PCB)
# CONFIG_ESP_HOSTED_P4_C61_CORE_BOARD=y

# Wi-Fi Performance
CONFIG_WIFI_RMT_STATIC_RX_BUFFER_NUM=10
CONFIG_WIFI_RMT_DYNAMIC_RX_BUFFER_NUM=16
CONFIG_WIFI_RMT_DYNAMIC_TX_BUFFER_NUM=16
CONFIG_WIFI_RMT_AMPDU_TX_ENABLED=y
CONFIG_WIFI_RMT_TX_BA_WIN=16
CONFIG_WIFI_RMT_AMPDU_RX_ENABLED=y
CONFIG_WIFI_RMT_RX_BA_WIN=16

# TCP/IP Performance
CONFIG_LWIP_TCP_SND_BUF_DEFAULT=12930
CONFIG_LWIP_TCP_WND_DEFAULT=22488
CONFIG_LWIP_TCP_RECVMBOX_SIZE=48
CONFIG_LWIP_UDP_RECVMBOX_SIZE=64
CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=48
CONFIG_LWIP_IP_REASS_MAX_PBUFS=15

CONFIG_LWIP_TCP_SACK_OUT=y

CONFIG_LWIP_TCPIP_CORE_LOCKING=y
CONFIG_LWIP_TCPIP_CORE_LOCKING_INPUT=y

Throughput using the settings.

Using SPI-FD Transport, running at 40MHz, connected to a 2.4GHz network over the air

Type Direction MBits/s
Raw P4 to C61 25
Raw C61 to P4 26
iPerf, TCP P4 to Test PC 12
iPerf, UDP P4 to Test PC 18
iPerf, TCP Test PC to P4 15
iPerf, UDP Test PC to P4 23

1.4 ESP32-C2 as Co-Processor

# Let P4 know, C2 is attached as slave
CONFIG_SLAVE_IDF_TARGET_ESP32C2=y
CONFIG_ESP_HOSTED_CP_TARGET_ESP32C2=y

### sdkconfig for ESP32-P4 + C2 as co-processor
# Wi-Fi Performance
CONFIG_WIFI_RMT_STATIC_RX_BUFFER_NUM=10
CONFIG_WIFI_RMT_DYNAMIC_RX_BUFFER_NUM=32
CONFIG_WIFI_RMT_DYNAMIC_TX_BUFFER_NUM=32
CONFIG_WIFI_RMT_AMPDU_TX_ENABLED=y
CONFIG_WIFI_RMT_TX_BA_WIN=6
CONFIG_WIFI_RMT_AMPDU_RX_ENABLED=y
CONFIG_WIFI_RMT_RX_BA_WIN=6

# TCP/IP Performance
CONFIG_LWIP_TCP_SND_BUF_DEFAULT=16384
CONFIG_LWIP_TCP_WND_DEFAULT=32768
CONFIG_LWIP_TCP_RECVMBOX_SIZE=20
CONFIG_LWIP_UDP_RECVMBOX_SIZE=20
CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=20

CONFIG_LWIP_TCP_SACK_OUT=y

Throughput using the settings.

Using SPI-FD Transport, running at 40MHz, connected to a 2.4GHz network over the air

Type Direction MBits/s
Raw P4 to C2 25
Raw C2 to P4 26
iPerf, TCP P4 to Test PC 12
iPerf, UDP P4 to Test PC 18
iPerf, TCP Test PC to P4 13
iPerf, UDP Test PC to P4 15

1.5 ESP32-S2 as Co-Processor

### sdkconfig for ESP32-P4 + S2 as co-processor

# Let P4 know, S2 is attached as slave
CONFIG_SLAVE_IDF_TARGET_ESP32S2=y
CONFIG_ESP_HOSTED_CP_TARGET_ESP32S2=y

# Wi-Fi Performance
CONFIG_WIFI_RMT_STATIC_RX_BUFFER_NUM=8
CONFIG_WIFI_RMT_DYNAMIC_RX_BUFFER_NUM=24
CONFIG_WIFI_RMT_DYNAMIC_TX_BUFFER_NUM=24
CONFIG_WIFI_RMT_AMPDU_TX_ENABLED=y
CONFIG_WIFI_RMT_TX_BA_WIN=16
CONFIG_WIFI_RMT_AMPDU_RX_ENABLED=y
CONFIG_WIFI_RMT_RX_BA_WIN=16

# TCP/IP Performance
CONFIG_LWIP_TCP_SND_BUF_DEFAULT=17280
CONFIG_LWIP_TCP_WND_DEFAULT=28000
CONFIG_LWIP_TCP_RECVMBOX_SIZE=32
CONFIG_LWIP_UDP_RECVMBOX_SIZE=32
CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32

CONFIG_LWIP_TCP_SACK_OUT=y

1.6 ESP32-C3 as Co-Processor

### sdkconfig for ESP32-P4 + C3 as co-processor

# Let P4 know, C3 is attached as slave
CONFIG_SLAVE_IDF_TARGET_ESP32C3=y
CONFIG_ESP_HOSTED_CP_TARGET_ESP32C3=y

# Wi-Fi Performance
CONFIG_WIFI_RMT_STATIC_RX_BUFFER_NUM=20
CONFIG_WIFI_RMT_DYNAMIC_RX_BUFFER_NUM=40
CONFIG_WIFI_RMT_DYNAMIC_TX_BUFFER_NUM=40
CONFIG_WIFI_RMT_AMPDU_TX_ENABLED=y
CONFIG_WIFI_RMT_TX_BA_WIN=32
CONFIG_WIFI_RMT_AMPDU_RX_ENABLED=y
CONFIG_WIFI_RMT_RX_BA_WIN=32

# TCP/IP Performance
CONFIG_LWIP_TCP_SND_BUF_DEFAULT=40960
CONFIG_LWIP_TCP_WND_DEFAULT=40960
CONFIG_LWIP_TCP_RECVMBOX_SIZE=64
CONFIG_LWIP_UDP_RECVMBOX_SIZE=64
CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=64

Throughput using the settings.

Using SPI-FD Transport, running at 40MHz, connected to a 2.4GHz network over the air

Type Direction MBits/s
Raw P4 to C3 26
Raw C3 to P4 26
iPerf, TCP P4 to Test PC 19
iPerf, UDP P4 to Test PC 25
iPerf, TCP Test PC to P4 18
iPerf, UDP Test PC to P4 20

Throughput using the settings.

Using SPI-FD Transport, running at 40MHz, connected to a 2.4GHz network over the air

Type Direction MBits/s
Raw P4 to S2 25
Raw S2 to P4 26
iPerf, TCP P4 to Test PC 8
iPerf, UDP P4 to Test PC 11
iPerf, TCP Test PC to P4 12
iPerf, UDP Test PC to P4 15

2 Transport Optimization

2.1 SDIO (Highest Performance)

  • Clock Speed: Start at 20 MHz, optimize up to 50 MHz
  • Bus Width: Use 4-bit mode
  • Hardware: Use PCB with controlled impedance, external pull-ups (51kΩ)
  • Checksum: Optional (SDIO hardware handles verification)
CONFIG_ESP_HOSTED_SDIO_CLOCK_FREQ_KHZ=40000
CONFIG_ESP_HOSTED_SDIO_BUS_WIDTH=4

Note

See Performance and Memory Usage on the trade-off between SDIO Performance and Memory Use

2.2 SPI Full-Duplex

  • Clock Speed: ESP32: ≤10 MHz, Others: ≤40 MHz
  • Hardware: Use IO_MUX pins, short traces (≤10cm for jumpers)
  • Checksum: Mandatory (SPI hardware lacks error detection)
CONFIG_ESP_HOSTED_SPI_CLK_FREQ=40

2.3 SPI Half-Duplex

  • Data Lines: Use 4-line (Quad SPI) mode
  • Similar optimizations as SPI Full-Duplex

2.4 UART (Lowest Performance)

  • Baud Rate: Use 921600 (highest stable rate)
  • Best for: Low-throughput applications, debugging

3 Memory Optimization

  • Reduce memory footprint for resource-constrained applications:

    # Reduce queue sizes
    CONFIG_ESP_HOSTED_SDIO_TX_Q_SIZE=10    # Default: 20
    CONFIG_ESP_HOSTED_SDIO_RX_Q_SIZE=10    # Default: 20
    
    # Enable memory pooling
    CONFIG_ESP_HOSTED_USE_MEMPOOL=y
    
  • Disable the not-in-use features

    • For example, disable bluetooth if not needed
  • Use external RAM, for higher memory (PSRAM is supported)

  • Optimise internal RAM using ESP-IDF iram optimization tricks

4 Hardware Guidelines

4.1 Critical Requirements

  1. Signal Integrity: Use PCB designs for production, jumpers only for prototyping
  2. Power Supply: Stable 3.3V, proper decoupling capacitors
  3. Trace Length: Match lengths, especially clock vs data lines
  4. Pull-ups: Required for SDIO (51kΩ) on CMD, D0-D3 lines

4.2 PCB Design Checklist

  • Equal trace lengths for communication signals
  • Ground plane for signal stability
  • Controlled impedance traces (50Ω typical)
  • Series termination resistors for high-speed signals
  • Extra GPIOs reserved for future features (deep sleep, etc.)

4.3 Development Workflow

  1. Proof of Concept: Start with jumper wires, low clock speeds
  2. Incremental Optimization: Increase transport clock step by step
  3. Hardware Validation: Move to PCB for final validation
  4. Performance Tuning: Optimize buffers and configurations
  5. Disable features: Any unused components from ESP-IDF or

ESP-Hosted-MCU features could be disabled for more memory availability.