YAHAL
Yet Another Hardware Abstraction Library
Loading...
Searching...
No Matches
sd_spi_drv.cpp
1
2#include "sd_spi_drv.h"
3#include "gpio_interface.h" // for LOW/HIGH
4
5sd_spi_drv::sd_spi_drv(spi_interface & spi) :
6 _spi(spi), _initialized(false), _isV200(false),
7 _isSDHC(false), _blockCount(0), _sd_status(0) { }
8
9blockio_status_t sd_spi_drv::initialize() {
10 // Check is device was successfully
11 // been initialized before
12 if (_initialized) return 0;
13
14 // Try to initialize the SD card
15 bool sd_init_ok = false;
16 for (int tries = 0; tries < 10; ++tries) {
17 int r = sd_init();
18 if (r == 0) {
19 sd_init_ok = true;
20 break;
21 }
22 }
23 if (!sd_init_ok)
24 return BLOCKIO::NOINIT;
25
26 // read various registers
27 if (sd_read_status()) return BLOCKIO::NOINIT;
28 if (sd_read_cid()) return BLOCKIO::NOINIT;
29 if (sd_read_csd()) return BLOCKIO::NOINIT;
30
31 _initialized = true;
32 return 0;
33}
34
35blockio_status_t sd_spi_drv::status() {
36 if (!_initialized) {
37 return BLOCKIO::NOINIT;
38 } else {
39 return 0;
40 }
41}
42
43BLOCKIO::result_t sd_spi_drv::readBlock (uint8_t* buff, uint32_t block, uint16_t count) {
44 if (!_initialized) initialize();
45
46 for (int i=0; i < count; ++i) {
47 int r = sd_readsector(block+i, buff+512*i);
48 if (r) return BLOCKIO::ERROR;
49 }
50 return BLOCKIO::OK;
51}
52
53BLOCKIO::result_t sd_spi_drv::writeBlock(const uint8_t* buff, uint32_t block, uint16_t count) {
54 if (!_initialized) initialize();
55
56 for (int i=0; i < count; ++i) {
57 int r = sd_writesector(block+i, buff+512*i);
58 if (r) return BLOCKIO::ERROR;
59 }
60 return BLOCKIO::OK;
61}
62
63
64uint32_t sd_spi_drv::getBlockCount() {
65 if (!_initialized) initialize();
66 return _blockCount;
67}
68
70
71int sd_spi_drv::sd_init()
72{
73 int tries;
74 uint8_t r;
75 uint32_t r3, r7;
76
77 // Set up SPI interface
78 _spi.generateCS(false);
79 _spi.setCS(HIGH);
80
81 // Start with a slow SPI clock
82 _spi.setSpeed(400000);
83
84 // 74+ clocks with CS high
85 for (int i=0; i < 10; i++)
86 spi_txrx(0xff);
87
88 // CMD0 (Reset)
89 _spi.setCS(LOW);
90 sd_cmd(0, 0);
91 r = sd_get_r1();
92 sd_nec();
93 _spi.setCS(HIGH);
94 if (r == 0xff) return -1; // SPI error
95 if (r != 0x01) return -2; // protocol error
96
97 // CMD8 (supply voltage)
98 _spi.setCS(LOW);
99 sd_cmd(8, 0x1aa); // 2.7-3.6V okay?
100 r = sd_get_r37(&r7);
101 sd_nec();
102 _spi.setCS(HIGH);
103 if (r == 0xff) return -1; // SPI error
104 if (r & 0xfa) return -2; // protocol error
105 if (r == 0x01) _isV200 = true;
106
107 // CMD58 (read OCR) (bits 30/31 maybe NOT available here!!)
108 _spi.setCS(LOW);
109 sd_cmd(58, 0);
110 r = sd_get_r37(&r3);
111 sd_nec();
112 _spi.setCS(HIGH);
113 if (r == 0xff) return -1; // SPI error
114 if (r & 0xfe) return -2; // protocol error
115
116 for (tries=100; tries > 0; --tries) {
117 // CMD55 (next is application command ACMD)
118 _spi.setCS(LOW);
119 sd_cmd(55, 0);
120 r = sd_get_r1();
121 sd_nec();
122 _spi.setCS(HIGH);
123 if (r == 0xff) return -1; // SPI error
124 if (r & 0xfe) return -2; // protocol error
125
126 // ACMD41 (activate initialization)
127 _spi.setCS(LOW);
128 // Try both versions!
129 r3 = (tries > 50) ? 0x40000000 : 0;
130 sd_cmd(41, r3);
131 r = sd_get_r1();
132 sd_nec();
133 _spi.setCS(HIGH);
134 if (r == 0xff) return -1; // SPI error
135 if (r & 0xfe) return -2; // protocol error
136 if (r == 0) break;
137 }
138 if (tries == 0) return -2; // protocol error
139
140 if (_isV200) {
141 // CMD58 (read OCR)
142 _spi.setCS(LOW);
143 sd_cmd(58, 0);
144 r = sd_get_r37(&r3);
145 sd_nec();
146 _spi.setCS(HIGH);
147 if (r == 0xff) return -1; // SPI error
148 if (r & 0xfe) return -2; // protocol error
149 _isSDHC = r3 & 0x40000000;
150 }
151
152 // CMD16 (Set block length)
153 // SDHC has fixed block length of 512 bytes,
154 // but non-SDHC cards might have other length...
155 if (!_isSDHC) {
156 _spi.setCS(LOW);
157 sd_cmd(16, 512);
158 r = sd_get_r1();
159 sd_nec();
160 _spi.setCS(HIGH);
161 if (r == 0xff) return -1; // SPI error
162 if (r & 0xfe) return -2; // protocol error
163 }
164
165 // CMD59 (CRC on/off)
166 _spi.setCS(LOW);
167 sd_cmd(59, 0);
168 r = sd_get_r1();
169 sd_nec();
170 _spi.setCS(HIGH);
171 if (r == 0xff) return -1; // SPI error
172 if (r & 0xfe) return -2; // protocol error
173
174 // set speed to 24MHz
175 _spi.setSpeed(24000000);
176 return 0;
177}
178
179int sd_spi_drv::sd_read_status()
180{
181 // CMD13 (read status)
182 _spi.setCS(LOW);
183 sd_cmd(13, 0);
184 uint16_t r2 = sd_get_r2();
185 sd_nec();
186 _spi.setCS(HIGH);
187
188 _sd_status = r2;
189 if (r2 & 0x8000)
190 return -1;
191
192 return 0;
193}
194
195
196 int sd_spi_drv::sd_read_cid()
197{
198 // CMD10 (send CID)
199 _spi.setCS(LOW);
200 sd_cmd(10, 0);
201 int r = sd_get_r1();
202 if (r == 0xff) {
203 _spi.setCS(HIGH);
204 return -1; // SPI error
205 }
206 if (r & 0xfe) {
207 _spi.setCS(HIGH);
208 return -2; // protocol error
209 }
210 r = sd_get_data(_cid, 16);
211 sd_nec();
212 _spi.setCS(HIGH);
213
214 return r;
215}
216
217
218int sd_spi_drv::sd_read_csd()
219{
220 int r;
221
222 // CMD9 (send CSD)
223 _spi.setCS(LOW);
224 sd_cmd(9, 0);
225 r = sd_get_r1();
226 if (r == 0xff) {
227 _spi.setCS(HIGH);
228 return -1; // SPI error
229 }
230 if (r & 0xfe) {
231 _spi.setCS(HIGH);
232 return -2; // protocol error
233 }
234 r = sd_get_data(_csd, 16);
235 sd_nec();
236 _spi.setCS(HIGH);
237
238 if (r) return r;
239
240 if ((_csd[0] & 0xc0) == 0) {
241 // CSD v1 or V2 standard capacity
242 uint32_t c_size = (((_csd[6] & 3) << 10) | (_csd[7] << 2) | (_csd[8] >> 6));
243 uint32_t c_mult = ((_csd[9] & 3) << 1) | (_csd[10] >> 7);
244 uint32_t blk_len = (_csd[5] & 0xf);
245 _blockCount = (c_size+1) * (1 << (c_mult + blk_len - 7));
246 } else {
247 // CSD V2 high capacity (HC)
248 uint32_t c_size = (_csd[7]<<16) | (_csd[8]<<8) | _csd[9]; // in 512 kB
249 _blockCount = c_size *1024;
250 }
251 return 0;
252}
253
254void sd_spi_drv::sd_cmd(uint8_t cmd, uint32_t arg)
255{
256 uint8_t crc = 0;
257 spi_txrx(0x40 | cmd);
258 crc = crc7_one(crc, 0x40 | cmd);
259 spi_txrx(arg >> 24);
260 crc = crc7_one(crc, arg >> 24);
261 spi_txrx(arg >> 16);
262 crc = crc7_one(crc, arg >> 16);
263 spi_txrx(arg >> 8);
264 crc = crc7_one(crc, arg >> 8);
265 spi_txrx(arg);
266 crc = crc7_one(crc, arg);
267 spi_txrx(crc | 0x1);
268}
269
270uint8_t sd_spi_drv::sd_get_r1()
271{
272 for (int tries=0; tries < 1000; ++tries) {
273 uint8_t r = spi_txrx(0xff);
274 if ((r & 0x80) == 0)
275 return r;
276 }
277 return 0xff;
278}
279
280uint16_t sd_spi_drv::sd_get_r2()
281{
282 int tries = 1000;
283 uint16_t r;
284 while (tries--) {
285 r = spi_txrx(0xff);
286 if ((r & 0x80) == 0)
287 break;
288 }
289 if (tries < 0)
290 return 0xff;
291 r = r<<8 | spi_txrx(0xff);
292 return r;
293}
294
295uint8_t sd_spi_drv::sd_get_r37(uint32_t *r37) {
296 uint32_t r;
297 r = sd_get_r1();
298 if (r != 0x01)
299 return r;
300 r = spi_txrx(0xff) << 24;
301 r |= spi_txrx(0xff) << 16;
302 r |= spi_txrx(0xff) << 8;
303 r |= spi_txrx(0xff);
304 *r37 = r;
305 return 0x01;
306}
307
308int sd_spi_drv::sd_get_data(uint8_t *buf, int len)
309{
310 int tries = 50000;
311 uint8_t r;
312 uint16_t _crc16;
313 uint16_t calc_crc;
314
315 // Wait for data to start (0xfe)
316 while (tries--) {
317 r = spi_txrx(0xff);
318 if (r == 0xfe)
319 break;
320 }
321 if (tries < 0)
322 return -4; // no data
323
324 _spi.spiRx(0xff, buf, len);
325
326 _crc16 = spi_txrx(0xff) << 8;
327 _crc16 |= spi_txrx(0xff);
328
329 calc_crc = crc16(buf, len);
330 if (_crc16 != calc_crc) {
331 return -5; // wrong CRC
332 }
333 return 0;
334}
335
336int sd_spi_drv::sd_put_data(const uint8_t *buf, int len)
337{
338 uint8_t r;
339 int tries = 10;
340 uint8_t b[16];
341 int bi = 0;
342 uint16_t crc;
343
344 (void)b;
345 spi_txrx(0xfe); // data start
346
347 _spi.spiTx(buf, len);
348
349 crc = crc16(buf, len);
350 // crc16
351 spi_txrx(crc>>8);
352 spi_txrx(crc);
353
354 // normally just one dummy read in between... specs don't say how many
355 while (tries--) {
356 b[bi++] = r = spi_txrx(0xff);
357 if (r != 0xff)
358 break;
359 }
360 if (tries < 0)
361 return -1;
362
363 // poll busy, about 300 reads for 256 MB card
364 tries = 100000;
365 while (tries--) {
366 if (spi_txrx(0xff) == 0xff)
367 break;
368 }
369 if (tries < 0)
370 return -2;
371
372 // data accepted, WIN
373 if ((r & 0x1f) == 0x05)
374 return 0;
375
376 return r;
377}
378
379void sd_spi_drv::sd_nec()
380{
381 for (int i=0; i<8; i++)
382 spi_txrx(0xff);
383}
384
385uint8_t sd_spi_drv::spi_txrx(uint8_t data)
386{
387 uint8_t out = 0;
388 _spi.spiTxRx(&data, &out, 1);
389 return out;
390}
391
392// CRC helper methods
393
394uint8_t sd_spi_drv::crc7_one(uint8_t t, uint8_t data)
395{
396 int i;
397 const uint8_t g = 0x89;
398 t ^= data;
399 for (i=0; i<8; i++) {
400 if (t & 0x80)
401 t ^= g;
402 t <<= 1;
403 }
404 return t;
405}
406
407uint16_t sd_spi_drv::crc16(const uint8_t *p, int len)
408{
409 int i;
410 uint16_t crc = 0;
411 for (i=0; i<len; i++)
412 crc = crc16_ccitt(crc, p[i]);
413 return crc;
414}
415
416uint16_t sd_spi_drv::crc16_ccitt(uint16_t crc, uint8_t ser_data)
417{
418 crc = (uint8_t)(crc >> 8) | (crc << 8);
419 crc ^= ser_data;
420 crc ^= (uint8_t)(crc & 0xff) >> 4;
421 crc ^= (crc << 8) << 4;
422 crc ^= ((crc & 0xff) << 4) << 1;
423 return crc;
424}
425
426int sd_spi_drv::sd_readsector(uint32_t sector, uint8_t *buf)
427{
428 int r;
429 // CMD17 (read single block)
430 _spi.setCS(LOW);
431 if (_isSDHC) sd_cmd(17, sector);
432 else sd_cmd(17, sector * 512);
433
434 r = sd_get_r1();
435 if (r == 0xff) {
436 _spi.setCS(HIGH);
437 return -1; // SPI error
438 }
439 if (r & 0xfe) {
440 _spi.setCS(HIGH);
441 return -2; // protocol error
442 }
443 r = sd_get_data(buf, 512);
444 sd_nec();
445 _spi.setCS(HIGH);
446 return r;
447}
448
449int sd_spi_drv::sd_writesector(uint32_t sector, const uint8_t *buf)
450{
451 // CMD24 (write single block)
452 _spi.setCS(LOW);
453 if (_isSDHC) sd_cmd(24, sector);
454 else sd_cmd(24, sector * 512);
455
456 uint8_t r = sd_get_r1();
457 if (r == 0xff) {
458 _spi.setCS(HIGH);
459 return -1; // SPI error
460 }
461 if (r & 0xfe) {
462 _spi.setCS(HIGH);
463 return -2; // protocol error
464 }
465
466 spi_txrx(0xff); // Nwr (>= 1) high bytes
467 r = sd_put_data(buf, 512);
468 sd_nec();
469 _spi.setCS(HIGH);
470 return r;
471}