@@ -25,6 +25,9 @@ class SDCard:
2525 #R1_ERASE_SEQUENCE_ERROR = const(1 << 4)
2626 #R1_ADDRESS_ERROR = const(1 << 5)
2727 #R1_PARAMETER_ERROR = const(1 << 6)
28+ TOKEN_CMD25 = const (0xfc )
29+ TOKEN_STOP_TRAN = const (0xfd )
30+ TOKEN_DATA = const (0xfe )
2831
2932 def __init__ (self , spi , cs ):
3033 self .spi = spi
@@ -136,6 +139,18 @@ def cmd(self, cmd, arg, crc, final=0, release=True):
136139 self .spi .send (0xff )
137140 return - 1
138141
142+ def cmd_nodata (self , cmd ):
143+ self .spi .send (cmd )
144+ self .spi .send_recv (0xff ) # ignore stuff byte
145+ for _ in range (CMD_TIMEOUT ):
146+ if self .spi .send_recv (0xff )[0 ] == 0xff :
147+ self .cs .high ()
148+ self .spi .send (0xff )
149+ return 0 # OK
150+ self .cs .high ()
151+ self .spi .send (0xff )
152+ return 1 # timeout
153+
139154 def readinto (self , buf ):
140155 self .cs .low ()
141156
@@ -154,11 +169,11 @@ def readinto(self, buf):
154169 self .cs .high ()
155170 self .spi .send (0xff )
156171
157- def write (self , buf ):
172+ def write (self , token , buf ):
158173 self .cs .low ()
159174
160175 # send: start of block, data, checksum
161- self .spi .send (0xfe )
176+ self .spi .send (token )
162177 self .spi .send (buf )
163178 self .spi .send (0xff )
164179 self .spi .send (0xff )
@@ -176,29 +191,62 @@ def write(self, buf):
176191 self .cs .high ()
177192 self .spi .send (0xff )
178193
194+ def write_token (self , token ):
195+ self .cs .low ()
196+ self .spi .send (token )
197+ self .spi .send (0xff )
198+ # wait for write to finish
199+ while self .spi .send_recv (0xff )[0 ] == 0 :
200+ pass
201+
202+ self .cs .high ()
203+ self .spi .send (0xff )
204+
179205 def count (self ):
180206 return self .sectors
181207
182208 def readblocks (self , block_num , buf ):
183- # TODO support multiple block reads
184- assert len (buf ) == 512
185-
186- # CMD17: set read address for single block
187- if self .cmd (17 , block_num * self .cdv , 0 ) != 0 :
188- return 1
189-
190- # receive the data
191- self .readinto (buf )
209+ nblocks , err = divmod (len (buf ), 512 )
210+ assert nblocks and not err , 'Buffer length is invalid'
211+ if nblocks == 1 :
212+ # CMD17: set read address for single block
213+ if self .cmd (17 , block_num * self .cdv , 0 ) != 0 :
214+ return 1
215+ # receive the data
216+ self .readinto (buf )
217+ else :
218+ # CMD18: set read address for multiple blocks
219+ if self .cmd (18 , block_num * self .cdv , 0 ) != 0 :
220+ return 1
221+ offset = 0
222+ mv = memoryview (buf )
223+ while nblocks :
224+ self .readinto (mv [offset : offset + 512 ])
225+ offset += 512
226+ nblocks -= 1
227+ return self .cmd_nodata (12 )
192228 return 0
193229
194230 def writeblocks (self , block_num , buf ):
195- # TODO support multiple block writes
196- assert len (buf ) == 512
197-
198- # CMD24: set write address for single block
199- if self .cmd (24 , block_num * self .cdv , 0 ) != 0 :
200- return 1
201-
202- # send the data
203- self .write (buf )
231+ nblocks , err = divmod (len (buf ), 512 )
232+ assert nblocks and not err , 'Buffer length is invalid'
233+ if nblocks == 1 :
234+ # CMD24: set write address for single block
235+ if self .cmd (24 , block_num * self .cdv , 0 ) != 0 :
236+ return 1
237+
238+ # send the data
239+ self .write (TOKEN_DATA , buf )
240+ else :
241+ # CMD25: set write address for first block
242+ if self .cmd (25 , block_num * self .cdv , 0 ) != 0 :
243+ return 1
244+ # send the data
245+ offset = 0
246+ mv = memoryview (buf )
247+ while nblocks :
248+ self .write (TOKEN_CMD25 , mv [offset : offset + 512 ])
249+ offset += 512
250+ nblocks -= 1
251+ self .write_token (TOKEN_STOP_TRAN )
204252 return 0
0 commit comments