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>
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "esp_ot_cli.c" "esp_hosted_openthread_app.c"
|
||||
INCLUDE_DIRS ".")
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: CC0-1.0
|
||||
*
|
||||
*/
|
||||
|
||||
#include "esp_hosted.h"
|
||||
#include "esp_hosted_openthread.h"
|
||||
#include "esp_hosted_openthread_app.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
#define TAG "h_ot_util"
|
||||
|
||||
esp_err_t esp_hosted_openthread_app_init(void)
|
||||
{
|
||||
esp_err_t res = ESP_OK;
|
||||
|
||||
res = esp_hosted_openthread_rcp_query(HOSTED_OPENTHREAD_QUERY_CONFIGURED);
|
||||
if (ESP_OK != res) {
|
||||
ESP_LOGE(TAG, "OT RCP not configured (enabled via Kconfig) on co-processor");
|
||||
return res;
|
||||
}
|
||||
|
||||
res = esp_hosted_openthread_rcp_init();
|
||||
if (ESP_OK != res) {
|
||||
ESP_LOGE(TAG, "failed to init OT RCP");
|
||||
return res;
|
||||
}
|
||||
|
||||
res = esp_hosted_openthread_rcp_query(HOSTED_OPENTHREAD_QUERY_INITED);
|
||||
if (ESP_OK != res) {
|
||||
ESP_LOGE(TAG, "OT RCP not inited on co-processor");
|
||||
return res;
|
||||
}
|
||||
|
||||
res = esp_hosted_openthread_rcp_start();
|
||||
if (ESP_OK != res) {
|
||||
ESP_LOGE(TAG, "failed to start OT RCP");
|
||||
return res;
|
||||
}
|
||||
|
||||
res = esp_hosted_openthread_rcp_query(HOSTED_OPENTHREAD_QUERY_ENABLED);
|
||||
if (ESP_OK != res) {
|
||||
ESP_LOGE(TAG, "OT RCP not enabled on co-processor");
|
||||
return res;
|
||||
}
|
||||
|
||||
res = esp_hosted_openthread_rcp_query(HOSTED_OPENTHREAD_QUERY_READY);
|
||||
if (ESP_OK != res) {
|
||||
ESP_LOGE(TAG, "OT RCP not ready on co-processor");
|
||||
return res;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
esp_err_t esp_hosted_openthread_app_deinit(void)
|
||||
{
|
||||
esp_err_t res = ESP_OK;
|
||||
|
||||
res = esp_hosted_openthread_rcp_stop();
|
||||
if (ESP_OK != res) {
|
||||
ESP_LOGE(TAG, "OT RCP failed to stop");
|
||||
return res;
|
||||
}
|
||||
|
||||
res = esp_hosted_openthread_rcp_deinit();
|
||||
if (ESP_OK != res) {
|
||||
ESP_LOGE(TAG, "OT RCP failed to deinit");
|
||||
return res;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: CC0-1.0
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __ESP_HOSTED_OPENTHREAD_APP_H__
|
||||
#define __ESP_HOSTED_OPENTHREAD_APP_H__
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
esp_err_t esp_hosted_openthread_app_init(void);
|
||||
esp_err_t esp_hosted_openthread_app_deinit(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: CC0-1.0
|
||||
*
|
||||
* OpenThread Command Line Example
|
||||
*
|
||||
* This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, this
|
||||
* software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_netif_types.h"
|
||||
#include "esp_openthread.h"
|
||||
#include "esp_openthread_lock.h"
|
||||
#include "esp_openthread_netif_glue.h"
|
||||
#include "esp_openthread_types.h"
|
||||
#include "esp_ot_config.h"
|
||||
#include "esp_vfs_eventfd.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "ot_examples_common.h"
|
||||
|
||||
#include "esp_hosted.h"
|
||||
#include "esp_hosted_openthread.h"
|
||||
#include "esp_hosted_openthread_app.h"
|
||||
|
||||
#if CONFIG_OPENTHREAD_STATE_INDICATOR_ENABLE
|
||||
#include "ot_led_strip.h"
|
||||
#endif
|
||||
|
||||
#if CONFIG_OPENTHREAD_CLI_ESP_EXTENSION
|
||||
#include "esp_ot_cli_extension.h"
|
||||
#endif // CONFIG_OPENTHREAD_CLI_ESP_EXTENSION
|
||||
|
||||
#define TAG "ot_esp_cli"
|
||||
|
||||
esp_err_t app_init_esp_hosted(void)
|
||||
{
|
||||
esp_err_t res = ESP_OK;
|
||||
|
||||
res = esp_hosted_init();
|
||||
if (res != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_hosted_init failed");
|
||||
return res;
|
||||
}
|
||||
|
||||
res = esp_hosted_connect_to_slave();
|
||||
if (res != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_hosted_connect_to_slave failed");
|
||||
return res;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
if (ESP_OK != app_init_esp_hosted()) {
|
||||
ESP_LOGE(TAG, "esp_hosted_util_init failed");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ESP_OK != esp_hosted_openthread_app_init()) {
|
||||
ESP_LOGE(TAG, "esp_hosted_openthread_app_init_init failed");
|
||||
return;
|
||||
}
|
||||
|
||||
// Used eventfds:
|
||||
// * netif
|
||||
// * OT task queue
|
||||
// * radio driver
|
||||
esp_vfs_eventfd_config_t eventfd_config = {
|
||||
.max_fds = 3,
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
#if CONFIG_OPENTHREAD_PLATFORM_NETIF
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
#endif
|
||||
ESP_ERROR_CHECK(esp_vfs_eventfd_register(&eventfd_config));
|
||||
|
||||
#if CONFIG_OPENTHREAD_CLI
|
||||
ot_console_start();
|
||||
ot_register_external_commands();
|
||||
#endif
|
||||
|
||||
static esp_openthread_config_t config = {
|
||||
#if CONFIG_OPENTHREAD_PLATFORM_NETIF
|
||||
.netif_config = ESP_NETIF_DEFAULT_OPENTHREAD(),
|
||||
#endif
|
||||
.platform_config = {
|
||||
.host_config = ESP_OPENTHREAD_DEFAULT_HOST_CONFIG(),
|
||||
.port_config = ESP_OPENTHREAD_DEFAULT_PORT_CONFIG(),
|
||||
},
|
||||
};
|
||||
|
||||
// get radio config from Hosted
|
||||
esp_hosted_openthread_radio_config_t hosted_radio_config = { 0 };
|
||||
if (0 != esp_hosted_openthread_get_radio_config(&hosted_radio_config)) {
|
||||
ESP_LOGE(TAG, "Failed to get OpenThread radio config from Hosted");
|
||||
return;
|
||||
}
|
||||
|
||||
// use Hosted Radio Config to setup our radio config
|
||||
#if CONFIG_OPENTHREAD_RADIO_SPINEL_UART
|
||||
if (hosted_radio_config.type != HOSTED_OPENTHREAD_TRANSPORT_UART) {
|
||||
ESP_LOGE(TAG, "Invalid Hosted Radio Config: expected UART radio config");
|
||||
return;
|
||||
}
|
||||
config.platform_config.radio_config.radio_mode = RADIO_MODE_UART_RCP;
|
||||
esp_hosted_openthread_uart_config_t *src = &hosted_radio_config.radio_uart_config;
|
||||
esp_openthread_uart_config_t *dst = &config.platform_config.radio_config.radio_uart_config;
|
||||
dst->port = src->port;
|
||||
dst->uart_config.baud_rate = src->baud_rate;
|
||||
dst->uart_config.data_bits = src->data_bits;
|
||||
dst->uart_config.parity = src->parity;
|
||||
dst->uart_config.stop_bits = src->stop_bits;
|
||||
dst->uart_config.flow_ctrl = src->flow_ctrl;
|
||||
dst->uart_config.rx_flow_ctrl_thresh = src->rx_flow_ctrl_thresh;
|
||||
dst->uart_config.source_clk = src->source_clk;
|
||||
dst->rx_pin = src->rx_pin;
|
||||
dst->tx_pin = src->tx_pin;
|
||||
#else
|
||||
#error "Unsupported Hosted Radio Config"
|
||||
#endif
|
||||
|
||||
ESP_ERROR_CHECK(esp_openthread_start(&config));
|
||||
#if CONFIG_OPENTHREAD_CLI_ESP_EXTENSION
|
||||
esp_cli_custom_command_init();
|
||||
#endif
|
||||
#if CONFIG_OPENTHREAD_STATE_INDICATOR_ENABLE
|
||||
ESP_ERROR_CHECK(esp_openthread_state_indicator_init(esp_openthread_get_instance()));
|
||||
#endif
|
||||
#if CONFIG_OPENTHREAD_NETWORK_AUTO_START
|
||||
ot_network_auto_start();
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: CC0-1.0
|
||||
*
|
||||
* OpenThread Command Line Example
|
||||
*
|
||||
* This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, this
|
||||
* software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_openthread_types.h"
|
||||
|
||||
#define ESP_OPENTHREAD_DEFAULT_HOST_CONFIG() \
|
||||
{ \
|
||||
.host_connection_mode = HOST_CONNECTION_MODE_NONE, \
|
||||
}
|
||||
|
||||
#define ESP_OPENTHREAD_DEFAULT_PORT_CONFIG() \
|
||||
{ \
|
||||
.storage_partition_name = "nvs", \
|
||||
.netif_queue_size = 10, \
|
||||
.task_queue_size = 10, \
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
dependencies:
|
||||
espressif/esp_hosted:
|
||||
rules:
|
||||
- if: target in [esp32p4, esp32h2]
|
||||
version: '*'
|
||||
espressif/esp_ot_cli_extension:
|
||||
version: ~2.0.0
|
||||
espressif/esp_wifi_remote:
|
||||
rules:
|
||||
- if: target in [esp32p4, esp32h2]
|
||||
- if: idf_version <6.1
|
||||
version: '>=1.3.1'
|
||||
idf:
|
||||
version: '>=4.1.0'
|
||||
ot_examples_common:
|
||||
path: ${IDF_PATH}/examples/openthread/ot_common_components/ot_examples_common
|
||||
ot_led:
|
||||
path: ${IDF_PATH}/examples/openthread/ot_common_components/ot_led
|
||||
Reference in New Issue
Block a user