Backported latest improvements and fixes from the SdFat liibrary to our own version. This includes support for CRC7 validation on commands and also, made sure that even if using software SPI implementations, SD card speed is properly adjusted when transitioning from INITIALIZATION to DATA TRANSFER mode. ALL HALs implement spiInit, even in SW SPI mode, and we NEED this change to improve 25x the transfer speed of the SD card and allow implementations of USB MSD
This commit is contained in:
parent
7447979110
commit
9aff55ed1f
|
@ -23,6 +23,7 @@
|
||||||
/**
|
/**
|
||||||
* Arduino Sd2Card Library
|
* Arduino Sd2Card Library
|
||||||
* Copyright (C) 2009 by William Greiman
|
* Copyright (C) 2009 by William Greiman
|
||||||
|
* Updated with backports of the latest SdFat library from the same author
|
||||||
*
|
*
|
||||||
* This file is part of the Arduino Sd2Card Library
|
* This file is part of the Arduino Sd2Card Library
|
||||||
*/
|
*/
|
||||||
|
@ -31,29 +32,92 @@
|
||||||
|
|
||||||
#if ENABLED(SDSUPPORT)
|
#if ENABLED(SDSUPPORT)
|
||||||
|
|
||||||
|
/* Enable FAST CRC computations - You can trade speed for FLASH space if
|
||||||
|
* needed by disabling the following define */
|
||||||
|
#define FAST_CRC 1
|
||||||
|
|
||||||
#include "Sd2Card.h"
|
#include "Sd2Card.h"
|
||||||
|
|
||||||
#include "../Marlin.h"
|
#include "../Marlin.h"
|
||||||
|
|
||||||
|
#if ENABLED(SD_CHECK_AND_RETRY)
|
||||||
|
#ifdef FAST_CRC
|
||||||
|
static const uint8_t crctab7[] PROGMEM = {
|
||||||
|
0x00,0x09,0x12,0x1b,0x24,0x2d,0x36,0x3f,0x48,0x41,0x5a,0x53,0x6c,0x65,0x7e,0x77,
|
||||||
|
0x19,0x10,0x0b,0x02,0x3d,0x34,0x2f,0x26,0x51,0x58,0x43,0x4a,0x75,0x7c,0x67,0x6e,
|
||||||
|
0x32,0x3b,0x20,0x29,0x16,0x1f,0x04,0x0d,0x7a,0x73,0x68,0x61,0x5e,0x57,0x4c,0x45,
|
||||||
|
0x2b,0x22,0x39,0x30,0x0f,0x06,0x1d,0x14,0x63,0x6a,0x71,0x78,0x47,0x4e,0x55,0x5c,
|
||||||
|
0x64,0x6d,0x76,0x7f,0x40,0x49,0x52,0x5b,0x2c,0x25,0x3e,0x37,0x08,0x01,0x1a,0x13,
|
||||||
|
0x7d,0x74,0x6f,0x66,0x59,0x50,0x4b,0x42,0x35,0x3c,0x27,0x2e,0x11,0x18,0x03,0x0a,
|
||||||
|
0x56,0x5f,0x44,0x4d,0x72,0x7b,0x60,0x69,0x1e,0x17,0x0c,0x05,0x3a,0x33,0x28,0x21,
|
||||||
|
0x4f,0x46,0x5d,0x54,0x6b,0x62,0x79,0x70,0x07,0x0e,0x15,0x1c,0x23,0x2a,0x31,0x38,
|
||||||
|
0x41,0x48,0x53,0x5a,0x65,0x6c,0x77,0x7e,0x09,0x00,0x1b,0x12,0x2d,0x24,0x3f,0x36,
|
||||||
|
0x58,0x51,0x4a,0x43,0x7c,0x75,0x6e,0x67,0x10,0x19,0x02,0x0b,0x34,0x3d,0x26,0x2f,
|
||||||
|
0x73,0x7a,0x61,0x68,0x57,0x5e,0x45,0x4c,0x3b,0x32,0x29,0x20,0x1f,0x16,0x0d,0x04,
|
||||||
|
0x6a,0x63,0x78,0x71,0x4e,0x47,0x5c,0x55,0x22,0x2b,0x30,0x39,0x06,0x0f,0x14,0x1d,
|
||||||
|
0x25,0x2c,0x37,0x3e,0x01,0x08,0x13,0x1a,0x6d,0x64,0x7f,0x76,0x49,0x40,0x5b,0x52,
|
||||||
|
0x3c,0x35,0x2e,0x27,0x18,0x11,0x0a,0x03,0x74,0x7d,0x66,0x6f,0x50,0x59,0x42,0x4b,
|
||||||
|
0x17,0x1e,0x05,0x0c,0x33,0x3a,0x21,0x28,0x5f,0x56,0x4d,0x44,0x7b,0x72,0x69,0x60,
|
||||||
|
0x0e,0x07,0x1c,0x15,0x2a,0x23,0x38,0x31,0x46,0x4f,0x54,0x5d,0x62,0x6b,0x70,0x79
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t CRC7(const uint8_t* data, uint8_t n) {
|
||||||
|
uint8_t crc = 0;
|
||||||
|
while ( n > 0 ) {
|
||||||
|
crc = pgm_read_byte(&crctab7[ (crc << 1) ^ *data++ ]);
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
return (crc << 1) | 1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static uint8_t CRC7(const uint8_t* data, uint8_t n) {
|
||||||
|
uint8_t crc = 0;
|
||||||
|
for (uint8_t i = 0; i < n; i++) {
|
||||||
|
uint8_t d = data[i];
|
||||||
|
d ^= crc << 1;
|
||||||
|
if (d & 0x80) d ^= 9;
|
||||||
|
crc = d ^ (crc & 0x78) ^ (crc << 4) ^ ((crc >> 3) & 15);
|
||||||
|
crc &= 0x7f;
|
||||||
|
}
|
||||||
|
crc = (crc << 1) ^ (crc << 4) ^ (crc & 0x70) ^ ((crc >> 3) & 0x0f);
|
||||||
|
return crc | 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
// send command and return error code. Return zero for OK
|
// send command and return error code. Return zero for OK
|
||||||
uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) {
|
uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) {
|
||||||
// select card
|
// select card
|
||||||
chipSelectLow();
|
chipSelect();
|
||||||
|
|
||||||
// wait up to 300 ms if busy
|
// wait up to 300 ms if busy
|
||||||
waitNotBusy(300);
|
waitNotBusy( SD_WRITE_TIMEOUT );
|
||||||
|
|
||||||
|
uint8_t *pa = (uint8_t *)(&arg);
|
||||||
|
|
||||||
|
#if ENABLED(SD_CHECK_AND_RETRY)
|
||||||
|
|
||||||
|
// form message
|
||||||
|
uint8_t d[6] = {(uint8_t) (cmd | 0x40), pa[3], pa[2], pa[1], pa[0] };
|
||||||
|
|
||||||
|
// add crc
|
||||||
|
d[5] = CRC7(d, 5);
|
||||||
|
|
||||||
|
// send message
|
||||||
|
for (uint8_t k = 0; k < 6; k++ )
|
||||||
|
spiSend( d[k] );
|
||||||
|
|
||||||
|
#else
|
||||||
// send command
|
// send command
|
||||||
spiSend(cmd | 0x40);
|
spiSend(cmd | 0x40);
|
||||||
|
|
||||||
// send argument
|
// send argument
|
||||||
for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s);
|
for( int8_t i = 3; i >= 0; i-- )
|
||||||
|
spiSend( pa[i] );
|
||||||
|
|
||||||
// send CRC
|
// send CRC - correct for CMD0 with arg zero or CMD8 with arg 0X1AA
|
||||||
uint8_t crc = 0xFF;
|
spiSend( cmd == CMD0 ? 0X95 : 0X87 );
|
||||||
if (cmd == CMD0) crc = 0x95; // correct crc for CMD0 with arg 0
|
#endif
|
||||||
if (cmd == CMD8) crc = 0x87; // correct crc for CMD8 with arg 0x1AA
|
|
||||||
spiSend(crc);
|
|
||||||
|
|
||||||
// skip stuff byte for stop read
|
// skip stuff byte for stop read
|
||||||
if (cmd == CMD12) spiRec();
|
if (cmd == CMD12) spiRec();
|
||||||
|
@ -91,14 +155,15 @@ uint32_t Sd2Card::cardSize() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sd2Card::chipSelectHigh() {
|
void Sd2Card::chipDeselect() {
|
||||||
digitalWrite(chipSelectPin_, HIGH);
|
digitalWrite(chipSelectPin_, HIGH);
|
||||||
|
|
||||||
|
// insure MISO goes high impedance
|
||||||
|
spiSend( 0xFF );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sd2Card::chipSelectLow() {
|
void Sd2Card::chipSelect() {
|
||||||
#if DISABLED(SOFTWARE_SPI)
|
spiInit(spiRate_);
|
||||||
spiInit(spiRate_);
|
|
||||||
#endif // SOFTWARE_SPI
|
|
||||||
digitalWrite(chipSelectPin_, LOW);
|
digitalWrite(chipSelectPin_, LOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,10 +207,10 @@ bool Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) {
|
||||||
error(SD_CARD_ERROR_ERASE_TIMEOUT);
|
error(SD_CARD_ERROR_ERASE_TIMEOUT);
|
||||||
goto FAIL;
|
goto FAIL;
|
||||||
}
|
}
|
||||||
chipSelectHigh();
|
chipDeselect();
|
||||||
return true;
|
return true;
|
||||||
FAIL:
|
FAIL:
|
||||||
chipSelectHigh();
|
chipDeselect();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,22 +265,36 @@ bool Sd2Card::init(uint8_t sckRateID, pin_t chipSelectPin) {
|
||||||
goto FAIL;
|
goto FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// check SD version
|
|
||||||
if ((cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND)) {
|
#if ENABLED(SD_CHECK_AND_RETRY)
|
||||||
type(SD_CARD_TYPE_SD1);
|
if (cardCommand( CMD59, 1 ) != R1_IDLE_STATE) {
|
||||||
|
error(SD_CARD_ERROR_CMD59);
|
||||||
|
goto FAIL;
|
||||||
}
|
}
|
||||||
else {
|
#endif
|
||||||
|
|
||||||
|
// check SD version
|
||||||
|
while (1) {
|
||||||
|
if (cardCommand(CMD8, 0x1AA) == (R1_ILLEGAL_COMMAND | R1_IDLE_STATE)) {
|
||||||
|
type(SD_CARD_TYPE_SD1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// only need last byte of r7 response
|
// only need last byte of r7 response
|
||||||
for (uint8_t i = 0; i < 4; i++) status_ = spiRec();
|
for (uint8_t i = 0; i < 4; i++) status_ = spiRec();
|
||||||
if (status_ != 0xAA) {
|
if (status_ == 0xAA) {
|
||||||
|
type(SD_CARD_TYPE_SD2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) {
|
||||||
error(SD_CARD_ERROR_CMD8);
|
error(SD_CARD_ERROR_CMD8);
|
||||||
goto FAIL;
|
goto FAIL;
|
||||||
}
|
}
|
||||||
type(SD_CARD_TYPE_SD2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize card and send host supports SDHC if SD2
|
// initialize card and send host supports SDHC if SD2
|
||||||
arg = type() == SD_CARD_TYPE_SD2 ? 0x40000000 : 0;
|
arg = type() == SD_CARD_TYPE_SD2 ? 0x40000000 : 0;
|
||||||
|
|
||||||
while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) {
|
while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) {
|
||||||
// check for timeout
|
// check for timeout
|
||||||
if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) {
|
if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) {
|
||||||
|
@ -233,17 +312,12 @@ bool Sd2Card::init(uint8_t sckRateID, pin_t chipSelectPin) {
|
||||||
// discard rest of ocr - contains allowed voltage range
|
// discard rest of ocr - contains allowed voltage range
|
||||||
for (uint8_t i = 0; i < 3; i++) spiRec();
|
for (uint8_t i = 0; i < 3; i++) spiRec();
|
||||||
}
|
}
|
||||||
chipSelectHigh();
|
chipDeselect();
|
||||||
|
|
||||||
#if DISABLED(SOFTWARE_SPI)
|
return setSckRate(sckRateID);
|
||||||
return setSckRate(sckRateID);
|
|
||||||
#else // SOFTWARE_SPI
|
|
||||||
UNUSED(sckRateID);
|
|
||||||
return true;
|
|
||||||
#endif // SOFTWARE_SPI
|
|
||||||
|
|
||||||
FAIL:
|
FAIL:
|
||||||
chipSelectHigh();
|
chipDeselect();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,7 +342,7 @@ bool Sd2Card::readBlock(uint32_t blockNumber, uint8_t* dst) {
|
||||||
|
|
||||||
if (!--retryCnt) break;
|
if (!--retryCnt) break;
|
||||||
|
|
||||||
chipSelectHigh();
|
chipDeselect();
|
||||||
cardCommand(CMD12, 0); // Try sending a stop command, ignore the result.
|
cardCommand(CMD12, 0); // Try sending a stop command, ignore the result.
|
||||||
errorCode_ = 0;
|
errorCode_ = 0;
|
||||||
}
|
}
|
||||||
|
@ -279,7 +353,7 @@ bool Sd2Card::readBlock(uint32_t blockNumber, uint8_t* dst) {
|
||||||
return readData(dst, 512);
|
return readData(dst, 512);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
chipSelectHigh();
|
chipDeselect();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,12 +365,13 @@ bool Sd2Card::readBlock(uint32_t blockNumber, uint8_t* dst) {
|
||||||
* \return true for success, false for failure.
|
* \return true for success, false for failure.
|
||||||
*/
|
*/
|
||||||
bool Sd2Card::readData(uint8_t* dst) {
|
bool Sd2Card::readData(uint8_t* dst) {
|
||||||
chipSelectLow();
|
chipSelect();
|
||||||
return readData(dst, 512);
|
return readData(dst, 512);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ENABLED(SD_CHECK_AND_RETRY)
|
#if ENABLED(SD_CHECK_AND_RETRY)
|
||||||
static const uint16_t crctab[] PROGMEM = {
|
#ifdef FAST_CRC
|
||||||
|
static const uint16_t crctab16[] PROGMEM = {
|
||||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
|
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
|
||||||
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
|
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
|
||||||
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
|
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
|
||||||
|
@ -330,13 +405,30 @@ bool Sd2Card::readData(uint8_t* dst) {
|
||||||
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
|
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
|
||||||
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
|
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
|
||||||
};
|
};
|
||||||
|
// faster CRC-CCITT
|
||||||
|
// uses the x^16,x^12,x^5,x^1 polynomial.
|
||||||
static uint16_t CRC_CCITT(const uint8_t* data, size_t n) {
|
static uint16_t CRC_CCITT(const uint8_t* data, size_t n) {
|
||||||
uint16_t crc = 0;
|
uint16_t crc = 0;
|
||||||
for (size_t i = 0; i < n; i++) {
|
for (size_t i = 0; i < n; i++) {
|
||||||
crc = pgm_read_word(&crctab[(crc >> 8 ^ data[i]) & 0xFF]) ^ (crc << 8);
|
crc = pgm_read_word(&crctab16[(crc >> 8 ^ data[i]) & 0xFF]) ^ (crc << 8);
|
||||||
}
|
}
|
||||||
return crc;
|
return crc;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
// slower CRC-CCITT
|
||||||
|
// uses the x^16,x^12,x^5,x^1 polynomial.
|
||||||
|
static uint16_t CRC_CCITT(const uint8_t* data, size_t n) {
|
||||||
|
uint16_t crc = 0;
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
crc = (uint8_t)(crc >> 8) | (crc << 8);
|
||||||
|
crc ^= data[i];
|
||||||
|
crc ^= (uint8_t)(crc & 0xff) >> 4;
|
||||||
|
crc ^= crc << 12;
|
||||||
|
crc ^= (crc & 0xff) << 5;
|
||||||
|
}
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#endif // SD_CHECK_AND_RETRY
|
#endif // SD_CHECK_AND_RETRY
|
||||||
|
|
||||||
bool Sd2Card::readData(uint8_t* dst, uint16_t count) {
|
bool Sd2Card::readData(uint8_t* dst, uint16_t count) {
|
||||||
|
@ -357,11 +449,9 @@ bool Sd2Card::readData(uint8_t* dst, uint16_t count) {
|
||||||
|
|
||||||
#if ENABLED(SD_CHECK_AND_RETRY)
|
#if ENABLED(SD_CHECK_AND_RETRY)
|
||||||
{
|
{
|
||||||
uint16_t calcCrc = CRC_CCITT(dst, count);
|
uint16_t recvCrc = (spiRec() << 8) | spiRec();
|
||||||
uint16_t recvCrc = spiRec() << 8;
|
if (recvCrc != CRC_CCITT(dst, count)) {
|
||||||
recvCrc |= spiRec();
|
error(SD_CARD_ERROR_READ_CRC);
|
||||||
if (calcCrc != recvCrc) {
|
|
||||||
error(SD_CARD_ERROR_CRC);
|
|
||||||
goto FAIL;
|
goto FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -370,14 +460,10 @@ bool Sd2Card::readData(uint8_t* dst, uint16_t count) {
|
||||||
spiRec();
|
spiRec();
|
||||||
spiRec();
|
spiRec();
|
||||||
#endif
|
#endif
|
||||||
chipSelectHigh();
|
chipDeselect();
|
||||||
// Send an additional dummy byte, required by Toshiba Flash Air SD Card
|
|
||||||
spiSend(0xFF);
|
|
||||||
return true;
|
return true;
|
||||||
FAIL:
|
FAIL:
|
||||||
chipSelectHigh();
|
chipDeselect();
|
||||||
// Send an additional dummy byte, required by Toshiba Flash Air SD Card
|
|
||||||
spiSend(0xFF);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,7 +472,7 @@ bool Sd2Card::readRegister(uint8_t cmd, void* buf) {
|
||||||
uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
|
uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
|
||||||
if (cardCommand(cmd, 0)) {
|
if (cardCommand(cmd, 0)) {
|
||||||
error(SD_CARD_ERROR_READ_REG);
|
error(SD_CARD_ERROR_READ_REG);
|
||||||
chipSelectHigh();
|
chipDeselect();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return readData(dst, 16);
|
return readData(dst, 16);
|
||||||
|
@ -406,10 +492,10 @@ bool Sd2Card::readStart(uint32_t blockNumber) {
|
||||||
if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9;
|
if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9;
|
||||||
if (cardCommand(CMD18, blockNumber)) {
|
if (cardCommand(CMD18, blockNumber)) {
|
||||||
error(SD_CARD_ERROR_CMD18);
|
error(SD_CARD_ERROR_CMD18);
|
||||||
chipSelectHigh();
|
chipDeselect();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
chipSelectHigh();
|
chipDeselect();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,13 +505,13 @@ bool Sd2Card::readStart(uint32_t blockNumber) {
|
||||||
* \return true for success, false for failure.
|
* \return true for success, false for failure.
|
||||||
*/
|
*/
|
||||||
bool Sd2Card::readStop() {
|
bool Sd2Card::readStop() {
|
||||||
chipSelectLow();
|
chipSelect();
|
||||||
if (cardCommand(CMD12, 0)) {
|
if (cardCommand(CMD12, 0)) {
|
||||||
error(SD_CARD_ERROR_CMD12);
|
error(SD_CARD_ERROR_CMD12);
|
||||||
chipSelectHigh();
|
chipDeselect();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
chipSelectHigh();
|
chipDeselect();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -485,10 +571,10 @@ bool Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) {
|
||||||
error(SD_CARD_ERROR_WRITE_PROGRAMMING);
|
error(SD_CARD_ERROR_WRITE_PROGRAMMING);
|
||||||
goto FAIL;
|
goto FAIL;
|
||||||
}
|
}
|
||||||
chipSelectHigh();
|
chipDeselect();
|
||||||
return true;
|
return true;
|
||||||
FAIL:
|
FAIL:
|
||||||
chipSelectHigh();
|
chipDeselect();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -498,28 +584,33 @@ bool Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) {
|
||||||
* \return true for success, false for failure.
|
* \return true for success, false for failure.
|
||||||
*/
|
*/
|
||||||
bool Sd2Card::writeData(const uint8_t* src) {
|
bool Sd2Card::writeData(const uint8_t* src) {
|
||||||
chipSelectLow();
|
chipSelect();
|
||||||
// wait for previous write to finish
|
// wait for previous write to finish
|
||||||
if (!waitNotBusy(SD_WRITE_TIMEOUT) || !writeData(WRITE_MULTIPLE_TOKEN, src)) {
|
if (!waitNotBusy(SD_WRITE_TIMEOUT) || !writeData(WRITE_MULTIPLE_TOKEN, src)) {
|
||||||
error(SD_CARD_ERROR_WRITE_MULTIPLE);
|
error(SD_CARD_ERROR_WRITE_MULTIPLE);
|
||||||
chipSelectHigh();
|
chipDeselect();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
chipSelectHigh();
|
chipDeselect();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// send one block of data for write block or write multiple blocks
|
// send one block of data for write block or write multiple blocks
|
||||||
bool Sd2Card::writeData(uint8_t token, const uint8_t* src) {
|
bool Sd2Card::writeData(uint8_t token, const uint8_t* src) {
|
||||||
spiSendBlock(token, src);
|
|
||||||
|
|
||||||
spiSend(0xFF); // dummy crc
|
#if ENABLED(SD_CHECK_AND_RETRY)
|
||||||
spiSend(0xFF); // dummy crc
|
uint16_t crc = CRC_CCITT( src, 512 );
|
||||||
|
#else // ENABLED(SD_CHECK_AND_RETRY)
|
||||||
|
uint16_t crc = 0xFFFF;
|
||||||
|
#endif // ENABLED(SD_CHECK_AND_RETRY)
|
||||||
|
spiSendBlock( token, src );
|
||||||
|
spiSend( crc >> 8 );
|
||||||
|
spiSend( crc & 0XFF );
|
||||||
|
|
||||||
status_ = spiRec();
|
status_ = spiRec();
|
||||||
if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) {
|
if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) {
|
||||||
error(SD_CARD_ERROR_WRITE);
|
error(SD_CARD_ERROR_WRITE);
|
||||||
chipSelectHigh();
|
chipDeselect();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -548,10 +639,10 @@ bool Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) {
|
||||||
error(SD_CARD_ERROR_CMD25);
|
error(SD_CARD_ERROR_CMD25);
|
||||||
goto FAIL;
|
goto FAIL;
|
||||||
}
|
}
|
||||||
chipSelectHigh();
|
chipDeselect();
|
||||||
return true;
|
return true;
|
||||||
FAIL:
|
FAIL:
|
||||||
chipSelectHigh();
|
chipDeselect();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -561,15 +652,15 @@ bool Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) {
|
||||||
* \return true for success, false for failure.
|
* \return true for success, false for failure.
|
||||||
*/
|
*/
|
||||||
bool Sd2Card::writeStop() {
|
bool Sd2Card::writeStop() {
|
||||||
chipSelectLow();
|
chipSelect();
|
||||||
if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto FAIL;
|
if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto FAIL;
|
||||||
spiSend(STOP_TRAN_TOKEN);
|
spiSend(STOP_TRAN_TOKEN);
|
||||||
if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto FAIL;
|
if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto FAIL;
|
||||||
chipSelectHigh();
|
chipDeselect();
|
||||||
return true;
|
return true;
|
||||||
FAIL:
|
FAIL:
|
||||||
error(SD_CARD_ERROR_STOP_TRAN);
|
error(SD_CARD_ERROR_STOP_TRAN);
|
||||||
chipSelectHigh();
|
chipDeselect();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,8 @@ uint8_t const SD_CARD_ERROR_CMD0 = 0x01, // timeout error for com
|
||||||
SD_CARD_ERROR_WRITE_TIMEOUT = 0x17, // timeout occurred during write programming
|
SD_CARD_ERROR_WRITE_TIMEOUT = 0x17, // timeout occurred during write programming
|
||||||
SD_CARD_ERROR_SCK_RATE = 0x18, // incorrect rate selected
|
SD_CARD_ERROR_SCK_RATE = 0x18, // incorrect rate selected
|
||||||
SD_CARD_ERROR_INIT_NOT_CALLED = 0x19, // init() not called
|
SD_CARD_ERROR_INIT_NOT_CALLED = 0x19, // init() not called
|
||||||
SD_CARD_ERROR_CRC = 0x20; // crc check error
|
SD_CARD_ERROR_CMD59 = 0x1A, // card returned an error for CMD59 (CRC_ON_OFF)
|
||||||
|
SD_CARD_ERROR_READ_CRC = 0x1B; // invalid read CRC
|
||||||
|
|
||||||
// card types
|
// card types
|
||||||
uint8_t const SD_CARD_TYPE_SD1 = 1, // Standard capacity V1 SD card
|
uint8_t const SD_CARD_TYPE_SD1 = 1, // Standard capacity V1 SD card
|
||||||
|
@ -196,8 +197,8 @@ class Sd2Card {
|
||||||
|
|
||||||
bool readData(uint8_t* dst, uint16_t count);
|
bool readData(uint8_t* dst, uint16_t count);
|
||||||
bool readRegister(uint8_t cmd, void* buf);
|
bool readRegister(uint8_t cmd, void* buf);
|
||||||
void chipSelectHigh();
|
void chipDeselect();
|
||||||
void chipSelectLow();
|
void chipSelect();
|
||||||
void type(uint8_t value) { type_ = value; }
|
void type(uint8_t value) { type_ = value; }
|
||||||
bool waitNotBusy(uint16_t timeoutMillis);
|
bool waitNotBusy(uint16_t timeoutMillis);
|
||||||
bool writeData(uint8_t token, const uint8_t* src);
|
bool writeData(uint8_t token, const uint8_t* src);
|
||||||
|
|
|
@ -54,12 +54,13 @@ uint8_t const CMD0 = 0x00, // GO_IDLE_STATE - init card in spi mode if CS low
|
||||||
CMD24 = 0x18, // WRITE_BLOCK - write a single data block to the card
|
CMD24 = 0x18, // WRITE_BLOCK - write a single data block to the card
|
||||||
CMD25 = 0x19, // WRITE_MULTIPLE_BLOCK - write blocks of data until a STOP_TRANSMISSION
|
CMD25 = 0x19, // WRITE_MULTIPLE_BLOCK - write blocks of data until a STOP_TRANSMISSION
|
||||||
CMD32 = 0x20, // ERASE_WR_BLK_START - sets the address of the first block to be erased
|
CMD32 = 0x20, // ERASE_WR_BLK_START - sets the address of the first block to be erased
|
||||||
CMD33 = 0x21, // ERASE_WR_BLK_END - sets the address of the last block of the continuous range to be erased*/
|
CMD33 = 0x21, // ERASE_WR_BLK_END - sets the address of the last block of the continuous range to be erased
|
||||||
CMD38 = 0x26, // ERASE - erase all previously selected blocks */
|
CMD38 = 0x26, // ERASE - erase all previously selected blocks
|
||||||
CMD55 = 0x37, // APP_CMD - escape for application specific command */
|
CMD55 = 0x37, // APP_CMD - escape for application specific command
|
||||||
CMD58 = 0x3A, // READ_OCR - read the OCR register of a card */
|
CMD58 = 0x3A, // READ_OCR - read the OCR register of a card
|
||||||
ACMD23 = 0x17, // SET_WR_BLK_ERASE_COUNT - Set the number of write blocks to be pre-erased before writing */
|
CMD59 = 0x3B, // CRC_ON_OFF - enable or disable CRC checking
|
||||||
ACMD41 = 0x29; // SD_SEND_OP_COMD - Sends host capacity support information and activates the card's initialization process */
|
ACMD23 = 0x17, // SET_WR_BLK_ERASE_COUNT - Set the number of write blocks to be pre-erased before writing
|
||||||
|
ACMD41 = 0x29; // SD_SEND_OP_COMD - Sends host capacity support information and activates the card's initialization process
|
||||||
|
|
||||||
/** status for card in the ready state */
|
/** status for card in the ready state */
|
||||||
uint8_t const R1_READY_STATE = 0x00;
|
uint8_t const R1_READY_STATE = 0x00;
|
||||||
|
|
Loading…
Reference in a new issue