Skip to content

Commit d04161a

Browse files
committed
sdcard: Compute CRC7 for all SPI commands.
Some SD cards (e.g. SDXC) have CRC checking permanently enabled in SPI mode. Sending commands with CRC=0x00 causes them to return ILLEGAL_COMMAND, making initialisation fail. Fix this by computing a valid CRC7 for every command. Signed-off-by: Kwabena W. Agyeman <kwagyeman@live.com>
1 parent 6ae440a commit d04161a

File tree

1 file changed

+26
-17
lines changed

1 file changed

+26
-17
lines changed

micropython/drivers/storage/sdcard/sdcard.py

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,15 @@
3838
_TOKEN_DATA = const(0xFE)
3939

4040

41+
def _crc7(buf, n):
42+
crc = 0
43+
for i in range(n):
44+
crc ^= buf[i]
45+
for j in range(8):
46+
crc = ((crc << 1) ^ (0x12 * (crc >> 7))) & 0xFF
47+
return crc | 1
48+
49+
4150
class SDCard:
4251
def __init__(self, spi, cs, baudrate=1320000):
4352
self.spi = spi
@@ -76,13 +85,13 @@ def init_card(self, baudrate):
7685

7786
# CMD0: init card; should return _R1_IDLE_STATE (allow 5 attempts)
7887
for _ in range(5):
79-
if self.cmd(0, 0, 0x95) == _R1_IDLE_STATE:
88+
if self.cmd(0, 0) == _R1_IDLE_STATE:
8089
break
8190
else:
8291
raise OSError("no SD card")
8392

8493
# CMD8: determine card version
85-
r = self.cmd(8, 0x01AA, 0x87, 4)
94+
r = self.cmd(8, 0x01AA, 4)
8695
if r == _R1_IDLE_STATE:
8796
self.init_card_v2()
8897
elif r == (_R1_IDLE_STATE | _R1_ILLEGAL_COMMAND):
@@ -92,7 +101,7 @@ def init_card(self, baudrate):
92101

93102
# get the number of sectors
94103
# CMD9: response R2 (R1 byte + 16-byte block read)
95-
if self.cmd(9, 0, 0, 0, False) != 0:
104+
if self.cmd(9, 0, 0, False) != 0:
96105
raise OSError("no response from SD card")
97106
csd = bytearray(16)
98107
self.readinto(csd)
@@ -109,7 +118,7 @@ def init_card(self, baudrate):
109118
# print('sectors', self.sectors)
110119

111120
# CMD16: set block length to 512 bytes
112-
if self.cmd(16, 512, 0) != 0:
121+
if self.cmd(16, 512) != 0:
113122
raise OSError("can't set 512 block size")
114123

115124
# set to high data rate now that it's initialised
@@ -118,8 +127,8 @@ def init_card(self, baudrate):
118127
def init_card_v1(self):
119128
for i in range(_CMD_TIMEOUT):
120129
time.sleep_ms(50)
121-
self.cmd(55, 0, 0)
122-
if self.cmd(41, 0, 0) == 0:
130+
self.cmd(55, 0)
131+
if self.cmd(41, 0) == 0:
123132
# SDSC card, uses byte addressing in read/write/erase commands
124133
self.cdv = 512
125134
# print("[SDCard] v1 card")
@@ -129,10 +138,10 @@ def init_card_v1(self):
129138
def init_card_v2(self):
130139
for i in range(_CMD_TIMEOUT):
131140
time.sleep_ms(50)
132-
self.cmd(58, 0, 0, 4)
133-
self.cmd(55, 0, 0)
134-
if self.cmd(41, 0x40000000, 0) == 0:
135-
self.cmd(58, 0, 0, -4) # 4-byte response, negative means keep the first byte
141+
self.cmd(58, 0, 4)
142+
self.cmd(55, 0)
143+
if self.cmd(41, 0x40000000) == 0:
144+
self.cmd(58, 0, -4) # 4-byte response, negative means keep the first byte
136145
ocr = self.tokenbuf[0] # get first byte of response, which is OCR
137146
if not ocr & 0x40:
138147
# SDSC card, uses byte addressing in read/write/erase commands
@@ -144,7 +153,7 @@ def init_card_v2(self):
144153
return
145154
raise OSError("timeout waiting for v2 card")
146155

147-
def cmd(self, cmd, arg, crc, final=0, release=True, skip1=False):
156+
def cmd(self, cmd, arg, final=0, release=True, skip1=False):
148157
self.cs(0)
149158

150159
# create and send the command
@@ -154,7 +163,7 @@ def cmd(self, cmd, arg, crc, final=0, release=True, skip1=False):
154163
buf[2] = arg >> 16
155164
buf[3] = arg >> 8
156165
buf[4] = arg
157-
buf[5] = crc
166+
buf[5] = _crc7(buf, 5)
158167
self.spi.write(buf)
159168

160169
if skip1:
@@ -250,15 +259,15 @@ def readblocks(self, block_num, buf):
250259
assert nblocks and not len(buf) % 512, "Buffer length is invalid"
251260
if nblocks == 1:
252261
# CMD17: set read address for single block
253-
if self.cmd(17, block_num * self.cdv, 0, release=False) != 0:
262+
if self.cmd(17, block_num * self.cdv, release=False) != 0:
254263
# release the card
255264
self.cs(1)
256265
raise OSError(5) # EIO
257266
# receive the data and release card
258267
self.readinto(buf)
259268
else:
260269
# CMD18: set read address for multiple blocks
261-
if self.cmd(18, block_num * self.cdv, 0, release=False) != 0:
270+
if self.cmd(18, block_num * self.cdv, release=False) != 0:
262271
# release the card
263272
self.cs(1)
264273
raise OSError(5) # EIO
@@ -269,7 +278,7 @@ def readblocks(self, block_num, buf):
269278
self.readinto(mv[offset : offset + 512])
270279
offset += 512
271280
nblocks -= 1
272-
if self.cmd(12, 0, 0xFF, skip1=True):
281+
if self.cmd(12, 0, skip1=True):
273282
raise OSError(5) # EIO
274283

275284
def writeblocks(self, block_num, buf):
@@ -281,14 +290,14 @@ def writeblocks(self, block_num, buf):
281290
assert nblocks and not err, "Buffer length is invalid"
282291
if nblocks == 1:
283292
# CMD24: set write address for single block
284-
if self.cmd(24, block_num * self.cdv, 0) != 0:
293+
if self.cmd(24, block_num * self.cdv) != 0:
285294
raise OSError(5) # EIO
286295

287296
# send the data
288297
self.write(_TOKEN_DATA, buf)
289298
else:
290299
# CMD25: set write address for first block
291-
if self.cmd(25, block_num * self.cdv, 0) != 0:
300+
if self.cmd(25, block_num * self.cdv) != 0:
292301
raise OSError(5) # EIO
293302
# send the data
294303
offset = 0

0 commit comments

Comments
 (0)