XIAO ESP32C3 Expansion Board SD Card MISO Line Stays Low - Fix

There are several other posts on various forums about the issue with SD cards in SPI mode and how the MISO is not released to high-Z when the chip select (CS) is returned high. I discovered this problem when testing out my new Xiao ESP32C3 board plugged down to the expansion board with the SD slot. I pulled up the example Arduino IDE sketch SD_Test, compiled it for XIAO_ESP32C3 and it ran perfect. I saw the disk info, etc reported to the serial monitor. Then I hit the reset button to see it again and I noticed the serial monitor just said “wait usb download”. For some reason it is now hanging out in bootloader mode? Each time I hit reset, I get the same thing, unless I eject the SD card and push it back in. Then it works again.

I looked at Xiao ESP32C3 schematics and Xiao Expansion Board schematics and noticed the MISO line (D9) is also used as the ESP32 BOOT button pin. This is a fixed chip feature, not an arbitrary pin selection by Seeed.

It turns out there is a much-propagated bug in the arduino SD card libraries using SPI such that the SD card is not properly clocked after CS goes high to cause the SD card to release MISO to high-Z. This is unlike most other SPI slave devices. Therefore, after the SD_Test sketch finished, the MISO line continues to pull low by the SD card, and when I hit reset, the ESP32 sees the BOOT pin pulled low and enters the bootloader.

I read about the SD card interface issue when I found the Arduino forum post “SD Card - MISO doesn’t release [Bad MISO, Bad MISO!!]”. The fix within that post doesn’t apply exactly to the XIAO_ESP32C3 library. I found the analogous cpp file called sd_diskio.cpp. It has a function called sdDeselectCard(). I added a single line to run the clock for a byte right after the CS goes high. This fixes it.

void sdDeselectCard(uint8_t pdrv)
    ardu_sdcard_t * card = s_cards[pdrv];
    digitalWrite(card->ssPin, HIGH);
    card->spi->transfer(0XFF);  // <- Add this line

Actually, this issue would happen with the Xiao ESP32C3 whether or not you are using the expansion board. As long as you are using D9 for MISO to the SD card. I suspect it would be an issue with any ESP32 board that shares the BOOT pin with MISO on D9 (GPIO9).

Hello gleebit,

we have the same problem with the XIAO ESP32C3. If we use the default MISO pin and after the reset the device will go in bootloading mode. But if we try to implement your solution we fail read and write file. We added the suggested line exactly as you did, into the file located “C:\Users<myname>\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.7\libraries\SD\src” and called “sd_diskio.cpp” at line 117/118.

Without that specific code line (card->spi->transfer(0XFF)) all works fine except for the entering into bootloading after reset. I mean all works fine about sd card operativity.

Do you have read/write success? Do you have further suggestion?

Thank you in advance

Hi. I did have read/write success. After adding the line I discussed in the original post, the SD card continued to work correctly in all functions, AND the reset action worked correctly (because the MISO line was released after being clocked a few more cycles). That was the only line I needed to change. I noticed that you are using the version 2.0.7 and I am using version 2.0.6. Not sure if that will make a difference. You might want to compare the source, or just try downgrading to that version to see if it works?

I am using the SEEED XIAO ESP32 C3 with the SEEED expansion board.

Are you using any other devices on the same SPI channel? If so, I would just try a simple SD_Test sketch (from the Arduino IDE) with only the SD card attached.

Is your card formatted as FAT32? I would also try just a blank freshly formatted card. I’m not sure of the size limitations for this SD card library, or directory depth. I was using a few different cards that worked equally well. They were Gigastone 8GB and 16GB, and some non-branded 16GB cards, for what it’s worth.

I also noticed in my top level sketch I needed to create a constant for the slave select pin and set it to 4. Then I use that constant as an argument to SD.Begin().

This is my slave select pin definition:

const uint8_t SD_SS = 4;

Then when calling SD.Begin:


I recall looking at the SD library and confirming that the other SPI pins were correct for the XIAO ESP32. Just the slave select was incorrect.

I hope this helps. Let us know what you find.

I will try 2.0.6 in order to see if there are differences or maybe I will compare two libraries.

Im using SEEED XIAO ESP32C3 with my own custom board (easy easy design).
And before that I used the same SEEED XIAO ESP32C3 with breadboard cables.

Both had the same result.

If I use the default MISO, I enter in bootload mode.
If I use the default MISO, I can read / write correctly.
If I apply the line code you suggest, I can not write file correctly (I can even read directories and files, but not delete them, not remove directories, and so on).

If I use as MISO the TX pin (GPIO21) all works fine.

I use global define for the CS (or SS) pin (#define MY_CS 20… I use the GPIO20, RX pin).

The SD card is Fat32, with a small dimension 2 GB, after I tried 8 GB and then 16 GB.

I don’t know.

Next step I will produce a board for our project with the GPIO21 pin connected to MISO of the SD card.
But in this way, 1 pin becomes unusable.