3838_TOKEN_DATA = const (0xFE )
3939
4040
41+ @micropython .viper
42+ def _crc7 (buf , n : int ) -> int :
43+ """CRC7 with end bit for SD card SPI command frames (polynomial x^7+x^3+1)."""
44+ d = ptr8 (buf )
45+ crc = 0
46+ for i in range (n ):
47+ crc ^= d [i ]
48+ for j in range (8 ):
49+ crc = ((crc << 1 ) ^ (0x12 * (crc >> 7 ))) & 0xFF
50+ return crc | 1
51+
52+
4153class SDCard :
4254 def __init__ (self , spi , cs , baudrate = 1320000 ):
4355 self .spi = spi
@@ -76,13 +88,13 @@ def init_card(self, baudrate):
7688
7789 # CMD0: init card; should return _R1_IDLE_STATE (allow 5 attempts)
7890 for _ in range (5 ):
79- if self .cmd (0 , 0 , 0x95 ) == _R1_IDLE_STATE :
91+ if self .cmd (0 , 0 ) == _R1_IDLE_STATE :
8092 break
8193 else :
8294 raise OSError ("no SD card" )
8395
8496 # CMD8: determine card version
85- r = self .cmd (8 , 0x01AA , 0x87 , 4 )
97+ r = self .cmd (8 , 0x01AA , 4 )
8698 if r == _R1_IDLE_STATE :
8799 self .init_card_v2 ()
88100 elif r == (_R1_IDLE_STATE | _R1_ILLEGAL_COMMAND ):
@@ -92,7 +104,7 @@ def init_card(self, baudrate):
92104
93105 # get the number of sectors
94106 # CMD9: response R2 (R1 byte + 16-byte block read)
95- if self .cmd (9 , 0 , 0 , 0 , False ) != 0 :
107+ if self .cmd (9 , 0 , 0 , False ) != 0 :
96108 raise OSError ("no response from SD card" )
97109 csd = bytearray (16 )
98110 self .readinto (csd )
@@ -109,7 +121,7 @@ def init_card(self, baudrate):
109121 # print('sectors', self.sectors)
110122
111123 # CMD16: set block length to 512 bytes
112- if self .cmd (16 , 512 , 0 ) != 0 :
124+ if self .cmd (16 , 512 ) != 0 :
113125 raise OSError ("can't set 512 block size" )
114126
115127 # set to high data rate now that it's initialised
@@ -118,8 +130,8 @@ def init_card(self, baudrate):
118130 def init_card_v1 (self ):
119131 for i in range (_CMD_TIMEOUT ):
120132 time .sleep_ms (50 )
121- self .cmd (55 , 0 , 0 )
122- if self .cmd (41 , 0 , 0 ) == 0 :
133+ self .cmd (55 , 0 )
134+ if self .cmd (41 , 0 ) == 0 :
123135 # SDSC card, uses byte addressing in read/write/erase commands
124136 self .cdv = 512
125137 # print("[SDCard] v1 card")
@@ -129,10 +141,10 @@ def init_card_v1(self):
129141 def init_card_v2 (self ):
130142 for i in range (_CMD_TIMEOUT ):
131143 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
144+ self .cmd (58 , 0 , 4 )
145+ self .cmd (55 , 0 )
146+ if self .cmd (41 , 0x40000000 ) == 0 :
147+ self .cmd (58 , 0 , - 4 ) # 4-byte response, negative means keep the first byte
136148 ocr = self .tokenbuf [0 ] # get first byte of response, which is OCR
137149 if not ocr & 0x40 :
138150 # SDSC card, uses byte addressing in read/write/erase commands
@@ -144,7 +156,7 @@ def init_card_v2(self):
144156 return
145157 raise OSError ("timeout waiting for v2 card" )
146158
147- def cmd (self , cmd , arg , crc , final = 0 , release = True , skip1 = False ):
159+ def cmd (self , cmd , arg , final = 0 , release = True , skip1 = False ):
148160 self .cs (0 )
149161
150162 # create and send the command
@@ -154,7 +166,7 @@ def cmd(self, cmd, arg, crc, final=0, release=True, skip1=False):
154166 buf [2 ] = arg >> 16
155167 buf [3 ] = arg >> 8
156168 buf [4 ] = arg
157- buf [5 ] = crc
169+ buf [5 ] = _crc7 ( buf , 5 )
158170 self .spi .write (buf )
159171
160172 if skip1 :
@@ -250,15 +262,15 @@ def readblocks(self, block_num, buf):
250262 assert nblocks and not len (buf ) % 512 , "Buffer length is invalid"
251263 if nblocks == 1 :
252264 # CMD17: set read address for single block
253- if self .cmd (17 , block_num * self .cdv , 0 , release = False ) != 0 :
265+ if self .cmd (17 , block_num * self .cdv , release = False ) != 0 :
254266 # release the card
255267 self .cs (1 )
256268 raise OSError (5 ) # EIO
257269 # receive the data and release card
258270 self .readinto (buf )
259271 else :
260272 # CMD18: set read address for multiple blocks
261- if self .cmd (18 , block_num * self .cdv , 0 , release = False ) != 0 :
273+ if self .cmd (18 , block_num * self .cdv , release = False ) != 0 :
262274 # release the card
263275 self .cs (1 )
264276 raise OSError (5 ) # EIO
@@ -269,7 +281,7 @@ def readblocks(self, block_num, buf):
269281 self .readinto (mv [offset : offset + 512 ])
270282 offset += 512
271283 nblocks -= 1
272- if self .cmd (12 , 0 , 0xFF , skip1 = True ):
284+ if self .cmd (12 , 0 , skip1 = True ):
273285 raise OSError (5 ) # EIO
274286
275287 def writeblocks (self , block_num , buf ):
@@ -281,14 +293,14 @@ def writeblocks(self, block_num, buf):
281293 assert nblocks and not err , "Buffer length is invalid"
282294 if nblocks == 1 :
283295 # CMD24: set write address for single block
284- if self .cmd (24 , block_num * self .cdv , 0 ) != 0 :
296+ if self .cmd (24 , block_num * self .cdv ) != 0 :
285297 raise OSError (5 ) # EIO
286298
287299 # send the data
288300 self .write (_TOKEN_DATA , buf )
289301 else :
290302 # CMD25: set write address for first block
291- if self .cmd (25 , block_num * self .cdv , 0 ) != 0 :
303+ if self .cmd (25 , block_num * self .cdv ) != 0 :
292304 raise OSError (5 ) # EIO
293305 # send the data
294306 offset = 0
0 commit comments