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

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

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

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

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

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

237 lines
11 KiB
Markdown

# OpenThread and Zigbee Support
**Table of Contents**
<details>
- [1. Introduction](#1-introduction)
- [1.1 Prerequisites](#11-prerequisites)
- [1.1.1 Basic OpenThread / Zigbee Operation](#111-basic-openthread--zigbee-operation)
- [1.1.2 Operating as an OpenThread Border Router / Zigbee Gateway](#112-operating-as-an-openthread-border-router--zigbee-gateway)
- [2. Configuration](#2-configuration)
- [2.1 RCP Configuration on the Co-processor](#21-rcp-configuration-on-the-co-processor)
- [2.2 OpenThread Configuration on the Host](#22-openthread-configuration-on-the-host)
- [2.2.1 Initialising the OpenThread Connection from the Host Application](#221-initialising-the-openthread-connection-from-the-host-application)
- [2.3 Zigbee Configuration on the Host](#23-zigbee-configuration-on-the-host)
- [2.3.1 Initialising the Zigbee Connection from the Host Application](#231-initialising-the-zigbee-connection-from-the-host-application)
- [3. More Information](#3-more-information)
</details>
## 1. Introduction
OpenThread is an IP stack which features mesh network and low power consumption. Zigbee is a low-power, wireless mesh networking protocol designed for IoT devices. Both operate on the 802.15.4 standard.
ESP-Hosted runs the OpenThread or Zigbee Host stack on the Host Processor and the RCP (Radio Co-Processor) on the co-processor. The RCP is common and can operate with either OpenThread or Zigbee Host stacks.
The diagram below shows how the OpenThread Host and RCP communicate.
```
+------------+ +------------+
| | ESP-Hosted Transport | |
| OpenThread |<------------------------------------>| RCP | (Example: ESP32-C6)
| / Zigbee | | |
| Host | | |
| | UART | |
| |<------------------------------------>| |
| | | |
+------------+ +------------+
```
> [!NOTE]
> Currently a dedicated UART channel is required to pass OpenThread data between the Host and RCP. OpenThread over the current ESP-Hosted Transport to be supported in the future.
>
> Zigbee only supports using a dedicated UART channel for communication.
### 1.1 Prerequisites
#### 1.1.1 Basic OpenThread / Zigbee Operation
The co-processor must support OpenThread / Zigbee RCP operation.
Example co-processors that support RCP include the ESP32-H2, ESP32-C5 and ESP32-C6.
#### 1.1.2 Operating as an OpenThread Border Router / Zigbee Gateway
The co-processor must support RCP operation and Wi-Fi to operate as part of an OpenThread Border Router or Zigbee Gateway, which passes packets between the OpenThread / Zigbee and Wi-Fi networks.
Example co-processors as RCPs that support OpenThread Border Router / Zigbee Gateway operation include the ESP32-C5 and ESP32-C6.
**Coexistence between OpenThread / Zigbee and Wi-Fi**
The co-processor has only one hardware radio, so Wi-Fi and OpenThread / Zigbee have to share the radio (coexistence). This may lead to performance issues or dropped packets if there is a lot of traffic on Wi-Fi and/or OpenThread. See this guide on [RF Coexistence](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c6/api-guides/coexist.html) for more information.
The recommended option is to use two co-processors: one for Wi-Fi and one for OpenThread / Zigbee:
```
+------------+
| | ESP-Hosted Transport +-----------+
| OpenThread |<------------------------------------>| Wi-Fi | (Example: ESP32-C6)
| Border | +-----------+
| Router |
| / Zigbee | UART +-----------+
| Gateway |<------------------------------------>| RCP | (Example: ESP32-H2)
| | +-----------+
+------------+
```
Here, OpenThread / Zigbee is operating independent of ESP-Hosted. Since there are now two hardware radios, coexistence is not required.
More information on this mode of operation for the ESP32-P4 can be found in the [ESP-IDF OpenThread Border Router Example for ESP32-P4](https://github.com/espressif/esp-thread-br/blob/main/examples/basic_thread_border_router/README_esp32p4.md) or the [Zigbee SDK Gateway Example](https://github.com/espressif/esp-zigbee-sdk/tree/main/examples/zigbee_gateway).
## 2. Configuration
### 2.1 RCP Configuration on the Co-processor
> [!NOTE]
> This section targets the ESP32-C6 as the RCP. The same configuration is required when using other supported co-processors as the RCP.
In the ESP-Hosted project `slave` directory:
Edit `sdkconfig.defaults.esp32c6` to add or enable the OpenThread section. These settings are required to enable OpenThread, configure it to be an RCP, and to disable OpenThread features not required for a RCP.
```text
CONFIG_OPENTHREAD_ENABLED=y
CONFIG_OPENTHREAD_RADIO=y
CONFIG_OPENTHREAD_DIAG=n
CONFIG_OPENTHREAD_COMMISSIONER=n
CONFIG_OPENTHREAD_JOINER=n
CONFIG_OPENTHREAD_BORDER_ROUTER=n
CONFIG_OPENTHREAD_CLI=n
CONFIG_OPENTHREAD_SRP_CLIENT=n
CONFIG_OPENTHREAD_DNS_CLIENT=n
CONFIG_OPENTHREAD_TASK_SIZE=3072
CONFIG_OPENTHREAD_CONSOLE_ENABLE=n
CONFIG_OPENTHREAD_LOG_LEVEL_DYNAMIC=n
CONFIG_ESP_COEX_SW_COEXIST_ENABLE=y
```
On the command-line:
```bash
idf.py set-target esp32c6
idf.py menuconfig
```
Enter the OpenThread section to configure the dedicated OpenThread UART:
```
Example Configuration
└── [*] Enable OpenThread RCP (Radio Co-Processor) <─── ENABLE
└── OpenThread RCP Configuration
├── OpenThread Transport ──> UART <─── SET TO THIS VALUE
└── (configure UART parameters)
```
If you did not edit `sdkconfig.defaults.esp32c6` to enable OpenThread (above), modify these settings instead:
```
Component config
├── Wireless Coexistence
│ └── [*] Software controls WiFi/Bluetooth coexistence <─── ENABLE
└── OpenThread
├── [*] OpenThread <─── ENABLE
├── Thread Task Parameters
│ └── (3072) Size of OpenThread task <─── SET TO THIS VALUE
├── Thread Console
│ ├── [ ] Enable OpenThread console <─── DISABLE
│ └── [ ] Enable Openthread Command-Line Interface <─── DISABLE
├── Thread Core Features
│ ├── Thread device type ──> Radio Only Device <─── SET TO THIS VALUE
│ ├── [ ] Enable Commissioner <─── DISABLE
│ ├── [ ] Enable Joiner <─── DISABLE
│ ├── [ ] Enable SRP Client <─── DISABLE
│ ├── [ ] Enable DNS Client <─── DISABLE
│ ├── [ ] Enable diag Client <─── DISABLE
└── Thread Log
└── [ ] Enable dynamic log level control <─── DISABLE
```
You can now build the co-processor as an RCP.
### 2.2 OpenThread Configuration on the Host
> [!NOTE]
> This section targets the ESP32-P4 as the OpenThread Host.
OpenThread configuration on the host depends on the OpenThread features to be enabled. ESP-Hosted includes two examples:
- [OpenThread as a Border Router](https://github.com/espressif/esp-hosted-mcu/tree/main/examples/host_openthread_border_router)
- [OpenThread with CLI interface](https://github.com/espressif/esp-hosted-mcu/tree/main/examples/host_openthread_cli)
Further OpenThread Host examples can be found in the [ESP-IDF Examples directory](https://github.com/espressif/esp-idf/tree/master/examples/openthread).
**Further configuration**
PSRAM should be enabled to run OpenThread with ESP-Hosted due to memory requirements.
The OpenThread host must also be configured to recognise that the OpenThread RCP has coexistence enabled: otherwise OpenThread initialisation will fail due to a mismatch of OpenThread capabilities between the Host and RCP.
```text
### enable SPIRAM, else application will not start (out of memory)
CONFIG_SPIRAM=y
CONFIG_ESP_HOSTED_DFLT_TASK_FROM_SPIRAM=y
### SW coexistence on the co-processor is on, so this option must be
### disabled on host to keep OpenThread capabilities consistent
CONFIG_OPENTHREAD_RX_ON_WHEN_IDLE=n
```
For the ESP32-P4, these have been set-up in the `sdkconfig.default.esp32p4` configuration files in the ESP-Hosted OpenThread examples.
### 2.2.1 Initialising the OpenThread Connection from the Host Application
Initialise the ESP-Hosted interface first:
```c
esp_hosted_init();
esp_hosted_connect_to_slave();
```
Then initialise the OpenThread RCP using ESP-Hosted:
```c
esp_hosted_openthread_rcp_init();
esp_hosted_openthread_rcp_start();
```
In ESP-IDF, the OpenThread Host interface needs to know the OpenThread radio configuration. This is provided via ESP-Hosted:
```c
esp_hosted_openthread_radio_config_t hosted_radio_config = { 0 };
esp_hosted_openthread_get_radio_config(&hosted_radio_config);
```
`hosted_radio_config` is then used to configure the OpenThread's radio configuration.
See the ESP-Hosted OpenThread examples for more information.
### 2.3 Zigbee Configuration on the Host
> [!NOTE]
> This section targets the ESP32-P4 as the Zigbee Host.
> [!IMPORTANT]
> Zigbee support has been tested using ESP-IDF 5.5.4.
ESP-Hosted includes the following example:
- [Home Automation thermostat on a Zigbee Coordinator](https://github.com/espressif/esp-hosted-mcu/tree/main/examples/host_zigbee_thermostat)
See the ESP Zigbee SDK for a [Zigbee Gateway Example](https://github.com/espressif/esp-zigbee-sdk/tree/main/examples/zigbee_gateway). Further Zigbee examples can be found in the [ESP Zigbee SDK](https://github.com/espressif/esp-zigbee-sdk/).
### 2.3.1 Initialising the Zigbee Connection from the Host Application
Initialising the ESP-Hosted interface and setting the Zigbee radio configuration is similar to setting up under OpenThread. See [Section 2.2.1 above](#221-initialising-the-openthread-connection-from-the-host-application)
## 3. More Information
- [ESP-IDF OpenThread documentation](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/openthread.html)
- [ESP-IDF Coexistence Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c6/api-guides/coexist.html)
- [ESP-IDF OpenThread Border Router Example for ESP32-P4 with two co-processors](https://github.com/espressif/esp-thread-br/blob/main/examples/basic_thread_border_router/README_esp32p4.md)
- [ESP Zigbee SDK Programming Guide](https://docs.espressif.com/projects/esp-zigbee-sdk/en/latest/esp32/index.html)
- [ESP Zigbee SDK](https://github.com/espressif/esp-zigbee-sdk/)