← index #11483PR #992
Related · high · value 0.478
QUERY · ISSUE

Raspberry Pi Pico SD Card Errors

openby Draxiss314opened 2023-05-12updated 2025-06-25
bug

Originally posted here, posted here as there's no response over on micropython-lib:

I am not able to consistently write to my microSD card using the sdcard.py library. EDIT/UPDATE: I'm running "MicroPython v1.20.0 on 2023-04-26." My errors still look like what I've written below.

I have been following this tutorial to get my Raspberry Pi Pico write to my SD card. As the requisite drivers are no longer available in the normal micropython branch, I assume that they've been moved to micropython-lib (and that the tutorial is slightly out-of-date) and copied over the sdcard.py code from micropython-lib to my Pico.

I'm using a Raspberry Pi Pico with a Maker Pi breakout board. My IDE is Thonmy with the Micropython (Raspberry Pi Pico) interpreter. The SD card I use is a Transcend 2GB MicroSD Card, which I have formatted to be FAT32.

These issues may (?) be replicated by following the steps I followed and using the SDcard.py code.

When I attempt to test my Pico's ability (see below for code) to read and write to the SD card, my results are inconsistent and frequently mangle the SD card's filing system, requiring me to reformat or repair the partition before I can access it from my computer. Here is a sample of my most recent results:
After having deleted all data from the SD card and subsequently repairing the card, my output acted as expected:
Writing . . .
Finished Writing.
Reading . . .
Hello, SD World!
This is a test

That is the expected output.

Checking the SD card on my computer showed the expected result: a file called test01.txt containing
Hello, SD World!
This is a test
and nothing else.

Returning the SD card to my Pico, I ran the test again with this result:
Traceback (most recent call last):
File "<stdin>", line 27, in <module>
File "sdcard.py", line 252, in readblocks
File "sdcard.py", line 190, in readinto
OSError: timeout waiting for response

Checking the SD card on my computer, I found I could not mount it and had to repair the filesystem. After repairing, the data was garbled so I deleted it. Running the test again yielded this:
Writing . . .
Traceback (most recent call last):
File "<stdin>", line 29, in <module>
File "sdcard.py", line 252, in readblocks
File "sdcard.py", line 190, in readinto
OSError: timeout waiting for response

Again, filesystem must be repaired and data is garbled. After fixing and deleting:
Writing . . .
Traceback (most recent call last):
File "<stdin>", line 34, in <module>
File "sdcard.py", line 279, in writeblocks
OSError: [Errno 5] EIO
I think the data was garbled again (can't remember precisely), but regardless I repaired and deleted everything and tried again with the same error. This time, however, my filesystem wasn't corrupted and I had a blank test01.txt file.

I've been dealing with this for a while now and these events represent the typical pattern of issues I've been having with this code. Any help explaining what's going on would be greatly appreciated.

This is the code that I am using to test being able to read/write to the SD card; it's very similar to the default but I've adjusted it to use the Maker Pi Pico board and added a few lines to tell me whether I'm reading or writing:

import machine
import sdcard
import uos
import utime

# Assign chip select (CS) pin (and start it high)
cs = machine.Pin(15, machine.Pin.OUT) #It's 15 on the board we're using.
# Intialize SPI peripheral (start with 1 MHz)
spi = machine.SPI(1, 
                  baudrate=1000000,
                  polarity=0,
                  phase=0,
                  bits=8,
                  firstbit=machine.SPI.MSB,
                  sck=machine.Pin(10),
                  mosi=machine.Pin(11),
                  miso=machine.Pin(12))

# Initialize SD card
sd = sdcard.SDCard(spi, cs)

# Mount filesystem
vfs = uos.VfsFat(sd)
uos.mount(vfs, "/sd")

# Create a file and write something to it
with open("/sd/test01.txt", "w") as file:
    print("Writing . . .")
    file.write("Hello, SD World!\r\n")
    #utime.sleep_ms(75)
    file.write("This is a test\r\n")
    #utime.sleep_ms(75)
    file.close()
    print("Finished Writing.")

# Open the file we just created and read from it
with open("/sd/test01.txt", "r") as file:
    print("Reading . . . ")
    data = file.read()
    print(data)
    file.close()
CANDIDATE · PULL REQUEST

micropython/drivers/sdcard.py: Add CRC7 values for SDCard.cmd() function calls

openby multicoder9opened 2025-03-29updated 2026-03-02

Seems to be needed for some SDXC cards (SanDisk Ultra SDXC). FIXES Issue #17039

Edit: I'm including the following from the issue to clarify this pull request.

This is my first post to GitHub, but I've been working with micropython for about 10 years.

Recently, I have been writing some micropython based sdcard dataloggers for a CANbus project, mostly with rp2040 and rp2350 devices. I have been using the sdcard.py source file as a driver in my projects.

Today I noticed that switching from my 32GB SanDisk Ultra SDHC which worked just fine to a 32GB SanDisk Ultra SDXC caused it to fail on initialization. Others have noticed the same thing caused by missing CRC7 such as issue #12687. But none of them resulted in the fix getting merged back upstream. Here is a trivial diff for sdcard.py which adds the CRC7 values needed to get it working with my SDXC card, while still appearing to work on the older cards I've tested it on. Just for completeness, I've added a commented out minimalist Python function to compute these CRC7 values. (A quick internet search didn't pull up any Python functions for this.)

I figured I'd try to get the minimal changes merged upstream while more significant rewrites like the one in the linked thread above work their way through the process.

7 comments
Josverl · 2025-03-29

Thanks for the PR.

It would be nice if you could add some information about these magic values that make things work better.
Either in comments, or by defining it as a const with an explanatory name.

That would make it possible for future maintainers to understand better wat the code's intent is.

multicoder9 · 2025-03-30

Sorry, I started this as an issue here. I'm new to GitHub and didn't realize that the pull request would start another conversation. Is there a way to link the conversations together besides just posting a link?

But short version, as I explained in the issue, is that older cards such as my 32GB SanDisk Ultra SDHC work just fine with the current sdcard.py code, but a newer 32GB SanDisk Ultra SDXC fails at initialization. This is due to CRC7 values missing from the original code. Older cards allow ignoring the CRC7 values, but newer ones seem to be more strict. At the top of my patch, I've commented out a short Python function to generate the correct CRC7 values. Since I couldn't find a Python of this while searching around, I'll post it here in case anyone comes along:

def crc7( cmd:bytes ):
    crc = 0
    for value in cmd:
        for i in range(8):
            crc <<= 1
            if (value&0x80)^(crc&0x80):
                crc ^= 0x09
            value <<= 1
    return ((crc<<1)|1)&0xFF
def cmd_args_to_bytes( cmd:int, args:int ):
    return bytes( [cmd|0x40,(args>>24)&0xFF,(args>>16)&0xFF,(args>>8)&0xFF,args&0xFF] )

So for example, on the line self.cmd(58, 0, 0xFD, 4), if you do:

print( f'0x{crc7( cmd_args_to_bytes( 58, 0 ) ):02X}' )

You'll get the 0xFD I've included in the code.

multicoder9 · 2025-03-30

... or why this is better than the long-pending, mostly-reviewed SDcard sdcard.py rewrite for efficiency and function by mendenm · Pull Request #765 · micropython/micropython-lib

As for that, my thought is simple. This gets the existing code working with SDXC cards by doing nothing more than filling in the correct CRC7 values according to the spec. It is more of a bug fix than a restructuring. In the entire file, I've done nothing more than set 11 numbers that were unset (10 were 0, and one was 0xFF). I was hoping this would allow the existing sdcard.py to work for the users having problems with it while the "long-pending, mostly-reviewed" pull request continues its process of getting reviewed. But that is a major rewrite for overall improvement. Mine is simply correcting the fact that the CRC7 values in the existing one are wrong, and while many older cards are okay with this, some newer ones aren't.

So I hoped it would get approved in the meantime, until the bigger cleanups are approved. Although one thing that is better about this than the sdcard.py in the PR#765 is that one is computing CRC's dynamically that can't possibly change. All the parameters are hardcoded, so the CRC will always be a constant value. On a desktop, I would have written it that way, but on a microcontroller, I would normally precompute any values that are known at coding time and will never change.

And hardcoding it has the advantage of not using any memory for storing a globally computed value, and keeping the value next to the hard coded parameters that it was computed from. If anyone changes a hard coded argument, it will be good to have the hard coded CRC next to it to update too.

But these are style differences, and most of the CRC computations will execute once, so it doesn't add a great impact, so I'll leave it to others to decide. The same with the 256 byte hardcoded memory usage in the global CRC table. Usually it is probably worth it, but may not be if you can get by without it.

For readblocks and writeblocks, I've read that passing a constant 0x7F will cause the card to accept the command, which I've done, and works on my card. But that PR computes the correct CRC values for these functions. Which I'd normally prefer, once that PR is approved. But the 0x7F value appears to be an allowed one while the value in the current file returns an error on some cards. So again, this is a minimal fix to get the existing code working while long languishing PRs get finalized.

multicoder9 · 2025-03-31

FYI I just found two more self.cmd lines in writeblocks() with zero CRC7 values. I changed them to 0x7F and have confirmed that writeblocks now works with my SDXC cards.

dpgeorge · 2025-04-10

Thanks @multicoder9 for the detailed explanation above. I agree that it's good to just have something that works. But hopefully #765 can be merged very soon, and that will supersede this PR.

kwagyeman · 2026-03-02

This PR is not needed anymore. Live CRC7 support has been added.

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