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.

Any news or updates on this one ?
I think I have the same issues with the ESP32C3 with my custom board using default MISO.
I have done the fix but Im running v2.09 and it seems I can no longer read the SD.
Will be testing more tomorrow before I end up using a different pin.

You said you can no longer read the SD. Does that mean you WERE reading the SD at one point after you did the fix? Using a different pin for MISO might be another adventure of itself, but worth a try. There are very few pins on this little device to work with, so hopefully you have another option that you aren’t using already. If you are using the expansion board, without any mods, then your SPI pin assignments are rigid and routed to the SD slot.

If I correctly interpret your statement as… you did the fix and were successfully reading SD, and then updated to v2.09, and now it’s broke, then I would expect the update to v2.09 wrote over your fix, and you would need to do the fix again. I haven’t done any work on this since my original post, so I don’t have any experience with other versions of the library. The basics of the fix is to clock the SD card for 1 byte, with anything, right after setting CS high. This just runs the clock to the SD card for 8 bits and causes the SD card to release the MISO pin. With a different library, you may have to dig to find where the CS is released and add an instruction to send another byte while CS is high. With CS high, the byte doesn’t go anywhere, but the clock cycles, and that’s the key.

If your issue is really the same as what I saw, then you would find that, without the fix, the SD card works fine until the end of the program. But at the end, the SD card is still holding the MISO line low. Then when you reset the device, that line is playing the role of the BOOT button pin and is seen as low and thinks you want to enter bootloader mode. You would have to remove the card and reset in order to get the boot pin to be seen as high (to skip bootloader and run your program). If you are experiencing some different type of symptom, then I’m not sure you are dealing with the same issue and “fix” as what I described.

Please keep us posted with what you find, for future readers.

Ive only recently started with ESP32C3 so never had anything other than v2.09
I have had the SDTest sketch working, writing and reading to a file on the SD card, but not working after a reset. I see MISO being held low and it enters boot mode.
I have applied the fix as mentioned, finding the sdDeselectCard function in sd_diskio.cpp, but after that fix, SDTest fails to read back the test file that it has just written too. I’ll be looking at this on the scope soon.

Initializing SD card…initialization done.
Writing to test.txt…done.
error opening test.txt

I have another SPI device hanging off the same bus, so I’ll be trying a few more things before I start hacking the board and changing the MISO line.

  • I have seen in the ESP32C3 documentation that there is a SPI_SLAVE_REG (0x00E0) with bits [1:0] setting SPI_CLK_MODE where 0x11 is SPI clock always on. I just have to work out how to write to this register in the Arduino Environment.
  • Use the ESP-IDF libraries in Platform IO and see if that library is any better.
  • Hack my PCB and move MISO elsewhere. Swap with a pin Im using as an LED.

Thanks for your help so far. Hope we can find a fix for me and then for others :wink: