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>
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
-
3. SPI HD Configuration => 1 Clock and Phase || 2 Data Lines || 3 Extra GPIO Signals || 4 Pin Assignments
-
4. SPI HD Protocol => 1 Data IO Modes || 2 Supported Commands || 3 Registers Used || 4 Timing Diagrams
-
5. SPI HD Operation => 1 Initialization || 2 Co-processor to Host Transfer || 3 Host to Co-processor Transfer || 4 Code Reference
-
6. Hardware Considerations => 1 General Considerations || 2 Jumper Wires || 3 PCB Design || 4 Advanced Considerations
-
8. Set-Up ESP-IDF => Option 1: Installer Way || Option 2: Manual Way
-
9. Flashing the Co-processor => 1 Create Co-processor Project || 2 Co-processor Config || 3 Co-processor Build || 4 Co-processor Flashing
-
10. Flashing the Host => 1 Select Example to Run in Hosted Mode || 2 Host Project Component Configuration || 3 Menuconfig, Build and Flash Host
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.
- 7. Hardware Setup
- 8. Set-Up ESP-IDF
- 9. Flashing the Co-processor
- 10. Flashing the Host
- 11. Testing and Troubleshooting
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_Readysignal: 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.Resetsignal: 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
Resetsignal can be configured to connect to theENorRSTpin on the co-processor, or assigned to a GPIO pin on the co-processor.To configure this, use
idf.py menuconfigon 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,Resetare explained above in 3.3 Extra GPIO Signals - The
SPI HD CS signal,Data_ReadyandResetcan 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_Readycould 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:
SPI Transaction using 4 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
slave/main/spi_hd_slave_api.cimplements the code to run the SPI HD driver on the co-processorhost/drivers/transport/spi_hd/spi_hd_drv.cimplements the generic code to run the SPI HD driver on the hosthost/port/spi_hd_wrapper.cimplements the ESP-IDF specific code used by the generic SPI HD driver on the host
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_FREQin 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
- Install and setup ESP-IDF on Windows as documented in the Standard Setup of Toolchain for Windows.
- Use the ESP-IDF Powershell Command Prompt for subsequent commands.
-
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
- For bash:
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
-
Create co-processor project possibly outside of ESP-IDF project directory using
idf.py create-project-from-example "espressif/esp_hosted:slave" -
Navigate to the created project directory.
-
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)
sdkconfigfile and (2) internalsdkconfig.hfile. - 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 runFlash 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.esp32p4file:### 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"
- Select "SPI Half-duplex" as the transport layer
- Change co-processor chipset to connect to under "Slave chipset to be used"
- Change Number of data lines to 2 or 4 based on the co-processor using "SPI Half-duplex Configuration" -> "Num Data Lines to use"
- 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:
-
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).
-
Power on both devices.
-
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.
-
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
-
-
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>
-
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')
- Get IP address:
-
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 3iperf -u -s -i 3UDP Host RX iperf -u -s -i 3iperf -u -c <HOST_IP> -t 60 -i 3TCP Host TX iperf -c <STA_IP> -t 60 -i 3iperf -s -i 3TCP Host RX iperf -s -i 3iperf -c <HOST_IP> -t 60 -i 3Note: 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.
-
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
-
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
- ESP SPI co-processor HD (Half Duplex) Mode Protocol: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/protocols/esp_spi_slave_protocol.html