sdcard: Keep card selected across multi-block transfers. - #1166
Open
VinceParsons wants to merge 1 commit into
Open
VinceParsons wants to merge 1 commit into
VinceParsons wants to merge 1 commit into
Conversation
readblocks() and writeblocks() released chip select after every block of a CMD18/CMD25 multi-block transfer (readinto() and write() end with cs(1) and an extra clocked byte), reselecting the card for the next block. A Lexar 32GB microSDHC card loses bit alignment across that release: every block after the first is read shifted by 4 bits, so the data token 0xfe arrives as 0xe0 (ff e0 00 ... for ff fe 00 ...) and readinto() times out. On a Pico 2 W, 200 of 200 two-block reads failed at both the default 1.32MHz and 12MHz. Keep the card selected from the command through to CMD12 or the stop token, as CircuitPython's sdcardio and adafruit_sdcard drivers do. readinto() and write() gain a release argument, True by default, so single-block transfers are unchanged. With this change, the same 200 two-block reads all succeed and match single-block reads of the same blocks, at both clock rates, and multi-block writes read back correctly. A card that worked before still works. Signed-off-by: Vince Parsons <micropython@vinceparsons.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
sdcard.pyreleases chip select between the blocks of a multi-block transfer:readblocks()callsreadinto()once per block of a CMD18 read, andreadinto()ends withcs(1)plus an extra clocked byte;writeblocks()does the same throughwrite()for CMD25. Some cards don't cope with that.With a new Lexar 32GB microSDHC card (Lexar Blue Series 633x), every multi-block read fails on its second block. Capturing the bytes the driver sees where the data token should be:
That's the
0xfedata token followed by data, read 4 bits late - the card loses bit alignment across the CS release. The driver then loops waiting for0xfeand raisesOSError('timeout waiting for response').This keeps the card selected from the command through to CMD12 / the stop token, as CircuitPython's drivers do:
sdcardioasserts CS once per transfer and releases it after the stop; its per-block helpers don't touch CS: https://github.com/adafruit/circuitpython/blob/main/shared-module/sdcardio/SDCard.cadafruit_sdcardbegan as a copy of this driver in 2017 and was changed to keep CS asserted through a transaction - their first PR notes "Samsung EVO cards do not work otherwise": Ensure that the chip select line is low between the read command, adafruit/Adafruit_CircuitPython_SD#1readinto()andwrite()take a newreleaseargument, defaulting toTrue, so single-block transfers and any external callers are unchanged. Version bumped to 0.2.1.Testing
Raspberry Pi Pico 2 W (RP2350), MicroPython 1.26.0, this repo's current
sdcard.pyvs this patch, with the Lexar card. Read-only test: 200 two-block reads (CMD18), each compared against single-block reads (CMD17) of the same blocks:sdcard.pytimeout waiting for response)With the patch, multi-block writes (3 x 256KB, written in 8KB chunks through
VfsFat) also read back correctly. A card of another brand that worked before the change still works with it.Not tested on other ports/boards.
Trade-offs and Alternatives
None significant - a few extra bytecode instructions. The card is held selected slightly longer (until the stop command), which is what the SD SPI protocol expects anyway.
Generative AI
I used generative AI tools when creating this PR, but a human has checked the code and is responsible for the code and the description above.