Fri, 17 Nov 2017 10:13:31 +0100
proper configuration, homing and planner optimization
0 | 1 | /* Arduino Sd2Card Library |
2 | * Copyright (C) 2009 by William Greiman | |
3 | * | |
4 | * This file is part of the Arduino Sd2Card Library | |
5 | * | |
6 | * This Library is free software: you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation, either version 3 of the License, or | |
9 | * (at your option) any later version. | |
10 | * | |
11 | * This Library is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with the Arduino Sd2Card Library. If not, see | |
18 | * <http://www.gnu.org/licenses/>. | |
19 | */ | |
20 | #include "Marlin.h" | |
21 | ||
22 | #ifdef SDSUPPORT | |
23 | #include "Sd2Card.h" | |
24 | //------------------------------------------------------------------------------ | |
25 | #ifndef SOFTWARE_SPI | |
26 | // functions for hardware SPI | |
27 | //------------------------------------------------------------------------------ | |
28 | // make sure SPCR rate is in expected bits | |
29 | #if (SPR0 != 0 || SPR1 != 1) | |
30 | #error unexpected SPCR bits | |
31 | #endif | |
32 | /** | |
33 | * Initialize hardware SPI | |
34 | * Set SCK rate to F_CPU/pow(2, 1 + spiRate) for spiRate [0,6] | |
35 | */ | |
36 | static void spiInit(uint8_t spiRate) { | |
37 | // See avr processor documentation | |
38 | SPCR = (1 << SPE) | (1 << MSTR) | (spiRate >> 1); | |
39 | SPSR = spiRate & 1 || spiRate == 6 ? 0 : 1 << SPI2X; | |
40 | } | |
41 | //------------------------------------------------------------------------------ | |
42 | /** SPI receive a byte */ | |
43 | static uint8_t spiRec() { | |
44 | SPDR = 0XFF; | |
45 | while (!(SPSR & (1 << SPIF))); | |
46 | return SPDR; | |
47 | } | |
48 | //------------------------------------------------------------------------------ | |
49 | /** SPI read data - only one call so force inline */ | |
50 | static inline __attribute__((always_inline)) | |
51 | void spiRead(uint8_t* buf, uint16_t nbyte) { | |
52 | if (nbyte-- == 0) return; | |
53 | SPDR = 0XFF; | |
54 | for (uint16_t i = 0; i < nbyte; i++) { | |
55 | while (!(SPSR & (1 << SPIF))); | |
56 | buf[i] = SPDR; | |
57 | SPDR = 0XFF; | |
58 | } | |
59 | while (!(SPSR & (1 << SPIF))); | |
60 | buf[nbyte] = SPDR; | |
61 | } | |
62 | //------------------------------------------------------------------------------ | |
63 | /** SPI send a byte */ | |
64 | static void spiSend(uint8_t b) { | |
65 | SPDR = b; | |
66 | while (!(SPSR & (1 << SPIF))); | |
67 | } | |
68 | //------------------------------------------------------------------------------ | |
69 | /** SPI send block - only one call so force inline */ | |
70 | static inline __attribute__((always_inline)) | |
71 | void spiSendBlock(uint8_t token, const uint8_t* buf) { | |
72 | SPDR = token; | |
73 | for (uint16_t i = 0; i < 512; i += 2) { | |
74 | while (!(SPSR & (1 << SPIF))); | |
75 | SPDR = buf[i]; | |
76 | while (!(SPSR & (1 << SPIF))); | |
77 | SPDR = buf[i + 1]; | |
78 | } | |
79 | while (!(SPSR & (1 << SPIF))); | |
80 | } | |
81 | //------------------------------------------------------------------------------ | |
82 | #else // SOFTWARE_SPI | |
83 | //------------------------------------------------------------------------------ | |
84 | /** nop to tune soft SPI timing */ | |
85 | #define nop asm volatile ("nop\n\t") | |
86 | //------------------------------------------------------------------------------ | |
87 | /** Soft SPI receive byte */ | |
88 | static uint8_t spiRec() { | |
89 | uint8_t data = 0; | |
90 | // no interrupts during byte receive - about 8 us | |
91 | cli(); | |
92 | // output pin high - like sending 0XFF | |
93 | fastDigitalWrite(SPI_MOSI_PIN, HIGH); | |
94 | ||
95 | for (uint8_t i = 0; i < 8; i++) { | |
96 | fastDigitalWrite(SPI_SCK_PIN, HIGH); | |
97 | ||
98 | // adjust so SCK is nice | |
99 | nop; | |
100 | nop; | |
101 | ||
102 | data <<= 1; | |
103 | ||
104 | if (fastDigitalRead(SPI_MISO_PIN)) data |= 1; | |
105 | ||
106 | fastDigitalWrite(SPI_SCK_PIN, LOW); | |
107 | } | |
108 | // enable interrupts | |
109 | sei(); | |
110 | return data; | |
111 | } | |
112 | //------------------------------------------------------------------------------ | |
113 | /** Soft SPI read data */ | |
114 | static void spiRead(uint8_t* buf, uint16_t nbyte) { | |
115 | for (uint16_t i = 0; i < nbyte; i++) { | |
116 | buf[i] = spiRec(); | |
117 | } | |
118 | } | |
119 | //------------------------------------------------------------------------------ | |
120 | /** Soft SPI send byte */ | |
121 | static void spiSend(uint8_t data) { | |
122 | // no interrupts during byte send - about 8 us | |
123 | cli(); | |
124 | for (uint8_t i = 0; i < 8; i++) { | |
125 | fastDigitalWrite(SPI_SCK_PIN, LOW); | |
126 | ||
127 | fastDigitalWrite(SPI_MOSI_PIN, data & 0X80); | |
128 | ||
129 | data <<= 1; | |
130 | ||
131 | fastDigitalWrite(SPI_SCK_PIN, HIGH); | |
132 | } | |
133 | // hold SCK high for a few ns | |
134 | nop; | |
135 | nop; | |
136 | nop; | |
137 | nop; | |
138 | ||
139 | fastDigitalWrite(SPI_SCK_PIN, LOW); | |
140 | // enable interrupts | |
141 | sei(); | |
142 | } | |
143 | //------------------------------------------------------------------------------ | |
144 | /** Soft SPI send block */ | |
145 | void spiSendBlock(uint8_t token, const uint8_t* buf) { | |
146 | spiSend(token); | |
147 | for (uint16_t i = 0; i < 512; i++) { | |
148 | spiSend(buf[i]); | |
149 | } | |
150 | } | |
151 | #endif // SOFTWARE_SPI | |
152 | //------------------------------------------------------------------------------ | |
153 | // send command and return error code. Return zero for OK | |
154 | uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) { | |
155 | // select card | |
156 | chipSelectLow(); | |
157 | ||
158 | // wait up to 300 ms if busy | |
159 | waitNotBusy(300); | |
160 | ||
161 | // send command | |
162 | spiSend(cmd | 0x40); | |
163 | ||
164 | // send argument | |
165 | for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s); | |
166 | ||
167 | // send CRC | |
168 | uint8_t crc = 0XFF; | |
169 | if (cmd == CMD0) crc = 0X95; // correct crc for CMD0 with arg 0 | |
170 | if (cmd == CMD8) crc = 0X87; // correct crc for CMD8 with arg 0X1AA | |
171 | spiSend(crc); | |
172 | ||
173 | // skip stuff byte for stop read | |
174 | if (cmd == CMD12) spiRec(); | |
175 | ||
176 | // wait for response | |
177 | for (uint8_t i = 0; ((status_ = spiRec()) & 0X80) && i != 0XFF; i++); | |
178 | return status_; | |
179 | } | |
180 | //------------------------------------------------------------------------------ | |
181 | /** | |
182 | * Determine the size of an SD flash memory card. | |
183 | * | |
184 | * \return The number of 512 byte data blocks in the card | |
185 | * or zero if an error occurs. | |
186 | */ | |
187 | uint32_t Sd2Card::cardSize() { | |
188 | csd_t csd; | |
189 | if (!readCSD(&csd)) return 0; | |
190 | if (csd.v1.csd_ver == 0) { | |
191 | uint8_t read_bl_len = csd.v1.read_bl_len; | |
192 | uint16_t c_size = (csd.v1.c_size_high << 10) | |
193 | | (csd.v1.c_size_mid << 2) | csd.v1.c_size_low; | |
194 | uint8_t c_size_mult = (csd.v1.c_size_mult_high << 1) | |
195 | | csd.v1.c_size_mult_low; | |
196 | return (uint32_t)(c_size + 1) << (c_size_mult + read_bl_len - 7); | |
197 | } else if (csd.v2.csd_ver == 1) { | |
198 | uint32_t c_size = ((uint32_t)csd.v2.c_size_high << 16) | |
199 | | (csd.v2.c_size_mid << 8) | csd.v2.c_size_low; | |
200 | return (c_size + 1) << 10; | |
201 | } else { | |
202 | error(SD_CARD_ERROR_BAD_CSD); | |
203 | return 0; | |
204 | } | |
205 | } | |
206 | //------------------------------------------------------------------------------ | |
207 | void Sd2Card::chipSelectHigh() { | |
208 | digitalWrite(chipSelectPin_, HIGH); | |
209 | } | |
210 | //------------------------------------------------------------------------------ | |
211 | void Sd2Card::chipSelectLow() { | |
212 | #ifndef SOFTWARE_SPI | |
213 | spiInit(spiRate_); | |
214 | #endif // SOFTWARE_SPI | |
215 | digitalWrite(chipSelectPin_, LOW); | |
216 | } | |
217 | //------------------------------------------------------------------------------ | |
218 | /** Erase a range of blocks. | |
219 | * | |
220 | * \param[in] firstBlock The address of the first block in the range. | |
221 | * \param[in] lastBlock The address of the last block in the range. | |
222 | * | |
223 | * \note This function requests the SD card to do a flash erase for a | |
224 | * range of blocks. The data on the card after an erase operation is | |
225 | * either 0 or 1, depends on the card vendor. The card must support | |
226 | * single block erase. | |
227 | * | |
228 | * \return The value one, true, is returned for success and | |
229 | * the value zero, false, is returned for failure. | |
230 | */ | |
231 | bool Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) { | |
232 | csd_t csd; | |
233 | if (!readCSD(&csd)) goto fail; | |
234 | // check for single block erase | |
235 | if (!csd.v1.erase_blk_en) { | |
236 | // erase size mask | |
237 | uint8_t m = (csd.v1.sector_size_high << 1) | csd.v1.sector_size_low; | |
238 | if ((firstBlock & m) != 0 || ((lastBlock + 1) & m) != 0) { | |
239 | // error card can't erase specified area | |
240 | error(SD_CARD_ERROR_ERASE_SINGLE_BLOCK); | |
241 | goto fail; | |
242 | } | |
243 | } | |
244 | if (type_ != SD_CARD_TYPE_SDHC) { | |
245 | firstBlock <<= 9; | |
246 | lastBlock <<= 9; | |
247 | } | |
248 | if (cardCommand(CMD32, firstBlock) | |
249 | || cardCommand(CMD33, lastBlock) | |
250 | || cardCommand(CMD38, 0)) { | |
251 | error(SD_CARD_ERROR_ERASE); | |
252 | goto fail; | |
253 | } | |
254 | if (!waitNotBusy(SD_ERASE_TIMEOUT)) { | |
255 | error(SD_CARD_ERROR_ERASE_TIMEOUT); | |
256 | goto fail; | |
257 | } | |
258 | chipSelectHigh(); | |
259 | return true; | |
260 | ||
261 | fail: | |
262 | chipSelectHigh(); | |
263 | return false; | |
264 | } | |
265 | //------------------------------------------------------------------------------ | |
266 | /** Determine if card supports single block erase. | |
267 | * | |
268 | * \return The value one, true, is returned if single block erase is supported. | |
269 | * The value zero, false, is returned if single block erase is not supported. | |
270 | */ | |
271 | bool Sd2Card::eraseSingleBlockEnable() { | |
272 | csd_t csd; | |
273 | return readCSD(&csd) ? csd.v1.erase_blk_en : false; | |
274 | } | |
275 | //------------------------------------------------------------------------------ | |
276 | /** | |
277 | * Initialize an SD flash memory card. | |
278 | * | |
279 | * \param[in] sckRateID SPI clock rate selector. See setSckRate(). | |
280 | * \param[in] chipSelectPin SD chip select pin number. | |
281 | * | |
282 | * \return The value one, true, is returned for success and | |
283 | * the value zero, false, is returned for failure. The reason for failure | |
284 | * can be determined by calling errorCode() and errorData(). | |
285 | */ | |
286 | bool Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) { | |
287 | errorCode_ = type_ = 0; | |
288 | chipSelectPin_ = chipSelectPin; | |
289 | // 16-bit init start time allows over a minute | |
290 | uint16_t t0 = (uint16_t)millis(); | |
291 | uint32_t arg; | |
292 | ||
293 | // set pin modes | |
294 | pinMode(chipSelectPin_, OUTPUT); | |
295 | chipSelectHigh(); | |
296 | pinMode(SPI_MISO_PIN, INPUT); | |
297 | pinMode(SPI_MOSI_PIN, OUTPUT); | |
298 | pinMode(SPI_SCK_PIN, OUTPUT); | |
299 | ||
300 | #ifndef SOFTWARE_SPI | |
301 | // SS must be in output mode even it is not chip select | |
302 | pinMode(SS_PIN, OUTPUT); | |
303 | // set SS high - may be chip select for another SPI device | |
304 | #if SET_SPI_SS_HIGH | |
305 | digitalWrite(SS_PIN, HIGH); | |
306 | #endif // SET_SPI_SS_HIGH | |
307 | // set SCK rate for initialization commands | |
308 | spiRate_ = SPI_SD_INIT_RATE; | |
309 | spiInit(spiRate_); | |
310 | #endif // SOFTWARE_SPI | |
311 | ||
312 | // must supply min of 74 clock cycles with CS high. | |
313 | for (uint8_t i = 0; i < 10; i++) spiSend(0XFF); | |
314 | ||
315 | // command to go idle in SPI mode | |
316 | while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) { | |
317 | if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { | |
318 | error(SD_CARD_ERROR_CMD0); | |
319 | goto fail; | |
320 | } | |
321 | } | |
322 | // check SD version | |
323 | if ((cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND)) { | |
324 | type(SD_CARD_TYPE_SD1); | |
325 | } else { | |
326 | // only need last byte of r7 response | |
327 | for (uint8_t i = 0; i < 4; i++) status_ = spiRec(); | |
328 | if (status_ != 0XAA) { | |
329 | error(SD_CARD_ERROR_CMD8); | |
330 | goto fail; | |
331 | } | |
332 | type(SD_CARD_TYPE_SD2); | |
333 | } | |
334 | // initialize card and send host supports SDHC if SD2 | |
335 | arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0; | |
336 | ||
337 | while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) { | |
338 | // check for timeout | |
339 | if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { | |
340 | error(SD_CARD_ERROR_ACMD41); | |
341 | goto fail; | |
342 | } | |
343 | } | |
344 | // if SD2 read OCR register to check for SDHC card | |
345 | if (type() == SD_CARD_TYPE_SD2) { | |
346 | if (cardCommand(CMD58, 0)) { | |
347 | error(SD_CARD_ERROR_CMD58); | |
348 | goto fail; | |
349 | } | |
350 | if ((spiRec() & 0XC0) == 0XC0) type(SD_CARD_TYPE_SDHC); | |
351 | // discard rest of ocr - contains allowed voltage range | |
352 | for (uint8_t i = 0; i < 3; i++) spiRec(); | |
353 | } | |
354 | chipSelectHigh(); | |
355 | ||
356 | #ifndef SOFTWARE_SPI | |
357 | return setSckRate(sckRateID); | |
358 | #else // SOFTWARE_SPI | |
359 | return true; | |
360 | #endif // SOFTWARE_SPI | |
361 | ||
362 | fail: | |
363 | chipSelectHigh(); | |
364 | return false; | |
365 | } | |
366 | //------------------------------------------------------------------------------ | |
367 | /** | |
368 | * Read a 512 byte block from an SD card. | |
369 | * | |
370 | * \param[in] blockNumber Logical block to be read. | |
371 | * \param[out] dst Pointer to the location that will receive the data. | |
372 | ||
373 | * \return The value one, true, is returned for success and | |
374 | * the value zero, false, is returned for failure. | |
375 | */ | |
376 | bool Sd2Card::readBlock(uint32_t blockNumber, uint8_t* dst) { | |
377 | // use address if not SDHC card | |
378 | if (type()!= SD_CARD_TYPE_SDHC) blockNumber <<= 9; | |
379 | if (cardCommand(CMD17, blockNumber)) { | |
380 | error(SD_CARD_ERROR_CMD17); | |
381 | goto fail; | |
382 | } | |
383 | return readData(dst, 512); | |
384 | ||
385 | fail: | |
386 | chipSelectHigh(); | |
387 | return false; | |
388 | } | |
389 | //------------------------------------------------------------------------------ | |
390 | /** Read one data block in a multiple block read sequence | |
391 | * | |
392 | * \param[in] dst Pointer to the location for the data to be read. | |
393 | * | |
394 | * \return The value one, true, is returned for success and | |
395 | * the value zero, false, is returned for failure. | |
396 | */ | |
397 | bool Sd2Card::readData(uint8_t *dst) { | |
398 | chipSelectLow(); | |
399 | return readData(dst, 512); | |
400 | } | |
401 | //------------------------------------------------------------------------------ | |
402 | bool Sd2Card::readData(uint8_t* dst, uint16_t count) { | |
403 | // wait for start block token | |
404 | uint16_t t0 = millis(); | |
405 | while ((status_ = spiRec()) == 0XFF) { | |
406 | if (((uint16_t)millis() - t0) > SD_READ_TIMEOUT) { | |
407 | error(SD_CARD_ERROR_READ_TIMEOUT); | |
408 | goto fail; | |
409 | } | |
410 | } | |
411 | if (status_ != DATA_START_BLOCK) { | |
412 | error(SD_CARD_ERROR_READ); | |
413 | goto fail; | |
414 | } | |
415 | // transfer data | |
416 | spiRead(dst, count); | |
417 | ||
418 | // discard CRC | |
419 | spiRec(); | |
420 | spiRec(); | |
421 | chipSelectHigh(); | |
422 | return true; | |
423 | ||
424 | fail: | |
425 | chipSelectHigh(); | |
426 | return false; | |
427 | } | |
428 | //------------------------------------------------------------------------------ | |
429 | /** read CID or CSR register */ | |
430 | bool Sd2Card::readRegister(uint8_t cmd, void* buf) { | |
431 | uint8_t* dst = reinterpret_cast<uint8_t*>(buf); | |
432 | if (cardCommand(cmd, 0)) { | |
433 | error(SD_CARD_ERROR_READ_REG); | |
434 | goto fail; | |
435 | } | |
436 | return readData(dst, 16); | |
437 | ||
438 | fail: | |
439 | chipSelectHigh(); | |
440 | return false; | |
441 | } | |
442 | //------------------------------------------------------------------------------ | |
443 | /** Start a read multiple blocks sequence. | |
444 | * | |
445 | * \param[in] blockNumber Address of first block in sequence. | |
446 | * | |
447 | * \note This function is used with readData() and readStop() for optimized | |
448 | * multiple block reads. SPI chipSelect must be low for the entire sequence. | |
449 | * | |
450 | * \return The value one, true, is returned for success and | |
451 | * the value zero, false, is returned for failure. | |
452 | */ | |
453 | bool Sd2Card::readStart(uint32_t blockNumber) { | |
454 | if (type()!= SD_CARD_TYPE_SDHC) blockNumber <<= 9; | |
455 | if (cardCommand(CMD18, blockNumber)) { | |
456 | error(SD_CARD_ERROR_CMD18); | |
457 | goto fail; | |
458 | } | |
459 | chipSelectHigh(); | |
460 | return true; | |
461 | ||
462 | fail: | |
463 | chipSelectHigh(); | |
464 | return false; | |
465 | } | |
466 | //------------------------------------------------------------------------------ | |
467 | /** End a read multiple blocks sequence. | |
468 | * | |
469 | * \return The value one, true, is returned for success and | |
470 | * the value zero, false, is returned for failure. | |
471 | */ | |
472 | bool Sd2Card::readStop() { | |
473 | chipSelectLow(); | |
474 | if (cardCommand(CMD12, 0)) { | |
475 | error(SD_CARD_ERROR_CMD12); | |
476 | goto fail; | |
477 | } | |
478 | chipSelectHigh(); | |
479 | return true; | |
480 | ||
481 | fail: | |
482 | chipSelectHigh(); | |
483 | return false; | |
484 | } | |
485 | //------------------------------------------------------------------------------ | |
486 | /** | |
487 | * Set the SPI clock rate. | |
488 | * | |
489 | * \param[in] sckRateID A value in the range [0, 6]. | |
490 | * | |
491 | * The SPI clock will be set to F_CPU/pow(2, 1 + sckRateID). The maximum | |
492 | * SPI rate is F_CPU/2 for \a sckRateID = 0 and the minimum rate is F_CPU/128 | |
493 | * for \a scsRateID = 6. | |
494 | * | |
495 | * \return The value one, true, is returned for success and the value zero, | |
496 | * false, is returned for an invalid value of \a sckRateID. | |
497 | */ | |
498 | bool Sd2Card::setSckRate(uint8_t sckRateID) { | |
499 | if (sckRateID > 6) { | |
500 | error(SD_CARD_ERROR_SCK_RATE); | |
501 | return false; | |
502 | } | |
503 | spiRate_ = sckRateID; | |
504 | return true; | |
505 | } | |
506 | //------------------------------------------------------------------------------ | |
507 | // wait for card to go not busy | |
508 | bool Sd2Card::waitNotBusy(uint16_t timeoutMillis) { | |
509 | uint16_t t0 = millis(); | |
510 | while (spiRec() != 0XFF) { | |
511 | if (((uint16_t)millis() - t0) >= timeoutMillis) goto fail; | |
512 | } | |
513 | return true; | |
514 | ||
515 | fail: | |
516 | return false; | |
517 | } | |
518 | //------------------------------------------------------------------------------ | |
519 | /** | |
520 | * Writes a 512 byte block to an SD card. | |
521 | * | |
522 | * \param[in] blockNumber Logical block to be written. | |
523 | * \param[in] src Pointer to the location of the data to be written. | |
524 | * \return The value one, true, is returned for success and | |
525 | * the value zero, false, is returned for failure. | |
526 | */ | |
527 | bool Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) { | |
528 | // use address if not SDHC card | |
529 | if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; | |
530 | if (cardCommand(CMD24, blockNumber)) { | |
531 | error(SD_CARD_ERROR_CMD24); | |
532 | goto fail; | |
533 | } | |
534 | if (!writeData(DATA_START_BLOCK, src)) goto fail; | |
535 | ||
536 | // wait for flash programming to complete | |
537 | if (!waitNotBusy(SD_WRITE_TIMEOUT)) { | |
538 | error(SD_CARD_ERROR_WRITE_TIMEOUT); | |
539 | goto fail; | |
540 | } | |
541 | // response is r2 so get and check two bytes for nonzero | |
542 | if (cardCommand(CMD13, 0) || spiRec()) { | |
543 | error(SD_CARD_ERROR_WRITE_PROGRAMMING); | |
544 | goto fail; | |
545 | } | |
546 | chipSelectHigh(); | |
547 | return true; | |
548 | ||
549 | fail: | |
550 | chipSelectHigh(); | |
551 | return false; | |
552 | } | |
553 | //------------------------------------------------------------------------------ | |
554 | /** Write one data block in a multiple block write sequence | |
555 | * \param[in] src Pointer to the location of the data to be written. | |
556 | * \return The value one, true, is returned for success and | |
557 | * the value zero, false, is returned for failure. | |
558 | */ | |
559 | bool Sd2Card::writeData(const uint8_t* src) { | |
560 | chipSelectLow(); | |
561 | // wait for previous write to finish | |
562 | if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail; | |
563 | if (!writeData(WRITE_MULTIPLE_TOKEN, src)) goto fail; | |
564 | chipSelectHigh(); | |
565 | return true; | |
566 | ||
567 | fail: | |
568 | error(SD_CARD_ERROR_WRITE_MULTIPLE); | |
569 | chipSelectHigh(); | |
570 | return false; | |
571 | } | |
572 | //------------------------------------------------------------------------------ | |
573 | // send one block of data for write block or write multiple blocks | |
574 | bool Sd2Card::writeData(uint8_t token, const uint8_t* src) { | |
575 | spiSendBlock(token, src); | |
576 | ||
577 | spiSend(0xff); // dummy crc | |
578 | spiSend(0xff); // dummy crc | |
579 | ||
580 | status_ = spiRec(); | |
581 | if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) { | |
582 | error(SD_CARD_ERROR_WRITE); | |
583 | goto fail; | |
584 | } | |
585 | return true; | |
586 | ||
587 | fail: | |
588 | chipSelectHigh(); | |
589 | return false; | |
590 | } | |
591 | //------------------------------------------------------------------------------ | |
592 | /** Start a write multiple blocks sequence. | |
593 | * | |
594 | * \param[in] blockNumber Address of first block in sequence. | |
595 | * \param[in] eraseCount The number of blocks to be pre-erased. | |
596 | * | |
597 | * \note This function is used with writeData() and writeStop() | |
598 | * for optimized multiple block writes. | |
599 | * | |
600 | * \return The value one, true, is returned for success and | |
601 | * the value zero, false, is returned for failure. | |
602 | */ | |
603 | bool Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) { | |
604 | // send pre-erase count | |
605 | if (cardAcmd(ACMD23, eraseCount)) { | |
606 | error(SD_CARD_ERROR_ACMD23); | |
607 | goto fail; | |
608 | } | |
609 | // use address if not SDHC card | |
610 | if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; | |
611 | if (cardCommand(CMD25, blockNumber)) { | |
612 | error(SD_CARD_ERROR_CMD25); | |
613 | goto fail; | |
614 | } | |
615 | chipSelectHigh(); | |
616 | return true; | |
617 | ||
618 | fail: | |
619 | chipSelectHigh(); | |
620 | return false; | |
621 | } | |
622 | //------------------------------------------------------------------------------ | |
623 | /** End a write multiple blocks sequence. | |
624 | * | |
625 | * \return The value one, true, is returned for success and | |
626 | * the value zero, false, is returned for failure. | |
627 | */ | |
628 | bool Sd2Card::writeStop() { | |
629 | chipSelectLow(); | |
630 | if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail; | |
631 | spiSend(STOP_TRAN_TOKEN); | |
632 | if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail; | |
633 | chipSelectHigh(); | |
634 | return true; | |
635 | ||
636 | fail: | |
637 | error(SD_CARD_ERROR_STOP_TRAN); | |
638 | chipSelectHigh(); | |
639 | return false; | |
640 | } | |
641 | ||
642 | ||
643 | #endif |