Skip to content

esp32/sdcard: Unable to use SD card on some ESP32-P4 boards. #18984

@sfe-SparkFro

Description

@sfe-SparkFro

Port, board and/or hardware

esp32 port, ESP32-P4-Function-EV-Board (probably other boards with the ESP32-P4 too)

MicroPython version

MicroPython v1.27.0 on 2025-12-09; Generic ESP32P4 module with ESP32P4

Reproduction

Following the docs:

>>> import machine
>>> vfs.mount(machine.SDCard(), "/sd")

Expected behaviour

SD card should mount and be readable/writable.

Observed behaviour

E (11418) sdmmc_common: sdmmc_init_ocr: send_op_cond (1) returned 0x107
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: 16

SD card does not mount, and is not readable/writable.

Additional Information

I've debugged this, and there are 2 problems.

For context, the ESP32-P4 supports 2 SDMMC slots. Espressif confusingly uses both 1 indexing and 0 indexing in different contexts, so I'll adhere to strict 0 indexing here.

  • Slot 0 supports SDIO 3.0, and is capable of the fast UHS-I mode, but is on fixed GPIO pins (39-48). SDIO 3.0 also requires IO signals to switch between 3.3V and 1.8V, so those GPIO pins are powered by the VDD_IO_5 power pin, which can be powered by one of the internal LDOs on the ESP32-P4.
  • Slot 1 is only SDIO 2.0, but can be routed to any GPIO pin via the GPIO matrix. It always runs at 3.3V.

Again, I'm using the ESP32-P4-Function-EV-Board. Here is the schematic, look at the use of ESP_LDO_VO4 to power VDD_IO_5 the SDIO pull up resistors.

Problem 1 - Default slot

The DEFAULT_SLOT is hard coded to 1 when using SDMMC:

#if SOC_SDMMC_HOST_SUPPORTED
static const int DEFAULT_SLOT = 1;
#else

This board uses slot 0. It's likely that other boards will also use slot 0, since it supports SDIO 3.0.
I propose 2 possible solutions:

  1. Make DEFAULT_SLOT=0 on the ESP32-P4.
  2. Make the default slot configurable in mpconfigboard.h. This is probably the better solution.

FWIW just setting slot=0 is not enough to get the SD card to work on this board.

Problem 2 - IO voltage

SDIO 3.0 requires the IO voltage level to change between 3.3V and 1.8V. To achieve this, the board must connect an internal LDO on the ESP32-P4 to the VDD_IO_5 power pin, and the self->host.pwr_ctrl_handle must be configured in machine_sdcard_make_new(). I have a working solution based on the ESP-IDF SDMMC example, with the following changes to machine_sdcard.c:

+#include "sd_pwr_ctrl_by_on_chip_ldo.h"
...
 static mp_obj_t machine_sdcard_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
...
     #if SOC_SDMMC_HOST_SUPPORTED
     else {
         sdmmc_host_t _temp_host = SDMMC_HOST_DEFAULT();
         _temp_host.max_freq_khz = freq / 1000;
         self->host = _temp_host;
     }
     #endif

+    sd_pwr_ctrl_ldo_config_t ldo_config = {
+        .ldo_chan_id = 4,
+    };
+    sd_pwr_ctrl_handle_t pwr_ctrl_handle = NULL;
+
+    int ret = sd_pwr_ctrl_new_on_chip_ldo(&ldo_config, &pwr_ctrl_handle);
+    if (ret != ESP_OK) {
+        DEBUG_printf("  Failed to create a new on-chip LDO power control driver");
+    }
+    self->host.pwr_ctrl_handle = pwr_ctrl_handle;

     DEBUG_printf("  Calling host.init()");

     check_esp_err(self->host.init());
     self->flags |= SDCARD_CARD_FLAGS_HOST_INIT_DONE;
...
 }

This is sufficient for the SD card to work:

>>> import machine, os
>>> vfs.mount(machine.SDCard(slot=0), "/sd")
>>> os.listdir()
['sd', 'boot.py']

I'm currently hard coding ldo_chan_id = 4 since that's what the ESP32-P4-Function-EV-Board uses, but other dev boards may use a different LDO. I think the best solution would be for the default LDO to be defined in mpconfigboard.h.

It's worth noting that a board could power VDD_IO_5 from somewhere other than an internal LDO, in which case this gets more tricky. Espressif's docs say to "implement a custom sd_pwr_ctrl driver"; IMO it's probably not worth the extra effort to support this.

Code of Conduct

Yes, I agree

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions