30
30
import time
31
31
import uctypes
32
32
from errno import ETIMEDOUT , EIO , ENODEV , EINVAL
33
- from crc7 import crc7
33
+
34
+ crc7_be_syndrome_table = (
35
+ b"\x00 \x12 $6HZl~\x90 \x82 \xb4 \xa6 \xd8 \xca \xfc \xee 2 \x16 \x04 zh^L\xa2 \xb0 \x86 \x94 \xea \xf8 "
36
+ b"\xce \xdc dv@R,>\x08 \x1a \xf4 \xe6 \xd0 \xc2 \xbc \xae \x98 \x8a VDr`\x1e \x0c :(\xc6 \xd4 \xe2 \xf0 "
37
+ b"\x8e \x9c \xaa \xb8 \xc8 \xda \xec \xfe \x80 \x92 \xa4 \xb6 XJ|n\x10 \x02 4&\xfa \xe8 \xde \xcc \xb2 \xa0 "
38
+ b'\x96 \x84 jxN\\ "0\x06 \x14 \xac \xbe \x88 \x9a \xe4 \xf6 \xc0 \xd2 <.\x18 \n tfPB\x9e \x8c \xba \xa8 '
39
+ b"\xd6 \xc4 \xf2 \xe0 \x0e \x1c *8FTbp\x82 \x90 \xa6 \xb4 \xca \xd8 \xee \xfc \x12 \x00 6$ZH~l\xb0 \xa2 "
40
+ b"\x94 \x86 \xf8 \xea \xdc \xce 2\x04 \x16 hzL^\xe6 \xf4 \xc2 \xd0 \xae \xbc \x8a \x98 vdR@>,\x1a \x08 "
41
+ b"\xd4 \xc6 \xf0 \xe2 \x9c \x8e \xb8 \xaa DV`r\x0c \x1e (:JXn|\x02 \x10 &4\xda \xc8 \xfe \xec \x92 \x80 "
42
+ b'\xb6 \xa4 xj\\ N0"\x14 \x06 \xe8 \xfa \xcc \xde \xa0 \xb2 \x84 \x96 .<\n \x18 ftBP\xbe \xac \x9a \x88 \xf6 '
43
+ b"\xe4 \xd2 \xc0 \x1c \x0e 8*TFpb\x8c \x9e \xa8 \xba \xc4 \xd6 \xe0 \xf2 "
44
+ )
45
+
46
+ # ruff: noqa: F821 - @asm_thumb and @viper decorator adds names to function scope
47
+ try :
48
+ from uctypes import addressof
49
+
50
+ @micropython .viper
51
+ def crc7 (buf ) -> int :
52
+ n = int (len (buf ))
53
+ table = ptr8 (addressof (crc7_be_syndrome_table ))
54
+ bp = ptr8 (addressof (buf ))
55
+ idx = 0
56
+ crc = 0
57
+ while idx < n :
58
+ crc = table [crc ^ bp [idx ]]
59
+ idx = idx + 1
60
+ return crc
61
+
62
+ # test to make sure this works!
63
+ # print(f"{crc7('abcde'):02x}")
64
+ assert crc7 (b"abcde" ) == 0x34
65
+ except :
66
+ # non-viper version if viper can'r be built
67
+ def crc7 (buf ) -> int :
68
+ crc = 0
69
+ for b in buf :
70
+ crc = crc7_be_syndrome_table [crc ^ b ]
71
+ return crc
72
+
73
+
74
+ def gb (bigval , b0 , bn ):
75
+ # get numbered bits from a buf_to_int from, for example, the CSD
76
+ return (bigval >> b0 ) & ((1 << (1 + bn - b0 )) - 1 )
77
+
34
78
35
79
_CMD_TIMEOUT = const (50 )
36
80
@@ -64,8 +108,9 @@ def __init__(self, spi, cs, baudrate=1320000, crc16_function=None):
64
108
def check_crcs (self , crc16_function ):
65
109
self .crc16 = crc16_function
66
110
result = self .cmd (
67
- 59 , 1 if crc16_function else 0 , None , release = True
111
+ 59 , 1 if crc16_function else 0 , release = True
68
112
) # send CRC enable/disable command
113
+ return result
69
114
70
115
def init_spi (self , baudrate ):
71
116
try :
@@ -77,12 +122,7 @@ def init_spi(self, baudrate):
77
122
# on pyboard
78
123
self .spi .init (master , baudrate = baudrate , phase = 0 , polarity = 0 )
79
124
80
- @staticmethod
81
- def gb (bigval , b0 , bn ):
82
- # get numbered bits from a buf_to_int from, for example, the CSD
83
- return (bigval >> b0 ) & ((1 << (1 + bn - b0 )) - 1 )
84
-
85
- def spiff (self ):
125
+ def _spiff (self ):
86
126
self .spi .write (b"\xff " )
87
127
88
128
def init_card (self , baudrate ):
@@ -104,40 +144,40 @@ def init_card(self, baudrate):
104
144
raise OSError (ENODEV , "no SD card" )
105
145
106
146
# CMD8: determine card version
107
- r = self .cmd (8 , 0x01AA , 0x87 , 4 ) # probe version
147
+ r = self .cmd (8 , 0x01AA , 4 ) # probe version
108
148
v2 = r == _R1_IDLE_STATE
109
149
v1 = r == (_R1_IDLE_STATE | _R1_ILLEGAL_COMMAND )
110
150
111
151
if not (v1 or v2 ):
112
152
raise OSError (EIO , "couldn't determine SD card version" )
113
153
arg41 = _HCS_BIT if v2 else 0 # we support high capacity, on v2 cards
114
154
for i in range (_CMD_TIMEOUT ): # loop on acmd41 to get
115
- self .cmd (55 , 0 , None )
116
- if (r := self .cmd (41 , arg41 , None )) == 0 :
155
+ self .cmd (55 , 0 )
156
+ if (r := self .cmd (41 , arg41 )) == 0 :
117
157
break
118
158
time .sleep_ms (5 )
119
159
if r != 0 :
120
160
raise OSError (ETIMEDOUT , "card type" , "v2" if v2 else "v1" )
121
161
122
162
# get the number of sectors
123
163
# CMD9: response R2 (R1 byte + 16-byte block read)
124
- if self .cmd (9 , 0 , None , 0 , False ) != 0 :
164
+ if self .cmd (9 , 0 , 0 , False ) != 0 :
125
165
raise OSError (EIO , "no CSD response" )
126
166
csd = bytearray (16 )
127
167
self .readinto (csd )
128
168
self .CSD = csd_int = int .from_bytes (
129
169
csd , "big"
130
170
) # convert 16-byte CSD to a giant integer for bit extraction
131
- gb = self . gb # just for shorter code
171
+ _gb = gb # just for local binding
132
172
# use bit numbers from SD card spec v9.0.0, table 5.3.2
133
- vers = gb (csd_int , 126 , 127 )
173
+ vers = _gb (csd_int , 126 , 127 )
134
174
if vers == 1 : # CSD version 2.0
135
- self .sectors = (gb (csd_int , 48 , 69 ) + 1 ) * 1024
175
+ self .sectors = (_gb (csd_int , 48 , 69 ) + 1 ) * 1024
136
176
self .cdv = 1
137
177
elif vers == 0x00 : # CSD version 1.0 (old, <=2GB)
138
- c_size = gb (csd_int , 62 , 73 )
139
- c_size_mult = gb (csd_int , 47 , 49 )
140
- read_bl_len = gb (csd_int , 80 , 83 )
178
+ c_size = _gb (csd_int , 62 , 73 )
179
+ c_size_mult = _gb (csd_int , 47 , 49 )
180
+ read_bl_len = _gb (csd_int , 80 , 83 )
141
181
capacity = (c_size + 1 ) * (2 ** (c_size_mult + 2 )) * (2 ** read_bl_len )
142
182
self .sectors = capacity // 512
143
183
self .cdv = 512 # converts bytes to sectors
@@ -146,18 +186,18 @@ def init_card(self, baudrate):
146
186
# print('sectors', self.sectors)
147
187
148
188
# CMD16: set block length to 512 bytes
149
- if self .cmd (16 , 512 , None ) != 0 :
189
+ if self .cmd (16 , 512 ) != 0 :
150
190
raise OSError (EIO , "can't set 512 block size" )
151
191
152
192
# set to high data rate now that it's initialised
153
193
self .init_spi (baudrate )
154
194
155
- def cmd (self , cmd , arg , crc , final = 0 , release = True , skip1 = False ):
195
+ def cmd (self , cmd , arg , final = 0 , release = True , skip1 = False ):
156
196
cs = self .cs # prebind
157
197
w = self .spi .write
158
198
r = self .spi .readinto
159
199
tb = self .tokenbuf
160
- spiff = self .spiff
200
+ spiff = self ._spiff
161
201
162
202
cs (0 ) # select chip
163
203
@@ -168,7 +208,7 @@ def cmd(self, cmd, arg, crc, final=0, release=True, skip1=False):
168
208
buf [2 ] = arg >> 16
169
209
buf [3 ] = arg >> 8
170
210
buf [4 ] = arg
171
- buf [5 ] = ( crc if crc is not None else crc7 (self .cmdbuf5 ) ) | 1
211
+ buf [5 ] = crc7 (self .cmdbuf5 ) | 1
172
212
w (buf )
173
213
174
214
if skip1 :
@@ -207,7 +247,7 @@ def cmd(self, cmd, arg, crc, final=0, release=True, skip1=False):
207
247
208
248
def readinto (self , buf ):
209
249
cs = self .cs
210
- spiff = self .spiff
250
+ spiff = self ._spiff
211
251
212
252
cs (0 )
213
253
@@ -237,7 +277,7 @@ def readinto(self, buf):
237
277
238
278
def write (self , token , buf ):
239
279
cs = self .cs
240
- spiff = self .spiff
280
+ spiff = self ._spiff
241
281
r = self .spi .read
242
282
w = self .spi .write
243
283
@@ -269,13 +309,13 @@ def write(self, token, buf):
269
309
def write_token (self , token ):
270
310
self .cs (0 )
271
311
self .spi .read (1 , token )
272
- self .spiff ()
312
+ self ._spiff ()
273
313
# wait for write to finish
274
314
while self .spi .read (1 , 0xFF )[0 ] == 0x00 :
275
315
pass
276
316
277
317
self .cs (1 )
278
- self .spiff ()
318
+ self ._spiff ()
279
319
280
320
@staticmethod
281
321
def blocks (buf ):
@@ -287,29 +327,29 @@ def blocks(buf):
287
327
def readblocks (self , block_num , buf ):
288
328
# workaround for shared bus, required for (at least) some Kingston
289
329
# devices, ensure MOSI is high before starting transaction
290
- self .spiff ()
330
+ self ._spiff ()
291
331
nblocks = self .blocks (buf )
292
332
293
333
# CMD18: set read address for multiple blocks
294
- if self .cmd (18 , block_num * self .cdv , None , release = False ) != 0 :
334
+ if self .cmd (18 , block_num * self .cdv , release = False ) != 0 :
295
335
# release the card
296
336
self .cs (1 )
297
337
raise OSError (EIO ) # EIO
298
338
mv = memoryview (buf )
299
339
for offset in range (0 , nblocks * 512 , 512 ):
300
340
self .readinto (mv [offset : offset + 512 ])
301
341
302
- if self .cmd (12 , 0 , None , skip1 = True ):
342
+ if self .cmd (12 , 0 , skip1 = True ):
303
343
raise OSError (EIO ) # EIO
304
344
305
345
def writeblocks (self , block_num , buf ):
306
346
# workaround for shared bus, required for (at least) some Kingston
307
347
# devices, ensure MOSI is high before starting transaction
308
- self .spiff ()
348
+ self ._spiff ()
309
349
nblocks = self .blocks (buf )
310
350
311
351
# CMD25: set write address for first block
312
- if ( r := self .cmd (25 , block_num * self .cdv , None ) ) != 0 :
352
+ if self .cmd (25 , block_num * self .cdv ) != 0 :
313
353
raise OSError (EIO ) # EIO`
314
354
# send the data
315
355
mv = memoryview (buf )
0 commit comments