esp32/sdcard: Unable to use SD card on some ESP32-P4 boards.
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:~
https://github.com/micropython/micropython/blob/5c00edcee28491b6961a5db6aa0e5aa856664de4/ports/esp32/machine_sdcard.c#L216-L218
~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
SDCard not supported for ESP32C3
I have a custom ESP32C3 board that has an SD Card on it. I can easily run SD Card functions in Arduino with it but when I put micropython on it using the latest release, SDCard isn't even found when you try to call it. It's not my first time compiling my own board though so went into ports/esp32/boards/ESP32_GENERIC_C3/mpconfigboard.h (Using v5.1 of esp-idf and a current copy of this repository), changed #define MICROPY_HW_ENABLE_SDCARD (0) to #define MICROPY_HW_ENABLE_SDCARD (1) and then changed ports/esp32/machine_sdcard.c to the proper pins of sck=4 miso=5 and mosi=6 (also cs=1 in my case). I get the following errors...
/home/brad/esp-idf/micropython/ports/esp32/machine_sdcard.c:124:20: error: 'SPI3_HOST' undeclared here (not in a function); did you mean 'SPI2_HOST'?
124 | .host_id = SPI3_HOST,
| ^~~~~~~~~
| SPI2_HOST
/home/brad/esp-idf/micropython/ports/esp32/machine_sdcard.c: In function 'machine_sdcard_make_new':
/home/brad/esp-idf/micropython/ports/esp32/machine_sdcard.c:238:35: error: implicit declaration of function 'SDMMC_HOST_DEFAULT'; did you mean 'SDSPI_HOST_DEFAULT'? [-Werror=implicit-function-declaration]
238 | sdmmc_host_t _temp_host = SDMMC_HOST_DEFAULT();
| ^~~~~~~~~~~~~~~~~~
| SDSPI_HOST_DEFAULT
/home/brad/esp-idf/micropython/ports/esp32/machine_sdcard.c:238:35: error: invalid initializer
/home/brad/esp-idf/micropython/ports/esp32/machine_sdcard.c:295:9: error: unknown type name 'sdmmc_slot_config_t'
295 | sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
| ^~~~~~~~~~~~~~~~~~~
/home/brad/esp-idf/micropython/ports/esp32/machine_sdcard.c:295:43: error: implicit declaration of function 'SDMMC_SLOT_CONFIG_DEFAULT'; did you mean 'SDSPI_DEVICE_CONFIG_DEFAULT'? [-Werror=implicit-function-declaration]
295 | sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
| ^~~~~~~~~~~~~~~~~~~~~~~~~
| SDSPI_DEVICE_CONFIG_DEFAULT
/home/brad/esp-idf/micropython/ports/esp32/machine_sdcard.c:136:11: error: request for member 'gpio_cd' in something not a structure or union
136 | config.pin_var = machine_pin_get_id(arg_vals[arg_id].u_obj)
| ^
/home/brad/esp-idf/micropython/ports/esp32/machine_sdcard.c:301:9: note: in expansion of macro 'SET_CONFIG_PIN'
301 | SET_CONFIG_PIN(slot_config, gpio_cd, ARG_cd);
| ^~~~~~~~~~~~~~
/home/brad/esp-idf/micropython/ports/esp32/machine_sdcard.c:136:11: error: request for member 'gpio_wp' in something not a structure or union
136 | config.pin_var = machine_pin_get_id(arg_vals[arg_id].u_obj)
| ^
/home/brad/esp-idf/micropython/ports/esp32/machine_sdcard.c:302:9: note: in expansion of macro 'SET_CONFIG_PIN'
302 | SET_CONFIG_PIN(slot_config, gpio_wp, ARG_wp);
| ^~~~~~~~~~~~~~
/home/brad/esp-idf/micropython/ports/esp32/machine_sdcard.c:306:24: error: request for member 'width' in something not a structure or union
306 | slot_config.width = width;
| ^
/home/brad/esp-idf/micropython/ports/esp32/machine_sdcard.c:312:23: error: implicit declaration of function 'sdmmc_host_init_slot' [-Werror=implicit-function-declaration]
312 | check_esp_err(sdmmc_host_init_slot(self->host.slot, &slot_config));
| ^~~~~~~~~~~~~~~~~~~~
cc1: some warnings being treated as errors
ninja: build stopped: subcommand failed.
ninja failed with exit code 1, output of the command is in the /home/brad/esp-idf/micropython/ports/esp32/build-ESP32_GENERIC_C3/log/idf_py_stderr_output_1718238 and /home/brad/esp-idf/micropython/ports/esp32/build-ESP32_GENERIC_C3/log/idf_py_stdout_output_1718238
-e See https://github.com/micropython/micropython/wiki/Build-Troubleshooting
make: *** [Makefile:62: all] Error 1
Like I said, SD works perfectly fine in Arduino so I know there's no hardware issue or anything like that because I know I'm calling the proper pins. When I change things back to #define MICROPY_HW_ENABLE_SDCARD (0) everything compiles fine, but obviously there's no way to use an sd card without it set to 1. It's also obvious there are no definitions in machine_sdcard.c to support the ESP32C3, but I don't know how to fix it aside from changing to the necessary SPI pins.