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>
2.2 KiB
GPIO Expander
The ESP-Hosted solution provides a feature to control the GPIOs of the slave (co-processor) from the host MCU. This acts as a virtual GPIO expander over the existing transport link (SPI, SDIO, or UART), saving hardware pins and complexity on the host board.
Use Cases
- Driving LEDs or status indicators on the slave board.
- Reading button presses or sensor states connected to the slave.
- Resetting or enabling/disabling peripherals connected to the slave.
- Any application where the host needs simple digital I/O control over the slave.
API
The GPIO control functionality is exposed through the esp_hosted_cp_gpio.h header file. The API is designed to be similar to the standard ESP-IDF GPIO driver.
Key functions include:
esp_hosted_cp_gpio_config(): Configure a GPIO's mode (input/output), pull-up/pull-down, and interrupt type.esp_hosted_cp_gpio_set_level(): Set the logic level of an output GPIO.esp_hosted_cp_gpio_get_level(): Read the logic level of an input GPIO.esp_hosted_cp_gpio_set_direction(): Change the direction (input/output) of a GPIO.- ... and more.
Enabling the Feature
To use this feature, it must be enabled on both the host and the slave firmware.
Host Configuration
In the host's menuconfig, enable the following option:
Component config --->
ESP-Hosted --->
[*] Enable GPIO Expander feature on host
This corresponds to the CONFIG_ESP_HOSTED_ENABLE_GPIO_EXPANDER=y option.
Slave Configuration
In the slave's menuconfig, enable the following option:
(Top) → Example Configuration
[*] Enable GPIO Expander support (host can control slave GPIOs)
This corresponds to the CONFIG_ESP_HOSTED_ENABLE_GPIO_EXPANDER=y option.
Safety Guard
The slave firmware includes a safety mechanism to prevent the host from accidentally or maliciously interfering with GPIOs that are critical for the ESP-Hosted transport link itself. Any RPC request from the host to control a pin used by the active SPI, SDIO, or UART interface will be rejected by the slave.
Example
An example demonstrating the usage of this feature can be found in the examples/host_gpio_expander directory.