Skip to content

Commit fdac8dc

Browse files
author
Vince Parsons
committed
sdcard: Keep card selected across multi-block transfers.
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>
1 parent 4fa59bd commit fdac8dc

2 files changed

Lines changed: 18 additions & 12 deletions

File tree

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
metadata(description="SDCard block device driver.", version="0.2.0")
1+
metadata(description="SDCard block device driver.", version="0.2.1")
22

33
module("sdcard.py", opt=3)

‎micropython/drivers/storage/sdcard/sdcard.py‎

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ def cmd(self, cmd, arg, final=0, release=True, skip1=False):
191191
self.spi.write(b"\xff")
192192
return -1
193193

194-
def readinto(self, buf):
194+
def readinto(self, buf, release=True):
195195
self.cs(0)
196196

197197
# read until start byte (0xff)
@@ -214,10 +214,11 @@ def readinto(self, buf):
214214
self.spi.write(b"\xff")
215215
self.spi.write(b"\xff")
216216

217-
self.cs(1)
218-
self.spi.write(b"\xff")
217+
if release:
218+
self.cs(1)
219+
self.spi.write(b"\xff")
219220

220-
def write(self, token, buf):
221+
def write(self, token, buf, release=True):
221222
self.cs(0)
222223

223224
# send: start of block, data, checksum
@@ -236,8 +237,9 @@ def write(self, token, buf):
236237
while self.spi.read(1, 0xFF)[0] == 0:
237238
pass
238239

239-
self.cs(1)
240-
self.spi.write(b"\xff")
240+
if release:
241+
self.cs(1)
242+
self.spi.write(b"\xff")
241243

242244
def write_token(self, token):
243245
self.cs(0)
@@ -274,8 +276,10 @@ def readblocks(self, block_num, buf):
274276
offset = 0
275277
mv = memoryview(buf)
276278
while nblocks:
277-
# receive the data and release card
278-
self.readinto(mv[offset : offset + 512])
279+
# receive the data, keeping the card selected until CMD12:
280+
# some cards lose bit alignment if CS is released between
281+
# the blocks of a multi-block read
282+
self.readinto(mv[offset : offset + 512], release=False)
279283
offset += 512
280284
nblocks -= 1
281285
if self.cmd(12, 0, skip1=True):
@@ -297,13 +301,15 @@ def writeblocks(self, block_num, buf):
297301
self.write(_TOKEN_DATA, buf)
298302
else:
299303
# CMD25: set write address for first block
300-
if self.cmd(25, block_num * self.cdv) != 0:
304+
if self.cmd(25, block_num * self.cdv, release=False) != 0:
305+
# release the card
306+
self.cs(1)
301307
raise OSError(5) # EIO
302-
# send the data
308+
# send the data, keeping the card selected until the stop token
303309
offset = 0
304310
mv = memoryview(buf)
305311
while nblocks:
306-
self.write(_TOKEN_CMD25, mv[offset : offset + 512])
312+
self.write(_TOKEN_CMD25, mv[offset : offset + 512], release=False)
307313
offset += 512
308314
nblocks -= 1
309315
self.write_token(_TOKEN_STOP_TRAN)

0 commit comments

Comments
 (0)