-
-
Notifications
You must be signed in to change notification settings - Fork 8.8k
esp32/sdcard: Unable to use SD card on some ESP32-P4 boards. #18984
Description
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_5power 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:
micropython/ports/esp32/machine_sdcard.c
Lines 216 to 218 in 5c00edc
| #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:
- Make
DEFAULT_SLOT=0on the ESP32-P4. - Make the default
slotconfigurable inmpconfigboard.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