4
4
Requires an SPI bus and a CS pin. Provides readblocks and writeblocks
5
5
methods so the device can be mounted as a filesystem.
6
6
7
- Example usage:
7
+ Example usage on pyboard :
8
8
9
9
import pyb, sdcard, os
10
10
sd = sdcard.SDCard(pyb.SPI(1), pyb.Pin.board.X5)
11
11
pyb.mount(sd, '/sd2')
12
12
os.listdir('/')
13
13
14
+ Example usage on ESP8266:
15
+
16
+ import machine, sdcard, os
17
+ sd = sdcard.SDCard(machine.SPI(0), machine.Pin(15))
18
+ os.umount()
19
+ os.VfsFat(sd, "")
20
+ os.listdir()
21
+
14
22
"""
15
23
16
- import pyb
24
+ import time
17
25
18
- class SDCard :
19
- CMD_TIMEOUT = const (100 )
20
-
21
- R1_IDLE_STATE = const (1 << 0 )
22
- #R1_ERASE_RESET = const(1 << 1)
23
- R1_ILLEGAL_COMMAND = const (1 << 2 )
24
- #R1_COM_CRC_ERROR = const(1 << 3)
25
- #R1_ERASE_SEQUENCE_ERROR = const(1 << 4)
26
- #R1_ADDRESS_ERROR = const(1 << 5)
27
- #R1_PARAMETER_ERROR = const(1 << 6)
28
- TOKEN_CMD25 = const (0xfc )
29
- TOKEN_STOP_TRAN = const (0xfd )
30
- TOKEN_DATA = const (0xfe )
31
26
27
+ _CMD_TIMEOUT = const (100 )
28
+
29
+ _R1_IDLE_STATE = const (1 << 0 )
30
+ #R1_ERASE_RESET = const(1 << 1)
31
+ _R1_ILLEGAL_COMMAND = const (1 << 2 )
32
+ #R1_COM_CRC_ERROR = const(1 << 3)
33
+ #R1_ERASE_SEQUENCE_ERROR = const(1 << 4)
34
+ #R1_ADDRESS_ERROR = const(1 << 5)
35
+ #R1_PARAMETER_ERROR = const(1 << 6)
36
+ _TOKEN_CMD25 = const (0xfc )
37
+ _TOKEN_STOP_TRAN = const (0xfd )
38
+ _TOKEN_DATA = const (0xfe )
39
+
40
+
41
+ class SDCard :
32
42
def __init__ (self , spi , cs ):
33
43
self .spi = spi
34
44
self .cs = cs
@@ -42,30 +52,39 @@ def __init__(self, spi, cs):
42
52
# initialise the card
43
53
self .init_card ()
44
54
55
+ def init_spi (self , baudrate ):
56
+ try :
57
+ master = self .spi .MASTER
58
+ except AttributeError :
59
+ # on ESP8266
60
+ self .spi .init (baudrate = baudrate , phase = 0 , polarity = 0 )
61
+ else :
62
+ # on pyboard
63
+ self .spi .init (master , baudrate = baudrate , phase = 0 , polarity = 0 )
64
+
45
65
def init_card (self ):
46
66
# init CS pin
47
- self .cs .high ()
48
- self .cs .init (self .cs .OUT_PP )
67
+ self .cs .init (self .cs .OUT , value = 1 )
49
68
50
69
# init SPI bus; use low data rate for initialisation
51
- self .spi . init ( self . spi . MASTER , baudrate = 100000 , phase = 0 , polarity = 0 )
70
+ self .init_spi ( 100000 )
52
71
53
72
# clock card at least 100 cycles with cs high
54
73
for i in range (16 ):
55
- self .spi .send ( 0xff )
74
+ self .spi .write ( b' \xff ' )
56
75
57
- # CMD0: init card; should return R1_IDLE_STATE (allow 5 attempts)
76
+ # CMD0: init card; should return _R1_IDLE_STATE (allow 5 attempts)
58
77
for _ in range (5 ):
59
- if self .cmd (0 , 0 , 0x95 ) == R1_IDLE_STATE :
78
+ if self .cmd (0 , 0 , 0x95 ) == _R1_IDLE_STATE :
60
79
break
61
80
else :
62
81
raise OSError ("no SD card" )
63
82
64
83
# CMD8: determine card version
65
84
r = self .cmd (8 , 0x01aa , 0x87 , 4 )
66
- if r == R1_IDLE_STATE :
85
+ if r == _R1_IDLE_STATE :
67
86
self .init_card_v2 ()
68
- elif r == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND ):
87
+ elif r == (_R1_IDLE_STATE | _R1_ILLEGAL_COMMAND ):
69
88
self .init_card_v1 ()
70
89
else :
71
90
raise OSError ("couldn't determine SD card version" )
@@ -86,10 +105,10 @@ def init_card(self):
86
105
raise OSError ("can't set 512 block size" )
87
106
88
107
# set to high data rate now that it's initialised
89
- self .spi . init ( self . spi . MASTER , baudrate = 1320000 , phase = 0 , polarity = 0 )
108
+ self .init_spi ( 1320000 )
90
109
91
110
def init_card_v1 (self ):
92
- for i in range (CMD_TIMEOUT ):
111
+ for i in range (_CMD_TIMEOUT ):
93
112
self .cmd (55 , 0 , 0 )
94
113
if self .cmd (41 , 0 , 0 ) == 0 :
95
114
self .cdv = 512
@@ -98,8 +117,8 @@ def init_card_v1(self):
98
117
raise OSError ("timeout waiting for v1 card" )
99
118
100
119
def init_card_v2 (self ):
101
- for i in range (CMD_TIMEOUT ):
102
- pyb . delay (50 )
120
+ for i in range (_CMD_TIMEOUT ):
121
+ time . sleep_ms (50 )
103
122
self .cmd (58 , 0 , 0 , 4 )
104
123
self .cmd (55 , 0 , 0 )
105
124
if self .cmd (41 , 0x40000000 , 0 ) == 0 :
@@ -120,87 +139,87 @@ def cmd(self, cmd, arg, crc, final=0, release=True):
120
139
buf [3 ] = arg >> 8
121
140
buf [4 ] = arg
122
141
buf [5 ] = crc
123
- self .spi .send (buf )
142
+ self .spi .write (buf )
124
143
125
144
# wait for the repsonse (response[7] == 0)
126
- for i in range (CMD_TIMEOUT ):
127
- response = self .spi .send_recv ( 0xff )[0 ]
145
+ for i in range (_CMD_TIMEOUT ):
146
+ response = self .spi .read ( 1 , 0xff )[0 ]
128
147
if not (response & 0x80 ):
129
148
# this could be a big-endian integer that we are getting here
130
149
for j in range (final ):
131
- self .spi .send ( 0xff )
150
+ self .spi .write ( b' \xff ' )
132
151
if release :
133
152
self .cs .high ()
134
- self .spi .send ( 0xff )
153
+ self .spi .write ( b' \xff ' )
135
154
return response
136
155
137
156
# timeout
138
157
self .cs .high ()
139
- self .spi .send ( 0xff )
158
+ self .spi .write ( b' \xff ' )
140
159
return - 1
141
160
142
161
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 :
162
+ self .spi .write (cmd )
163
+ self .spi .read ( 1 , 0xff ) # ignore stuff byte
164
+ for _ in range (_CMD_TIMEOUT ):
165
+ if self .spi .read ( 1 , 0xff )[0 ] == 0xff :
147
166
self .cs .high ()
148
- self .spi .send ( 0xff )
167
+ self .spi .write ( b' \xff ' )
149
168
return 0 # OK
150
169
self .cs .high ()
151
- self .spi .send ( 0xff )
170
+ self .spi .write ( b' \xff ' )
152
171
return 1 # timeout
153
172
154
173
def readinto (self , buf ):
155
174
self .cs .low ()
156
175
157
176
# read until start byte (0xff)
158
- while self .spi .send_recv ( 0xff )[0 ] != 0xfe :
177
+ while self .spi .read ( 1 , 0xff )[0 ] != 0xfe :
159
178
pass
160
179
161
180
# read data
162
181
mv = self .dummybuf_memoryview [:len (buf )]
163
- self .spi .send_recv (mv , recv = buf )
182
+ self .spi .write_readinto (mv , buf )
164
183
165
184
# read checksum
166
- self .spi .send ( 0xff )
167
- self .spi .send ( 0xff )
185
+ self .spi .write ( b' \xff ' )
186
+ self .spi .write ( b' \xff ' )
168
187
169
188
self .cs .high ()
170
- self .spi .send ( 0xff )
189
+ self .spi .write ( b' \xff ' )
171
190
172
191
def write (self , token , buf ):
173
192
self .cs .low ()
174
193
175
194
# send: start of block, data, checksum
176
- self .spi .send ( token )
177
- self .spi .send (buf )
178
- self .spi .send ( 0xff )
179
- self .spi .send ( 0xff )
195
+ self .spi .read ( 1 , token )
196
+ self .spi .write (buf )
197
+ self .spi .write ( b' \xff ' )
198
+ self .spi .write ( b' \xff ' )
180
199
181
200
# check the response
182
- if (self .spi .send_recv ( 0xff )[0 ] & 0x1f ) != 0x05 :
201
+ if (self .spi .read ( 1 , 0xff )[0 ] & 0x1f ) != 0x05 :
183
202
self .cs .high ()
184
- self .spi .send ( 0xff )
203
+ self .spi .write ( b' \xff ' )
185
204
return
186
205
187
206
# wait for write to finish
188
- while self .spi .send_recv ( 0xff )[0 ] == 0 :
207
+ while self .spi .read ( 1 , 0xff )[0 ] == 0 :
189
208
pass
190
209
191
210
self .cs .high ()
192
- self .spi .send (0xff )
211
+ self .spi .write ( b' \xff ' )
193
212
194
213
def write_token (self , token ):
195
214
self .cs .low ()
196
- self .spi .send ( token )
197
- self .spi .send ( 0xff )
215
+ self .spi .read ( 1 , token )
216
+ self .spi .write ( b' \xff ' )
198
217
# wait for write to finish
199
- while self .spi .send_recv ( 0xff )[0 ] == 0 :
218
+ while self .spi .read ( 1 , 0xff )[0 ] == 0x00 :
200
219
pass
201
220
202
221
self .cs .high ()
203
- self .spi .send ( 0xff )
222
+ self .spi .write ( b' \xff ' )
204
223
205
224
def count (self ):
206
225
return self .sectors
@@ -224,7 +243,7 @@ def readblocks(self, block_num, buf):
224
243
self .readinto (mv [offset : offset + 512 ])
225
244
offset += 512
226
245
nblocks -= 1
227
- return self .cmd_nodata (12 )
246
+ return self .cmd_nodata (b' \x0c ' ) # cmd 12
228
247
return 0
229
248
230
249
def writeblocks (self , block_num , buf ):
@@ -236,7 +255,7 @@ def writeblocks(self, block_num, buf):
236
255
return 1
237
256
238
257
# send the data
239
- self .write (TOKEN_DATA , buf )
258
+ self .write (_TOKEN_DATA , buf )
240
259
else :
241
260
# CMD25: set write address for first block
242
261
if self .cmd (25 , block_num * self .cdv , 0 ) != 0 :
@@ -245,8 +264,8 @@ def writeblocks(self, block_num, buf):
245
264
offset = 0
246
265
mv = memoryview (buf )
247
266
while nblocks :
248
- self .write (TOKEN_CMD25 , mv [offset : offset + 512 ])
267
+ self .write (_TOKEN_CMD25 , mv [offset : offset + 512 ])
249
268
offset += 512
250
269
nblocks -= 1
251
- self .write_token (TOKEN_STOP_TRAN )
270
+ self .write_token (_TOKEN_STOP_TRAN )
252
271
return 0
0 commit comments