← index #18984Issue #16526
Related · high · value 2.719
QUERY · ISSUE

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

openby sfe-SparkFroopened 2026-03-23updated 2026-03-24
bugport-esp32

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:~

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:~

  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

CANDIDATE · ISSUE

ESP32-S3 SDCard(width=4) uses undocumented hard-coded pin assignments

closedby specternecteropened 2025-01-05updated 2025-03-13
bugport-esp32

Port, board and/or hardware

esp32 port - ESP32-S3

MicroPython version

MicroPython v1.25.0-preview.114.gbdda91fe7 on 2025-01-05

Reproduction

`
import machine
import os
import esp
esp.osdebug(True, esp.LOG_VERBOSE)

try:
sd = machine.SDCard(slot=1, width=4)
os.mount(sd, "/sd")
print("SD card mounted successfully.")

print("Contents of the SD card:")
for filename in os.listdir("/sd"):
    print(filename)

except Exception as e:
print("Error initializing SD card:", e)
`

Expected behaviour

Print a list of files on the SD card.

Observed behaviour

import sd_test
I (809804) gpio: GPIO[14]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (809854) gpio: GPIO[15]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (809854) gpio: GPIO[2]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (809864) gpio: GPIO[4]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (809874) gpio: GPIO[12]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (809884) gpio: GPIO[13]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
E (809924) sdmmc_common: sdmmc_init_ocr: send_op_cond (1) returned 0x107
Error initializing SD card: 16

Additional Information

I have tried everything to get an SD card to work like it does in sdmmc example for esp-idf (https://github.com/espressif/esp-idf/tree/master/examples/storage/sd_card/sdmmc). If I run this example in esp-idf, everything works perfectly fine right out of the box. It literally took 3 seconds to set up. After 7 hours of work and research, I simply can't get the sd card to work in micropython. Not SPI, not MMC, nothing. Micropython is supposed to be built on top of esp-idf so I would assume it should be just as easy. I looked at the SDCard class (https://docs.micropython.org/en/latest/library/machine.SDCard.html) and found that I should be able to configure the pins in mpconfigboard.h, to which I tried #define USDHC_DUMMY_PIN NULL , 0 #define MICROPY_USDHC1 \ { \ .cmd = { 35}, \ .clk = { 36 }, \ .cd_b = { USDHC_DUMMY_PIN },\ .data0 = { 37 },\ .data1 = { 38 },\ .data2 = { 33 },\ .data3 = { 34 },\ }
like it says, but it still tries to use ESP32 pins when I call the machine.SDCard(), like it also says to do. If I try to add the pins inside machine.SDCard() it says I have too many arguments. At one point I found someone with the same complaint but it had literally no information aside from "modify machine_sdcard.c" with no information on how to modify it and honestly I find that an absolutely terrible idea. Why modify the entire port to make a single board work, that should work from the beginning by default? I have no problem modifying a board to make it work but to me, modifying the port makes no sense unless it gets modified for everybody. I have spent 7 hours trying to get an sd card to work in micropython when it took 3 seconds to get to work in esp-idf. The only information I find are complaints about the same thing but no answers. This is insane.

Code of Conduct

Yes, I agree

Keyboard

j / / n
next pair
k / / p
previous pair
1 / / h
show query pane
2 / / l
show candidate pane
c
copy suggested comment
r
toggle reasoning
g i
go to index
?
show this help
esc
close overlays

press ? or esc to close

copied