Skip to content

espressif: release SDMMC cards per slot - #11500

Closed
ladyada-eagleclaw wants to merge 4 commits into
mainfrom
fix-sdio-slot-lifetime
Closed

ladyada-eagleclaw wants to merge 4 commits into
mainfrom
fix-sdio-slot-lifetime

Conversation

@ladyada-eagleclaw

Copy link
Copy Markdown

AI-assisted with Codex during Metro ESP32-P4 bring-up. This PR extracts the SDMMC slot-lifetime fix from #11497; frequency units and ESP-Hosted integration are separate changes.

Problem and fix

sdioio could select one slot while leaving sdmmc_host_t.slot at its default. It also released the entire controller when its own cards were closed, instead of releasing each card's slot. This prevents independent users, including a Wi-Fi coprocessor, from sharing the controller safely.

Set host.slot to the selected slot and use sdmmc_host_deinit_slot() for explicit deinitialization and VM cleanup. Remove the now-redundant controller-lifetime flag.

SDK fixes

The SDK pin contains two narrowly scoped prerequisites on the existing CircuitPython SDK base:

  • Controller reinitialization backport, from Espressif commit df53e6a2c312c677d2d2c3d738985b26b04a805d: make initialization idempotent and clear the released controller pointer.
  • Protect interrupt handling during slot removal: serialize ISR access with slot removal, ignore stale data events, and dispatch SDIO callbacks to the interrupting slot. A reproduced late DMA interrupt dereferenced a removed slot in sd_host_get_free_descriptors_count (MCAUSE=5, MTVAL=0x94).

Both commits are publicly fetchable from adafruit/esp-idf:metro-p4-sdmmc-reinit.

Validation

Metro ESP32-P4 Rev A, silicon v0.1, 16 MB flash/PSRAM, SD card and C6 connected. On the integrated tree: SD-first startup; 8 MiB patterned file write/read checks at 20 and 40 MHz; all 64 byte offsets for a 32 KiB read with garbage collection; and 24 mount/read/unmount/deinit cycles while Wi-Fi scanned all passed. Normal reboot returned with safe-mode reason NONE.

The hardware run included the separately submitted C6 integration; this PR isolates the controller/slot fix. The earlier integrated tree built for all six P4 configurations and an ESP32-S3. The isolated PR also builds with make -C ports/espressif BOARD=adafruit_feather_esp32s3_4mbflash_2mbpsram -j6 (1,847,072 bytes used; 1,036,512 bytes free in its firmware partition). Changed-file pre-commit and git diff --check pass. Only Metro was hardware-tested.

ladyada-eagleclaw and others added 2 commits October 2, 2026 21:51
Select the actual host slot and deinitialize only that slot, preserving other users of the controller. Pin the SDK reinitialization and interrupt-lifetime fixes required for repeated slot teardown.

Co-authored-by: Limor Fried <[email protected]>
Use remote Wi-Fi components and preserve the configured SDIO transport across VM reloads. Reserve its slot from sdioio allocation. Board wiring remains in the board definition.

Co-authored-by: Limor Fried <[email protected]>
@mikeysklar

Copy link
Copy Markdown
Collaborator

Could the two esp-idf commits merge into circuitpython-v6.0.1 first? The pin is on a side branch right now.

Initialize the required nested runtime after fetching ESP-Hosted, using the same filter or shallow-clone options as mbedtls.

Co-authored-by: Limor Fried <[email protected]>

@dhalbert dhalbert left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ladyada-eagleclaw Please submit a separate PR to our ESP-IDF fork for the ESP-IDF changes. Also re those changes:

  1. Why is one change in the legacy driver? Is that just an artifact of how that driver is structured?
  2. See if the problems these changes fixed are mentioned upstream in an issue or a recent commit.

espressif: add optional ESP-Hosted Wi-Fi on ESP32-P4
@ladyada-eagleclaw

Copy link
Copy Markdown
Author

The separate SDK PR is now open: adafruit/esp-idf#17, targeting circuitpython-v6.0.1.

The legacy/ directory is the compatibility API layer used by sdmmc_host_init() and sdmmc_host_init_slot(). It is built together with the shared src/sd_host_sdmmc.c implementation for ESP32, ESP32-S3, and P4; it is not an older-chip-only driver. CircuitPython and ESP-Hosted both use those entry points.

The reinitialization fix already exists upstream as df53e6a2 on release/v6.0 and c9a7a0fd on master. espressif/esp-idf#17889 describes the same SDMMC/Hosted double-initialization problem, with a v6.0.1 confirmation.

For the ISR/removal fix, the upstream search found related cleanup, a null-slot guard, and slot add/remove mutex changes, linked in the SDK PR. I did not find an exact counterpart that both serializes ISR access with removal and dispatches SDIO callbacks to the actual interrupting slot. Simply returning when the current transfer slot is gone can skip the surviving Hosted slot's interrupt.

The SDK PR's source tree is identical to the previously tested 577a17f7e4; its two commits retain upstream attribution and the linked contributor identities. It includes the existing build/hardware evidence and an independent source audit. Once that PR merges, the SDK pin here can move to the supported branch. No new SDK source changes or repeat hardware measurements are claimed by this packaging step.

AI-assisted with Codex.

@ladyada
ladyada requested a balanced review from Copilot October 5, 2026 19:44

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

Copilot was unable to run its full agentic suite in this review.

Copilot review overview

Review effort: Lite
Findings: 5 High severity

Open (5)
What changed in this PR

Adds support for using ESP-Hosted (Wi-Fi coprocessor) on the Espressif port, including new submodules and build system integration.

Changes:

  • Add esp-hosted and esp-wifi-remote submodules and fetch nested submodules in CI.
  • Introduce CIRCUITPY_ESP_HOSTED build flag and wire it through Make/CMake component selection.
  • Update Wi-Fi and SDIO codepaths to accommodate ESP-Hosted SDIO pin usage / slot conflicts.
File Description
tools/​ci_fetch_deps.py Initializes esp-hosted nested protobuf-c submodule during CI dependency fetch.
ports/​espressif/​mpconfigport.mk Adds CIRCUITPY_ESP_HOSTED option for esp32p4 and ties Wi-Fi/SSL to it.
ports/​espressif/​esp-wifi-remote Adds new submodule pointer for ESP Wi-Fi remote component.
ports/​espressif/​esp-idf Updates esp-idf submodule revision.
ports/​espressif/​esp-hosted Adds new submodule pointer for esp-hosted-mcu.
ports/​espressif/​common-hal/​wifi/​__init__.c Adds ESP-Hosted init path and SDIO pin claiming; switches to #include "esp_wifi.h".
ports/​espressif/​common-hal/​wifi/​ScannedNetworks.c Switches to #include "esp_wifi.h".
ports/​espressif/​common-hal/​wifi/​Radio.c Switches to #include "esp_wifi.h".
ports/​espressif/​common-hal/​sdioio/​SDCard.c Avoids ESP-Hosted SDIO slot; changes slot init/deinit lifecycle.
ports/​espressif/​Makefile Adds ESP-Hosted build/link integration and include injection paths.
ports/​espressif/​CMakeLists.txt Adds ESP-Hosted components/dirs when enabled; sets ESP_IDF_VERSION env var.
.gitmodules Registers new esp-hosted and esp-wifi-remote submodules.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 8 to +13
set(COMPONENTS bt driver esp_driver_dac esp_driver_gpio esp_driver_gptimer esp_driver_i2c esp_driver_i2s esp_driver_ledc esp_driver_pcnt esp_driver_rmt esp_driver_sdmmc esp_driver_spi esp_driver_touch_sens esp_driver_tsens esp_driver_uart esp-tls esp_adc esp_event esp_netif esp_psram esp_security esp_wifi esptool_py freertos log lwip main mbedtls mdns pthread soc ulp wpa_supplicant esp_lcd vfs esp_stdio sdmmc esp-camera)
set(EXTRA_COMPONENT_DIRS "esp-protocols/components/mdns" "esp-camera")

if(CIRCUITPY_ESP_HOSTED)
list(APPEND EXTRA_COMPONENT_DIRS "esp-hosted" "esp-wifi-remote/components/esp_wifi_remote")
list(APPEND COMPONENTS esp-hosted esp_wifi_remote)
Comment thread ports/espressif/Makefile
Comment on lines +948 to +950
ESP_IDF_COMPONENTS_LINK += esp_netif esp_security esp-tls esp_wifi lwip mbedtls mdns
ifneq ($(CIRCUITPY_ESP_HOSTED),1)
ESP_IDF_COMPONENTS_LINK += esp_coex esp_phy wpa_supplicant
Comment on lines +261 to 263
sdmmc_host_deinit_slot(self->slot);
never_reset_sdio[get_slot_index(self)] = false;
slot_in_use[get_slot_index(self)] = false;
Comment on lines +300 to 303
if (slot_in_use[i]) {
sdmmc_host_deinit_slot(i);
}
slot_in_use[i] = false;
Comment on lines +465 to +477
#ifdef CONFIG_ESP_HOSTED_ENABLED
const uint8_t pins[] = {
CONFIG_ESP_HOSTED_SDIO_PIN_CLK, CONFIG_ESP_HOSTED_SDIO_PIN_CMD,
CONFIG_ESP_HOSTED_SDIO_PIN_D0, CONFIG_ESP_HOSTED_SDIO_PIN_D1,
CONFIG_ESP_HOSTED_SDIO_PIN_D2, CONFIG_ESP_HOSTED_SDIO_PIN_D3,
CONFIG_ESP_HOSTED_SDIO_GPIO_RESET_SLAVE,
};
for (size_t i = 0; i < MP_ARRAY_SIZE(pins); i++) {
claim_pin_number(pins[i]);
never_reset_pin_number(pins[i]);
}
ESP_ERROR_CHECK(esp_hosted_init());
#endif
@tannewt

tannewt commented Oct 6, 2026

Copy link
Copy Markdown
Member

Just merged #11513 instead.

@tannewt tannewt closed this Oct 6, 2026
@dhalbert

dhalbert commented Oct 6, 2026

Copy link
Copy Markdown
Collaborator

@ladyada-eagleclaw There may still be a need for a smaller number of adafruit-specific ESP-IDF changes. That's what my Claude review said when considering how this PR would change if we updated to ESP-IDF v6.1. So check if you need a new PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants