This commit is contained in:
iranl
2025-06-25 22:52:12 +02:00
parent 5fe5614686
commit 6c74d62531
519 changed files with 191600 additions and 5 deletions

View File

@@ -0,0 +1,527 @@
# Bluetooth Implementation in ESP-Hosted
**Table of Contents**
- [1. Introduction](#1-introduction)
- [1.1 Choosing a Bluetooth Host stack](#11-choosing-a-bluetooth-host-stack)
- [2. Bluetooth Controller](#2-bluetooth-controller)
- [3. Bluetooth Interface](#3-bluetooth-interface)
- [4. NimBLE Host Stack](#4-nimble-host-stack)
- [4.1. Transporting HCI data using Hosted HCI in NimBLE](#41-transporting-hci-data-using-hosted-hci-in-nimble)
- [4.1.1. Bluetooth Host Hosted HCI Initialization](#411-bluetooth-host-hosted-hci-initialization)
- [4.1.2. Bluetooth Host Sending Data through Hosted HCI in NimBLE](#412-bluetooth-host-sending-data-through-hosted-hci-in-nimble)
- [4.1.3. Bluetooth Host Receiving Data from Hosted HCI in NimBLE](#413-bluetooth-host-receiving-data-from-hosted-hci-in-nimble)
- [4.2. Transporting HCI data using UART](#42-transporting-hci-data-using-uart)
- [4.2.1. Bluetooth Host HCI Initialization](#421-bluetooth-host-hci-initialization)
- [4.2.2. Bluetooth Host Sending Data using HCI](#422-bluetooth-host-sending-data-using-hci)
- [4.2.3. Bluetooth Host Receiving Data using HCI](#423-bluetooth-host-receiving-data-using-hci)
- [5. BlueDroid Host Stack](#5-bluedroid-host-stack)
- [5.1. Transporting HCI data using Hosted HCI in BlueDroid](#51-transporting-hci-data-using-hosted-hci-in-bluedroid)
- [5.1.1. Bluetooth Host Hosted HCI Initialization](#511-bluetooth-host-hosted-hci-initialization)
- [5.1.2. Bluetooth Host Sending Data through Hosted HCI in BlueDroid](#512-bluetooth-host-sending-data-through-hosted-hci-in-bluedroid)
- [5.1.3. Bluetooth Host Receiving Data from Hosted HCI in BlueDroid](#513-bluetooth-host-receiving-data-from-hosted-hci-in-bluedroid)
- [5.2. Transporting HCI data using UART](#52-transporting-hci-data-using-uart)
- [5.2.1. Bluetooth Host HCI Initialization](#521-bluetooth-host-hci-initialization)
- [5.2.2. Bluetooth Host Sending Data using HCI](#522-bluetooth-host-sending-data-using-hci)
- [5.2.3. Bluetooth Host Receiving Data using HCI](#523-bluetooth-host-receiving-data-using-hci)
- [6. Configuring the Co-processor for Standard HCI over UART](#6-configuring-the-co-processor-for-standard-hci-over-uart)
- [7. References](#7-references)
## 1. Introduction
ESP-Hosted can transport Bluetooth HCI packets between the Bluetooth
Host on the Hosted Master and the Bluetooth Controller on the Hosted
Co-processor. The Host MCU implement the Bluetooth app and Bluetooth
Host Stack and the co-processor runs the Bluetooth controller and
hardware.
> [!NOTE]
> Check that the memory requirement for your preferred Bluetooth host
> stack can be satisfied on the Host.
> [!WARNING]
> The ESP32 only supports Bluetooth v4.2. If you are using a ESP32 as
> the co-processor, the host Bluetooth stack must also be v4.2.
ESP-Hosted is Bluetooth stack agnostic. To showcase ESP-Hosted's
Bluetooth support, both `esp-nimble` and `esp-bluedroid` are used
here. Users can use their own preferred Bluetooth stack with some
porting effort.
`esp-nimble` is a fork of Apache NimBLE and available from
ESP-IDF. The NimBLE Bluetooth stack provides Bluetooth Low Energy (BLE)
only functionality.
`esp-bluedroid` is a fork of the Bluedroid based stack and available
from ESP-IDF. The BlueDroid stack supports classic Bluetooth as well
as Bluetooth Low Energy.
See [References](#7-references) for links with more information.
### 1.1 Choosing a Bluetooth Host stack
For usecases involving classic Bluetooth as well as Bluetooth Low
Energy, BlueDroid should be used.
For Bluetooth Low Energy-only usecases, using NimBLE is
recommended. It is less demanding in terms of code footprint and
runtime memory, making it suitable for such scenarios.
## 2. Bluetooth Controller
ESP-Hosted uses the Bluetooth controller running on the co-processor.
As ESP-Hosted is just the communication medium, it supports both
Classic BT and BLE controllers. The controller available depends upon
the ESP chipset chosen. As of today, ESP32 supports Classic-BT+BLE,
whereas, the other ESP chipsets support BLE only.
## 3. Bluetooth Interface
Hosted provides two ways to let the Bluetooth stack running on the
Host to communicate with the Bluetooth controller on the co-processor:
Standard HCI and Hosted HCI.
**Standard HCI**
Standard HCI works in dedicated mode. Bluetooth traffic cannot be
multiplexed with other traffic, so a dedicated transport is
needed. Bluetooth HCI frames are transferred over the dedicated
transport.
- standard HCI is a transparent way of handling HCI messages
- HCI messages originating from the Bluetooth stack on the Host are
sent through an interface (like UART) directly to the Bluetooth
controller on the co-processor.
- requires extra GPIOs for the standard HCI interface, independent of
the GPIOs used for the ESP-Hosted interface
Use this option if you want:
- transparency: no extra data added to the HCI messages
- portability: because it is standard HCI, you can replace the
co-processor with any other co-processor (ESP or otherwise) that has
a Bluetooth controller
**Hosted HCI**
Hosted HCI is Standard HCI encapsulated for transport over
ESP-Hosted. Bluetooth traffic is multiplexed with other traffic types
on the same transport, each with different Interface types. See the [traffic
types](../README.md#72-interface-types) support by ESP-Hosted message
headers.
- Hosted HCI is standard HCI with extra headers or metadata added
- Hosted HCI embeds the ESP-Hosted header and re-uses the underlying
ESP-Hosted transport, such as SPI/SDIO
- this option is easier to set up. Once the existing ESP-Hosted
Transport (SPI or SDIO, for example) has been set up, Bluetooth
just works
Use this option if you want:
- complete control of Bluetooth messages
- extra flexibility of debugging
- no extra GPIOs (required for Standard HCI)
> [!NOTE]
> If Hosted HCI is configured as the Bluetooth transport, then your
> Bluetooth over Standard HCI configuration must be disabled, and vice
> versa.
## 4. NimBLE Host Stack
The ESP-Hosted Master implements the set of API calls required by the
NimBLE Bluetooth stack to initialize, send and receive Bluetooth data:
- `hci_drv_init`
- `ble_transport_ll_init`
- `ble_transport_to_ll_acl_impl`
- `ble_transport_to_ll_cmd_impl`
- `ble_transport_to_hs_evt`
- `ble_transport_to_hs_acl`
The following sequence diagrams show how to send and receive Bluetooth
on both the Hosted Master and co-processor.
### 4.1. Transporting HCI data using Hosted HCI in NimBLE
#### 4.1.1. Bluetooth Host Hosted HCI Initialization
```mermaid
sequenceDiagram
box rgb(128, 128, 128) Hosted Master
participant ble as NimBLE Host Bluetooth Stack
participant hhci as Hosted HCI Driver
participant master as SPI/SDIO Interface
end
box rgb(128, 128, 128) Hosted Co-processor
participant sinterface as SPI/SDIO Interface
participant slave as Bluetooth Controller
end
ble ->> +hhci : hci_drv_init()
Note over hhci: do any init required
hhci -->> -ble :
ble ->> +hhci : ble_transport_ll_init()
Note over hhci : do any transport init required
hhci -->> -ble :
```
**Bluetooth Host Initialization**
#### 4.1.2. Bluetooth Host Sending Data through Hosted HCI in NimBLE
```mermaid
sequenceDiagram
box rgb(128, 128, 128) Hosted Master
participant ble as NimBLE Host Bluetooth Stack
participant hhci as Hosted HCI Driver
participant master as SPI/SDIO Interface
end
box rgb(128, 128, 128) Hosted Co-processor
participant sinterface as SPI/SDIO Interface
participant slave as Bluetooth Controller
end
ble ->> +hhci : ble_transport_to_ll_acl_impl()
Note over hhci : convert ACL data to HCI
hhci ->> +master : esp_hosted_tx()
Note over master : add Hosted header
master ->> +sinterface: SPI/SDIO
Note over master,sinterface : (Hosted HCI data)
master -->> -hhci :
hhci -->> -ble :
Note over sinterface : remove Hosted header
sinterface ->> -slave : HCI data
```
**Bluetooth Host Sending Data**
#### 4.1.3. Bluetooth Host Receiving Data from Hosted HCI in NimBLE
```mermaid
sequenceDiagram
box rgb(128, 128, 128) Hosted Master
participant ble as NimBLE Host Bluetooth Stack
participant hhci as Hosted HCI Driver
participant master as SPI/SDIO Interface
end
box rgb(128, 128, 128) Hosted Co-processor
participant sinterface as SPI/SDIO Interface
participant slave as Bluetooth Controller
end
slave ->> +sinterface : HCI data
Note over sinterface : Add Hosted header
sinterface ->> -master : SPI/SDIO
Note over sinterface,master : (Hosted HCI data)
Note over master : Remove Hosted header
master ->> +hhci : hci_rx_handler()
alt Receive Event Data
Note over hhci: convert HCI data to Event
hhci ->> ble : ble_transport_to_hs_evt()
ble -->> hhci :
else Receive ACL Data
Note over hhci: convert HCI data to ACL
hhci ->> ble : ble_transport_to_hs_acl()
ble -->> hhci :
end
hhci -->> -master :
```
**Bluetooth Host Receiving Data**
### 4.2. Transporting HCI data using UART
#### 4.2.1. Bluetooth Host HCI Initialization
```mermaid
sequenceDiagram
box rgb(128, 128, 128) Master
participant ble as NimBLE Host Bluetooth Stack
participant huart as UART Driver
end
box rgb(128, 128, 128) Co-processor
participant slave as Bluetooth Controller with UART Interface
end
ble ->> huart : hci_drv_init()
Note over huart : do any init required
huart -->> ble :
ble ->> huart : ble_transport_ll_init()
Note over huart : do any transport init required
huart --> ble :
```
**Bluetooth Host Initialization**
#### 4.2.2. Bluetooth Host Sending Data using HCI
```mermaid
sequenceDiagram
box rgb(128, 128, 128) Master
participant ble as NimBLE Host Bluetooth Stack
participant huart as UART Driver
end
box rgb(128, 128, 128) Co-processor
participant slave as Bluetooth Controller with UART Interface
end
ble ->> huart : ble_transport_to_ll_acl_impl()
Note over huart : convert ACL data to HCI
huart ->> slave : UART TX
Note over huart,slave : (standard HCI)
huart -->> ble :
```
**Bluetooth Host Sending Data**
#### 4.2.3. Bluetooth Host Receiving Data using HCI
```mermaid
sequenceDiagram
box rgb(128, 128, 128) Master
participant ble as NimBLE Host Bluetooth Stack
participant huart as UART Driver
end
box rgb(128, 128, 128) Co-processor
participant slave as Bluetooth Controller with UART Interface
end
slave ->> huart : UART RX
Note over slave,huart: (standard HCI)
alt Receive Event Data
Note over huart : convert HCI data to Event
huart ->> ble : ble_transport_to_hs_evt()
ble -->> huart :
else Receive ACL Data
Note over huart : convert HCI data to ACL
huart ->> ble : ble_transport_to_hs_acl()
ble -->> huart :
end
```
**Bluetooth Host Receiving Data**
## 5. BlueDroid Host Stack
ESP-Hosted implements the set of API calls required by the BlueDroid
Bluetooth stack to initialise, send and receive Bluetooth data.
- `hosted_hci_bluedroid_open`
- `hosted_hci_bluedroid_close`
- `hosted_hci_bluedroid_send`
- `hosted_hci_bluedroid_check_send_available`
- `hosted_hci_bluedroid_register_host_callback`
`hosted_hci_bluedroid_open` must be called by the application before
attaching the transport APIs to BlueDroid and starting BlueDroid. This
initializes the underlying transport.
`hosted_hci_bluedroid_register_host_callback` records the callback
provided by BlueDroid that is use to notify the Bluetooth stack of
incoming HCI data (as `notify_host_recv`).
The following sequence diagrams show how to send and receive Bluetooth
on both the Hosted Master and Co-processor.
### 5.1. Transporting HCI data using Hosted HCI in BlueDroid
#### 5.1.1. Bluetooth Host Hosted HCI Initialization
```mermaid
sequenceDiagram
box rgb(128, 128, 128) Hosted Master
participant bt as Host Application
participant hhci as Hosted HCI Driver
participant master as SPI/SDIO Interface
end
box rgb(128, 128, 128) Hosted Co-processor
participant sinterface as SPI/SDIO Interface
participant slave as Bluetooth Controller
end
bt ->> +hhci : hosted_hci_bluedroid_open()
Note over hhci: do any init required
hhci -->> -bt :
```
**Bluetooth Host Initialization**
#### 5.1.2. Bluetooth Host Sending Data through Hosted HCI in BlueDroid
```mermaid
sequenceDiagram
box rgb(128, 128, 128) Hosted Master
participant bt as BlueDroid Host Bluetooth Stack
participant hhci as Hosted HCI Driver
participant master as SPI/SDIO Interface
end
box rgb(128, 128, 128) Hosted Co-processor
participant sinterface as SPI/SDIO Interface
participant slave as Bluetooth Controller
end
bt ->> +hhci : hosted_hci_bluedroid_send()
Note over hhci : HCI data
hhci ->> +master : esp_hosted_tx()
Note over master : add Hosted header
master ->> +sinterface: SPI/SDIO
Note over master,sinterface : (Hosted HCI data)
master -->> -hhci :
hhci -->> -bt :
Note over sinterface : remove Hosted header
sinterface ->> -slave : HCI data
```
**Bluetooth Host Sending Data**
#### 5.1.3. Bluetooth Host Receiving Data from Hosted HCI in BlueDroid
```mermaid
sequenceDiagram
box rgb(128, 128, 128) Hosted Master
participant bt as BlueDroid Host Bluetooth Stack
participant hhci as Hosted HCI Driver
participant master as SPI/SDIO Interface
end
box rgb(128, 128, 128) Hosted Co-processor
participant sinterface as SPI/SDIO Interface
participant slave as Bluetooth Controller
end
slave ->> +sinterface : HCI data
Note over sinterface : Add Hosted header
sinterface ->> -master : SPI/SDIO
Note over sinterface,master : (Hosted HCI data)
Note over master : Remove Hosted header
master ->> +hhci : hci_rx_handler()
hhci ->> bt : notify_host_recv()
Note over hhci, bt: HCI data
hhci -->> -master :
```
**Bluetooth Host Receiving Data**
### 5.2. Transporting HCI data using UART
When using BlueDroid Host Bluetooth Stack with UART, UART functions
that do the following are required:
- `uart_open` to open the UART driver and initialise the UART (set GPIOs, Baud Rate, etc.)
- `uart_tx` to transmit data over UART
- `UART RX` is a thread that waits for incoming UART data
- `notify_host_recv` is a BlueDroid callback registered with `UART RX` to receive UART data
`uart_open` is called before starting BlueDroid, while `uart_tx` and
`notify_host_recv` are registered by BlueDroid with the UART Driver. See this [ESP-IDF BlueDroid Example using UART](https://github.com/espressif/esp-idf/tree/master/examples/bluetooth/bluedroid/bluedroid_host_only/bluedroid_host_only_uart) for an example implementation.
#### 5.2.1. Bluetooth Host HCI Initialization
```mermaid
sequenceDiagram
box rgb(128, 128, 128) Master
participant bt as Host Application
participant huart as UART Driver
end
box rgb(128, 128, 128) Co-processor
participant slave as Bluetooth Controller with UART Interface
end
bt ->> +huart : uart_open()
Note over huart: do any uart init required
huart -->> -bt :
```
**Bluetooth Host Initialization**
#### 5.2.2. Bluetooth Host Sending Data using HCI
```mermaid
sequenceDiagram
box rgb(128, 128, 128) Master
participant bt as BlueDroid Host Bluetooth Stack
participant huart as UART Driver
end
box rgb(128, 128, 128) Co-processor
participant slave as Bluetooth Controller with UART Interface
end
bt ->> huart : uart_tx()
huart ->> slave : UART TX
Note over huart,slave : (standard HCI)
huart -->> bt :
```
**Bluetooth Host Sending Data**
#### 5.2.3. Bluetooth Host Receiving Data using HCI
```mermaid
sequenceDiagram
box rgb(128, 128, 128) Master
participant bt as BlueDroid Host Bluetooth Stack
participant huart as UART Driver
end
box rgb(128, 128, 128) Co-processor
participant slave as Bluetooth Controller with UART Interface
end
slave ->> huart : UART RX
Note over slave,huart: (standard HCI)
huart ->> bt : notify_host_recv()
Note over huart, bt: HCI data
bt -->> huart:
```
**Bluetooth Host Receiving Data**
## 6. Configuring the Co-processor for Standard HCI over UART
Standard HCI over UART setup is done through the Bluetooth Component
kconfig settings. In menuconfig, select `Component config` ->
`Bluetooth` -> `Controller Options` -> `HCI mode` or `HCI Config` and
set it to `UART(H4)`.
Depending on the selected co-processor, you can configure various UART
parameters (Tx, Rx pins, hardware flow control, RTS, CTS pins,
baudrate) through the Bluetooth Component. Other UART parameters not
handled by the Bluetooth Component are configured by ESP-Hosted
through `Example Configuration` -> `HCI UART Settings`.
> [!NOTE]
> Make sure the Standard HCI UART GPIO pins selected do not conflict
> with the GPIO pins used for the selected ESP-Hosted transport.
## 7. References
- esp-nimble: https://github.com/espressif/esp-nimble
- ESP-IDF NimBLE-based Host APIs: https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/bluetooth/nimble/index.html
- Bluetooth API: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/bluetooth/index.html
- ESP-IDF example using NimBLE on Host to send HCI through UART to co-processor: https://github.com/espressif/esp-idf/tree/master/examples/bluetooth/nimble/bleprph_host_only
- ESP-IDF example using BlueDroid on Host to send HCI through UART to co-processor: https://github.com/espressif/esp-idf/tree/master/examples/bluetooth/bluedroid/bluedroid_host_only/bluedroid_host_only_uart

View File

@@ -0,0 +1,195 @@
# Design Considerations and Debugging ESP-Hosted
**Table of Contents**
- [1. Choosing the Correct ESP chip as Slave](#1-choosing-the-correct-esp-chip-as-slave)
- [1.1. Using ESP chip as Hosted Master](#11-using-esp-chip-as-hosted-master)
- [2. General Hardware Considerations](#2-general-hardware-considerations)
- [2.1. GPIOs used for interface](#21-gpios-used-for-interface)
- [2.2. Using SPI insted of SDIO](#22-using-spi-insted-of-sdio)
- [2.3. Whenever possible, Use `IO_MUX` GPIOs.](#23-whenever-possible-use-io_mux-gpios)
- [2.4. Signal Length and Noise Reduction](#24-signal-length-and-noise-reduction)
- [3. General Debugging Guidelines](#3-general-debugging-guidelines)
- [3.1. Add tapping points to your PCB prototype](#31-add-tapping-points-to-your-pcb-prototype)
- [3.2. Tap out additional GPIO signals as testing points and future expansion](#32-tap-out-additional-gpio-signals-as-testing-points-and-future-expansion)
- [3.3. Verifying Hosted Interface with Raw Throughput](#33-verifying-hosted-interface-with-raw-throughput)
- [4. Others](#4-others)
- [5. References](#5-references)
There are several considerations that need to be taken into account
when implementing ESP-Hosted for your system.
## 1 Choosing the Correct ESP chip as Slave
For prototyping, any ESP32 chip can be used as the slave, provided it
has the required interface (SPI, SDIO). But when creating an actual
product, it is important to select the proper ESP32 chip as a Hosted
Slave.
There are many ESP32 chips, each with difference features and
performance capabilities. Based on your product requirements
(interface to use, CPU, memory, power requirements, etc.), choose the
ESP32 chip(s) that can meet your requirements.
Use the ESP Product Selector guide to help you decide which ESP32
chips and/or modules are suitable for your product.
> [!NOTE]
> See [References](#5-references) for links to the Selector Guide
> and other links.
## 1.1 Using ESP chip as Hosted Master
The project defaults to using an ESP chip as the Hosted Master. This
is to act as a reference platform and make it easier to evaluate and
test Hosted before porting it to your MCU of choice.
## 2 General Hardware Considerations
### 2.1 GPIOs used for interface
Make sure the correct GPIOs pins on the Hosted Slave and Master are
connected together. Verify that the correct GPIOs are set-up in
`Menuconfig` for both the Slave and Master.
> [!NOTE]
> In general most ESP GPIOs can be used for input and output. But on
> the ESP32, some GPIOs can only be used for input and are not usable
> under Hosted. Check the ESP datasheet to verify the GPIOs you select
> can be used as a Hosted interface.
### 2.2 Evaluate with jumpers first
It is flexible to evaluate with jumper cables or bread board than full-fledged PCB.
In general, SPI (Standard & Dual SPI) imposes fewer hardware requirements compared to
SDIO. SPI is easier to prototype, and available on more ESP chips and
MCUs compared to SDIO.
Before going to SDIO 4 bit mode PCB, it's better to evaluate SDIO 1-Bit mode.
Once you evaluate the solution on jumper cables, you can move to PCB solutions with same or high performance transport.
###### Jumper cable considerations
- Use high quality jumper cables
- Use jumper cables as small as possible. you can cut and solder the joints if need be.
- Use equal length jumper cables for all the connections
- Grounds: Connect as many grounds as possible, this lowers the interference.
- Jumper cable lengths
- Standard SPI: At max 10cm, lower the better
- Dual SPI: At max 10cm, lower the better
- SDIO 1 Bit: At max 5cm, lower the better
- Quad SPI : jumpers not supported, only PCB
- SDIO 4 Bit: Jumpers not supported, only PCB
### 2.3 Whenever possible, Use `IO_MUX` GPIOs.
In general, ESP peripheral interfaces can be assigned to any available
GPIO through a multiplexer. But some ESPs have dedicated GPIOs for
peripherals (`IO_MUX`). These `IO_MUX` GPIOs have better timing
characteristics and support higher frequencies. They should be use
when possible to minimise timing and skew issues when using the
interface for Hosted.
> [!NOTE]
> The SDIO interface on the ESP32 and ESP32-C6 have fixed GPIO
> assignments and cannot be changed.
### 2.4 Signal Length and Noise Reduction
For best performance, a PCB with traces should be used to connect the
Hosted Slave and Master. For prototyping, jumper cables can be used,
but may only work at a lower `CLK` frequency.
In general, keep the cable and PCB traces short and of the same
length, to minimise propogation delay and clock skew:
- for SPI, keep them to 10 cm or less
- for SDIO, keep them to 5 cm or less
Isolate the interface signals, expecially the `CLK` signal, from other
signals. For PCBs, surround the signal swith a ground plane, and keep
the `CLK` signal clean by not routing it close to other high frequency
signals.
For jumper cables, you can try surrounding the signals, especially the
`CLK` signal, with grounded wires to shield them from interference.
> [!NOTE]
> For SDIO, external pull-up resistors (recommended value: 51 kOhms)
> are required. Using jumper cable are **not** recommended for SDIO. You
> may be able to get SDIO working with jumper cables by using a lower
> `CLK` frequency and using 1-bit SDIO mode.
> [!NOTE]
> Also check the Hosted documentation for SPI and SDIO for more
> information and guidelines on the interfaces.
## 3 General Debugging Guidelines
### 3.1 Add tapping points to your prototype
Adding tapping points or headers to the Hosted interface signals on
your prototype will make it easier to check whether the Hosted
interface is working as expected.
### 3.2 Tap out additional GPIO signals as testing points and future expansion
Add tapping points to some unused GPIOs on both the Hosted Slave and
Host on your prototype PCB. This can later be use for debugging or
enhancing your own Hosted code.
For example, add your own debugging code to the Hosted Slave and
Master code to set a GPIO value when a condition is met. This GPIO can
be used to light a LED or trigger a capture on an oscilloscope or
logic analyzer, for example. This is useful for capturing rare or
intermittent conditions while testing Hosted.
In the future, Hosted may also offer newer transport options or more features, like controlling
power modes on the Host and Slave. These may require additional GPIOs
for control, so it would be good to keep some additional GPIOs
available and accesable for future use.
### 3.3 Verifying Hosted Interface with Raw Throughput
ESP-Hosted has a Raw Throughput Option to test sending of data between
the Host and Slave. This can be used to verify the hardware for signal
errors and to check the achievable throughput of Hosted.
> [!IMPORTANT]
> Use this option to verify that Hosted hardware and software are
> working as expected before involving other software layers like
> networking.
To enable the Raw Throughput Option on Slave, enter `Menuconfig` and
enable **Example Configuration** ---> **Hosted Debugging** --->
**RawTP**.
To enable the Raw Throughput Option and set Raw Throughput direction
on Host, enter `Menuconfig` and enable **Component config** --->
**ESP-Hosted config** ---> **Debug Settings** ---> **RawTP**. Set
the data transfer direction: **Host to Slave**, **Slave to Host** or
**Bidirectional**.
## 4 Others
Check the References below for links to the Product Selector, and more
detailed information on the interfaces used in Hosted. If you have
other issues with Hosted, you can check the Troubleshooting Guide.
You can also raise an Issue on the ESP-Hosted Github repository. Check
that the issue has not already been raised before submitting. The
solution to your problem may have already been provided.
## 5 References
**External Links**
- ESP Product Selector: https://products.espressif.com/
- ESP-Hosted Github Issues: https://github.com/espressif/esp-hosted-mcu/issues
**ESP-Hosted Documentation Links**
- SPI Full Duplex interface documentation: [spi_full_duplex.md](spi_full_duplex.md)
- SDIO interface documentation: [sdio.md](sdio.md)
- SPI Half Duplex interface documentation: [spi_half_duplex.md](spi_half_duplex.md)
- UART documentation: [uart.md](uart.md)
- Troubleshooting Guide: [troubleshooting.md](troubleshooting.md)

View File

@@ -0,0 +1,393 @@
# ESP-Hosted on the ESP32-P4-Function-EV-Board DevKit
<details>
<summary>Table of Contents</summary>
- [1. Introduction](#1-introduction)
- [2. Set-Up ESP-IDF](#2-set-up-esp-idf)
- [3. Building Host for the P4](#3-building-host-for-the-p4)
- [Adding Components](#31-adding-components)
- [Configuring Defaults](#32-configuring-defaults)
- [Building Firmware](#33-building-firmware)
- [4. Checking ESP-Hosted](#4-checking-esp-hosted)
- [5. Flashing ESP32-C6](#5-flashing-esp32-c6)
- [Using ESP-Prog](#51-using-esp-prog)
- [OTA Updates](#52-ota-updates)
- [6. Troubleshooting](#6-troubleshooting)
- [7. Flashing the On-board ESP32-P4 through the ESP-Prog](#7-flashing-esp32-p4)
- [8. Testing ESP-Hosted with SPI-FD with other MCUs](#8-testing-esp-hosted-with-spi-fd-with-other-mcus)
- [9. References](#10-references)
</details>
## 1. Introduction
This page documents using ESP-Hosted-MCU on the ESP32-P4-Function-EV-Board. The board comes with an on-board ESP32-C6 module, pre-flashed with ESP-Hosted-MCU slave code (v0.0.6). The board provides a Wi-Fi connection to the on-board ESP32-P4, which acts as the host.
The image below shows the board.
<img src="images/esp32-p4-function-ev-board.jpg" alt="ESP32-P4-Function-EV-Board" width="800" />
*ESP32-P4-Function-EV-Board*
The ESP32-P4 communicates with the ESP32-C6 module using SDIO.
## 2. Set-Up ESP-IDF
As you have reached here, it is highly likely that you have already setup ESP-IDF.
If not done, Please set up ESP-IDF:
#### Option 1: Installer Way
- **Windows**
- Install and setup ESP-IDF on Windows as documented in the [Standard Setup of Toolchain for Windows](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/windows-setup.html).
- Use the ESP-IDF [Powershell Command Prompt](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/windows-setup.html#using-the-command-prompt) for subsequent commands.
- **Linux or MacOS**
- For bash:
```bash
bash docs/setup_esp_idf__latest_stable__linux_macos.sh
```
- For fish:
```fish
fish docs/setup_esp_idf__latest_stable__linux_macos.fish
```
#### Option 2: Manual Way
Please follow the [ESP-IDF Get Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html) for manual installation.
## 3. Building Host for the P4
### 3.1. Adding Components
Add `esp_wifi_remote` and `esp_hosted` components to the project:
```
idf.py add-dependency "espressif/esp_wifi_remote"
idf.py add-dependency "espressif/esp_hosted"
```
Remove 'esp-extconn' if present in `main/idf_component.yml`, as esp-extconn and esp-hosted cannot work together.
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]"
# -----------------------------------
```
It is always good to use `esp_wifi_remote` as it provides all the Wi-Fi config and a wrapper abstraction layer.
But you can also evaluate without using it.
> [!IMPORTANT]
> Co-processor selection is done by wifi-remote. Ensure the correct
> co-processor chip is selected in `Component config` -> `Wi-Fi
> Remote` -> `choose slave target`. The target selected will affect
> the ESP-Hosted transport options and default GPIOs used.
### 3.2. Configuring Defaults
Edit the `sdkconfig.defaults.esp32p4` file such that, it would have following content:
```
#### Comment below two lines if present:
# CONFIG_ESP_HOST_WIFI_ENABLED=y
# CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
#### Add Wi-Fi Remote config for better performance:
CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=16
CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=64
CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM=64
CONFIG_ESP_WIFI_AMPDU_TX_ENABLED=y
CONFIG_ESP_WIFI_TX_BA_WIN=32
CONFIG_ESP_WIFI_AMPDU_RX_ENABLED=y
CONFIG_ESP_WIFI_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
```
### 3.3. Building Firmware
Set the ESP32-P4 as the target, build, flash the firmware and
(optionally) monitor ESP32-P4 console output:
```sh
idf.py set-target esp32p4
idf.py build
idf.py -p <Serial Port> flash monitor
```
## 4. Checking ESP-Hosted
When the P4 is running with Hosted, you should see console output similar to this after start-up:
```
I (498) H_API: esp_wifi_remote_init
I (498) transport: Attempt connection with slave: retry[0]
I (498) transport: Reset slave using GPIO[54]
I (498) os_wrapper_esp: GPIO [54] configured
I (508) gpio: GPIO[54]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
I (1678) sdio_wrapper: SDIO master: Data-Lines: 4-bit Freq(KHz)[40000 KHz]
I (1678) sdio_wrapper: GPIOs: CLK[18] CMD[19] D0[14] D1[15] D2[16] D3[17] Slave_Reset[54]
I (1678) H_SDIO_DRV: Starting SDIO process rx task
I (1678) sdio_wrapper: Queues: Tx[20] Rx[20] SDIO-Rx-Mode[3]
I (1718) gpio: GPIO[15]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (1718) gpio: GPIO[17]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
Name:
Type: SDIO
Speed: 40.00 MHz (limit: 40.00 MHz)
Size: 0MB
CSD: ver=1, sector_size=0, capacity=0 read_bl_len=0
SCR: sd_spec=0, bus_width=0
TUPLE: DEVICE, size: 3: D9 01 FF
TUPLE: MANFID, size: 4
MANF: 0092, CARD: 6666
TUPLE: FUNCID, size: 2: 0C 00
TUPLE: FUNCE, size: 4: 00 00 02 32
TUPLE: CONFIG, size: 5: 01 01 00 02 07
TUPLE: CFTABLE_ENTRY, size: 8
INDX: C1, Intface: 1, Default: 1, Conf-Entry-Num: 1
IF: 41
FS: 30, misc: 0, mem_space: 1, irq: 1, io_space: 0, timing: 0, power: 0
IR: 30, mask: 1, IRQ: FF FF
LEN: FFFF
TUPLE: END
I (1768) sdio_wrapper: Function 0 Blocksize: 512
I (1778) sdio_wrapper: Function 1 Blocksize: 512
I (1778) H_SDIO_DRV: SDIO Host operating in PACKET MODE
I (1788) H_SDIO_DRV: generate slave intr
I (1798) transport: Received INIT event from ESP32 peripheral
I (1798) transport: EVENT: 12
I (1798) transport: EVENT: 11
I (1808) transport: capabilities: 0xd
I (1808) transport: Features supported are:
I (1818) transport: * WLAN
I (1818) transport: - HCI over SDIO
I (1818) transport: - BLE only
I (1828) transport: EVENT: 13
I (1828) transport: ESP board type is : 13
I (1838) transport: Base transport is set-up
I (1838) transport: Slave chip Id[12]
I (1848) hci_stub_drv: Host BT Support: Disabled
I (1848) H_SDIO_DRV: Received INIT event
I (1868) rpc_wrap: Received Slave ESP Init
```
## 5. Flashing ESP32-C6
ESP32-C6 flashing is totally **optional**, as C6 is expected to be pre-flashed with ESP-Hosted slave firmware, 0.0.6. If you wish to get updated ESP-Hosted slave firmware, you can flash it using two ways, Either with ESP-Prog on ESP32-C6, or using OTA update configured using web server.
### 5.1 OTA Updates
To update the ESP32-C6 slave module using Over-The-Air (OTA) updates, follow these steps:
1. Build the ESP-Hosted slave firmware for the ESP32-C6 module:
```
idf.py create-project-from-example "espressif/esp_hosted:slave"
```
2. Set the target and start `Menuconfig`:
```sh
idf.py set-target esp32c6
idf.py menuconfig
```
3. Under **Example Configuration**, ensure that the Hosted transport
selected is `SDIO`.
4. Build the firmware:
```sh
idf.py build
```
5. Upload the firmware (the build/network_adapter.bin file) to a server or a local directory accessible via HTTP.
6. On the ESP32-P4 host, add the following code to your application to initiate the OTA update:
```
#include "esp_hosted.h"
esp_err_t esp_hosted_slave_ota(const char *url);
```
7. Call the `esp_hosted_slave_ota` function with the URL of the firmware binary:
```
esp_err_t err = esp_hosted_slave_ota("http://example.com/path/to/network_adapter.bin");
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to start OTA update: %s", esp_err_to_name(err));
}
```
8. Monitor the console output to see the OTA update progress.
### 5.2 Using ESP-Prog
> [!NOTE]
> ESP-Prog is only required if you want to flash firmware to the
> ESP32-C6 module using the standard ESP Tools.
This step is optional, as C6 is expected to be pre-flashed with ESP-Hosted slave firmware, 0.0.6.
The image below shows the board with an ESP-Prog connected to the
header to communicate with the on-board ESP32-C6..
<img src="images/esp32-p4-function-ev-board-esp-prog.jpg" alt="ESP32-P4-Function-EV-Board with ESP-Prog Connected to ESP32-C6" width="800" />
*ESP32-P4-Function-EV-Board with ESP-Prog Connected to ESP32-C6*
If you need to update the ESP-Hosted slave firmware on the on-board
ESP32-C6 module using ESP-Prog, follow these steps:
1. Check out the ESP-Hosted slave example project:
```
idf.py create-project-from-example "espressif/esp_hosted:slave"
```
2. Set the target and start `Menuconfig`:
```sh
idf.py set-target esp32c6
idf.py menuconfig
```
3. Under **Example Configuration**, ensure that the Hosted transport
selected is `SDIO`.
4. Build the firmware:
```sh
idf.py build
```
5. Connect the Program Header on the ESP-Prog to the `PROG_C6` header
on the board. The connections are as follows:
| ESP-Prog | PROG_C6 | Notes |
| --- | --- | --- |
| ESP\_EN | EN | |
| ESP\_TXD | TXD | |
| ESP\_RXD | RXD | |
| VDD | - | Do not connect |
| GND | GND | |
| ESP\_IO0 | IO0 | |
6. Flashing the firmware
The on-board ESP32-P4 controls the reset signal for the ESP32-C6. To
prevent the P4 interfering with the C6 while flashing (by asserting
the C6 Reset signal during the firmware download), set the P4 into
Bootloader mode before flashing the firmware to the C6:
###### Manual Way
1. hold down the `BOOT` button on the board
2. press and release the `RST` button on the board
3. release the `BOOT` button
###### Script Way
```sh
esptool.py -p <host_serial_port> --before default_reset --after no_reset run
```
You can now flash the firmware to the C6 (and monitor the console
output):
```sh
idf.py -p <Serial Port> flash monitor
```
## 6. Troubleshooting
If you encounter issues with using ESP-Hosted, see the following guide:
- [Troubleshooting Guide](troubleshooting.md)
<details>
<summary>Flashing the On-board ESP32-P4 through the Serial Interface</summary>
## 7. Flashing the On-board ESP32-P4 through the ESP-Prog
The USB connector on the board is the standard method for flashing the
firmware to the P4. An alternative method is to flash the P4 through
its serial interface using a ESP-Prog.
The image below shows the connection between the ESP-Prog and the
serial port pins on the P4 header for programming.
<img src="images/esp32-p4-esp-prog.jpg" alt="ESP32-P4 Serial Connection with ESP-Prog" width="600" />
*ESP32-P4 Serial Connection with ESP-Prog*
The connection between the ESP-Prog and the P4 header is as follows:
| ESP-Prog | P4 Header |
| --- | --- |
| ESP\_TXD | U0TXD (GPIO 37) |
| ESP\_RXD | U0RXD (GPIO 38) |
| GND | GND |
Leave the other ESP-Prog connected unconnected.
To flash the P4:
1. hold down the `BOOT` button on the board
2. press and release the `RST` button on the board
3. release the `BOOT` button
You can now flash the firmware (and monitor the console output):
```sh
idf.py -p <Serial Port> flash monitor
```
To restart the P4 after flashing, press and release the `RST` button
on the board.
</details>
## 8. Testing ESP-Hosted with SPI-FD with other MCUs
You can use SPI-FD (Full Duplex) on the ESP32-P4 to test ESP-Hosted with other ESP32s. Do this by connecting the ESP32 to the P4 through the J1 GPIO header on the ESP32-P4 DevKit.
Use GPIOs 36 or lower on the P4 DevKit to avoid LDO power issues with high numbered GPIOs. Here is one combination on GPIOs that can be used on the P4:
| Function | GPIO |
|------------|------|
| MOSI | 4 |
| MISO | 5 |
| CLK | 26 |
| CS | 6 |
| Handshake | 20 |
| Data Ready | 32 |
| Reset | 2 |
> [!NOTE]
> Avoid using GPIO 35 and 36 as they affect the ESP32-P4 Bootloader Mode. See [ESP32-P4 Boot Mode Selection](https://docs.espressif.com/projects/esptool/en/latest/esp32p4/advanced-topics/boot-mode-selection.html#select-bootloader-mode) for more information.
> [!TIP]
>
> To measure the optimal performance, check out the [Shield Box Test Setup](shield-box-test-setup.md).
## 9. References
- ESP32-P4-Function-EV-Board: https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32p4/esp32-p4-function-ev-board/
- ESP-Prog: https://docs.espressif.com/projects/esp-iot-solution/en/latest/hw-reference/ESP-Prog_guide.html
- `esp_wifi_remote` component: https://components.espressif.com/components/espressif/esp_wifi_remote/
- `esp_hosted` component: https://components.espressif.com/components/espressif/esp_hosted/

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

View File

@@ -0,0 +1,53 @@
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg
xmlns='http://www.w3.org/2000/svg'
width='630'
height='728'
shape-rendering='geometricPrecision'
version='1.0'>
<defs>
<filter id='f2' x='0' y='0' width='200%' height='200%'>
<feOffset result='offOut' in='SourceGraphic' dx='5' dy='5' />
<feGaussianBlur result='blurOut' in='offOut' stdDeviation='3' />
<feBlend in='SourceGraphic' in2='blurOut' mode='normal' />
</filter>
</defs>
<g stroke-width='1' stroke-linecap='square' stroke-linejoin='round'>
<rect x='0' y='0' width='630' height='728' style='fill: #ffffff'/>
<path stroke='#000000' stroke-width='1.000000' stroke-linecap='round' stroke-linejoin='round' fill='white' d='M85.0 294.0 Q85.0 301.0 90.0 301.0 L490.0 301.0 Q495.0 301.0 495.0 294.0 L495.0 42.0 L495.0 42.0 Q495.0 35.0 490.0 35.0 L90.0 35.0 L90.0 35.0 Q85.0 35.0 85.0 42.0 L85.0 294.0 z' />
<path stroke='#000000' stroke-width='1.000000' stroke-linecap='round' stroke-linejoin='round' fill='white' d='M90.0 385.0 Q85.0 385.0 85.0 392.0 L85.0 588.0 Q85.0 595.0 90.0 595.0 L490.0 595.0 L490.0 595.0 Q495.0 595.0 495.0 588.0 L495.0 392.0 L495.0 392.0 Q495.0 385.0 490.0 385.0 L90.0 385.0 z' />
<path stroke='#000000' stroke-width='1.000000' stroke-linecap='round' stroke-linejoin='round' fill='white' d='M115.0 84.0 Q115.0 77.0 120.0 77.0 L460.0 77.0 Q465.0 77.0 465.0 84.0 L465.0 238.0 L465.0 238.0 Q465.0 245.0 460.0 245.0 L120.0 245.0 L120.0 245.0 Q115.0 245.0 115.0 238.0 L115.0 84.0 z' />
<path stroke='#000000' stroke-width='1.000000' stroke-linecap='round' stroke-linejoin='round' fill='white' d='M120.0 441.0 Q115.0 441.0 115.0 448.0 L115.0 546.0 Q115.0 553.0 120.0 553.0 L460.0 553.0 L460.0 553.0 Q465.0 553.0 465.0 546.0 L465.0 448.0 L465.0 448.0 Q465.0 441.0 460.0 441.0 L120.0 441.0 z' />
<path stroke='#000000' stroke-width='1.000000' stroke-linecap='round' stroke-linejoin='round' fill='#eeeeee' d='M115.0 133.0 L115.0 84.0 Q115.0 77.0 120.0 77.0 L460.0 77.0 L460.0 77.0 Q465.0 77.0 465.0 84.0 L465.0 133.0 L465.0 133.0 z' />
<path stroke='#000000' stroke-width='1.000000' stroke-linecap='round' stroke-linejoin='round' fill='#aaffff' d='M115.0 189.0 L115.0 238.0 Q115.0 245.0 120.0 245.0 L460.0 245.0 L460.0 245.0 Q465.0 245.0 465.0 238.0 L465.0 189.0 L465.0 189.0 z' />
<path stroke='#000000' stroke-width='1.000000' stroke-linecap='round' stroke-linejoin='round' fill='#aaffff' d='M120.0 441.0 Q115.0 441.0 115.0 448.0 L115.0 497.0 L465.0 497.0 L465.0 448.0 Q465.0 441.0 460.0 441.0 L120.0 441.0 z' />
<path stroke='#000000' stroke-width='1.000000' stroke-linecap='round' stroke-linejoin='round' fill='#eeeeee' d='M285.0 189.0 L465.0 189.0 L465.0 133.0 L285.0 133.0 z' />
<path stroke='#000000' stroke-width='1.000000' stroke-linecap='round' stroke-linejoin='round' fill='#5555bb' d='M115.0 497.0 L115.0 546.0 Q115.0 553.0 120.0 553.0 L295.0 553.0 L295.0 553.0 L295.0 497.0 z' />
<path stroke='#000000' stroke-width='1.000000' stroke-linecap='round' stroke-linejoin='round' fill='#eeeeee' d='M115.0 133.0 L285.0 133.0 L285.0 189.0 L115.0 189.0 z' />
<path stroke='#000000' stroke-width='1.000000' stroke-linecap='round' stroke-linejoin='round' fill='#5555bb' d='M295.0 497.0 L295.0 553.0 L460.0 553.0 Q465.0 553.0 465.0 546.0 L465.0 497.0 L465.0 497.0 z' />
<path stroke='#000000' stroke-width='1.000000' stroke-linecap='round' stroke-linejoin='round' fill='#5555bb' d='M435.0 672.0 Q435.0 665.0 430.0 665.0 L390.0 665.0 Q385.0 665.0 385.0 672.0 L385.0 686.0 L385.0 686.0 Q385.0 693.0 390.0 693.0 L430.0 693.0 L430.0 693.0 Q435.0 693.0 435.0 686.0 L435.0 672.0 z' />
<path stroke='#000000' stroke-width='1.000000' stroke-linecap='round' stroke-linejoin='round' fill='#eeeeee' d='M70.0 665.0 Q75.0 665.0 75.0 672.0 L75.0 686.0 Q75.0 693.0 70.0 693.0 L30.0 693.0 L30.0 693.0 Q25.0 693.0 25.0 686.0 L25.0 672.0 L25.0 672.0 Q25.0 665.0 30.0 665.0 L70.0 665.0 z' />
<path stroke='#000000' stroke-width='1.000000' stroke-linecap='round' stroke-linejoin='round' fill='#aaffff' d='M205.0 686.0 Q205.0 693.0 210.0 693.0 L250.0 693.0 Q255.0 693.0 255.0 686.0 L255.0 672.0 L255.0 672.0 Q255.0 665.0 250.0 665.0 L210.0 665.0 L210.0 665.0 Q205.0 665.0 205.0 672.0 L205.0 686.0 z' />
<path stroke='none' stroke-width='1.000000' stroke-linecap='round' stroke-linejoin='round' fill='#000000' d='M285.0 308.0 L280.0 322.0 L290.0 322.0 z' />
<path stroke='none' stroke-width='1.000000' stroke-linecap='round' stroke-linejoin='round' fill='#000000' d='M280.0 364.0 L285.0 378.0 L290.0 364.0 z' />
<path stroke='#000000' stroke-width='1.000000' stroke-linecap='round' stroke-linejoin='round' fill='none' d='M595.0 623.0 L25.0 623.0 ' />
<path stroke='#000000' stroke-width='1.000000' stroke-linecap='round' stroke-linejoin='round' fill='none' d='M285.0 371.0 L285.0 315.0 ' />
<text x='223' y='418' font-family='Courier' font-size='14' stroke='none' fill='#000000' ><![CDATA[ESP (Hosted Slave)]]></text>
<text x='242' y='474' font-family='Courier' font-size='14' stroke='none' fill='#000000' ><![CDATA[ESP Firmware]]></text>
<text x='319' y='530' font-family='Courier' font-size='14' stroke='none' fill='#ffffff' ><![CDATA[ESP HCI Driver]]></text>
<text x='450' y='684' font-family='Courier' font-size='14' stroke='none' fill='#000000' ><![CDATA[Standard ESP IDF]]></text>
<text x='450' y='698' font-family='Courier' font-size='14' stroke='none' fill='#000000' ><![CDATA[components]]></text>
<text x='147' y='166' font-family='Courier' font-size='14' stroke='none' fill='#000000' ><![CDATA[TCP/IP Stack]]></text>
<text x='238' y='278' font-family='Courier' font-size='14' stroke='none' fill='#000000' ><![CDATA[Host MCU/MPU]]></text>
<text x='305' y='348' font-family='Courier' font-size='14' stroke='none' fill='#000000' ><![CDATA[SPI/SDIO/UART]]></text>
<text x='246' y='110' font-family='Courier' font-size='14' stroke='none' fill='#000000' ><![CDATA[Application]]></text>
<text x='230' y='222' font-family='Courier' font-size='14' stroke='none' fill='#000000' ><![CDATA[ESP Host Driver]]></text>
<text x='270' y='684' font-family='Courier' font-size='14' stroke='none' fill='#000000' ><![CDATA[ESP Hosted]]></text>
<text x='267' y='698' font-family='Courier' font-size='14' stroke='none' fill='#000000' ><![CDATA[components]]></text>
<text x='310' y='166' font-family='Courier' font-size='14' stroke='none' fill='#000000' ><![CDATA[Bluetooth Stack]]></text>
<text x='94' y='684' font-family='Courier' font-size='14' stroke='none' fill='#000000' ><![CDATA[3rd Party]]></text>
<text x='97' y='698' font-family='Courier' font-size='14' stroke='none' fill='#000000' ><![CDATA[components]]></text>
<text x='143' y='530' font-family='Courier' font-size='14' stroke='none' fill='#ffffff' ><![CDATA[ESP Wifi Driver]]></text>
<text x='24' y='642' font-family='Courier' font-size='14' stroke='none' fill='#000000' ><![CDATA[Legend]]></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

@@ -0,0 +1,48 @@
/----------------------------------------\
| |
| |
| /----------------------------------\ |
| | cEEE | |
| | Application | |
| | | |
| +----------------+-----------------+ |
| | cEEE |cEEE | |
| | TCP/IP Stack |Bluetooth Stack | |
| | | | |
| +----------------+-----------------+ |
| | | |
| | cAFF ESP Host Driver | |
| | | |
| \----------------------------------/ |
| |
| Host MCU/MPU |
| |
\----------------------------------------/
^
|
|SPI/SDIO/UART
|
v
/----------------------------------------\
| |
| ESP (Hosted Slave) |
| |
| /----------------------------------\ |
| | | |
| | cAFF ESP Firmware | |
| | | |
| +-----------------+----------------+ |
| |cBLU |cBLU | |
| |ESP Wifi Driver |ESP HCI Driver | |
| | | | |
| \-----------------+----------------/ |
| |
| |
\----------------------------------------/
----------------------------------------------------------
Legend
/----\ /----\ /----\
|cEEE|3rd Party |cAFF|ESP Hosted |cBLU| Standard ESP IDF
\----/ components \----/components \----/ components

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,49 @@
@startuml
skinparam BoxPadding 20
box "Host with ESP-Hosted" #LightBlue
participant Application as app
participant "Wi-Fi Remote" as remote
participant "ESP Hosted" as hostedh
participant "Host Transport" as transporth
end box
box "Slave ESP-Hosted" #LightGrey
participant "Slave Transport" as transports
participant "Slave Hosted" as hosteds
participant "ESP-IDF Wi-Fi Library" as api
participant "Wi-Fi Hardware" as wifi
end box
skinparam ArrowThickness 1
app -> remote : esp_wifi_xxx()
remote -> hostedh : esp_wifi_remote_xxx()
hostedh -> transporth
skinparam ArrowThickness 5
transporth -> transports : SPI/SDIO
skinparam ArrowThickness 1
transports -> hosteds
hosteds -> api : esp_wifi_xxx()
api -> wifi
wifi -> wifi : Wi-Fi action
wifi --> api : response
api --> hosteds : return value +\ndata (if any)
hosteds --> transports
skinparam ArrowThickness 5
transports --> transporth : SPI/SDIO
skinparam ArrowThickness 1
transporth --> hostedh
hostedh --> remote
remote --> app : return value +\ndata (if any)
@enduml

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentStyleType="text/css" height="258px" preserveAspectRatio="none" style="width:398px;height:258px;background:#FFFFFF;" version="1.1" viewBox="0 0 398 258" width="398px" zoomAndPan="magnify"><defs/><g><line style="stroke:#181818;stroke-width:0.5;stroke-dasharray:5.0,5.0;" x1="46" x2="46" y1="37.6094" y2="222.3672"/><line style="stroke:#181818;stroke-width:0.5;stroke-dasharray:5.0,5.0;" x1="173.4893" x2="173.4893" y1="37.6094" y2="222.3672"/><line style="stroke:#181818;stroke-width:0.5;stroke-dasharray:5.0,5.0;" x1="314.9375" x2="314.9375" y1="37.6094" y2="222.3672"/><rect fill="#E2E2F0" height="31.6094" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="82.4893" x="5" y="5"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="68.4893" x="12" y="26.5332">Application</text><rect fill="#E2E2F0" height="31.6094" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="82.4893" x="5" y="221.3672"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="68.4893" x="12" y="242.9004">Application</text><rect fill="#E2E2F0" height="31.6094" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="152.4482" x="97.4893" y="5"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="138.4482" x="104.4893" y="26.5332">ESP-IDF Wi-Fi Library</text><rect fill="#E2E2F0" height="31.6094" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="152.4482" x="97.4893" y="221.3672"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="138.4482" x="104.4893" y="242.9004">ESP-IDF Wi-Fi Library</text><rect fill="#E2E2F0" height="31.6094" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="111.2275" x="259.9375" y="5"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="97.2275" x="266.9375" y="26.5332">Wi-Fi Hardware</text><rect fill="#E2E2F0" height="31.6094" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="111.2275" x="259.9375" y="221.3672"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="97.2275" x="266.9375" y="242.9004">Wi-Fi Hardware</text><polygon fill="#181818" points="161.7134,65.9609,171.7134,69.9609,161.7134,73.9609,165.7134,69.9609" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="46.2446" x2="167.7134" y1="69.9609" y2="69.9609"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="82.3545" x="53.2446" y="65.1045">esp_wifi_xxx()</text><polygon fill="#181818" points="303.5513,79.9609,313.5513,83.9609,303.5513,87.9609,307.5513,83.9609" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="173.7134" x2="309.5513" y1="83.9609" y2="83.9609"/><line style="stroke:#181818;stroke-width:1.0;" x1="315.5513" x2="357.5513" y1="114.3125" y2="114.3125"/><line style="stroke:#181818;stroke-width:1.0;" x1="357.5513" x2="357.5513" y1="114.3125" y2="127.3125"/><line style="stroke:#181818;stroke-width:1.0;" x1="316.5513" x2="357.5513" y1="127.3125" y2="127.3125"/><polygon fill="#181818" points="326.5513,123.3125,316.5513,127.3125,326.5513,131.3125,322.5513,127.3125" style="stroke:#181818;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="68.6182" x="322.5513" y="109.4561">Wi-Fi action</text><polygon fill="#181818" points="184.7134,153.6641,174.7134,157.6641,184.7134,161.6641,180.7134,157.6641" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="178.7134" x2="314.5513" y1="157.6641" y2="157.6641"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="53.479" x="190.7134" y="152.8076">response</text><polygon fill="#181818" points="57.2446,200.3672,47.2446,204.3672,57.2446,208.3672,53.2446,204.3672" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="51.2446" x2="172.7134" y1="204.3672" y2="204.3672"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="79.8535" x="63.2446" y="183.1592">return value +</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="68.6436" x="63.2446" y="199.5107">data (if any)</text><!--SRC=[LOwz2eD03CVtUuhWf1HVmA5GQAK5XqA7BWL9zOI0d25tLdtx6XLfbq1-_u-4KG9LnEW2d9XRgZ1Gvm0z8BFX7pcwFExfxPp3azASeA2te4pHQgL_wsgvejG3Ybqy0pLap5mAwL43a87rN2eknt6C4wDmrfHaHkU-RIUnqjysQM-HkQPptgxv1RFIq8k33xQzXSFBrHWGOce0tPIOBm00]--></g></svg>

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@@ -0,0 +1,13 @@
@startuml
participant Application as app
participant "ESP-IDF Wi-Fi Library" as api
participant "Wi-Fi Hardware" as wifi
app -> api : esp_wifi_xxx()
api -> wifi
wifi -> wifi : Wi-Fi action
wifi --> api : response
api --> app : return value +\ndata (if any)
@enduml

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.9 KiB

View File

@@ -0,0 +1,34 @@
@startuml
Title SPI HD Host and Slave Initialization
participant Slave
participant Host
note across: Init
Host -> Slave: Read SLAVE_READY reg
Slave -> Host: Not Ready (!0xEE)
...(loop)...
note over Slave: Now Ready: Set\nSLAVE_READY = 0xEE
Host -> Slave: Read SLAVE_READY reg
Slave -> Host: Ready (0xEE)
Host -> Slave: Set SLAVE_CONTROL = 1
note over Slave: Open Data Path
note over Slave: Prepare Capability data
Slave -> Host: Assert Data_Ready
Host -> Slave: Read Data
Slave -> Host: Capability
note over Host: Configure based\non slave capabilities
@enduml

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

@@ -0,0 +1,27 @@
@startuml
Title SPI HD Host Read
participant Slave
participant Host
note over Slave: Prepare data to send
Slave -> Host: Assert Data_Ready
Host -> Slave: Read TX_BUF_LEN
note over Host: Bytes to transfer =\nTX_BUF_LEN - (cached)TX_BUF_LEN
Host -> Slave: Send CMD9
note over Slave: De-Assert Data_Ready
Host -> Slave: Send RDDMA
Slave -> Host: Transfer Data
Host -> Slave: CMD8\n(at end of transfer)
note over Host: update (cached)TX_BUF_LEN
@enduml

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@@ -0,0 +1,24 @@
@startuml
Title SPI HD Host Write
participant Slave
participant Host
note over Host: Prepare data to send
Host -> Slave: Read RX_BUF_LEN
note over Host: available buffers =\nRX_BUF_LEN - (cached)RX_BUF_LEN
note over Host: loop reading RX_BUF_LEN until\nbuffers available
Host -> Slave: Send WRDMA
Host -> Slave: Tranfer Data
Host -> Slave: Send WR_DONE\n(at end of transfer)
note over Host: update (cached)RX_BUF_LEN
@enduml

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -0,0 +1,42 @@
@startuml
hide time-axis
binary "Chip Select" as cs
clock "Clock" as clk with period 1
concise "Data0-1" as data
Title SPI HD Transaction Using Two Data Lines
@0
cs is high
data is {-}
@+1
cs is low
data is "Command (D0 only)"
@+8
data is "Address (D0-1)"
@+4
data is "Dummy"
@+8
data is "Data (D0-1)"
@+4
data is "..."
@+4
cs is high
data is {-}
@1 <-> @9 : 8 clk
@9 <-> @13 : 4 clk
@13 <-> @21 : 8 clk
@21 <-> @25 : 4 clk
@25 <-> @29 : 4 clk
highlight 21 to 29 : Optional for SPI Transactions\nwithout data
@enduml

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -0,0 +1,42 @@
@startuml
hide time-axis
binary "Chip Select" as cs
clock "Clock" as clk with period 1
concise "Data0-3" as data
Title SPI HD Transaction Using Four Data Lines
@0
cs is high
data is {-}
@+1
cs is low
data is "Command (D0 only)"
@+8
data is "Address (D0-3)"
@+2
data is "Dummy"
@+8
data is "Data (D0-3)"
@+2
data is "..."
@+2
cs is high
data is {-}
@1 <-> @9 : 8 clk
@9 <-> @11 : 2 clk
@11 <-> @19 : 8 clk
@19 <-> @21 : 2 clk
@21 <-> @23 : 2 clk
highlight 19 to 23 : Optional for SPI Transactions\nwithout data
@enduml

View File

@@ -0,0 +1,102 @@
# ESP-Hosted Performance Optimization Guide
Quick reference for optimizing ESP-Hosted performance across different transport interfaces.
## Quick Start - High Performance Config
For immediate performance gains, add these to your host's `sdkconfig.defaults.esp32XX` file:
```
# Wi-Fi Performance
CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=16
CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=64
CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM=64
CONFIG_ESP_WIFI_AMPDU_TX_ENABLED=y
CONFIG_ESP_WIFI_TX_BA_WIN=32
CONFIG_ESP_WIFI_AMPDU_RX_ENABLED=y
CONFIG_ESP_WIFI_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
```
> **Note**: Adjust values based on your MCU host's memory capacity and as per change as per build system
## Transport Optimization
### 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](sdio.md#9-performance-and-memory-usage) on the trade-off between SDIO Performance and Memory Use
### 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
```
### SPI Half-Duplex
- **Data Lines**: Use 4-line (Quad SPI) mode
- **Similar optimizations as SPI Full-Duplex**
### UART (Lowest Performance)
- **Baud Rate**: Use 921600 (highest stable rate)
- **Best for**: Low-throughput applications, debugging
## 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](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/performance/ram-usage.html)
## Hardware Guidelines
### 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
### 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.)
## 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 unsued components from ESP-IDF or
ESP-Hosted-MCU features could be disabled for more memory
availability.

View File

@@ -0,0 +1,640 @@
# ESP-Hosted SDIO Operation
Sections 3 below covers the hardware requirements like external pull-up requirement, possible efuse burning for co-processor and other hardware aspects to consider for SDIO.
Section 4 to 8 covers the complete step-wise setup co-processor and host with SDIO, for 1-bit and 4-bit SDIO.
If you wish to skip the theory, you can refer the [Quick Start Guide](#1-quick-start-guide) below. For quick navigation, please unfold the Table of Contents below.
<details>
<summary>Table of Contents</summary>
1. [Quick Start Guide](#1-quick-start-guide)
2. [Introduction](#2-introduction)
3. [Hardware Considerations](#3-hardware-considerations) || [3.1 General Considerations](#31-general-considerations) || [3.2 Pull-up Resistors](#32-pull-up-resistors) || [3.3 Voltage Levels & eFuse burning](#33-voltage-levels--efuse-burning) || [3.4 Jumper Wires](#34-jumper-wires) || [3.5 PCB Design](#35-pcb-design) || [3.6 Advanced Considerations](#36-advanced-considerations) || [3.7 Testing Connections](#37-testing-connections)
4. [Hardware Setup](#4-hardware-setup)
5. [Set-Up ESP-IDF](#5-set-up-esp-idf)
6. [Flashing the Co-processor](#6-flashing-the-co-processor) || [6.1 Create Co-processor Project](#61-create-co-processor-project) || [6.2 Co-processor Config](#62-co-processor-config) || [6.3 Co-processor Build](#63-co-processor-build) || [6.4 Co-processor Flashing](#64-co-processor-flashing)
7. [Flashing the Host](#7-flashing-the-host) || [7.1 Select Example to Run in Hosted Mode](#71-select-example-to-run-in-hosted-mode) || [7.2 Host Project Component Configuration](#72-host-project-component-configuration) || [7.3 Menuconfig, Build and Flash Host](#73-menuconfig-build-and-flash-host)
8. [Testing and Troubleshooting](#8-testing-and-troubleshooting)
9. [Performance and Memory Usage](#9-performance-and-memory-usage) || [9.1 Stream and Packet Mode](#91-stream-and-packet-mode) || [9.2 Double Buffering on the Host](#92-double-buffering-on-the-host) || [9.3 Reducing Memory Usage](#93-reducing-memory-usage) || [9.4 Switching to Packet Mode](#94-switching-to-packet-mode)
10. [References](#10-references)
</details>
## 1 Quick Start Guide
This section provides a brief overview of how to get started with ESP-Hosted using SDIO mode. For detailed instructions on each step, please refer to the following sections:
- [4. Hardware Setup](#4-hardware-setup)
- [5. Set-Up ESP-IDF](#5-set-up-esp-idf)
- [6. Flashing the Co-processor](#6-flashing-the-co-processor)
- [7. Flashing the Host](#7-flashing-the-host)
- [8. Testing and Troubleshooting](#8-testing-and-troubleshooting)
- [9. Performance and Memory Usage](#9-performance-and-memory-usage)
These sections will guide you through the process of flashing both the co-processor and host devices, setting up the hardware connections, and verifying successful communication.
## 2 Introduction
SDIO is a high-speed bus that uses the same SDMMC hardware protocol used for SD Cards, but with its own set of commands for communicating with SDIO aware peripherals.
> [!NOTE]
> Only some ESP32 chips support the SDIO Protocol:
>
> A. SDIO as Slave (Co-processor): ESP32, ESP32-C6 \
> B. SDIO as Master: ESP32, ESP32-S3, ESP32-P4
## 3 Hardware Considerations
### 3.1 GPIO Configuration for SDIO
The SDIO interface can use almost any GPIO pins. For maximum speed and minimal delays, it is recommended to select the SDIO pin configuration that uses the dedicated `IO_MUX` pins. Hardware connections in later sections use `IO_MUX` pins, as much as possible.
ESP32 only supports `IO_MUX` pins for SDIO. other chips may support other flexible pins using GPIO_Matrix, with small performance penalty.
### 3.2 Extra GPIO Signals Required
Extra GPIO signals are required for SDIO on Hosted and can be assigned to any free GPIO pins:
- `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 suggested to connect to the `EN` or `RST` pin on the co-processor, It is however configurable to use another GPIO pin.
>
> To configure this, use `idf.py menuconfig` on the co-processor: **Example configuration** ---> **SDIO Configuration** ---> **Host SDIO GPIOs** and set **Slave GPIO pin to reset itself**.
### 3.3 General Hardware Considerations
- For SDIO, signal integrity is crucial, hence jumper wires are not recommended.
- Jumper wires are only suitable for initial testing and prototyping.
- If you wish, you can test SDIO 1-Bit mode using jumper cables, only for initial testing and prototyping. Pull-Ups are still mandatory for all, [CMD, DAT0, DAT1, DAT2, DAT3] irrespective how do you connect, using jumpers or PCB.
- Ensure equal trace lengths for all SDIO connections, whether using jumper wires or PCB traces.
- Very strict requirement, to keep wires as short as possible, under 5 cm. Smaller the better.
- Use the lower clock frequency like 5 MHz for evaluation. Once solution verified, optimise the clock frequency in increasing steps to max possible value. Max SDIO host clock frequency that all SDIO co-processors can work is upto 50 MHz.
- Provide proper power supply for both host and co-processor devices. Lower or incorrect power supplies can cause communication issues & suboptimal performance.
### 3.4 Pull-up Resistors
- SDIO requires external pull-up resistor (51 kOhm recommended) and clean signals for proper operation.
- For this reason, it is not recommended to use jumper cables. Use PCB traces to connect between a Hosted Master and Co-processor.
- For full requirements, refer to ESP-IDF SDIO pull-up resistor requirements at [Pull-Up Requirements](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/sd_pullup_requirements.html).
### 3.5 Voltage Levels & eFuse burning
- SDIO expects all signals to be at 3.3V level. If you are using level shifter, ensure that the level shifter output is set to 3.3V.
- If you use classic ESP32, there is good chance that you would need to burn the eFuse.
- eFuse burning is one time and **non reversible process**. You may brick your device, if burn the eFuse incorrectly.
- Please check full documentation at [eFuse burning](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/sd_pullup_requirements.html) If your chip is listed explicitly, not to burn eFuse, you can ignore this.
- This document covers below issues and their solutions:
- External pull-ups to be used on: CMD, DAT0, DAT1, DAT2, DAT3, with 51K Ohm recommended, irrespective of jumpers or PCB.
- Bootstrapping pin and DAT2 voltage issues and solution of eFuse burning, with complete procedure.
### 3.6 Jumper Wires (only for SDIO 1-Bit mode)
- External Pull-ups mandatory for CMD, DAT0, DAT1, DAT2, DAT3 of 51 kOhm.
- Smaller the better, strictly under 5 cm. All equal length.
- Use high-quality, low-capacitance jumper wires.
- 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.
### 3.7 PCB Design
For optimal performance and reliability in production designs:
- Ensure equal trace lengths for all SDIO signals (CLK, CMD, DAT0, DAT1, DAT2, DAT3) 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.
### 3.8 Advanced Considerations
- Calculate the maximum allowed trace length based on your clock frequency and PCB material.
- Consider the capacitive load on the SDIO bus, especially for longer traces
- For very high-speed designs, consider using differential signaling techniques.
- Implement proper EMI/EMC design techniques to minimize electromagnetic interference.
## 4 Hardware Setup
Setting up the hardware involves connecting the master and co-processor devices via the SDIO pins and ensuring all extra GPIO signals are properly connected. Below is the table of connections for the SDIO setup between a host ESP chipset and another ESP chipset as co-processor:
### Host Connections
SDIO-capable host microcontrollers (MCUs) can connect their GPIO lines to the co-processor as detailed in the table below.
#### GPIO Flexibility
- The ESP32 supports SDIO host on fixed GPIOs.
- The ESP32-S3 supports SDIO host on flexible GPIOs.
- For the ESP32-P4, Slot 0 supports fixed GPIOs, while Slot 1 supports flexible GPIOs.
By default, Slot 1 is used on the ESP32-P4 to take advantage of its flexible pin mapping; however, Slot 0 is also supported. Parallel access to both Slot 0 and Slot 1 is supported for all hosts.
| Signal | ESP32 | ESP32-S3 |
|-----------|-------|----------|
| CLK | 14 | 19 |
| CMD | 15+[ext-pull-up](#34-pull-up-resistors) | 47+[ext-pull-up](#34-pull-up-resistors) |
| D0 | 2+[ext-pull-up](#34-pull-up-resistors) | 13+[ext-pull-up](#34-pull-up-resistors) |
| D1 | 4+[ext-pull-up](#34-pull-up-resistors) | 35+[ext-pull-up](#34-pull-up-resistors) |
| D2 | 12+[ext-pull-up](#34-pull-up-resistors) | 20+[ext-pull-up](#34-pull-up-resistors) |
| D3 | 13+[ext-pull-up](#34-pull-up-resistors) | 9+[ext-pull-up](#34-pull-up-resistors) |
| Reset Out | 5 | 42 |
### ESP32-P4-Function-EV-Board Host Pin Mapping
| Signal | ESP32-P4 with ESP32-C6 Co-processor | ESP32-P4 with ESP32-C5 Co-processor |
|-----------|-------------------------------------|-------------------------------------|
| CLK | 18 | 33 |
| CMD | 19+[ext-pull-up](#34-pull-up-resistors) | 4+[ext-pull-up](#34-pull-up-resistors) |
| D0 | 14+[ext-pull-up](#34-pull-up-resistors) | 20+[ext-pull-up](#34-pull-up-resistors) |
| D1 | 15+[ext-pull-up](#34-pull-up-resistors) | 23+[ext-pull-up](#34-pull-up-resistors) |
| D2 | 16+[ext-pull-up](#34-pull-up-resistors) | 21+[ext-pull-up](#34-pull-up-resistors) |
| D3 | 17+[ext-pull-up](#34-pull-up-resistors) | 22+[ext-pull-up](#34-pull-up-resistors) |
| Reset Out | 54 | 53 |
>
### Co-processor connections
SDIO slave provider ESP chips are : ESP32, ESP32-C5, ESP32-C6.\
All these chips have fixed GPIOs SDIO support.
| Signal | ESP32 | ESP32-C6 | ESP32-C5 |
|----------|-------|----------|----------|
| CLK | 14 | 19 | 9 |
| CMD | 15 | 18 | 10 |
| D0 | 2 | 20 | 8 |
| D1 | 4 | 21 | 7 |
| D2 | 12 | 22 | 14 |
| D3 | 13 | 23 | 13 |
| Reset In | EN | EN/RST | RST |
> [!NOTE]
>
> - External pull-ups are mandatory
## 5 Set-Up ESP-IDF
Before setting up the ESP-Hosted co-processor & host for SDIO mode, ensure that ESP-IDF is properly installed and set up on your system.
### 5.1 Installer Way
- **Windows**
- Install and setup ESP-IDF on Windows as documented in the [Standard Setup of Toolchain for Windows](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/windows-setup.html).
- Use the ESP-IDF [Powershell Command Prompt](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/windows-setup.html#using-the-command-prompt) for subsequent commands.
- **Linux or MacOS**
- For bash:
```bash
bash docs/setup_esp_idf__latest_stable__linux_macos.sh
```
- For fish:
```fish
fish docs/setup_esp_idf__latest_stable__linux_macos.fish
```
### 5.2 Manual Way
Please follow the [ESP-IDF Get Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html) for manual installation.
## 6. Flashing the Co-processor
| Supported Co-processor Targets | ESP32 | ESP32-C6 | ESP32-C5 |
| ------------------------------ | ----- | -------- | -------- |
There are four steps to flash the ESP-Hosted co-processor firmware:
### 6.1 Create Co-processor Project
1. Navigate to the directory where you want to create the co-processor project.
2. Use the following command to create a new project:
```bash
idf.py create-project <project_name>
```
Replace `<project_name>` with your desired project name.
### 6.2 Co-processor Config
1. Navigate to the project directory:
```bash
cd <project_name>
```
2. Configure the project:
```bash
idf.py menuconfig
```
#### 6.2.1 Transport config
- Navigate to "Example configuration" -> "Transport layer"
- Select "SDIO"
#### 6.2.2 Any other config
- Optionally, Configure any additional SDIO-specific settings like co-processor GPIOs, SDIO Mode, SDIO timing,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.
### 6.3 Co-processor Build
1. Build the project:
```bash
idf.py build
```
### 6.4 Co-processor Flashing
There are two methods to flash the ESP-Hosted co-processor firmware:
#### 6.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`
##### 6.4.2 Co-processor OTA Flashing (Subsequent Updates)
For subsequent updates, you can re-use ESP-Hosted-MCU transport, as it should be already working. While doing OTA, Complete co-processor firmware image is not needed and only co-processor application partition, 'network_adapter.bin' need to be re-flashed remotely from host.
1. Ensure your co-processor device is connected and communicating with the host with existing ESP-Hosted-MCU.
2. Create a web server
You can re-use your existing web server or create a new locally for testing. Below is example to do it.
- Make a new directory so that web server can be run into it and navigate into it
- Create simple local web server using python3
```bash
python3 -m http.server 8080
```
3. Copy the co-processor app partition `network_adapter.bin` in the directory where you created the web server.
- The `network_adapter.bin` can be found in your co-processor project build at `<co-processor_project>/build/network_adapter.bin`
4. Verify if web server is set-up correctly
- Open link `http://127.0.0.1:8080` in the browser and check if network_adapter.bin is available.
- Right click and copy the complete URL of this network_adapter.bin and note somewhere.
5. On the **host side**, use the `esp_hosted_slave_ota` function to initiate the OTA update:
```c
#include "esp_hosted.h"
const char* image_url = "http://example.com/path/to/network_adapter.bin"; //web server full url
esp_err_t ret = esp_hosted_slave_ota(image_url);
if (ret == ESP_OK) {
printf("co-processor OTA update failed[%d]\n", ret);
}
```
This function will download the firmware in chunk by chunk as http client from the specified URL and flash it to the co-processor device through the established transport.
In above web server example, You can paste the copied url earlier.
6. Monitor the OTA progress through the console output on both the host and co-processor devices.
> [!NOTE]
>
> A. The `esp_hosted_slave_ota` function is part of the ESP-Hosted-MCU API and handles the OTA process through the transport layer. \
> B. Ensure that your host application has web server connectivity to download the firmware file. \
> C. The co-processor device doesn't need to be connected to the web server for this OTA method.
## 7 Flashing the Host
| Supported Host Targets | Any ESP chipset | Any Non-ESP chipset |
| ----------------------- | --------------- | ------------------- |
Any host having SDIO master can be used as host. Please make sure the hardware configurations, like external pull-ups are installed correctly. Tthe voltage at SDIO pins is expected to be 3v3 volts.
- ESP chipsets as SDIO master
- ESP as host could be one of ESP32, ESP32-S3, ESP32-P4.
- For ESP32 as host, may need additional **eFuse burning** for voltage correction on one of data pin. ESP32-S3 and ESP32-P4 does **not** need this.
- Non ESP SDIO Master
- Any other host having SDIO master can be used as host. Please make sure the hardware configurations, like ([external Pull-up Resistors](#42-pull-up-resistors)) are installed correctly. Tthe voltage at SDIO pins is expected to be 3v3 volts.
- Pull-ups required for CMD, DAT0, DAT1, DAT2, DAT3 lines (for both 1-Bit and 4-Bit SDIO)
- eFuse burning may be required for classic ESP32.
- Pull-Up and eFuse burning is detailed in [(3) Hardware Considerations](#3-hardware-considerations)
### 7.1 Select Example to Run in Hosted Mode
Select an example from the [ESP-IDF examples directory](https://github.com/espressif/esp-idf/tree/master/examples) 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](https://github.com/espressif/esp-idf/tree/master/examples/wifi/iperf).
### 7.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)
### 7.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:
- Remove the default `sdkconfig.defaults.esp32p4` file.
- Create a new `sdkconfig.defaults.esp32p4` file with the following content:
```
CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=16
CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=64
CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM=64
CONFIG_ESP_WIFI_AMPDU_TX_ENABLED=y
CONFIG_ESP_WIFI_TX_BA_WIN=32
CONFIG_ESP_WIFI_AMPDU_RX_ENABLED=y
CONFIG_ESP_WIFI_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 hosts also, you can merge above configs in corresponding `sdkconfig.defaults.esp32XX` file.
###### 2. Set environment for your host ESP chip:
```
idf.py set-target <host_target>
```
Replace `<host_target>` with your specific ESP chip (e.g., esp32, esp32s3, esp32p4).
###### 3. Flexible Menuconfig configurations
```
idf.py menuconfig
```
ESP-Hosted-MCU host configurations are available under "Component config" -> "ESP-Hosted config"
1. Select "SDIO" as the transport layer
2. Change co-processor chipset currently in-use under, "Slave chipset to be used"
3. Change SDIO Bus Width to 1-bit or 4-bit based on the co-processor using "Hosted SDIO Configuration" -> "SDIO Bus Width"
4. Optionally, configure SDIO-specific settings like:
- SDIO Host GPIO Pins
- Lower SDIO Clock Speed
You can use a lower clock speed to verify the connections. Start with a clock speed between 400 kHz to 20 MHz.
To configure this, use `Menuconfig` on the Host: **Component config** ---> **ESP-Hosted config** ---> **Hosted SDIO Configuration** and set **SDIO Clock Freq (in kHz)**.
> [!NOTE]
>
> The actual clock frequency used is determined by the hardware. Use an oscilloscope or logic analyzer to check the clock frequency.
- Using 1-bit SDIO Mode
By default, SDIO operates in 4-Bit mode.
You can set the SDIO Bus Width to 1-Bit. In 1-Bit mode, only `DAT0` and `DAT1` signals are used for data and are less affected by noise on the signal lines. This can help you verify that the SDIO protocol is working at the logical level, if you have issues getting 4-Bit SDIO to work on your prototype board.
To configure this, use `Menuconfig` on the Host: **Component config** ---> **ESP-Hosted config** ---> **Hosted SDIO Configuration** ---> **SDIO Bus Width** to **1 Bit**.
- SDIO Mode
Packet or Streaming mode could be used, but co-processor has to use same SDIO mode used.
> [!NOTE]
> Pull-ups are still required on `DAT2` and `DAT3` lines to prevent
> the SDIO slave from going into SPI mode upon startup.
After confirming the functionality of the 1-Bit SDIO mode, you can revert to the 4-Bit mode with PCB to benefit from increased data transfer rates. Using the previous configuration, switch back to `4 Bit`.
###### 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
## 8 Testing and Troubleshooting
After flashing both the co-processor and host devices, follow these steps to connect and test your ESP-Hosted SDIO setup:
1. Connect the hardware:
- Follow the pin assignments for SDIO as specified in [Hardware Setup](#4-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. Apply correct input rating power for both chipsets.
3. Verify the connection:
- Check the serial output of both devices for successful initialization messages.
- Look for messages indicating that the SDIO 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 SDIO
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 :: SDIO
I (520) fg_mcu_slave: *********************************************************************
I (529) fg_mcu_slave: Supported features are:
I (534) fg_mcu_slave: - WLAN over SDIO
I (538) h_bt: - BT/BLE
I (541) h_bt: - HCI Over SDIO
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:
| 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](shield-box-test-setup.md).
8. Troubleshooting:
- Consider using a lower clock speed or checking your [hardware setup](docs/sdio.md#7-hardware-setup) if you experience communication problems.
- ESP-Hosted-MCU troubleshooting guide: [docs/troubleshooting.md](docs/troubleshooting.md)
9. 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 SDIO signals.
- Use a logic analyzer or oscilloscope to verify the SDIO signals.
- Ensure that the power supply to both devices is stable and within the required voltage levels.
## 9 Performance and Memory Usage
Quick summary:
- for maximum network performance, at the cost of more memory usage on host and co-processor, use SDIO Streaming Mode (default mode of operation)
- for lower memory usage, at the cost of lower network performance, use [SDIO Packet Mode](#94-switching-to-packet-mode)
### 9.1 Stream and Packet Mode
The co-processor SDIO can operate in two modes: Streaming Mode and Packet Mode.
| **Streaming Mode** | **Packet Mode** |
| --- | --- |
| Co-processor combines multiple queued Tx packets together into one large packet | Co-processor queues individual Tx packets |
| Host fetches the large packet as one SDIO transfer | Host fetches each packet one at a time |
| Host breaks the large packet back into individual packets to send to the Rx queue | Host sends each packet to the Rx queue |
| More efficient (less SDIO overhead), but requires more memory at Host to hold the large packet | Less efficient (higher SDIO overhead for each packet), but minimises memory required at Host |
### 9.2 Double Buffering on the Host
The Host implements a double-buffering scheme to receive data. One thread fetches data (using hardware DMA) from the co-processor and stores it in one Rx buffer, while another thread breaks up previously received data into packets for processing.
### 9.3 Reducing Memory Usage in Streaming Mode
#### 9.3.1 Host Receive
> [!NOTE]
> **Host Receive**: Router --Network Data--> Co-processor --SDIO--> Host
In SDIO streaming mode, the host receives SDIO data from the co-processor in one large SDIO transfer. For this reason, **Streaming mode consumes more heap memory** compared to Packet mode, and has a higher throughput (less SDIO overhead).
For Host systems with high heap memory usage, you can reduce the amount of heap memory used by ESP-Hosted for buffers, at the cost of reduced throughput, by adjusting the number of Tx buffers used by the co-processor.
**On the co-processor**: run `idf.py menuconfig` ---> `Example Configuration` ---> `SDIO Configuration` and adjust `SDIO Tx queue size`. The default queue size is `20`.
The table below shows the effect of changing `SDIO Tx queue size` on throughput and memory usage on the Host. The throughput numbers are obtained by using the RawTP option in ESP-Hosted to send / receive raw SDIO data.
| SDIO Tx queue size | Host Rx Raw Throughput (Mbits/s) | Memory Used by Buffers (Tested) | Memory Used by Buffers (Theoretical) |
| ---: | ---: | ---: | ---: |
| 5 | 54 | 12,288 | 15,360 |
| 10 | 70 | 26,624 | 30,720 |
| 15 | 76 | 41,984 | 46,080 |
| 20 | 80 | 56,320 | 61,440 |
| 25 | 82 | 65,536 | 76,800 |
| 30 | 84 | 65,536 | 92,160 |
> [!NOTE]
> The SDIO packet size is 1536 bytes. The co-processor can send at most `(Tx queue size) * 1536` bytes. Since the Host does double buffering, the theoretical Buffer Size needed is `2 * (Tx queue size) * 1536`.
From the table above, throughput is more or less stagnant on and above Rx queue size of `25`. For a good trade off between memory consumption vs performance, the Rx queue sizes are currently defaulted to `20`.
#### 9.3.2 Host Transmit
> [!NOTE]
> **Host Transmit**: Host --SDIO--> Co-Processor --Network Data--> Router
To reduce memory usage on the co-processor, you can reduce the number of buffers the co-processor uses to receive data from the Host.
**On the co-processor**: run `idf.py menuconfig` ---> `Example Configuration` ---> `SDIO Configuration` and adjust `SDIO Rx queue size`. The default queue size is `20`.
Reducing the number of Rx buffers on the co-processor can affect the Tx throughput from the Host if the number of Rx buffers is set to a small value.
### 9.4 Switching to Packet Mode
For mimimal memory usage with a lower throughput, you can switch to Packet Mode. To do this:
- on the co-processor: run `idf.py menuconfig` ---> `Example Configuration` ---> `SDIO Configuration` and untoggle `Enable SDIO Streaming Mode`
- on the host: run `idf.py menuconfig` ---> `Component config` ---> `ESP-Hosted config` ---> `Hosted SDIO COnfiguration` ---> `SDIO Receive Optimization` and select either `No optimization` or `Always Rx Max Packet size`. `Always Rx Max Packet size` will give a slightly higher throughput.
In Packet Mode, the host uses `2 * 1536` or `3,072` bytes of memory for Rx buffers.
- with `No optimization`, Rx Raw Throughput is 33.0 Mbits/s
- with `Always Rx Max Packet size`, Rx Raw Throughput is 33.2 Mbits/s
## 10 References
- [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/)
- [ESP32 Hardware Design Guidelines](https://www.espressif.com/en/products/hardware/esp32/resources)
- [ESP SDIO Slave Communication](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/protocols/esp_sdio_slave_protocol.html)
- [ESP SDIO Card Slave Driver](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/sdio_slave.html)

View File

@@ -0,0 +1,65 @@
#!/usr/bin/env fish
echo "Setting up ESP-IDF using fish"
set SHELL_RC "$HOME/.config/fish/config.fish"
# Step 1: Check if curl and git are installed
echo "============== Step 1: Checking if dependencies =========================="
if not type -q curl
echo "curl is not installed. Please install curl."
exit 1
end
if not type -q git
echo "git is not installed. Please install git."
exit 1
end
echo "Dependencies for current script are installed."
# Step 2: Fetch the branches from the GitHub API and find the latest stable release branch
echo "============== Step 2: Fetching branch list from ESP-IDF GitHub API =============="
set LATEST_BRANCH (curl -s https://api.github.com/repos/espressif/esp-idf/branches | grep -o '"name": "release/[^"]*' | awk -F'"' '{print $4}' | sort -V | tail -n 1)
# Log the latest branch found
echo "Latest stable branch found: $LATEST_BRANCH"
# Step 3: Clone or update the ESP-IDF repository
if not test -d "$HOME/esp-idf"
echo "============== Step 3: Cloning the ESP-IDF repository ================"
git clone -b "$LATEST_BRANCH" --recursive --depth 1 https://github.com/espressif/esp-idf.git "$HOME/esp-idf"
else
echo "ESP-IDF repository already exists."
cd "$HOME/esp-idf" || exit
git checkout "$LATEST_BRANCH"
git pull --recurse-submodules
end
cd "$HOME/esp-idf" || exit
set IDF_COMMIT (git rev-parse HEAD)
echo "ESP-IDF is set to commit: $IDF_COMMIT"
# Step 4: Set up the ESP-IDF environment
echo "============== Step 4: Setting up the ESP-IDF environment ================"
"$HOME/esp-idf/install.fish"
source "$HOME/esp-idf/export.fish" | source
# Step 5: Add alias to Fish config
echo "============== Step 5: Adding alias to Fish configuration ==============="
if not grep -q "alias get-idf" "$SHELL_RC"
read -P "Do you want to add the alias 'get-idf' to $SHELL_RC? [yes/no] " response
if string match -i -r '^yes$' $response
echo "alias get-idf='source $HOME/esp-idf/export.fish | source'" >> "$SHELL_RC"
echo "ESP-IDF setup alias added to $SHELL_RC. Run 'get-idf' to configure your environment."
else
echo "Alias not added. You can manually add 'alias get-idf=\". $HOME/esp-idf/export.fish | source\"' to $SHELL_RC."
end
else
echo "ESP-IDF setup alias already exists in $SHELL_RC."
end
# Step 6: Inform user to reload shell
echo "============== Step 6: Informing user to reload shell ==============="
echo "Please run 'source $SHELL_RC' to reload the shell with the new alias."
echo "In new shell, run 'get-idf' to enable ESP-IDF environment."

View File

@@ -0,0 +1,62 @@
#!/usr/bin/env bash
SHELL_RC="$HOME/.bashrc"
# Step 1: Check if curl and git are installed
echo "============== Step 1: Checking if dependencies are installed =============="
if ! command -v curl &> /dev/null; then
echo "curl is not installed. Please install curl."
exit 1
fi
if ! command -v git &> /dev/null; then
echo "git is not installed. Please install git."
exit 1
fi
echo "All required dependencies are installed."
# Step 2: Fetch the branches from the GitHub API and find the latest stable release branch
echo "============== Step 2: Fetching branch list from ESP-IDF GitHub API =============="
LATEST_BRANCH=$(curl -s https://api.github.com/repos/espressif/esp-idf/branches | grep -o '"name": "release/[^"]*' | awk -F'"' '{print $4}' | sort -V | tail -n 1)
echo "Latest stable branch found: $LATEST_BRANCH"
# Step 3: Clone or update the ESP-IDF repository
if [ ! -d "$HOME/esp-idf" ]; then
echo "========= Step 3: Cloning the ESP-IDF repository (takes 3-4 mins) ============="
git clone -b "$LATEST_BRANCH" --recursive --depth 1 https://github.com/espressif/esp-idf.git "$HOME/esp-idf"
else
echo "ESP-IDF repository already exists. Updating..."
cd "$HOME/esp-idf" || exit
git checkout "$LATEST_BRANCH"
git pull --recurse-submodules
fi
# Log the current commit hash
cd "$HOME/esp-idf" || exit
IDF_COMMIT=$(git rev-parse HEAD)
echo "<< ESP-IDF is set to commit: $IDF_COMMIT >>"
# Step 4: Set up the ESP-IDF environment
echo "============== Step 4: Setting up the ESP-IDF environment ================"
"$HOME/esp-idf/install.sh"
source "$HOME/esp-idf/export.sh"
# Step 5: Optionally add an alias to shell configuration for easy setup
echo "============== Step 5: Adding alias to shell configuration ==============="
if ! grep -q "alias get-idf" "$SHELL_RC"; then
read -p "Do you want to add the alias 'get-idf' to $SHELL_RC? [yes/no] " -r
if [[ $REPLY =~ ^[Yy][Ee][Ss]$ ]]; then
echo "alias get-idf='source $HOME/esp-idf/export.sh'" >> "$SHELL_RC"
echo "ESP-IDF setup alias added to $SHELL_RC. Run 'get-idf' to configure your environment."
else
echo "Alias not added. You can manually add 'alias get-idf=\"source $HOME/esp-idf/export.sh\"' to $SHELL_RC."
fi
else
echo "ESP-IDF setup alias already exists in $SHELL_RC."
fi
# Step 6: Inform the user to reload the shell
echo "============== Step 6: Informing user to reload shell ==============="
echo "\nPlease run 'source $SHELL_RC' to reload the shell with the new alias."
echo "\nIn a new shell, run 'get-idf' to enable the ESP-IDF environment."

View File

@@ -0,0 +1,75 @@
# Shield Box Test Setup for ESP-Hosted
Controlled RF environment for consistent throughput measurements and performance evaluation.
## Overview
**Shield Box Testing** uses RF-shielded enclosure to eliminate external interference and provide repeatable test conditions.
**Key Benefits:**
- Controlled RF environment (no external Wi-Fi/cellular interference)
- Repeatable, consistent results
- Better measurement accuracy vs open air
## Equipment Required
### Essential Components
- **RF Shield Box/Chamber**: Faraday cage enclosure
- **ESP32-P4 Function EV Board**: Host device
- **ESP32-C6/C5 Test Board**: Co-processor device
- **External PC**: For iPerf client/server
- **Router/Access Point**: Wi-Fi infrastructure
- **Ethernet Connection**: Wired backhaul to PC
Please change the host and co-processor nodes as per current use-case under test.
## Test Setup
### Physical Configuration
<img src="images/PerformanceSetup-ShieldBox.png" alt="Shield box testing setup" width="800" />
### Data Flow
- **PC to MCU Host**:
```
PC -> Router -> ESP Co-processor == SDIO/SPI/UART ==> ESP32-P4
```
- **MCU Host to PC**:
```
PC <- Router <- ESP Co-processor <== SDIO/SPI/UART == ESP32-P4
```
**Traffic route:**
- PC-to-Router: Ethernet with static IP (eliminates wireless variables)
- Router-to-ESP: Wi-Fi connection (only wireless link in test chain)
## Transport Configurations
### SDIO (Highest Performance)
- **Clock**: 20-50 MHz (start low, optimize up)
- **Bus Width**: 4-bit mode
- **Hardware**: External pull-ups (51kΩ) on CMD, D0-D3
### SPI
- **Clock**: ESP32: ≤10 MHz, Others: ≤40 MHz
- **Mode**: Full-duplex (simple) or Quad SPI (highest throughput)
### UART
- **Baud Rate**: 921600 (highest stable rate)
- **Use Case**: Low-throughput validation, debugging
## Shield Box vs Open Air
| Aspect | Shield Box | Open Air |
|--------|------------|----------|
| **Repeatability** | High | Variable |
| **Interference** | Eliminated | Present |
| **Debugging** | Easier | Complex |
| **Reality** | Lower | Higher |
---
*For transport setup details: [SDIO](sdio.md) | [SPI Full-Duplex](spi_full_duplex.md) | [SPI Half-Duplex](spi_half_duplex.md) | [UART](uart.md)*

View File

@@ -0,0 +1,565 @@
# ESP-Hosted SPI FD (Full Duplex) Operation
Sections 2 to 4 below covers the theoretical part where the SPI Full duplex design and implementation details are explained.
Section 5 to 9 covers the complete step-wise setup co-processor and host with SPI Full Duplex, using 2 or 4 data lines.
If you wish to skip the theory, you can refer the [Quick Start Guide](#1-quick-start-guide) below. For quick navigation, please unfold the Table of Contents below.
<details>
<summary>Table of Contents</summary>
1. [Quick Start Guide](#1-quick-start-guide)
2. [Introduction](#2-introduction)
3. [High Level Design and Implementation](#3-high-level-design-and-implementation) || [3.1 Number of Pins Required](#31-number-of-pins-required) || [3.2 SPI Full Duplex Mode Implementation](#32-spi-full-duplex-mode-implementation) || [3.3 Code Reference](#35-code-reference)
4. [Hardware Considerations](#4-hardware-considerations) || [4.1 General Considerations](#41-general-considerations) || [4.2 Jumper Wires](#42-jumper-wires) || [4.3 PCB Design](#43-pcb-design) || [4.4 Advanced Considerations](#44-advanced-considerations)
5. [Hardware Setup](#5-hardware-setup)
6. [Set-Up ESP-IDF](#6-set-up-esp-idf)
7. [Flashing the Co-processor](#7-flashing-the-co-processor) || [7.1 Create Co-processor Project](#71-create-co-processor-project) || [7.2 Co-processor Config](#72-co-processor-config) || [7.3 Co-processor Build](#73-co-processor-build) || [7.4 Co-processor Flashing](#74-co-processor-flashing) || [7.4.1 Serial Flashing (Initial Setup)](#741-serial-flashing-initial-setup) || [7.4.2 Co-processor OTA Flashing (Subsequent Updates)](#742-co-processor-ota-flashing-subsequent-updates)
8. [Flashing the Host](#8-flashing-the-host) || [8.1 Select Example to Run in Hosted Mode](#81-select-example-to-run-in-hosted-mode) || [8.2 Host Project Component Configuration](#82-host-project-component-configuration) || [8.3 Menuconfig, Build and Flash Host](#83-menuconfig-build-and-flash-host)
9. [Testing and Troubleshooting](#9-testing-and-troubleshooting)
10. [References](#10-references)
</details>
## 1 Quick Start Guide
This section provides a brief overview of how to get started with ESP-Hosted using SPI FD mode. For detailed instructions on each step, please refer to the following sections:
- [5. Hardware Setup](#5-hardware-setup)
- [6. Set-Up ESP-IDF](#6-set-up-esp-idf)
- [7. Flashing the Co-processor](#7-flashing-the-co-processor)
- [8. Flashing the Host](#8-flashing-the-host)
- [9. Testing and Troubleshooting](#9-testing-and-troubleshooting)
These sections will guide you through the process of flashing both the co-processor and host devices, setting up the hardware connections, and verifying successful communication.
## 2 Introduction
The ESP32 family of chips supports the standard SPI FD (Full Duplex) Mode Protocol. In this mode, SPI uses two data lines (MISO and MOSI) to transfer data to and from the co-processor simultaneously during an SPI transaction.
## 3 High Level Design and Implementation
SPI Full duplex mode is the simplest mode of operation in ESP-Hosted. It can be easily tested with jumper wires. It doesn't require much complex hardware setup. For any non ESP chipsets as host also can prefer this mode for testing. This can also served as stepping stone before moving on to more complex modes of operations, like Dual SPI, Quad SPI and SDIO.
### 3.1 Number of Pins Required
In SPI Full Duplex mode, the following pins are required:
1. **MISO (Master In Slave Out)**: Data line for the co-processor to send data to the host.
2. **MOSI (Master Out Slave In)**: Data line for the host to send data to the co-processor.
3. **SCLK (Serial Clock)**: Clock signal generated by the host to synchronize data transmission.
4. **CS (Chip Select)**: Signal used by the host to select the co-processor for communication.
5. **Reset Pin**: An output signal from the host to the co-processor. When asserted, the host resets the co-processor to synchronize the state of the host and co-processor.
6. **Handshake Pin**: An output signal from the co-processor to the host. When asserted, it tells the host that the co-processor is ready for an SPI transaction.
7. **Data Ready Pin**: 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 SPI used is full duplex. Handshake, Data Ready and Reset are additional GPIOs used in addition to MISO, MOSI, SCLK and CS. All pins are mandatory.
### 3.2 SPI Full Duplex Mode Implementation
- This solution uses SPI full duplex communication mode:
- Read and write operations occur simultaneously in the same SPI transaction
- Handshake and Data ready are configured as interrupts at host. On loading host, it should automatically reset the co-processor using reset pin.
- Protocol rules:
- Host must not start a transaction before ESP SPI peripheral is ready
- ESP peripheral indicates readiness via Handshake pin
- ESP peripheral preparation:
- Always ready for data reception from host
- Queues next SPI transaction immediately after completing previous one
- SPI transaction structure:
- Each transaction has a TX buffer and an RX buffer
- TX buffer: Contains data ESP peripheral wants to send to host
- RX buffer: Empty space to hold data received from host
- Buffer initialization:
- ESP peripheral sets TX and RX buffers to 1600 bytes (maximum size)
- Host can send/receive up to 1600 bytes per transaction
- TX buffer scenarios:
1. No data to transfer:
- Allocate 1600-byte dummy TX buffer
- Set packet length field in payload header to 0
2. Valid data to send:
- TX buffer points to that data
- SPI transaction setup:
- Set transaction length to 1600 bytes regardless of TX buffer size
- Submit transaction to SPI driver on ESP peripheral
- Pull Handshake pin high to signal readiness
- If TX buffer has valid data, also pull Data ready pin high
- Host response to Handshake / Data ready interrupt:
- Decide whether to perform SPI transaction (if Handshake is high)
- Perform transfer if Data ready pin is high or host has data to transfer
- If either condition is false, do not perform transfer, just ignore the interrupt
- During SPI transaction:
- Exchange TX and RX buffers on SPI data lines
- Post-transaction processing:
- Both ESP peripheral and host process received buffer based on payload header
- Transaction completion:
- ESP peripheral pulls Handshake pin low
- If transaction had valid co-processor TX buffer, also pulls Data ready pin low
### 3.3 Code Reference
For a detailed implementation of SPI full duplex communication using the ESP-Hosted framework, refer to the following code files in the ESP-Hosted repository:
- **Master SPI Communication Code**:
- [spi_drv.c](https://github.com/espressif/esp-hosted-mcu/blob/main/host/drivers/transport/spi/spi_drv.c): Contains the implementation for configuring and handling SPI transactions on the master side.
- [spi_wrapper.c](https://github.com/espressif/esp-hosted-mcu/blob/main/host/port/spi_wrapper.c): Provides an OS abstraction layer for SPI operations, making it easier to handle SPI communication in a platform-independent manner.
- **Co-processor SPI Communication Code**:
- [spi_slave_api.c](https://github.com/espressif/esp-hosted-mcu/blob/main/slave/main/spi_slave_api.c): Includes the setup and transaction handling for the SPI co-processor, detailing how the co-processor should configure its SPI interface and handle incoming and outgoing data.
## 4 Hardware Considerations
### 4.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 slave frequency for your co-processor, check `IDF_PERFORMANCE_MAX_SPI_CLK_FREQ` in [ESP-IDF SPI slave benchmark](https://github.com/espressif/esp-idf/blob/master/components/esp_driver_spi/test_apps/components/spi_bench_mark/include/spi_performance.h)
- Verify voltage compatibility between host and co-processor devices.
- Provide proper power supply decoupling for both host and co-processor devices.
### 4.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.
### 4.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.
### 4.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.
**Debugging Tips**
- 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.
## 5 Hardware Setup
Setting up the hardware involves connecting the master and co-processor devices via the SPI pins and ensuring all extra GPIO signals are properly connected. Below is the table of connections for the SPI full duplex setup between an host ESP chipset and another ESP chipset as co-processor:
### Host connections
| Signal | ESP32 | ESP32-S2/S3 | ESP32-C2/C3/C5/C6 | ESP32-P4 (ESP32-P4-Function-EV-Board) |
|-------------|-------|-------------|-------------------|---------------------------------------|
| CLK | 14 | 12 | 6 | 18 |
| MOSI | 13 | 11 | 7 | 14 |
| MISO | 12 | 13 | 2 | 15 |
| CS | 15 | 10 | 10 | 19 |
| Handshake | 26 | 17 | 3 | 16 |
| Data Ready | 4 | 4 | 4 | 17 |
| Reset Out | 5 | 5 | 5 | 54 |
### Co-processor connections
| Signal | ESP32 | ESP32-C2/C3/C5/C6 | ESP32-S2/S3 | ESP32-C6 on ESP32-P4-Function-EV-Board |
|-------------|-------|-------------------|-------------|---------------------------------------|
| CLK | 14 | 6 | 12 | 19 |
| MOSI | 13 | 7 | 11 | 20 |
| MISO | 12 | 2 | 13 | 21 |
| CS | 15 | 10 | 10 | 18 |
| Handshake | 26 | 3 | 17 | 22 |
| Data Ready | 4 | 4 | 5 | 23 |
| Reset In | EN | EN/RST | EN/RST | EN/RST |
> [!NOTE]
> - Always try to use IO_MUX pins from the datasheet for optimal performance on both sides.
> - These GPIO assignments are based on default Kconfig configurations & are configurable.
> - Once ported, any other non ESP host with standard SPI can be used.
> - All ESP chipsets support SPI Full Duplex mode. Chipsets with Wi-Fi/Bluetooth can be used as co-processor.
> [!IMPORTANT]
> - Ensure proper grounding between host and co-processor devices.
> - Use short, high-quality cables for connections.
> - For production designs, consider using a properly designed PCB with controlled impedance traces.
## 6 Set-Up ESP-IDF
Before setting up the ESP-Hosted host & co-processor for SPI Full 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](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/windows-setup.html).
- Use the ESP-IDF [Powershell Command Prompt](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/windows-setup.html#using-the-command-prompt) for subsequent commands.
- **Linux or MacOS**
- For bash:
```bash
bash docs/setup_esp_idf__latest_stable__linux_macos.sh
```
- For fish:
```fish
fish docs/setup_esp_idf__latest_stable__linux_macos.fish
```
#### Option 2: Manual Way
Please follow the [ESP-IDF Get Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html) for manual installation.
## 7 Flashing the Co-processor
| Supported Co-processor Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-S2 | ESP32-S3 |
| ------------------------------ | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
There are two methods to flash the ESP-Hosted co-processor firmware:
### 7.1 Create Co-processor Project
1. Create co-processor project possibly outside of ESP-IDF project directory using
```bash
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:
```bash
idf.py set-target <target>
```
Replace `<target>` with your specific ESP chip (e.g., esp32c3, esp32s3).
### 7.2 Co-processor Config
Configure the co-processor project using
```
idf.py menuconfig
```
#### 7.2.1 Transport config
- Navigate to "Example configuration" -> "Transport layer"
- Select "SPI Full-duplex"
#### 7.2.2 Any other config
Optionally, configure any additional SPI-specific settings under "SPI Full-duplex"
- Set the GPIO pins for SPI signals (MOSI, MISO, CLK, CS), Handshake, Data Ready, Reset
- Configure SPI mode (0, 1, 2, or 3)
- Set the SPI clock frequency
- Checksum enable/disable (Checksum is recommended to be enabled as spi hardware doesn't have any error detection)
###### 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.
### 7.3 Co-processor Build
Build the co-processor project
```
idf.py build
```
### 7.4 Co-processor Flashing
##### 7.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`
##### 7.4.2 Co-processor OTA Flashing (Subsequent Updates)
For subsequent updates, you can re-use ESP-Hosted-MCU transport, as it should be already working. While doing OTA, Complete co-processor firmware image is not needed and only co-processor application partition, 'network_adapter.bin' need to be re-flashed remotely from host.
1. Ensure your co-processor device is connected and communicating with the host with existing ESP-Hosted-MCU.
2. Create a web server
You can re-use your existing web server or create a new locally for testing. Below is example to do it.
- Make a new directory so that web server can be run into it and navigate into it
- Create simple local web server using python3
```bash
python3 -m http.server 8080
```
3. Copy the co-processor app partition `network_adapter.bin` in the directory where you created the web server.
- The `network_adapter.bin` can be found in your co-processor project build at `<co-processor_project>/build/network_adapter.bin`
4. Verify if web server is set-up correctly
- Open link `http://127.0.0.1:8080` in the browser and check if network_adapter.bin is available.
- Right click and copy the complete URL of this network_adapter.bin and note somewhere.
5. On the **host side**, use the `esp_hosted_slave_ota` function to initiate the OTA update:
```c
#include "esp_hosted.h"
const char* image_url = "http://example.com/path/to/network_adapter.bin"; //web server full url
esp_err_t ret = esp_hosted_slave_ota(image_url);
if (ret == ESP_OK) {
printf("co-processor OTA update failed[%d]\n", ret);
}
```
This function will download the firmware in chunk by chunk as http client from the specified URL and flash it to the co-processor device through the established transport.
In above web server example, You can paste the copied url earlier.
6. Monitor the OTA progress through the console output on both the host and co-processor devices.
> [!NOTE]
>
> A. The `esp_hosted_slave_ota` function is part of the ESP-Hosted-MCU API and handles the OTA process through the transport layer. \
> B. Ensure that your host application has web server connectivity to download the firmware file. \
> C. The co-processor device doesn't need to be connected to the web server for this OTA method.
## 8 Flashing the Host
| Supported Host Targets | Any ESP chipset | Any Non-ESP chipset |
| ----------------------- | --------------- | ------------------- |
### 8.1 Select Example to Run in Hosted Mode
Select an example from the [ESP-IDF examples directory](https://github.com/espressif/esp-idf/tree/master/examples) 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](https://github.com/espressif/esp-idf/tree/master/examples/wifi/iperf).
### 8.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)
### 8.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:
- Remove the default `sdkconfig.defaults.esp32p4` file.
- Create a new `sdkconfig.defaults.esp32p4` file with the following content:
```
CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=16
CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=64
CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM=64
CONFIG_ESP_WIFI_AMPDU_TX_ENABLED=y
CONFIG_ESP_WIFI_TX_BA_WIN=32
CONFIG_ESP_WIFI_AMPDU_RX_ENABLED=y
CONFIG_ESP_WIFI_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 hosts also, you can merge above configs in corresponding `sdkconfig.defaults.esp32XX` file.
###### 2. Set environment for your host ESP chip:
```
idf.py set-target <host_target>
```
###### 3. Flexible Menuconfig configurations
```
idf.py menuconfig
```
ESP-Hosted-MCU host configurations are available under "Component config" -> "ESP-Hosted config"
1. Select "SPI Full-duplex" as the transport layer
2. Change co chipset to connect to under "slave chipset to be used"
3. Optionally, configure SPI-specific settings like
- SPI Clock Freq (MHz)
- SPI Mode
- SPI 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
## 9 Testing and Troubleshooting
After flashing both the co-processor and host devices, follow these steps to connect and test your ESP-Hosted SPI Full Duplex setup:
1. Connect the hardware:
- Follow the pin assignments for SPI Full Duplex as specified in [Hardware Setup](docs/spi_full_duplex.md#5-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 Full 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 :: 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](shield-box-test-setup.md).
8. 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 connections](#5-hardware-setup) if you experience communication problems.
- ESP-Hosted-MCU troubleshooting guide: [docs/troubleshooting.md](docs/troubleshooting.md)
9. 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.
## 10 References
- [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/)
- [ESP32 Hardware Design Guidelines](https://www.espressif.com/en/products/hardware/esp32/resources)
- [SPI Protocol Basics](https://en.wikipedia.org/wiki/Serial_Peripheral_Interface)

View File

@@ -0,0 +1,811 @@
# 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](#1-quick-start-guide) below. For quick navigation, please unfold the Table of Contents below.
<details>
<summary>Table of Contents</summary>
- [1. Quick Start Guide](#1-quick-start-guide)
- [2. Introduction](#2-introduction)
- [3. SPI HD Configuration](#3-spi-hd-configuration) => [1 Clock and Phase](#31-clock-and-phase) || [2 Data Lines](#32-data-lines) || [3 Extra GPIO Signals](#33-extra-gpio-signals) || [4 Pin Assignments](#34-pin-assignments)
- [4. SPI HD Protocol](#4-spi-hd-protocol) => [1 Data IO Modes](#41-data-io-modes) || [2 Supported Commands](#42-supported-commands) || [3 Registers Used](#43-registers-used) || [4 Timing Diagrams](#44-timing-diagrams)
- [5. SPI HD Operation](#5-spi-hd-operation) => [1 Initialization](#51-initialization) || [2 Co-processor to Host Transfer](#52-co-processor-to-host-transfer) || [3 Host to Co-processor Transfer](#53-host-to-co-processor-transfer) || [4 Code Reference](#54-code-reference)
- [6. Hardware Considerations](#6-hardware-considerations) => [1 General Considerations](#61-general-considerations) || [2 Jumper Wires](#62-jumper-wires) || [3 PCB Design](#63-pcb-design) || [4 Advanced Considerations](#64-advanced-considerations)
- [7. Hardware Setup](#7-hardware-setup)
- [8. Set-Up ESP-IDF](#8-set-up-esp-idf) => [Option 1: Installer Way](#option-1-installer-way) || [Option 2: Manual Way](#option-2-manual-way)
- [9. Flashing the Co-processor](#9-flashing-the-co-processor) => [1 Create Co-processor Project](#91-create-co-processor-project) || [2 Co-processor Config](#92-co-processor-config) || [3 Co-processor Build](#93-co-processor-build) || [4 Co-processor Flashing](#94-co-processor-flashing)
- [10. Flashing the Host](#10-flashing-the-host) => [1 Select Example to Run in Hosted Mode](#101-select-example-to-run-in-hosted-mode) || [2 Host Project Component Configuration](#102-host-project-component-configuration) || [3 Menuconfig, Build and Flash Host](#103-menuconfig-build-and-flash-host)
- [11. Testing and Troubleshooting](#11-testing-and-troubleshooting)
- [12. References](#12-references)
</details>
## 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](#7-hardware-setup)
- [8. Set-Up ESP-IDF](#8-set-up-esp-idf)
- [9. Flashing the Co-processor](#9-flashing-the-co-processor)
- [10. Flashing the Host](#10-flashing-the-host)
- [11. Testing and Troubleshooting](#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](#4-spi-hd-protocol).
## 3 SPI HD Configuration
To enable SPI HD on the Host and co-processor using `idf.py menuconfig`:
1. On Host: **Component config** ---> **ESP-Hosted config** --->
**Transport layer** and choose **SPI Half-duplex**.
2. On Co-processor: **Example configuration** ---> **Transport layer** and
choose **SPI Half-duplex**.
### 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 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.
### 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** ---> **SPI Half-duplex Configuration** --->
> **GPIOs** and set **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](#33-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](#11-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](#44-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](images/spi_hd_timing_4_lines.svg)
*SPI Transaction using 4 data lines*
![Using Two Data Lines](images/spi_hd_timing_2_lines.svg)
*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.
```mermaid
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.
```mermaid
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.
```mermaid
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.c`](https://github.com/espressif/esp-hosted-mcu/blob/main/slave/main/spi_hd_slave_api.c) implements the code to run the SPI HD driver on the co-processor
- [`host/drivers/transport/spi_hd/spi_hd_drv.c`](https://github.com/espressif/esp-hosted-mcu/blob/main/host/drivers/transport/spi_hd/spi_hd_drv.c) implements the generic code to run the SPI HD driver on the host
- [`host/port/spi_hd_wrapper.c`](https://github.com/espressif/esp-hosted-mcu/blob/main/host/port/spi_hd_wrapper.c) implements 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_FREQ` in [ESP-IDF co-processor SPI clock benchmark](https://github.com/espressif/esp-idf/blob/master/components/esp_driver_spi/test_apps/components/spi_bench_mark/include/spi_performance.h)
- 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 re-used 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](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/windows-setup.html).
- Use the ESP-IDF [Powershell Command Prompt](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/windows-setup.html#using-the-command-prompt) for subsequent commands.
- **Linux or MacOS**
- For bash:
```bash
bash docs/setup_esp_idf__latest_stable__linux_macos.sh
```
- For fish:
```fish
fish docs/setup_esp_idf__latest_stable__linux_macos.fish
```
#### Option 2: Manual Way
Please follow the [ESP-IDF Get Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html) 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
```bash
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:
```bash
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 to "Example configuration" -> "Transport layer"
- Select "SPI Half-duplex"
#### 9.2.2 Any other config
- Optionally, Configure any additional SPI-specific settings 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
There are two methods to flash the ESP-Hosted co-processor firmware:
##### 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)
For subsequent updates, you can re-use ESP-Hosted-MCU transport, as it should be already working. While doing OTA, Complete co-processor firmware image is not needed and only co-processor application partition, 'network_adapter.bin' need to be re-flashed remotely from host.
1. Ensure your co-processor device is connected and communicating with the host with existing ESP-Hosted-MCU.
2. Create a web server
You can re-use your existing web server or create a new locally for testing. Below is example to do it.
- Make a new directory so that web server can be run into it and navigate into it
- Create simple local web server using python3
```bash
python3 -m http.server 8080
```
3. Copy the co-processor app partition `network_adapter.bin` in the directory where you created the web server.
- The `network_adapter.bin` can be found in your co-processor project build at `<co-processor_project>/build/network_adapter.bin`
4. Verify if web server is set-up correctly
- Open link `http://127.0.0.1:8080` in the browser and check if network_adapter.bin is available.
- Right click and copy the complete URL of this network_adapter.bin and note somewhere.
5. On the **host side**, use the `esp_hosted_slave_ota` function to initiate the OTA update:
```c
#include "esp_hosted.h"
const char* image_url = "http://example.com/path/to/network_adapter.bin"; //web server full url
esp_err_t ret = esp_hosted_slave_ota(image_url);
if (ret == ESP_OK) {
printf("co-processor OTA update failed[%d]\n", ret);
}
```
This function will download the firmware in chunk by chunk as http client from the specified URL and flash it to the co-processor device through the established transport.
In above web server example, You can paste the copied url earlier.
6. Monitor the OTA progress through the console output on both the host and co-processor devices.
> [!NOTE]
>
> - The `esp_hosted_slave_ota` function is part of the ESP-Hosted-MCU API and handles the OTA process through the transport layer.
> - Ensure that your host application has web server connectivity to download the firmware file.
> - The co-processor device doesn't need to be connected to the web server for this OTA method.
## 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 recommanded 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 evaluted 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](https://github.com/espressif/esp-idf/tree/master/examples) 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](https://github.com/espressif/esp-idf/tree/master/examples/wifi/iperf).
### 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:
- Remove the default `sdkconfig.defaults.esp32p4` file.
- Create a new `sdkconfig.defaults.esp32p4` file with the following content:
```
CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=16
CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=64
CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM=64
CONFIG_ESP_WIFI_AMPDU_TX_ENABLED=y
CONFIG_ESP_WIFI_TX_BA_WIN=32
CONFIG_ESP_WIFI_AMPDU_RX_ENABLED=y
CONFIG_ESP_WIFI_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 hosts also, you can merge above configs in corresponding `sdkconfig.defaults.esp32XX` file.
###### 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 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](#7-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](shield-box-test-setup.md).
8. 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](#7-hardware-setup) if you experience communication problems.
- ESP-Hosted-MCU troubleshooting guide: [docs/troubleshooting.md](docs/troubleshooting.md)
9. 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

View File

@@ -0,0 +1,149 @@
# Troubleshooting ESP-Hosted
**Table of Contents**
- [1. ESP host to evaluate already has Native Wi-Fi](#1-esp-host-to-evaluate-already-has-native-wi-fi)
- [2. Raw Throughput Testing](#2-raw-throughput-testing)
- [3. Make sure Hosted code is in sync for Master and Slave](#3-make-sure-hosted-code-is-in-sync-for-master-and-slave)
- [4. Make sure GPIOs match on both the Host and Slave](#4-make-sure-gpios-match-on-both-the-host-and-slave)
- [5. ESP-Hosted Master Not Connecting to Slave](#5-esp-hosted-master-not-connecting-to-slave)
- [6. Getting `Drop Packet` Errors](#6-getting-drop-packet-errors)
- [7. References](#7-references)
## 1 ESP host to evaluate already has Native Wi-Fi
Sometimes users have two ESPs, but both having Wi-Fi native capability.
This section explains how to run ESP-Hosted-MCU on ESP host chipsets that already have native Wi-Fi support. To run ESP-Hosted-MCU on such hosts, native Wi-Fi support needs to be disabled from base ESP-IDF in use. There are alternatives to do this:
##### 1.1 Different ESP chipset types for host and slave
If host and slave not the same ESP chipset types, Wi-Fi capability can be disabled for host ESP chipset alone. Edit the ESP-IDF file
`components/soc/<soc>/include/soc/Kconfig.soc_caps.in` and change
all `WIFI` related configs to `n`. For example:
```
config SOC_WIFI_SUPPORTED
bool
# default y # original configuration
default n
```
This should be done for all `SOC_WIFI_xxx` configs found in the file.
For ESP Chipsets without native Wi-FI, `SOC_WIFI_xxx` configs will be
`n` by default.
##### 1.2 Same ESP chipset types for host and slave
There is possibility that you have two chipsets to evaluate, but both are exactly same chipset type. For example, two ESP32-C3. In this case, it is a two step build, first for host and second for slave.
While building for host ESP chipset, follow above (1) and flash, monitor. Once host is flashed fine, revert all the changes and flash the slave ESP chipset.
## 2 Raw Throughput Testing
While aiming the high performance and even while assessing the solution correctness, It is crucial to understand the bottlenecks in the system.
'Raw throughput testing' is simple transport level testing, which would showcase the maximum throughput that the transport is able to achieve, right now in current set-up.
In this test, dummy data is sent from one transport end to other continously, without involving Wi-Fi, Bluetooth or any other code legs. This test can be performed in following ways:
- Host to slave (Half duplex) : dummy data to be sent from host to slave continously
- Slave to Host (Half duplex) : dummy data to be sent from slave to host continously
- Full duplex bi-directional : dummy data to be sent from both the directions simulataneously
This can verify hardware signal integrity and address porting issues. It also helps to assess the achievable throughput of the Hosted solution. It can be further optionally used for transport throughput fine-tuning.
> [!IMPORTANT]
> Use Raw throughput test to verify that Hosted hardware and software are
> working as expected before involving other software layers like
> networking.
To enable the Raw Throughput Option on Slave, enter `Menuconfig` and
enable **Example Configuration** ---> **Hosted Debugging** --->
**RawTP**.
To enable the Raw Throughput Option and set Raw Throughput direction
on Host, enter `Menuconfig` and enable **Component config** --->
**ESP-Hosted config** ---> **Debug Settings** ---> **RawTP**. Set
the data transfer direction: **Host to Slave**, **Slave to Host** or
**Bidirectional**.
## 3 Make sure Hosted code is in sync for Master and Slave
The [README](../README.md) instructions will always fetch the latest
version of ESP-Hosted from the Component Registry. Generally, this
should be fine. But you can also fetch ESP-Hosted code based on a
revision to get a fixed version of the code:
For example, to fetch version 0.0.9 of ESP-Hosted Master:
```
idf.py add-dependency "espressif/esp_hosted^0.0.9"
```
To fetch version 0.0.9 of the ESP-Hosted Slave:
```
idf.py create-project-from-example "espressif/esp_hosted^0.0.9:slave"
```
This will ensure that both the Master and Slave code are fixed and in
sync for your project. Please ensure you use latest versions for bug-fixes
> [!NOTE]
> When you switch Hosted versions, make sure you use the same version
> of the Master and Slave code. There may be changes to the Hosted
> implementation that may make different versions of Hosted Master and
> Slave incompatible.
## 4 Make sure GPIOs match on both the Host and Slave
- Check that the GPIOs you use on the Host and Slave are correct and are connected together as expected
- Verify that the GPIO values you set in `menuconfig` match the hardware GPIOs you are actually using
- Ensure that you are not using incompatible GPIOs:
- on the ESP32, some GPIOs are input only and cannot be used for output
- on the ESP32 and ESP32-C6, the GPIOs used for SDIO are fixed and cannot be changed
## 5 ESP-Hosted Master Not Connecting to Slave
If you see the following error on the ESP-Hosted Master console using the SPI Interface:
```
E (10645) transport: Not able to connect with ESP-Hosted slave device
```
or this error on the ESP-Hosted Master console using the SDIO Interface:
```
E (1735) sdmmc_common: sdmmc_init_ocr: send_op_cond (1) returned 0x107
```
It means that something is wrong with the SPI or SDIO connection and
the Host cannot communicate with the slave.
- Check your physical GPIO signals and verify that they are connected
- Ensure that you have selected the same transports for the slave and
host (both are using the same SPI or SDIO interface).
- It is expected that slave and host uses exact same codebase (git commit)
- Transport configured at slave matches to that of host
- Firmware configured with incompatible configurations also would result in issues.
- Verify that the physical GPIO signals is the same as those assigned to the system using `Menuconfig` on both the Host and Slave
- If you selected SDIO as the interface and your host is a classic ESP32, there may be conflict with the GPIO used to bootstrap the ESP32 and used in SDIO. See "Conflicts Between Bootstrap and SDIO on DAT2" in
[References](#7-references) for more information
- for SDIO, verify that pull-ups and other signalling requirments (short, shielded connections) are also met. See the [SDIO interface](sdio.md) page for more information on SDIO requirements
- If your transport allows on jumper cables, cross-check max length of jumper cables allowed
## 6 Getting `Drop Packet` Errors
For the SPI interface, if you see an error similar to this:
```
I (478522) spi: rcvd_crc[30224] != exp_crc[36043], drop pkt
```
Your SPI interface is facing signal integrity errors.
- try reducing the SPI `CLK` frequency (using `Menuconfig`). If the
problem goes away, it indicates that there is an issue with the
physcial SPI signals
- use an oscilloscope to check the physical signals on the SPI
interface for noise, ringing, etc. that may affect the signals
## 7 References
- [Conflicts Between Bootstrap and SDIO on DAT2](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/sd_pullup_requirements.html#conflicts-between-bootstrap-and-sdio-on-dat2)

View File

@@ -0,0 +1,450 @@
# ESP-Hosted UART Operation for Wi-Fi and Bluetooth
Section 6 to 8 covers the complete step-wise setup co-processor and host with UART.
If you wish to skip the theory, you can refer the [Quick Start Guide](#1-quick-start-guide) below. For quick navigation, please unfold the Table of Contents below.
<details>
<summary>Table of Contents</summary>
- [1 Quick Start Guide](#1-quick-start-guide)
- [2 Introduction](#2-introduction)
- [3 Hardware Considerations](#3-hardware-considerations) => [1 GPIO Configuration for UART](#31-gpio-configuration-for-uart) || [2 Extra GPIO Signals Required](#32-extra-gpio-signals-required) || [3 General Hardware Considerations](#33-general-hardware-considerations) || [4 PCB Design](#34-pcb-design) || [5 Advanced Considerations](#35-advanced-considerations)
- [4 Hardware Setup](#4-hardware-setup)
- [5 Set-Up ESP-IDF](#5-set-up-esp-idf) => [Option 1: Installer Way](#option-1-installer-way) || [Option 2: Manual Way](#option-2-manual-way)
- [6 Flashing the Co-processor](#6-flashing-the-co-processor) => [1 Create Co-processor Project](#61-create-co-processor-project) || [2 Co-processor Config](#62-co-processor-config) || [3 Co-processor Build](#63-co-processor-build) || [4 Co-processor Flashing](#64-co-processor-flashing)
- [7 Flashing the Host](#7-flashing-the-host) => [1 Select Example to Run in Hosted Mode](#71-select-example-to-run-in-hosted-mode) || [2 Host Project Component Configuration](#72-host-project-component-configuration) || [3 Menuconfig, Build and Flash Host](#73-menuconfig-build-and-flash-host)
- [8 Testing and Troubleshooting](#8-testing-and-troubleshooting)
- [9 References](#9-references)
</details>
## 1 Quick Start Guide
This section provides a brief overview of how to get started with ESP-Hosted using UART mode.
These sections will guide you through the process of flashing both the co-processor and host devices, setting up the hardware connections, and verifying successful communication.
## 2 Introduction
UART is a low-speed bus that only requires two signal lines to communicate between the host and co-processor.
UART is supported on all ESP devices, and many other MCUs and operating systems. It is quick to bring up and test.
However, UART is a low-speed bus, and not recommended for environments where high network throughput (more than 1 Mbits/s) is required.
> [!NOTE]
> UART is used to transport both Wi-Fi and Bluetooth data (as Hosted HCI). Do not confuse this with standard HCI sent over UART, which does not support Wi-Fi.
## 3 Hardware Considerations
### 3.1 GPIO Configuration for UART
The UART interface can use almost any GPIO pins. For maximum speed and minimal delays, it is recommended to select the SDIO pin configuration that uses the dedicated `IO_MUX` pins.
### 3.2 Extra GPIO Signals Required
Extra GPIO signals are required for UART on Hosted and can be assigned to any free GPIO pins:
- `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 suggested to connect to the `EN` or `RST` pin on the co-processor, It is however configurable to use another GPIO pin.
>
> To configure this, use `idf.py menuconfig` on the co-processor: **Example configuration** ---> **UART Configuration** and set **Slave GPIO pin to reset itself**.
### 3.3 General Hardware Considerations
- Due to UART's low speed, signal integrity is less of a concern compared to SPI or SDIO. However, general rules on signal routing and noise reduction still applies.
- Jumper wires are only suitable for initial testing and prototyping.
- Ensure equal trace lengths for all UART connections, whether using jumper wires or PCB traces.
- Keep wires as short as possible, under 10 cm. Smaller the better.
- Use the lower baud rates like 115200 for evaluation. Once solution verified, optimise the baud rate in increasing steps to max possible value.
- Provide proper power supply for both host and co-processor devices. Lower or incorrect power supplies can cause communication issues & suboptimal performance.
- 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.
### 3.4 PCB Design
For optimal performance and reliability in production designs:
- Ensure equal trace lengths for all UART signals (Rx, Tx) as much as possible. This practice, known as length matching, is crucial for maintaining signal integrity and reducing timing skew, especially at higher frequencies.
- 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.
### 3.5 Advanced Considerations
- Calculate the maximum allowed trace length based on your baud rate and PCB material.
- Consider the capacitive load on the UART signals, especially for longer traces
- For very high-speed designs, consider using differential signaling techniques.
- Implement proper EMI/EMC design techniques to minimize electromagnetic interference.
## 4 Hardware Setup
Setting up the hardware involves connecting the master and co-processor devices via the UART pins and ensuring all extra GPIO signals are properly connected.
Any GPIO pin can be used for ESP-Hosted UART Rx and Tx. But avoid using the ESP assigned UART Tx0 and Rx0 pins. There are for debugging output. (ESP-Hosted uses another UART controller.)
## 5 Set-Up ESP-IDF
Before setting up the ESP-Hosted co-processor & host for UART 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](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/windows-setup.html).
- Use the ESP-IDF [Powershell Command Prompt](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/windows-setup.html#using-the-command-prompt) for subsequent commands.
- **Linux or MacOS**
- For bash:
```bash
bash docs/setup_esp_idf__latest_stable__linux_macos.sh
```
- For fish:
```fish
fish docs/setup_esp_idf__latest_stable__linux_macos.fish
```
### Option 2: Manual Way
Please follow the [ESP-IDF Get Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html) for manual installation.
## 6 Flashing the Co-processor
| Supported Co-processor Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-S2 | ESP32-S3 |
| ------------------------------ | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
### 6.1 Create Co-processor Project
1. Create co-processor project possibly outside of ESP-IDF project directory using
```bash
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:
```bash
idf.py set-target <target>
```
Replace `<target>` with your specific co-processor ESP chip (e.g., esp32c3, esp32s3).
### 6.2 Co-processor Config
Configure the co-processor project using
```
idf.py menuconfig
```
#### 6.2.1 Transport config
- Navigate to "Example configuration" -> "Transport layer"
- Select "UART"
#### 6.2.2 Any other config
- Optionally, Configure any additional UART-specific settings like TX and Rx GPIOs, baud rate, 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.
### 6.3 Co-processor Build
Build the co-processor project
```
idf.py build
```
### 6.4 Co-processor Flashing
There are two methods to flash the ESP-Hosted co-processor firmware:
##### 6.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`
##### 6.4.2 Co-processor OTA Flashing (Subsequent Updates)
For subsequent updates, you can re-use ESP-Hosted-MCU transport, as it should be already working. While doing OTA, Complete co-processor firmware image is not needed and only co-processor application partition, 'network_adapter.bin' need to be re-flashed remotely from host.
1. Ensure your co-processor device is connected and communicating with the host with existing ESP-Hosted-MCU.
2. Create a web server
You can re-use your existing web server or create a new locally for testing. Below is example to do it.
- Make a new directory so that web server can be run into it and navigate into it
- Create simple local web server using python3
```bash
python3 -m http.server 8080
```
3. Copy the co-processor app partition `network_adapter.bin` in the directory where you created the web server.
- The `network_adapter.bin` can be found in your co-processor project build at `<co-processor_project>/build/network_adapter.bin`
4. Verify if web server is set-up correctly
- Open link `http://127.0.0.1:8080` in the browser and check if network_adapter.bin is available.
- Right click and copy the complete URL of this network_adapter.bin and note somewhere.
5. On the **host side**, use the `esp_hosted_slave_ota` function to initiate the OTA update:
```c
#include "esp_hosted.h"
const char* image_url = "http://example.com/path/to/network_adapter.bin"; //web server full url
esp_err_t ret = esp_hosted_slave_ota(image_url);
if (ret == ESP_OK) {
printf("co-processor OTA update failed[%d]\n", ret);
}
```
This function will download the firmware in chunk by chunk as http client from the specified URL and flash it to the co-processor device through the established transport.
In above web server example, You can paste the copied url earlier.
6. Monitor the OTA progress through the console output on both the host and co-processor devices.
> [!NOTE]
>
> - The `esp_hosted_slave_ota` function is part of the ESP-Hosted-MCU API and handles the OTA process through the transport layer.
> - Ensure that your host application has web server connectivity to download the firmware file.
> - The co-processor device doesn't need to be connected to the web server for this OTA method.
## 7 Flashing the Host
Host are required to support two-line UART and the required baud rate in their hardware. All ESP chipsets hardware support UART.
| Supported Host Targets | Any ESP chipset | Any Non-ESP chipset |
| ----------------------- | --------------- | ------------------- |
Non ESP chipset may need to port the porting layer. It is strongly recommanded to evaluate the solution using ESP chipset as host before porting to any non-esp chipset.
### 7.1 Select Example to Run in Hosted Mode
Select an example from the [ESP-IDF examples directory](https://github.com/espressif/esp-idf/tree/master/examples) 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](https://github.com/espressif/esp-idf/tree/master/examples/wifi/iperf).
### 7.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)
### 7.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:
- Remove the default `sdkconfig.defaults.esp32p4` file.
- Create a new `sdkconfig.defaults.esp32p4` file with the following content:
```
CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=16
CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=64
CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM=64
CONFIG_ESP_WIFI_AMPDU_TX_ENABLED=y
CONFIG_ESP_WIFI_TX_BA_WIN=32
CONFIG_ESP_WIFI_AMPDU_RX_ENABLED=y
CONFIG_ESP_WIFI_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 hosts also, you can merge above configs in corresponding `sdkconfig.defaults.esp32XX` file.
###### 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 "UART" as the transport layer
2. Change co-processor chipset to connect to under "Slave chipset to be used"
3. Optionally, Configure UART-specific settings like
- UART Tx and Rx GPIOs
- UART baud rate
- UART Checksum Enable/Disable (Checksum is recommended to be enabled)
> [!NOTE]
> The actual baud rate used is determined by the hardware. Use an oscilloscope or logic analyzer to check the baud rate and its accuracy. If the actual baud rate used to send data drifts by more than a few percent from the expected baud rate, the receiver may not be able to correctly decode the data.
###### 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
## 8 Testing and Troubleshooting
After flashing both the co-processor and host devices, follow these steps to connect and test your ESP-Hosted UART setup:
1. Connect the hardware:
- Follow the pin assignments for UART as specified in [Hardware Setup](#4-hardware-setup).
- Ensure all necessary connections are made, including power, ground.
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 UART transport layer has been established.
4. Logs at both sides:
- Host:
```
I (465) transport: Attempt connection with slave: retry[0]
I (468) transport: Reset slave using GPIO[54]
I (473) os_wrapper_esp: GPIO [54] configured
I (478) gpio: GPIO[54]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
I (1650) transport: Received INIT event from ESP32 peripheral
I (1650) transport: EVENT: 12
I (1650) transport: EVENT: 11
I (1652) transport: capabilities: 0x88
I (1657) transport: Features supported are:
I (1662) transport: - BLE only
I (1666) transport: EVENT: 16
I (1669) transport: extended capabilities: 0x120
I (1675) transport: Extended Features supported:
I (1680) transport: * WLAN over UART
I (1684) transport: EVENT: 13
I (1688) transport: ESP board type is : 13
I (1693) transport: Base transport is set-up
```
- Co-processor:
```
I (484) fg_mcu_slave: *********************************************************************
I (493) fg_mcu_slave: ESP-Hosted-MCU Slave FW version :: 0.0.6
I (503) fg_mcu_slave: Transport used :: UART only
I (512) fg_mcu_slave: *********************************************************************
I (521) fg_mcu_slave: Supported features are:
I (526) h_bt: - BT/BLE
I (529) h_bt: - BLE only
I (532) fg_mcu_slave: capabilities: 0x88
I (537) fg_mcu_slave: Supported extended features are:
I (543) fg_mcu_slave: - WLAN over UART
I (547) h_bt: - BT/BLE (extended)
I (551) h_bt: - HCI Over UART (VHCI)
I (556) fg_mcu_slave: extended capabilities: 0x120
```
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](shield-box-test-setup.md).
8. Troubleshooting:
- If you encounter issues, refer to section 3.3 for checking the UART connection.
- Consider using a lower baud rate or checking your [hardware setup](#4-hardware-setup) if you experience communication problems.
- ESP-Hosted-MCU troubleshooting guide: [docs/troubleshooting.md](docs/troubleshooting.md)
9. 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 UART signals.
## 9 References
- ESP Universal Asynchronous Receiver/Transmitter (UART): https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/uart.html

View File

@@ -0,0 +1,79 @@
# ESP-Hosted-MCU Wi-Fi Design & Implementation details
## Sequence Diagram for Wi-Fi communication
On a ESP chipset with native Wi-Fi, a Wi-Fi api call or network data
from the application is processed internally on the chip and a Wi-Fi
response is returned to the application.
```mermaid
sequenceDiagram
box rgb(128, 128, 128) Host With Native WI-Fi
participant app as Application
participant api as ESP-IDF Wi-Fi Library
participant wifi as Wi-Fi Hardware
end
app ->> api : esp_wifi_xxx() or Network Data
api ->> wifi :
Note over wifi : Do Wi-Fi action
wifi -->> api : Wi-Fi response or Data
api -->> app : Response or Network Data
```
Using Wi-Remote and ESP-Hosted, the Wi-Fi api call from the
application is converted into a Hosted Call and transported to the
slave. The slave converts the Hosted Call back into an Wi-Fi api
call. The response (optionally with data) is converted into a Hosted
Response and transported back to the host. On the host, the Hosted
Response is converted back into a Wi-Fi response (optionally with
data) is returned to the application.
For Network Data, Hosted does not do data conversion and only
encapsulates the data for transport.
```mermaid
sequenceDiagram
box rgb(128, 128, 128) Host with ESP-Hosted
participant app as Application
participant remote as Wi-Fi Remote
participant hostedh as ESP-Hosted
participant transporth as Host Transport
end
box rgb(128, 128, 128) Slave ESP-Hosted
participant transports as Slave Transport
participant hosteds as Slave Hosted
participant api as ESP-IDF Wi-Fi Library
participant wifi as Wi-Fi Hardware
end
app ->> remote : esp_wifi_xxx()
remote ->> hostedh : esp_wifi_remote_xxx()
app ->> hostedh : Network Data
Note over hostedh : add Hosted header
hostedh ->> transporth :
transporth ->> transports : SPI/SDIO
transports ->> hosteds :
Note over hosteds : remove Hosted header
hosteds ->> api : esp_wifi_xxx()
hosteds ->> wifi : Network Data
api ->> wifi : Wi-Fi command or Data
Note over wifi: Do Wi-Fi action
wifi -->> api : Wi-Fi response or Data
wifi -->> hosteds : Network Data
api -->> hosteds : Response
Note over hosteds : add Hosted header
hosteds -->> transports :
transports -->> transporth : SPI/SDIO
transporth -->> hostedh :
Note over hostedh : remove Hosted header
hostedh -->> app : Network Data
hostedh -->> remote : Wi-Fi Command response
remote -->> app : Response
```