ESP32 SDIO Error: Fix For A2DP & WiFi Coexistence

by SLV Team 50 views
ESP32 SDIO Error: Fix for A2DP & WiFi Coexistence

Hey guys! 👋 I'm diving into a tricky issue I've been wrestling with: the dreaded H_SDIO_DRV: invalid ret or len_from_slave: 0 0 error when trying to get both A2DP streaming and Wi-Fi working simultaneously on an ESP32-P4 and ESP32 setup. This is a common challenge, so let's break it down and see if we can find a solution. The goal here is to help you, and anyone else, who's facing this problem.

The Core Problem: H_SDIO_DRV Error

First off, let's nail down what this H_SDIO_DRV: invalid ret or len_from_slave: 0 0 message means. It's a warning from the SDIO driver, the communication link between your host (ESP32-P4) and the coprocessor (ESP32). It's essentially saying that something went wrong during data transfer—the host isn't getting the expected response or data length from the slave. The fact that the return value (ret) and the length (len_from_slave) are both zero strongly indicates a major problem in the data exchange. This issue appears when running Bluetooth (A2DP streaming) and WiFi simultaneously.

This is a common issue when combining Bluetooth and WiFi. The main symptom is communication locking up between the host and coprocessor.

My Setup: The Battleground

Here’s what I’m working with:

  • ESP-IDF: 5.5.1 (the framework)
  • Espressif-IDE: 3.6.0 (the IDE)
  • ESP-Hosted: 2.6.4 (for SDIO communication)
  • ESP-Wifi-Remote: 1.2.0 (for WiFi connectivity)
  • Host: ESP32-P4NRW32
  • Coprocessor: ESP32-WROOM-32E-N16R2 (also tested on ESP32-WROOM-32E-N4)
  • Transport: SDIO (the communication method between host and coprocessor)

I’ve got a custom PCB, so I'm using SDIO for the communication, which adds another layer of complexity. The coprocessor is the ESP32-WROOM-32E-N16R2 module. I've also been able to replicate this on the ESP32-WROOM-32E-N4 base model.

The Minimal Example: Replicating the Issue

To make this reproducible, I've created a minimal example that replicates the problem. Let me walk you through it.

Host Side (ESP32-P4)

  1. A2DP Example: I started with the A2DP example from the ESP-IDF. You can find this example under the examples/bluetooth/bluedroid/classic_bt/a2dp_sink directory within the ESP-IDF. This is your foundation for Bluetooth audio streaming.
  2. Dependencies: I then integrated the esp-hosted and esp-wifi-remote libraries. These are crucial for managing the SDIO communication and WiFi connectivity.
  3. Configuration: I configured the coprocessor to be an ESP32 and set up the SDIO transport with the appropriate GPIO pins. I also enabled Bluedroid support, which is necessary for Bluetooth functionality.
  4. Memory Optimization for WiFi Remote: To ensure the WiFi and Bluetooth can coexist, I tweaked the esp-wifi-remote configuration to reduce memory usage. This is super important for avoiding conflicts:
    CONFIG_WIFI_RMT_STATIC_RX_BUFFER_NUM=2
    CONFIG_WIFI_RMT_DYNAMIC_RX_BUFFER_NUM=2
    # CONFIG_WIFI_RMT_STATIC_TX_BUFFER is not set
    CONFIG_WIFI_RMT_DYNAMIC_TX_BUFFER=y
    CONFIG_WIFI_RMT_TX_BUFFER_TYPE=1
    CONFIG_WIFI_RMT_DYNAMIC_TX_BUFFER_NUM=2
    CONFIG_WIFI_RMT_STATIC_RX_MGMT_BUFFER=y
    # CONFIG_WIFI_RMT_DYNAMIC_RX_MGMT_BUFFER is not set
    CONFIG_WIFI_RMT_DYNAMIC_RX_MGMT_BUF=0
    CONFIG_WIFI_RMT_RX_MGMT_BUF_NUM_DEF=5
    # CONFIG_WIFI_RMT_CSI_ENABLED is not set
    CONFIG_WIFI_RMT_AMPDU_TX_ENABLED=y
    CONFIG_WIFI_RMT_TX_BA_WIN=2
    CONFIG_WIFI_RMT_AMPDU_RX_ENABLED=y
    CONFIG_WIFI_RMT_RX_BA_WIN=2
    
  5. Main.c Modifications: In the main.c file, I replaced the controller initialization routine with the ESP-Hosted init, remote BT Controller init, and remote WiFi init routines. This is where you set up the SDIO, Bluetooth, and WiFi components to work together. Here is the code I used:
    // ------ ESP HOSTED
    esp_hosted_connect_to_slave();
    esp_hosted_init();
    // ------ ESP HOSTED
    
    // ------ BLUETOOTH
    /* initialize TRANSPORT first */
    if ((err = esp_hosted_bt_controller_init() != ESP_OK)) {
        ESP_LOGE(BT_AV_TAG, "%s esp_hosted_bt_controller_init() failed: %s", __func__, esp_err_to_name(err));
        return;
    }
    // enable bt controller
    if ((err = esp_hosted_bt_controller_enable() != ESP_OK)) {
        ESP_LOGE(BT_AV_TAG, "%s esp_hosted_bt_controller_enable() failed: %s", __func__, esp_err_to_name(err));
        return;
    }
    hosted_hci_bluedroid_open();
    /* get HCI driver operations */
    esp_bluedroid_hci_driver_operations_t operations = {
        .send = hosted_hci_bluedroid_send,
        .check_send_available = hosted_hci_bluedroid_check_send_available,
        .register_host_callback = hosted_hci_bluedroid_register_host_callback,
    };
    if ((err = esp_bluedroid_attach_hci_driver(&operations)) != ESP_OK)
    {
        ESP_LOGE(BT_AV_TAG, "%s esp_bluedroid_attach_hci_driver failed: %s", __func__, esp_err_to_name(err));
        return;
    }
    // ------ BLUETOOTH
    
    // ------ SIMPLE WIFI TEST
    esp_netif_init();
    esp_event_loop_create_default();
    esp_netif_create_default_wifi_sta();
    wifi_init_config_t wifi_initiation = WIFI_INIT_CONFIG_DEFAULT();
    esp_wifi_init(&wifi_initiation);
    wifi_config_t wifi_configuration = {
        .sta = {
            .ssid = "SSID",
            .password= "PASS"
          }
    };
    
    esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_configuration);
    esp_wifi_start();
    esp_wifi_set_mode(WIFI_MODE_STA);
    do
    {
        err = esp_wifi_connect();
        vTaskDelay(100);
    } while (err != ESP_OK);
    // ------ SIMPLE WIFI TEST
    

Coprocessor Side (ESP32)

  1. ESP-Hosted Slave Example: I used the ESP-Hosted slave example. You can create this using the ESP-IDF. The command is `idf.py create-project-from-example