|
@@ -65,7 +65,7 @@
|
65
|
65
|
|
66
|
66
|
static uint8_t CRC7(const uint8_t* data, uint8_t n) {
|
67
|
67
|
uint8_t crc = 0;
|
68
|
|
- while ( n > 0 ) {
|
|
68
|
+ while (n > 0) {
|
69
|
69
|
crc = pgm_read_byte(&crctab7[ (crc << 1) ^ *data++ ]);
|
70
|
70
|
n--;
|
71
|
71
|
}
|
|
@@ -87,44 +87,42 @@
|
87
|
87
|
#endif
|
88
|
88
|
#endif
|
89
|
89
|
|
90
|
|
-// send command and return error code. Return zero for OK
|
91
|
|
-uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) {
|
92
|
|
- // select card
|
|
90
|
+// Send command and return error code. Return zero for OK
|
|
91
|
+uint8_t Sd2Card::cardCommand(const uint8_t cmd, const uint32_t arg) {
|
|
92
|
+ // Select card
|
93
|
93
|
chipSelect();
|
94
|
94
|
|
95
|
|
- // wait up to 300 ms if busy
|
96
|
|
- waitNotBusy( SD_WRITE_TIMEOUT );
|
|
95
|
+ // Wait up to 300 ms if busy
|
|
96
|
+ waitNotBusy(SD_WRITE_TIMEOUT);
|
97
|
97
|
|
98
|
98
|
uint8_t *pa = (uint8_t *)(&arg);
|
99
|
99
|
|
100
|
|
-#if ENABLED(SD_CHECK_AND_RETRY)
|
|
100
|
+ #if ENABLED(SD_CHECK_AND_RETRY)
|
101
|
101
|
|
102
|
|
- // form message
|
103
|
|
- uint8_t d[6] = {(uint8_t) (cmd | 0x40), pa[3], pa[2], pa[1], pa[0] };
|
|
102
|
+ // Form message
|
|
103
|
+ uint8_t d[6] = {(uint8_t) (cmd | 0x40), pa[3], pa[2], pa[1], pa[0] };
|
104
|
104
|
|
105
|
|
- // add crc
|
106
|
|
- d[5] = CRC7(d, 5);
|
|
105
|
+ // Add crc
|
|
106
|
+ d[5] = CRC7(d, 5);
|
107
|
107
|
|
108
|
|
- // send message
|
109
|
|
- for (uint8_t k = 0; k < 6; k++ )
|
110
|
|
- spiSend( d[k] );
|
|
108
|
+ // Send message
|
|
109
|
+ for (uint8_t k = 0; k < 6; k++) spiSend(d[k]);
|
111
|
110
|
|
112
|
|
-#else
|
113
|
|
- // send command
|
114
|
|
- spiSend(cmd | 0x40);
|
|
111
|
+ #else
|
|
112
|
+ // Send command
|
|
113
|
+ spiSend(cmd | 0x40);
|
115
|
114
|
|
116
|
|
- // send argument
|
117
|
|
- for( int8_t i = 3; i >= 0; i-- )
|
118
|
|
- spiSend( pa[i] );
|
|
115
|
+ // Send argument
|
|
116
|
+ for (int8_t i = 3; i >= 0; i--) spiSend(pa[i]);
|
119
|
117
|
|
120
|
|
- // send CRC - correct for CMD0 with arg zero or CMD8 with arg 0X1AA
|
121
|
|
- spiSend( cmd == CMD0 ? 0X95 : 0X87 );
|
122
|
|
-#endif
|
|
118
|
+ // Send CRC - correct for CMD0 with arg zero or CMD8 with arg 0X1AA
|
|
119
|
+ spiSend(cmd == CMD0 ? 0X95 : 0X87);
|
|
120
|
+ #endif
|
123
|
121
|
|
124
|
|
- // skip stuff byte for stop read
|
|
122
|
+ // Skip stuff byte for stop read
|
125
|
123
|
if (cmd == CMD12) spiRec();
|
126
|
124
|
|
127
|
|
- // wait for response
|
|
125
|
+ // Wait for response
|
128
|
126
|
for (uint8_t i = 0; ((status_ = spiRec()) & 0x80) && i != 0xFF; i++) { /* Intentionally left empty */ }
|
129
|
127
|
return status_;
|
130
|
128
|
}
|
|
@@ -159,9 +157,7 @@ uint32_t Sd2Card::cardSize() {
|
159
|
157
|
|
160
|
158
|
void Sd2Card::chipDeselect() {
|
161
|
159
|
digitalWrite(chipSelectPin_, HIGH);
|
162
|
|
-
|
163
|
|
- // insure MISO goes high impedance
|
164
|
|
- spiSend( 0xFF );
|
|
160
|
+ spiSend(0xFF); // Ensure MISO goes high impedance
|
165
|
161
|
}
|
166
|
162
|
|
167
|
163
|
void Sd2Card::chipSelect() {
|
|
@@ -195,13 +191,8 @@ bool Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) {
|
195
|
191
|
goto FAIL;
|
196
|
192
|
}
|
197
|
193
|
}
|
198
|
|
- if (type_ != SD_CARD_TYPE_SDHC) {
|
199
|
|
- firstBlock <<= 9;
|
200
|
|
- lastBlock <<= 9;
|
201
|
|
- }
|
202
|
|
- if (cardCommand(CMD32, firstBlock)
|
203
|
|
- || cardCommand(CMD33, lastBlock)
|
204
|
|
- || cardCommand(CMD38, 0)) {
|
|
194
|
+ if (type_ != SD_CARD_TYPE_SDHC) { firstBlock <<= 9; lastBlock <<= 9; }
|
|
195
|
+ if (cardCommand(CMD32, firstBlock) || cardCommand(CMD33, lastBlock) || cardCommand(CMD38, 0)) {
|
205
|
196
|
error(SD_CARD_ERROR_ERASE);
|
206
|
197
|
goto FAIL;
|
207
|
198
|
}
|
|
@@ -236,7 +227,7 @@ bool Sd2Card::eraseSingleBlockEnable() {
|
236
|
227
|
* \return true for success, false for failure.
|
237
|
228
|
* The reason for failure can be determined by calling errorCode() and errorData().
|
238
|
229
|
*/
|
239
|
|
-bool Sd2Card::init(uint8_t sckRateID, pin_t chipSelectPin) {
|
|
230
|
+bool Sd2Card::init(const uint8_t sckRateID/*=0*/, const pin_t chipSelectPin/*=SD_CHIP_SELECT_PIN*/) {
|
240
|
231
|
errorCode_ = type_ = 0;
|
241
|
232
|
chipSelectPin_ = chipSelectPin;
|
242
|
233
|
// 16-bit init start time allows over a minute
|
|
@@ -308,23 +299,23 @@ bool Sd2Card::init(uint8_t sckRateID, pin_t chipSelectPin) {
|
308
|
299
|
watchdog_reset();
|
309
|
300
|
#endif
|
310
|
301
|
|
311
|
|
- // initialize card and send host supports SDHC if SD2
|
|
302
|
+ // Initialize card and send host supports SDHC if SD2
|
312
|
303
|
arg = type() == SD_CARD_TYPE_SD2 ? 0x40000000 : 0;
|
313
|
304
|
while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) {
|
314
|
|
- // check for timeout
|
|
305
|
+ // Check for timeout
|
315
|
306
|
if (ELAPSED(millis(), init_timeout)) {
|
316
|
307
|
error(SD_CARD_ERROR_ACMD41);
|
317
|
308
|
goto FAIL;
|
318
|
309
|
}
|
319
|
310
|
}
|
320
|
|
- // if SD2 read OCR register to check for SDHC card
|
|
311
|
+ // If SD2 read OCR register to check for SDHC card
|
321
|
312
|
if (type() == SD_CARD_TYPE_SD2) {
|
322
|
313
|
if (cardCommand(CMD58, 0)) {
|
323
|
314
|
error(SD_CARD_ERROR_CMD58);
|
324
|
315
|
goto FAIL;
|
325
|
316
|
}
|
326
|
317
|
if ((spiRec() & 0xC0) == 0xC0) type(SD_CARD_TYPE_SDHC);
|
327
|
|
- // discard rest of ocr - contains allowed voltage range
|
|
318
|
+ // Discard rest of ocr - contains allowed voltage range
|
328
|
319
|
for (uint8_t i = 0; i < 3; i++) spiRec();
|
329
|
320
|
}
|
330
|
321
|
chipDeselect();
|
|
@@ -344,8 +335,7 @@ bool Sd2Card::init(uint8_t sckRateID, pin_t chipSelectPin) {
|
344
|
335
|
* \return true for success, false for failure.
|
345
|
336
|
*/
|
346
|
337
|
bool Sd2Card::readBlock(uint32_t blockNumber, uint8_t* dst) {
|
347
|
|
- // use address if not SDHC card
|
348
|
|
- if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9;
|
|
338
|
+ if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; // Use address if not SDHC card
|
349
|
339
|
|
350
|
340
|
#if ENABLED(SD_CHECK_AND_RETRY)
|
351
|
341
|
uint8_t retryCnt = 3;
|
|
@@ -447,44 +437,39 @@ bool Sd2Card::readData(uint8_t* dst) {
|
447
|
437
|
#endif
|
448
|
438
|
#endif // SD_CHECK_AND_RETRY
|
449
|
439
|
|
450
|
|
-bool Sd2Card::readData(uint8_t* dst, uint16_t count) {
|
451
|
|
- // wait for start block token
|
|
440
|
+bool Sd2Card::readData(uint8_t* dst, const uint16_t count) {
|
|
441
|
+ bool success = false;
|
|
442
|
+
|
452
|
443
|
const millis_t read_timeout = millis() + SD_READ_TIMEOUT;
|
453
|
|
- while ((status_ = spiRec()) == 0xFF) {
|
|
444
|
+ while ((status_ = spiRec()) == 0xFF) { // Wait for start block token
|
454
|
445
|
if (ELAPSED(millis(), read_timeout)) {
|
455
|
446
|
error(SD_CARD_ERROR_READ_TIMEOUT);
|
456
|
447
|
goto FAIL;
|
457
|
448
|
}
|
458
|
449
|
}
|
459
|
|
- if (status_ != DATA_START_BLOCK) {
|
460
|
|
- error(SD_CARD_ERROR_READ);
|
461
|
|
- goto FAIL;
|
462
|
|
- }
|
463
|
|
- // transfer data
|
464
|
|
- spiRead(dst, count);
|
465
|
450
|
|
466
|
|
-#if ENABLED(SD_CHECK_AND_RETRY)
|
467
|
|
- {
|
468
|
|
- uint16_t recvCrc = (spiRec() << 8) | spiRec();
|
469
|
|
- if (crcSupported && recvCrc != CRC_CCITT(dst, count)) {
|
470
|
|
- error(SD_CARD_ERROR_READ_CRC);
|
471
|
|
- goto FAIL;
|
472
|
|
- }
|
|
451
|
+ if (status_ == DATA_START_BLOCK) {
|
|
452
|
+ spiRead(dst, count); // Transfer data
|
|
453
|
+
|
|
454
|
+ const uint16_t recvCrc = (spiRec() << 8) | spiRec();
|
|
455
|
+ #if ENABLED(SD_CHECK_AND_RETRY)
|
|
456
|
+ success = !crcSupported || recvCrc == CRC_CCITT(dst, count);
|
|
457
|
+ if (!success) error(SD_CARD_ERROR_READ_CRC);
|
|
458
|
+ #else
|
|
459
|
+ success = true;
|
|
460
|
+ UNUSED(recvCrc);
|
|
461
|
+ #endif
|
473
|
462
|
}
|
474
|
|
-#else
|
475
|
|
- // discard CRC
|
476
|
|
- spiRec();
|
477
|
|
- spiRec();
|
478
|
|
-#endif
|
479
|
|
- chipDeselect();
|
480
|
|
- return true;
|
|
463
|
+ else
|
|
464
|
+ error(SD_CARD_ERROR_READ);
|
|
465
|
+
|
481
|
466
|
FAIL:
|
482
|
467
|
chipDeselect();
|
483
|
|
- return false;
|
|
468
|
+ return success;
|
484
|
469
|
}
|
485
|
470
|
|
486
|
471
|
/** read CID or CSR register */
|
487
|
|
-bool Sd2Card::readRegister(uint8_t cmd, void* buf) {
|
|
472
|
+bool Sd2Card::readRegister(const uint8_t cmd, void* buf) {
|
488
|
473
|
uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
|
489
|
474
|
if (cardCommand(cmd, 0)) {
|
490
|
475
|
error(SD_CARD_ERROR_READ_REG);
|
|
@@ -506,13 +491,11 @@ bool Sd2Card::readRegister(uint8_t cmd, void* buf) {
|
506
|
491
|
*/
|
507
|
492
|
bool Sd2Card::readStart(uint32_t blockNumber) {
|
508
|
493
|
if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9;
|
509
|
|
- if (cardCommand(CMD18, blockNumber)) {
|
510
|
|
- error(SD_CARD_ERROR_CMD18);
|
511
|
|
- chipDeselect();
|
512
|
|
- return false;
|
513
|
|
- }
|
|
494
|
+
|
|
495
|
+ const bool success = !cardCommand(CMD18, blockNumber);
|
|
496
|
+ if (!success) error(SD_CARD_ERROR_CMD18);
|
514
|
497
|
chipDeselect();
|
515
|
|
- return true;
|
|
498
|
+ return success;
|
516
|
499
|
}
|
517
|
500
|
|
518
|
501
|
/**
|
|
@@ -522,13 +505,10 @@ bool Sd2Card::readStart(uint32_t blockNumber) {
|
522
|
505
|
*/
|
523
|
506
|
bool Sd2Card::readStop() {
|
524
|
507
|
chipSelect();
|
525
|
|
- if (cardCommand(CMD12, 0)) {
|
526
|
|
- error(SD_CARD_ERROR_CMD12);
|
527
|
|
- chipDeselect();
|
528
|
|
- return false;
|
529
|
|
- }
|
|
508
|
+ const bool success = !cardCommand(CMD12, 0);
|
|
509
|
+ if (!success) error(SD_CARD_ERROR_CMD12);
|
530
|
510
|
chipDeselect();
|
531
|
|
- return true;
|
|
511
|
+ return success;
|
532
|
512
|
}
|
533
|
513
|
|
534
|
514
|
/**
|
|
@@ -543,16 +523,20 @@ bool Sd2Card::readStop() {
|
543
|
523
|
* \return The value one, true, is returned for success and the value zero,
|
544
|
524
|
* false, is returned for an invalid value of \a sckRateID.
|
545
|
525
|
*/
|
546
|
|
-bool Sd2Card::setSckRate(uint8_t sckRateID) {
|
547
|
|
- if (sckRateID > 6) {
|
|
526
|
+bool Sd2Card::setSckRate(const uint8_t sckRateID) {
|
|
527
|
+ const bool success = (sckRateID <= 6);
|
|
528
|
+ if (success)
|
|
529
|
+ spiRate_ = sckRateID;
|
|
530
|
+ else
|
548
|
531
|
error(SD_CARD_ERROR_SCK_RATE);
|
549
|
|
- return false;
|
550
|
|
- }
|
551
|
|
- spiRate_ = sckRateID;
|
552
|
|
- return true;
|
|
532
|
+ return success;
|
553
|
533
|
}
|
554
|
534
|
|
555
|
|
-// wait for card to go not busy
|
|
535
|
+/**
|
|
536
|
+ * Wait for card to become not-busy
|
|
537
|
+ * \param[in] timeout_ms Timeout to abort.
|
|
538
|
+ * \return true for success, false for timeout.
|
|
539
|
+ */
|
556
|
540
|
bool Sd2Card::waitNotBusy(const millis_t timeout_ms) {
|
557
|
541
|
const millis_t wait_timeout = millis() + timeout_ms;
|
558
|
542
|
while (spiRec() != 0xFF)
|
|
@@ -562,36 +546,31 @@ bool Sd2Card::waitNotBusy(const millis_t timeout_ms) {
|
562
|
546
|
}
|
563
|
547
|
|
564
|
548
|
/**
|
565
|
|
- * Writes a 512 byte block to an SD card.
|
|
549
|
+ * Write a 512 byte block to an SD card.
|
566
|
550
|
*
|
567
|
551
|
* \param[in] blockNumber Logical block to be written.
|
568
|
552
|
* \param[in] src Pointer to the location of the data to be written.
|
569
|
553
|
* \return true for success, false for failure.
|
570
|
554
|
*/
|
571
|
555
|
bool Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) {
|
572
|
|
- // use address if not SDHC card
|
573
|
|
- if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9;
|
574
|
|
- if (cardCommand(CMD24, blockNumber)) {
|
575
|
|
- error(SD_CARD_ERROR_CMD24);
|
576
|
|
- goto FAIL;
|
|
556
|
+ if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; // Use address if not SDHC card
|
|
557
|
+
|
|
558
|
+ bool success = false;
|
|
559
|
+ if (!cardCommand(CMD24, blockNumber)) {
|
|
560
|
+ if (writeData(DATA_START_BLOCK, src)) {
|
|
561
|
+ if (waitNotBusy(SD_WRITE_TIMEOUT)) { // Wait for flashing to complete
|
|
562
|
+ success = !(cardCommand(CMD13, 0) || spiRec()); // Response is r2 so get and check two bytes for nonzero
|
|
563
|
+ if (!success) error(SD_CARD_ERROR_WRITE_PROGRAMMING);
|
|
564
|
+ }
|
|
565
|
+ else
|
|
566
|
+ error(SD_CARD_ERROR_WRITE_TIMEOUT);
|
|
567
|
+ }
|
577
|
568
|
}
|
578
|
|
- if (!writeData(DATA_START_BLOCK, src)) goto FAIL;
|
|
569
|
+ else
|
|
570
|
+ error(SD_CARD_ERROR_CMD24);
|
579
|
571
|
|
580
|
|
- // wait for flash programming to complete
|
581
|
|
- if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
|
582
|
|
- error(SD_CARD_ERROR_WRITE_TIMEOUT);
|
583
|
|
- goto FAIL;
|
584
|
|
- }
|
585
|
|
- // response is r2 so get and check two bytes for nonzero
|
586
|
|
- if (cardCommand(CMD13, 0) || spiRec()) {
|
587
|
|
- error(SD_CARD_ERROR_WRITE_PROGRAMMING);
|
588
|
|
- goto FAIL;
|
589
|
|
- }
|
590
|
572
|
chipDeselect();
|
591
|
|
- return true;
|
592
|
|
- FAIL:
|
593
|
|
- chipDeselect();
|
594
|
|
- return false;
|
|
573
|
+ return success;
|
595
|
574
|
}
|
596
|
575
|
|
597
|
576
|
/**
|
|
@@ -600,28 +579,30 @@ bool Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) {
|
600
|
579
|
* \return true for success, false for failure.
|
601
|
580
|
*/
|
602
|
581
|
bool Sd2Card::writeData(const uint8_t* src) {
|
|
582
|
+ bool success = true;
|
603
|
583
|
chipSelect();
|
604
|
|
- // wait for previous write to finish
|
|
584
|
+ // Wait for previous write to finish
|
605
|
585
|
if (!waitNotBusy(SD_WRITE_TIMEOUT) || !writeData(WRITE_MULTIPLE_TOKEN, src)) {
|
606
|
586
|
error(SD_CARD_ERROR_WRITE_MULTIPLE);
|
607
|
|
- chipDeselect();
|
608
|
|
- return false;
|
|
587
|
+ success = false;
|
609
|
588
|
}
|
610
|
589
|
chipDeselect();
|
611
|
|
- return true;
|
|
590
|
+ return success;
|
612
|
591
|
}
|
613
|
592
|
|
614
|
|
-// send one block of data for write block or write multiple blocks
|
615
|
|
-bool Sd2Card::writeData(uint8_t token, const uint8_t* src) {
|
|
593
|
+// Send one block of data for write block or write multiple blocks
|
|
594
|
+bool Sd2Card::writeData(const uint8_t token, const uint8_t* src) {
|
616
|
595
|
|
617
|
|
-#if ENABLED(SD_CHECK_AND_RETRY)
|
618
|
|
- uint16_t crc = CRC_CCITT( src, 512 );
|
619
|
|
-#else // ENABLED(SD_CHECK_AND_RETRY)
|
620
|
|
- uint16_t crc = 0xFFFF;
|
621
|
|
-#endif // ENABLED(SD_CHECK_AND_RETRY)
|
622
|
|
- spiSendBlock( token, src );
|
623
|
|
- spiSend( crc >> 8 );
|
624
|
|
- spiSend( crc & 0XFF );
|
|
596
|
+ uint16_t crc =
|
|
597
|
+ #if ENABLED(SD_CHECK_AND_RETRY)
|
|
598
|
+ CRC_CCITT(src, 512)
|
|
599
|
+ #else
|
|
600
|
+ 0xFFFF
|
|
601
|
+ #endif
|
|
602
|
+ ;
|
|
603
|
+ spiSendBlock(token, src);
|
|
604
|
+ spiSend(crc >> 8);
|
|
605
|
+ spiSend(crc & 0xFF);
|
625
|
606
|
|
626
|
607
|
status_ = spiRec();
|
627
|
608
|
if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) {
|
|
@@ -643,23 +624,18 @@ bool Sd2Card::writeData(uint8_t token, const uint8_t* src) {
|
643
|
624
|
*
|
644
|
625
|
* \return true for success, false for failure.
|
645
|
626
|
*/
|
646
|
|
-bool Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) {
|
647
|
|
- // send pre-erase count
|
648
|
|
- if (cardAcmd(ACMD23, eraseCount)) {
|
649
|
|
- error(SD_CARD_ERROR_ACMD23);
|
650
|
|
- goto FAIL;
|
651
|
|
- }
|
652
|
|
- // use address if not SDHC card
|
653
|
|
- if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9;
|
654
|
|
- if (cardCommand(CMD25, blockNumber)) {
|
655
|
|
- error(SD_CARD_ERROR_CMD25);
|
656
|
|
- goto FAIL;
|
|
627
|
+bool Sd2Card::writeStart(uint32_t blockNumber, const uint32_t eraseCount) {
|
|
628
|
+ bool success = false;
|
|
629
|
+ if (!cardAcmd(ACMD23, eraseCount)) { // Send pre-erase count
|
|
630
|
+ if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; // Use address if not SDHC card
|
|
631
|
+ success = !cardCommand(CMD25, blockNumber);
|
|
632
|
+ if (!success) error(SD_CARD_ERROR_CMD25);
|
657
|
633
|
}
|
|
634
|
+ else
|
|
635
|
+ error(SD_CARD_ERROR_ACMD23);
|
|
636
|
+
|
658
|
637
|
chipDeselect();
|
659
|
|
- return true;
|
660
|
|
- FAIL:
|
661
|
|
- chipDeselect();
|
662
|
|
- return false;
|
|
638
|
+ return success;
|
663
|
639
|
}
|
664
|
640
|
|
665
|
641
|
/**
|
|
@@ -668,16 +644,17 @@ bool Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) {
|
668
|
644
|
* \return true for success, false for failure.
|
669
|
645
|
*/
|
670
|
646
|
bool Sd2Card::writeStop() {
|
|
647
|
+ bool success = false;
|
671
|
648
|
chipSelect();
|
672
|
|
- if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto FAIL;
|
673
|
|
- spiSend(STOP_TRAN_TOKEN);
|
674
|
|
- if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto FAIL;
|
675
|
|
- chipDeselect();
|
676
|
|
- return true;
|
677
|
|
- FAIL:
|
678
|
|
- error(SD_CARD_ERROR_STOP_TRAN);
|
|
649
|
+ if (waitNotBusy(SD_WRITE_TIMEOUT)) {
|
|
650
|
+ spiSend(STOP_TRAN_TOKEN);
|
|
651
|
+ success = waitNotBusy(SD_WRITE_TIMEOUT);
|
|
652
|
+ }
|
|
653
|
+ else
|
|
654
|
+ error(SD_CARD_ERROR_STOP_TRAN);
|
|
655
|
+
|
679
|
656
|
chipDeselect();
|
680
|
|
- return false;
|
|
657
|
+ return success;
|
681
|
658
|
}
|
682
|
659
|
|
683
|
660
|
#endif // SDSUPPORT
|