Files
desklock/firmware/components/esp_hosted/docs/spi_half_duplex.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

36 KiB

ESP-Hosted SPI HD (Half Duplex) Operation

Sections 2 to 6 below covers the theoretical part where the SPI Half duplex protocol and expected framing structure is explained. This frame structure is flexible. Host and Co-processor follow the same frame structure.

Section 7 to 11 covers the complete step-wise setup co-processor and host with SPI Half Duplex, using 2 or 4 data lines.

If you wish to skip the theory, you can refer the Quick Start Guide below. For quick navigation, please unfold the Table of Contents below.

Table of Contents

1 Quick Start Guide

This section provides a brief overview of how to get started with ESP-Hosted using SPI HD mode, bypassing the theory and explanation. Please refer to the following sections to quickly set-up demo.

These sections will guide you through the process of configuring and flashing both the co-processor and host devices, setting up the hardware connections, and verifying successful communication.

2 Introduction

The ESP32 family of chips (except the ESP32) support the SPI co-processor HD (Half Duplex) Mode Protocol.

In this mode of operation, SPI supports 2 or 4 data lines to transfer data to the co-processor or from the co-processor (half duplex) during an SPI transaction. This is different from 'standard' SPI mode which transfers data bidirectionally (full duplex) over two data lines (one for host to co-processor data [MOSI], one for co-processor to host data [MISO]) during an SPI transaction.

Note

SPI Half Duplex mode is not supported on the classic ESP32. Other all chipsets support half duplex. Please use SPI full duplex for classic ESP32

Important

SPI Half Duplex is not an industry standard and has multiple implementations. Make sure your host processor supports the SPI HD protocol implemented by the Hosted co-processor before proceeding. See SPI HD protocol used by Hosted.

3 SPI HD Configuration

To enable SPI HD on the Host and co-processor using idf.py menuconfig:

On Host:

Component config
└── ESP-Hosted config
    ├── Transport layer ──> SPI Half-duplex
    └── (configure SPI Half-duplex parameters)

On Co-processor:

Example Configuration
└── Bus Config in between Host and Co-processor
    ├── Transport layer ──> SPI Half-duplex
    └── (configure SPI Half-duplex parameters)

3.1 Clock and Phase

The standard SPI CPOL clock and CPHA phase must be configured correctly on both the host and co-processor for the protocol to work.

3.2 Data Lines

Both the host and co-processor can support one, two or four data lines. Four data lines will be used to transfer data if configured on both the host and co-processor. If the host is configured to use two data lines, only two lines will be used to transfer data even if the co-processor is configured to use four data lines.

Warning

One data line support must be configured on both the host and co-processor for the transport to work.

3.3 Extra GPIO Signals

Extra GPIO signals are required for SPI HD on Hosted and can be assigned to any free GPIO pins:

  • Data_Ready signal: an output signal from the co-processor to the host. When asserted, the co-processor is telling the host that it has data to send. The host should perform a data read SPI transaction to fetch data from the co-processor.
  • Reset signal: an output signal from the host to the co-processor. When asserted, the host resets the co-processor. This is done when ESP-Hosted is started on the host, to synchronise the state of the host and co-processor.

Note

The Reset signal can be configured to connect to the EN or RST pin on the co-processor, or assigned to a GPIO pin on the co-processor.

To configure this, use idf.py menuconfig on the co-processor:

Example Configuration
└── Bus Config in between Host and Co-processor
    └── SPI Half-duplex Configuration
        └── GPIOs
            └── Slave GPIO pin to reset itself

3.4 Pin Assignments

Using the pins already assigned to SPI signals (dedicated IO_MUX pins) is recommended to minimise propagation delays. Using other GPIO pins for SPI signals will route the signals through the GPIO matrix which may limit the maximum clock frequency that can be used.

The following table shows the mapping between the SPI bus signals and their SPI HD Function:

SPI Bus Signal SPI HD Function Applicable
SPI_CS Chip Select Dual, Quad SPI
SPICLK Clock Dual, Quad SPI
SPID Data Bit 0 Dual, Quad SPI
SPIQ Data Bit 1 Dual, Quad SPI
SPIWP Data Bit 2 Quad SPI
SPIHD Data Bit 3 Quad SPI
Data_Ready Extra GPIO* Dual, Quad SPI
Reset Extra GPIO* Dual, Quad SPI
  • Extra GPIOs Data_Ready, Reset are explained above in 3.3 Extra GPIO Signals
  • The SPI HD CS signal, Data_Ready and Reset can be assigned to any GPIO pin on the host and co-processor.
  • By default, the SPI bus would idle (no CS, no clock, no data) when no transaction needed from either side, co-processor or host.
  • Data_Ready could be made optional with some code changes, but it would mean that the SPI bus would not be idled out when no transaction needed. This would be lower number of GPIOs used, but the power consumption would be higher. We are adding this feature soon.

4 SPI HD Protocol

Hosted uses the ESP SPI co-processor HD (Half Duplex) Mode Protocol (see References) with some modifications.

4.1 Data IO Modes

When communicating with the co-processor, the master uses the Command, Address, Dummy and Data phases during an SPI transaction. The number of bits and number of data lines used in each phase are:

  • Command: 8 bits, 1 data line
  • Address: 8 bits, 2 or 4 data lines
  • Dummy: 8 bits, 1 data line
  • Data: variable length, 2 or 4 data lines

Note

The number of data lines used in the Address and Data phase depends on the Command Mask in the Command sent by the host. See Supported Commands.

4.2 Supported Commands

Hosted uses the following SPI HD commands when communicating with the co-processor:

Command OpCode Purpose
WRBUF 0x01 Write to a 32-bit buffer register on the co-processor
RDBUF 0x02 Read from a 32-bit buffer register on the co-processor
WRDMA 0x03 Write data to the co-processor using DMA
RDDMA 0x04 Read data from the co-processor during DMA
WR_DONE 0x07 End of DMA write
CMD8 0x08 End of DMA read
CMD9 0x09 End of register read

4.2.1 Command Mask

The Commands are masked with a command mask to tell the co-processor the correct number of data lines to use during the transaction (2 or 4 data lines). Hosted uses the following masks, which are bit ORed with the command during a SPI transactions:

Mode Mask
2-bits 0x50
4-bits 0xA0

For example, if the host sends command 0x51 (2-bit mask + WRBUF), the host and co-processor will use 2 data lines to send the address and data. If the host sends command 0xA1 (4-bit mask + WRBUF), the host and co-processor will use 4 data lines to send the address and data.

The Command Mask determines the number of data lines used for the transaction. Even if there are four data lines between the host and co-processor, the host can tell the co-processor to use only two data lines by applying the 0x50 command mask.

Warning

It is an error to apply the 4-bit data mask (0xA0) when there are only two data lines connecting the host and co-processor.

4.3 Registers Used

The ESP SPI Co-processor HD Mode Protocol defines a number of registers on the co-processor. These registers are used in Hosted as follows:

Register Name Purpose
0x00 COPROCESSOR_READY Indicates if co-processor is ready
0x04 MAX_TX_BUF_LEN Maximum length of DMA data co-processor can transmit
0x08 MAX_RX_BUF_LEN Maximum length of DMA data co-processor can receive
0x0C TX_BUF_LEN Updated whenever co-processor wants to transmit data
0x10 RX_BUF_LEN Updated whenever co-processor can receive data
0x14 COPROCESSOR_CONTROL Controls co-processor operation

4.4 Timing Diagrams

The following diagrams summarize the SPI transactions as used by Hosted:

Using Four Data Lines

SPI Transaction using 4 data lines

Using Two Data Lines

SPI Transaction using 2 data lines

5 SPI HD Operation

5.1 Initialization

5.1.1 Co-processor and Host Initialization

The co-processor starts up and initialises the SPI HD transport. When the co-processor is ready it writes the value COPROCESSOR_IS_READY (0xEE) to the COPROCESSOR_READY register.

The Host starts up and initialises the SPI HD transport. When ready, it polls the COPROCESSOR_READY register on the co-processor until it reads the value COPROCESSOR_IS_READY.

Once co-processor is ready, host prepare for interrupts triggered by Data_Ready, and sets bit 0 on the COPROCESSOR_CONTROL register to 1. This opens the data path to the co-processor.

Both host and co-processor are now ready to communicate.

The first packet the co-processor transfers to the host is a Capabilities Packet, stating what the co-processor is capable of supporting:

  • WLAN, Bluetooth, etc.
  • the number of data lines supported for SPI HD

The host uses this packet to determine what the co-processor is capable of supporting.

sequenceDiagram
    participant h as Host
    participant s as Co-processor

    note over s,h : Init

    loop Executed periodically
        h ->> s : Read COPROCESSOR_READY reg
        s -->> h : Not Ready (!0xEE)
    end

    note over s : Ready: COPROCESSOR_READY = 0xEE
    h ->> s : Read COPROCESSOR_READY reg
    s -->> h : Ready (0xEE)
    note over h : Enable Data_Ready interrupt
    h ->> s : Set COPROCESSOR_CONTROL reg = 1

    note over s : Open Data Path
    note over s : Prepare Capability Data

    note over s : Assert Data_Ready
    h ->> s : Read Data
    s -->> h : Capability
    note over s : Deassert Data_Ready

    note over s,h : SPI HD Transport Ready

SPI HD Initialization Sequence

5.1.2 Number of Data Lines Used

After initialization, the host initially communicates with the co-processor using two data lines. If the co-processor is capable of supporting four data lines (from the Capabilities Packet sent by the co-processor), and the host is configured to also use four data lines, then four data lines will be used for subsequent data transfers.

If neither the host or co-processor is capable of transferring data using four data lines, then only two data lines will be used.

5.2 Co-processor to Host Transfer

Co-processor asserts Data_Ready to tell the host it has data to send.

Host reads the TX_BUF_LEN register.

Note

The upper 8-bits of the TX_BUF_LEN register are reserved, and should be masked out to get the correct read length from the TX_BUF_LEN register.

The host subtracts the read length from its cached read length (initial value is zero) to discover how much more data the co-processor wants to transfer to the host. The host can now read the data using the RDDMA command, ending the transfer with CMD8. The host now updates its cached read length with the co-processor's read length.

After reading TX_BUF_LEN register, host sends CMD9. This tells the co-processor that the host has read the register and it is safe for the co-processor to update the register (if required) and deassert the Data_Ready signal.

sequenceDiagram
    participant h as Host
    participant s as Co-processor

    note over s : Prepare data to send, update TX_BUF_LEN

    note over s : Assert Data_Ready

    h ->> s : Read TX_BUF_LEN
    note over h : Bytes to transfer = TX_BUF_LEN - (cached)TX_BUF_LEN

    h ->> s : Send CMD9
    note over s : Deassert Data_Ready

    h ->> s : Send RDDMA
    s -->> h : Transfer Data

    h ->> s : CMD8 (at end of transfer)

    note over h : update (cached)TX_BUF_LEN

SPI HD Read Sequence

5.3 Host to Co-processor Transfer

Host reads the RX_BUF_LEN register to discover how many buffers are available on the co-processor (each buffer is of size MAX_RX_BUF_LEN). If there are not enough buffers to store the data to be sent, the host should wait and re-read the register until there are enough buffers.

Once there are enough buffers, the host can use WRDMA to send data, ending each buffer transfer with WR_DONE.

sequenceDiagram
    participant h as Host
    participant s as Co-processor

    note over h : Prepare data to send

    loop Read until got buffer space
        h ->> s : Read RX_BUF_LEN
        note over h : available buffers = RX_BUF_LEN - (cached)RX_BUF_LEN
    end

    h ->> s : Send WRDMA
    h ->> s : Transfer Data
    h ->> s : WR_DONE (at end of transfer)

    note over h : Update (cached)RX_BUF_LEN

SPI HD Write Sequence

5.4 Code Reference

6 Hardware Considerations

6.1 General Considerations

  • Ensure equal trace lengths for all SPI connections, whether using jumper wires or PCB traces.
  • Use the lower clock frequency like 5 MHz for evaluation. Once solution verified, optimise the clock frequency in increasing steps to max possible value. To find out practical maximum SPI co-processor frequency for your co-processor, check IDF_PERFORMANCE_MAX_SPI_CLK_FREQ in ESP-IDF co-processor SPI clock benchmark
  • Verify voltage compatibility between host and co-processor devices.
  • Provide proper power supply decoupling for both host and co-processor devices.

6.2 Jumper Wires

  • Jumper wires are suitable for initial testing and prototyping.
  • Use high-quality, low-capacitance jumper wires.
  • Keep wires as short as possible, ideally under 10 cm.
  • Arrange wires to minimize crosstalk, especially for clock and data lines.
  • Possibly, use twisted pairs for clock and data lines to reduce electromagnetic interference.
  • If possible, use a ground wire between every signal wire to improve signal integrity.
  • Connect as many grounds as possible to improve common ground reference and reduce ground noise.

Important

Quad SPI (QSPI) should not be used with jumper cables due to signal integrity issues. Use Dual SPI for evaluation with jumper cables.

6.3 PCB Design

For optimal performance and reliability in production designs:

  • Ensure equal trace lengths for all SPI signals (CLK, MOSI, MISO, CS) as much as possible. This practice, known as length matching, is crucial for maintaining signal integrity and reducing timing skew, especially at higher frequencies.
  • If perfect length matching is not possible, prioritize matching the clock (CLK) trace length with the data lines.
  • Use controlled impedance traces for high-speed signals.
  • Place bypass capacitors close to the power pins of both the host and co-processor devices.
  • Consider using series termination resistors on the clock and data lines to reduce reflections.
  • For high-speed designs, use a 4-layer PCB with dedicated power and ground planes.
  • Quad SPI (QSPI) should only be implemented on a properly designed PCB.

6.4 Advanced Considerations

  • Calculate the maximum allowed trace length based on your clock frequency and PCB material.
  • Consider the capacitive load on the SPI bus, especially for longer traces or when using multiple co-processor devices.
  • For very high-speed designs, consider using differential signaling techniques.
  • Implement proper EMI/EMC design techniques to minimize electromagnetic interference.
  • Use an oscilloscope or logic analyzer to verify signal integrity and timing.
  • Start with a lower clock frequency and gradually increase it while monitoring performance.
  • Ensure proper grounding between the host and co-processor devices.
  • If using multiple power supplies, ensure they share a common ground.
  • Consider using level shifters if the host and co-processor operate at different voltage levels.

7 Hardware Setup

Important

Remember that Quad SPI (using D2 and D3) should only be used with a properly designed PCB, not with jumper wires.

Before flashing the co-processor and host, ensure that you have made the correct hardware connections. The following tables show the recommended connections for SPI Half Duplex mode:

Host connections

Signal ESP32-S3 ESP32-P4-Function-EV-Board Applicable
CLK 19 18 Dual, Quad SPI
D0 13 14 Dual, Quad SPI
D1 35 15 Dual, Quad SPI
CS 47 19 Dual, Quad SPI
Data Ready 12 6 Dual, Quad SPI
Reset Out 42 54 Dual, Quad SPI
GND GND GND Dual, Quad SPI
D2 20 16 Quad SPI only
D3 9 17 Quad SPI only
  • Host GPIOs can be re-configured to any other GPIOs, while co-processor configuration is done.
    • Make sure the configuration and hardware connections match.
  • Classic ESP32
    • Not supported as host or co-processor
    • Rest all chipsets are supported as host
  • ESP32-S2/C2/C3/C5/C6/C61
    • Pins for SPI Half Duplex Host need to be figured out yet.
  • ESP32-P4
    • For ESP32-P4-Function-EV-Board, the SDIO onboard pins are reused for SPI Half Duplex Host.
    • For Non ESP32-P4-Function-EV-Board, pins for SPI Half Duplex Host need to be figured out yet.

Co-processor connections

Signal ESP32-C6 on ESP32-P4-Function-EV-Board ESP32-C2/C3/C6 ESP32-C5 Applicable
CLK 19 6 6 Dual, Quad SPI
D0 20 7 7 Dual, Quad SPI
D1 21 2 2 Dual, Quad SPI
CS 18 10 10 Dual, Quad SPI
Data Ready 2 0 13 Dual, Quad SPI
Reset In EN/RST EN/RST EN/RST Dual, Quad SPI
GND GND GND GND Dual, Quad SPI
D2 22 5 5 Quad SPI only
D3 23 4 4 Quad SPI only
  • Co-processor GPIOs can be re-configured to any other GPIOs, while co-processor configuration is done.
    • Make sure the configuration and hardware connections match.
  • ESP32-C2/C3/C5/C6/C61/S2/S3
    • All supported as SPI Half Duplex co-processor
    • Pins for SPI Half Duplex co-processor need to be figured out yet for other boards

Note

A. QSPI Testing

  • Tested on ESP32-P4-Function-EV-Board
  • ESP32-P4 as host, ESP32-C6/C3 as QSPI co-processor
  • Reused existing SDIO connections for QSPI on C6 and P4

B. Dual SPI Testing

  • ESP32-S3 host with ESP32-C5 co-processor
  • Tested using jumper cables

C. Performance Optimization

  • Always prefer to use IO_MUX pins from datasheet for optimal performance on both sides

D. Portability

  • Once ported, any other non ESP host with Dual SPI or QSPI can be used

8 Set-Up ESP-IDF

Before setting up the ESP-Hosted co-processor & host for SPI Half Duplex mode, ensure that ESP-IDF is properly installed and set up on your system.

Option 1: Installer Way

  • Windows

  • Linux or MacOS

    • For bash:
      bash docs/setup_esp_idf__latest_stable__linux_macos.sh
      
    • For fish:
      fish docs/setup_esp_idf__latest_stable__linux_macos.fish
      

Option 2: Manual Way

Please follow the ESP-IDF Get Started Guide for manual installation.

9 Flashing the Co-processor

Supported Co-processor Targets ESP32 ESP32-C2 ESP32-C3 ESP32-C5 ESP32-C6 ESP32-C61 ESP32-S2 ESP32-S3

9.1 Create Co-processor Project

  1. Create co-processor project possibly outside of ESP-IDF project directory using

    idf.py create-project-from-example "espressif/esp_hosted:slave"
    
  2. Navigate to the created project directory.

  3. Configure the project for your target ESP chip:

    idf.py set-target <target>
    

    Replace <target> with your specific co-processor ESP chip (e.g., esp32c3, esp32s3).

9.2 Co-processor Config

Configure the co-processor project using

idf.py menuconfig

9.2.1 Transport config

Navigate and change as following:

Example Configuration
└── Bus Config in between Host and Co-processor
    └── Transport layer
        └── Select "SPI Half-duplex"

9.2.2 Any other config

  • Optionally, Configure any additional SPI-specific settings in the "SPI Half-duplex Configuration" menu, like co-processor GPIOs, SPI mode, etc.
Generated files
  • Generated config files are (1) sdkconfig file and (2) internal sdkconfig.h file.
  • Please note, any manually changes done to these generated files, would not take effect.
Defaulting specific config (Optional)
  • This is advanced option, so please be careful.
  • To mark some config options as default, you can add specific config line in file, sdkconfig.defaults.<target>. So whenever next time building, you do not need to re-configure.

9.3 Co-processor Build

Build the co-processor project

idf.py build

9.4 Co-processor Flashing

Firmware Upgrade Guidelines

It is recommended to periodically upgrade the slave firmware to leverage new features, bug fixes, and performance improvements.

Method Description Recommended Use
Direct Serial Flashing Uses UART pins for direct firmware installation First-time setup to install ESP-Hosted slave firmware
Slave OTA Update Performs slave firmware updates directly from Host All subsequent updates after initial installation
9.4.1 Serial Flashing (Initial Setup)

For the initial setup or when OTA is not available, use serial flashing.

Flash the co-processor firmware using

idf.py -p <co-processor_serial_port> flash

Note

If you are not able to flash the co-processor, there might be a chance that host is not allowing to to do so.

Put host in bootloader mode using following command and then retry flashing the co-processor

esptool.py -p **<host_serial_port>** --before default_reset --after no_reset run

Flash the co-processor and log the output:

idf.py -p <co-processor_serial_port> flash monitor

9.4.2 Co-processor OTA Flashing (Subsequent Updates)

The ESP-Hosted link comes pre-configured and ready to use on first boot. You can update the slave firmware remotely from the host MCU using OTA (Over-The-Air) updates: No ESP-Prog, serial cable, or extra GPIO connections are required.

For step-by-step instructions, see the Host Performs Slave OTA Example.

10 Flashing the Host

Host are required to support 2 data line SPI (dual SPI) or 4 line SPI (quad SPI or QSPI) in their hardware. All ESP chipsets hardware support dual, quad SPI.

Supported Host Targets Any ESP chipset Any Non-ESP chipset

Non ESP chipset may need to port the porting layer. It is strongly recommended to evaluate the solution using ESP chipset as host before porting to any non-esp chipset. For Quad SPI, PCB is only supported. Dual SPI could be evaluated using jumper cables.

Non-ESP Hosts, while porting, need to ensure that the Half duplex protocol and framing is exactly same as that of co-processor.

10.1 Select Example to Run in Hosted Mode

Select an example from the ESP-IDF examples directory that you wish to run in ESP-Hosted mode. All Wi-Fi and Bluetooth examples are supported. For simplicity and demonstration purposes, we will use the ESP-IDF iperf example.

10.2 Host Project Component Configuration

Now that ESP-IDF is set up, follow these steps to prepare the host:

1. Navigate to the iperf example in your ESP-IDF directory:
cd $IDF_PATH/examples/wifi/iperf
2. Dependency components

Add the required components to the project's idf_component.yml file:

idf.py add-dependency "espressif/esp_wifi_remote"
idf.py add-dependency "espressif/esp_hosted"
3. Remove conflicting configuration

Open the main/idf_component.yml file and remove/comment the following block if present:

# ------- Delete or comment this block ---------
espressif/esp-extconn:
  version: "~0.1.0"
  rules:
    - if: "target in [esp32p4]"
# -----------------------------------

This step is necessary because esp-extconn and esp-hosted cannot work together.

4. Disable native Wi-Fi if available

If your host ESP chip already has native Wi-Fi support, disable it by editing the components/soc/<soc>/include/soc/Kconfig.soc_caps.in file and changing all WIFI related configs to n.

If you happen to have both, host and co-processor as same ESP chipset type (for example two ESP32-C2), note an [additional step](docs/troubleshooting/#1-esp-host-to-evaluate-already-has-native-wi-fi)

10.3 Menuconfig, Build and Flash Host

1. High performance configurations

This is optional step, suggested for high performance applications.

If using ESP32-P4 as host and the ESP32-C6 as the co-processor:

  • Remove all CONFIG_ESP_WIFI_ settings. They do not apply to ESP-Hosted.
  • Add the following settings to your sdkconfig.defaults.esp32p4 file:
    ### sdkconfig for ESP32-P4 + C6 Dev board
    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
    
    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
    

For other ESP32 hosts, you can merge above configs into the corresponding sdkconfig.defaults.esp32XX file.

To adjust other Wi-Fi parameters, run idf.py menuconfig and go to Component config ---> Wi-Fi Remote ---> Wi-Fi configuration.

Optimised parameters for other co-processors can be found in the Performance Optimization Guide.

2. Set environment for your host ESP chip:
idf.py set-target <host_target>

Replace <host_target> with your specific ESP chip (one of esp32, esp32c2, esp32c3, esp32c5, esp32c6, esp32s2, esp32s3, esp32p4).

3. Flexible Menuconfig configurations
idf.py menuconfig

ESP-Hosted-MCU host configurations are available under "Component config" -> "ESP-Hosted config"

  1. Select "SPI Half-duplex" as the transport layer
  2. Change co-processor chipset to connect to under "Slave chipset to be used"
  3. Change Number of data lines to 2 or 4 based on the co-processor using "SPI Half-duplex Configuration" -> "Num Data Lines to use"
  4. Optionally, Configure SPI-specific settings in the "SPI Half-duplex Configuration" menu, like: - SPI Clock Freq (MHz) - SPI Mode - SPI Host GPIO Pins - SPI Checksum Enable/Disable (Checksum is recommended to be enabled as spi hardware doesn't have any error detection)

Note

The actual clock frequency used is determined by the hardware. Use an oscilloscope or logic analyzer to check the clock frequency.

4. Build the project:
idf.py build
5. Flash the firmware:
idf.py -p <host_serial_port> flash
6. Monitor the output:
```
idf.py -p <host_serial_port> monitor
```
- If host was put into bootloader mode earlier, it may need manual reset

11 Testing and Troubleshooting

After flashing both the co-processor and host devices, follow these steps to connect and test your ESP-Hosted SPI Half Duplex setup:

  1. Connect the hardware:

    • Follow the pin assignments for SPI Half Duplex as specified in Hardware Setup.
    • Ensure all necessary connections are made, including power, ground, and the extra GPIO signals (Data_Ready and Reset).
  2. Power on both devices.

  3. Verify the connection:

    • Check the serial output of both devices for successful initialization messages.
    • Look for messages indicating that the SPI Half Duplex transport layer has been established.
  4. Logs at both sides:

    • Host:

      I (522) transport: Attempt connection with slave: retry[0]
      I (525) transport: Reset slave using GPIO[54]
      I (530) os_wrapper_esp: GPIO [54] configured
      I (535) gpio: GPIO[54]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
      I (1712) transport: Received INIT event from ESP32 peripheral
      I (1712) transport: EVENT: 12
      I (1712) transport: EVENT: 11
      I (1715) transport: capabilities: 0xe8
      I (1719) transport: Features supported are:
      I (1724) transport:        - HCI over SPI
      I (1728) transport:        - BLE only
      I (1732) transport: EVENT: 13
      I (1736) transport: ESP board type is : 13
      
      I (1741) transport: Base transport is set-up
      
    • Co-processor:

      I (492) fg_mcu_slave: *********************************************************************
      I (501) fg_mcu_slave:                 ESP-Hosted-MCU Slave FW version :: X.Y.Z
      
      I (511) fg_mcu_slave:                 Transport used :: <Dual/Quad SPI>
      I (520) fg_mcu_slave: *********************************************************************
      I (529) fg_mcu_slave: Supported features are:
      I (534) fg_mcu_slave: - WLAN over SPI
      I (538) h_bt: - BT/BLE
      I (541) h_bt:    - HCI Over SPI
      I (545) h_bt:    - BLE only
      
  5. Test basic functionality:

    • The iperf example automatically attempts to connect to the configured Wi-Fi network. Watch the serial output for connection status.
    • If the automatic connection fails, you can manually initiate a Wi-Fi scan and connection:
      sta_scan
      sta_connect <SSID> <password>
      
  6. Additional commands to test:

    • Get IP address: sta_ip
    • Disconnect from Wi-Fi: sta_disconnect
    • Set Wi-Fi mode: wifi_mode <mode> (where mode can be 'sta', 'ap', or 'apsta')
  7. Advanced iperf testing: Once connected, you can run iperf tests to verify performance:

    Test Case Host Command External STA Command
    UDP Host TX iperf -u -c <STA_IP> -t 60 -i 3 iperf -u -s -i 3
    UDP Host RX iperf -u -s -i 3 iperf -u -c <HOST_IP> -t 60 -i 3
    TCP Host TX iperf -c <STA_IP> -t 60 -i 3 iperf -s -i 3
    TCP Host RX iperf -s -i 3 iperf -c <HOST_IP> -t 60 -i 3

    Note: Replace <STA_IP> with the IP address of the external STA, and <HOST_IP> with the IP address of the ESP-Hosted device.

Tip

To measure the optimal performance, check out the Shield Box Test Setup.

  1. Troubleshooting:

    • If you encounter issues, refer to section 6.3 for testing the SPI connection.
    • Consider using a lower clock speed or checking your hardware setup if you experience communication problems.
    • ESP-Hosted-MCU troubleshooting guide: docs/troubleshooting.md
  2. Monitoring and debugging:

    • Use the serial monitor on both devices to observe the communication between the host and co-processor.
    • For more detailed debugging, consider using a logic analyzer to examine the SPI signals.

12 References