@ -87,44 +87,42 @@
# endif
# endif
# 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 ( const uint8_t cmd , const uint32_t arg ) {
// s elect card
// S elect card
chipSelect ( ) ;
chipSelect ( ) ;
// w ait up to 300 ms if busy
// W ait up to 300 ms if busy
waitNotBusy ( SD_WRITE_TIMEOUT ) ;
waitNotBusy ( SD_WRITE_TIMEOUT ) ;
uint8_t * pa = ( uint8_t * ) ( & arg ) ;
uint8_t * pa = ( uint8_t * ) ( & arg ) ;
# if ENABLED(SD_CHECK_AND_RETRY)
# if ENABLED(SD_CHECK_AND_RETRY)
// f orm message
// F orm message
uint8_t d [ 6 ] = { ( uint8_t ) ( cmd | 0x40 ) , pa [ 3 ] , pa [ 2 ] , pa [ 1 ] , pa [ 0 ] } ;
uint8_t d [ 6 ] = { ( uint8_t ) ( cmd | 0x40 ) , pa [ 3 ] , pa [ 2 ] , pa [ 1 ] , pa [ 0 ] } ;
// a dd crc
// A dd crc
d [ 5 ] = CRC7 ( d , 5 ) ;
d [ 5 ] = CRC7 ( d , 5 ) ;
// send message
// Send message
for ( uint8_t k = 0 ; k < 6 ; k + + )
for ( uint8_t k = 0 ; k < 6 ; k + + ) spiSend ( d [ k ] ) ;
spiSend ( d [ k ] ) ;
# else
# else
// s end command
// S end command
spiSend ( cmd | 0x40 ) ;
spiSend ( cmd | 0x40 ) ;
// send argument
// Send argument
for ( int8_t i = 3 ; i > = 0 ; i - - )
for ( int8_t i = 3 ; i > = 0 ; i - - ) spiSend ( pa [ i ] ) ;
spiSend ( pa [ i ] ) ;
// s end CRC - correct for CMD0 with arg zero or CMD8 with arg 0X1AA
// S end CRC - correct for CMD0 with arg zero or CMD8 with arg 0X1AA
spiSend ( cmd = = CMD0 ? 0X95 : 0X87 ) ;
spiSend ( cmd = = CMD0 ? 0X95 : 0X87 ) ;
# endif
# endif
// s kip stuff byte for stop read
// S kip stuff byte for stop read
if ( cmd = = CMD12 ) spiRec ( ) ;
if ( cmd = = CMD12 ) spiRec ( ) ;
// w ait for response
// W ait for response
for ( uint8_t i = 0 ; ( ( status_ = spiRec ( ) ) & 0x80 ) & & i ! = 0xFF ; i + + ) { /* Intentionally left empty */ }
for ( uint8_t i = 0 ; ( ( status_ = spiRec ( ) ) & 0x80 ) & & i ! = 0xFF ; i + + ) { /* Intentionally left empty */ }
return status_ ;
return status_ ;
}
}
@ -159,9 +157,7 @@ uint32_t Sd2Card::cardSize() {
void Sd2Card : : chipDeselect ( ) {
void Sd2Card : : chipDeselect ( ) {
digitalWrite ( chipSelectPin_ , HIGH ) ;
digitalWrite ( chipSelectPin_ , HIGH ) ;
spiSend ( 0xFF ) ; // Ensure MISO goes high impedance
// insure MISO goes high impedance
spiSend ( 0xFF ) ;
}
}
void Sd2Card : : chipSelect ( ) {
void Sd2Card : : chipSelect ( ) {
@ -195,13 +191,8 @@ bool Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) {
goto FAIL ;
goto FAIL ;
}
}
}
}
if ( type_ ! = SD_CARD_TYPE_SDHC ) {
if ( type_ ! = SD_CARD_TYPE_SDHC ) { firstBlock < < = 9 ; lastBlock < < = 9 ; }
firstBlock < < = 9 ;
if ( cardCommand ( CMD32 , firstBlock ) | | cardCommand ( CMD33 , lastBlock ) | | cardCommand ( CMD38 , 0 ) ) {
lastBlock < < = 9 ;
}
if ( cardCommand ( CMD32 , firstBlock )
| | cardCommand ( CMD33 , lastBlock )
| | cardCommand ( CMD38 , 0 ) ) {
error ( SD_CARD_ERROR_ERASE ) ;
error ( SD_CARD_ERROR_ERASE ) ;
goto FAIL ;
goto FAIL ;
}
}
@ -236,7 +227,7 @@ bool Sd2Card::eraseSingleBlockEnable() {
* \ return true for success , false for failure .
* \ return true for success , false for failure .
* The reason for failure can be determined by calling errorCode ( ) and errorData ( ) .
* The reason for failure can be determined by calling errorCode ( ) and errorData ( ) .
*/
*/
bool Sd2Card : : init ( uint8_t sckRateID , pin_t chipSelectPin ) {
bool Sd2Card : : init ( const uint8_t sckRateID /*=0*/ , const pin_t chipSelectPin /*=SD_CHIP_SELECT_PIN*/ ) {
errorCode_ = type_ = 0 ;
errorCode_ = type_ = 0 ;
chipSelectPin_ = chipSelectPin ;
chipSelectPin_ = chipSelectPin ;
// 16-bit init start time allows over a minute
// 16-bit init start time allows over a minute
@ -308,23 +299,23 @@ bool Sd2Card::init(uint8_t sckRateID, pin_t chipSelectPin) {
watchdog_reset ( ) ;
watchdog_reset ( ) ;
# endif
# endif
// i nitialize card and send host supports SDHC if SD2
// I nitialize 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 ) {
// c heck for timeout
// C heck for timeout
if ( ELAPSED ( millis ( ) , init_timeout ) ) {
if ( ELAPSED ( millis ( ) , init_timeout ) ) {
error ( SD_CARD_ERROR_ACMD41 ) ;
error ( SD_CARD_ERROR_ACMD41 ) ;
goto FAIL ;
goto FAIL ;
}
}
}
}
// i f SD2 read OCR register to check for SDHC card
// I f SD2 read OCR register to check for SDHC card
if ( type ( ) = = SD_CARD_TYPE_SD2 ) {
if ( type ( ) = = SD_CARD_TYPE_SD2 ) {
if ( cardCommand ( CMD58 , 0 ) ) {
if ( cardCommand ( CMD58 , 0 ) ) {
error ( SD_CARD_ERROR_CMD58 ) ;
error ( SD_CARD_ERROR_CMD58 ) ;
goto FAIL ;
goto FAIL ;
}
}
if ( ( spiRec ( ) & 0xC0 ) = = 0xC0 ) type ( SD_CARD_TYPE_SDHC ) ;
if ( ( spiRec ( ) & 0xC0 ) = = 0xC0 ) type ( SD_CARD_TYPE_SDHC ) ;
// d iscard rest of ocr - contains allowed voltage range
// D iscard 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 ( ) ;
}
}
chipDeselect ( ) ;
chipDeselect ( ) ;
@ -344,8 +335,7 @@ bool Sd2Card::init(uint8_t sckRateID, pin_t chipSelectPin) {
* \ return true for success , false for failure .
* \ return true for success , false for failure .
*/
*/
bool Sd2Card : : readBlock ( uint32_t blockNumber , uint8_t * dst ) {
bool Sd2Card : : readBlock ( uint32_t blockNumber , uint8_t * dst ) {
// use address if not SDHC card
if ( type ( ) ! = SD_CARD_TYPE_SDHC ) blockNumber < < = 9 ; // Use address if not SDHC card
if ( type ( ) ! = SD_CARD_TYPE_SDHC ) blockNumber < < = 9 ;
# if ENABLED(SD_CHECK_AND_RETRY)
# if ENABLED(SD_CHECK_AND_RETRY)
uint8_t retryCnt = 3 ;
uint8_t retryCnt = 3 ;
@ -447,44 +437,39 @@ bool Sd2Card::readData(uint8_t* dst) {
# endif
# 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 , const uint16_t count ) {
// wait for start block token
bool success = false ;
const millis_t read_timeout = millis ( ) + SD_READ_TIMEOUT ;
const millis_t read_timeout = millis ( ) + SD_READ_TIMEOUT ;
while ( ( status_ = spiRec ( ) ) = = 0xFF ) {
while ( ( status_ = spiRec ( ) ) = = 0xFF ) { // Wait for start block token
if ( ELAPSED ( millis ( ) , read_timeout ) ) {
if ( ELAPSED ( millis ( ) , read_timeout ) ) {
error ( SD_CARD_ERROR_READ_TIMEOUT ) ;
error ( SD_CARD_ERROR_READ_TIMEOUT ) ;
goto FAIL ;
goto FAIL ;
}
}
}
}
if ( status_ ! = DATA_START_BLOCK ) {
error ( SD_CARD_ERROR_READ ) ;
goto FAIL ;
}
// transfer data
spiRead ( dst , count ) ;
if ( status_ = = DATA_START_BLOCK ) {
spiRead ( dst , count ) ; // Transfer data
const uint16_t recvCrc = ( spiRec ( ) < < 8 ) | spiRec ( ) ;
# if ENABLED(SD_CHECK_AND_RETRY)
# if ENABLED(SD_CHECK_AND_RETRY)
{
success = ! crcSupported | | recvCrc = = CRC_CCITT ( dst , count ) ;
uint16_t recvCrc = ( spiRec ( ) < < 8 ) | spiRec ( ) ;
if ( ! success ) error ( SD_CARD_ERROR_READ_CRC ) ;
if ( crcSupported & & recvCrc ! = CRC_CCITT ( dst , count ) ) {
error ( SD_CARD_ERROR_READ_CRC ) ;
goto FAIL ;
}
}
# else
# else
// discard CRC
success = true ;
spiRec ( ) ;
UNUSED ( recvCrc ) ;
spiRec ( ) ;
# endif
# endif
chipDeselect ( ) ;
}
return true ;
else
error ( SD_CARD_ERROR_READ ) ;
FAIL :
FAIL :
chipDeselect ( ) ;
chipDeselect ( ) ;
return fal se;
return succ ess ;
}
}
/** read CID or CSR register */
/** read CID or CSR register */
bool Sd2Card : : readRegister ( uint8_t cmd , void * buf ) {
bool Sd2Card : : readRegister ( const 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 ) ;
@ -506,13 +491,11 @@ bool Sd2Card::readRegister(uint8_t cmd, void* buf) {
*/
*/
bool Sd2Card : : readStart ( uint32_t blockNumber ) {
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 ) ) {
error ( SD_CARD_ERROR_CMD18 ) ;
const bool success = ! cardCommand ( CMD18 , blockNumber ) ;
chipDeselect ( ) ;
if ( ! success ) error ( SD_CARD_ERROR_CMD18 ) ;
return false ;
}
chipDeselect ( ) ;
chipDeselect ( ) ;
return true ;
return success ;
}
}
/**
/**
@ -522,13 +505,10 @@ bool Sd2Card::readStart(uint32_t blockNumber) {
*/
*/
bool Sd2Card : : readStop ( ) {
bool Sd2Card : : readStop ( ) {
chipSelect ( ) ;
chipSelect ( ) ;
if ( cardCommand ( CMD12 , 0 ) ) {
const bool success = ! cardCommand ( CMD12 , 0 ) ;
error ( SD_CARD_ERROR_CMD12 ) ;
if ( ! success ) error ( SD_CARD_ERROR_CMD12 ) ;
chipDeselect ( ) ;
chipDeselect ( ) ;
return false ;
return success ;
}
chipDeselect ( ) ;
return true ;
}
}
/**
/**
@ -543,16 +523,20 @@ bool Sd2Card::readStop() {
* \ return The value one , true , is returned for success and the value zero ,
* \ return The value one , true , is returned for success and the value zero ,
* false , is returned for an invalid value of \ a sckRateID .
* false , is returned for an invalid value of \ a sckRateID .
*/
*/
bool Sd2Card : : setSckRate ( uint8_t sckRateID ) {
bool Sd2Card : : setSckRate ( const uint8_t sckRateID ) {
if ( sckRateID > 6 ) {
const bool success = ( sckRateID < = 6 ) ;
error ( SD_CARD_ERROR_SCK_RATE ) ;
if ( success )
return false ;
}
spiRate_ = sckRateID ;
spiRate_ = sckRateID ;
return true ;
else
error ( SD_CARD_ERROR_SCK_RATE ) ;
return success ;
}
}
// wait for card to go not busy
/**
* Wait for card to become not - busy
* \ param [ in ] timeout_ms Timeout to abort .
* \ return true for success , false for timeout .
*/
bool Sd2Card : : waitNotBusy ( const millis_t timeout_ms ) {
bool Sd2Card : : waitNotBusy ( const millis_t timeout_ms ) {
const millis_t wait_timeout = millis ( ) + timeout_ms ;
const millis_t wait_timeout = millis ( ) + timeout_ms ;
while ( spiRec ( ) ! = 0xFF )
while ( spiRec ( ) ! = 0xFF )
@ -562,36 +546,31 @@ bool Sd2Card::waitNotBusy(const millis_t timeout_ms) {
}
}
/**
/**
* Writes a 512 byte block to an SD card .
* Write a 512 byte block to an SD card .
*
*
* \ param [ in ] blockNumber Logical block to be written .
* \ param [ in ] blockNumber Logical block to be written .
* \ param [ in ] src Pointer to the location of the data to be written .
* \ param [ in ] src Pointer to the location of the data to be written .
* \ return true for success , false for failure .
* \ return true for success , false for failure .
*/
*/
bool Sd2Card : : writeBlock ( uint32_t blockNumber , const uint8_t * src ) {
bool Sd2Card : : writeBlock ( uint32_t blockNumber , const uint8_t * src ) {
// use address if not SDHC card
if ( type ( ) ! = SD_CARD_TYPE_SDHC ) blockNumber < < = 9 ; // Use address if not SDHC card
if ( type ( ) ! = SD_CARD_TYPE_SDHC ) blockNumber < < = 9 ;
if ( cardCommand ( CMD24 , blockNumber ) ) {
error ( SD_CARD_ERROR_CMD24 ) ;
goto FAIL ;
}
if ( ! writeData ( DATA_START_BLOCK , src ) ) goto FAIL ;
// wait for flash programming to complete
bool success = false ;
if ( ! waitNotBusy ( SD_WRITE_TIMEOUT ) ) {
if ( ! cardCommand ( CMD24 , blockNumber ) ) {
if ( writeData ( DATA_START_BLOCK , src ) ) {
if ( waitNotBusy ( SD_WRITE_TIMEOUT ) ) { // Wait for flashing to complete
success = ! ( cardCommand ( CMD13 , 0 ) | | spiRec ( ) ) ; // Response is r2 so get and check two bytes for nonzero
if ( ! success ) error ( SD_CARD_ERROR_WRITE_PROGRAMMING ) ;
}
else
error ( SD_CARD_ERROR_WRITE_TIMEOUT ) ;
error ( SD_CARD_ERROR_WRITE_TIMEOUT ) ;
goto FAIL ;
}
}
// response is r2 so get and check two bytes for nonzero
if ( cardCommand ( CMD13 , 0 ) | | spiRec ( ) ) {
error ( SD_CARD_ERROR_WRITE_PROGRAMMING ) ;
goto FAIL ;
}
}
else
error ( SD_CARD_ERROR_CMD24 ) ;
chipDeselect ( ) ;
chipDeselect ( ) ;
return true ;
return success ;
FAIL :
chipDeselect ( ) ;
return false ;
}
}
/**
/**
@ -600,28 +579,30 @@ 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 ) {
bool success = true ;
chipSelect ( ) ;
chipSelect ( ) ;
// w ait for previous write to finish
// W ait 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 ) ;
chipDeselect ( ) ;
success = false ;
return false ;
}
}
chipDeselect ( ) ;
chipDeselect ( ) ;
return true ;
return success ;
}
}
// s end one block of data for write block or write multiple blocks
// S end one block of data for write block or write multiple blocks
bool Sd2Card : : writeData ( uint8_t token , const uint8_t * src ) {
bool Sd2Card : : writeData ( const uint8_t token , const uint8_t * src ) {
uint16_t crc =
# if ENABLED(SD_CHECK_AND_RETRY)
# if ENABLED(SD_CHECK_AND_RETRY)
uint16_t crc = CRC_CCITT ( src , 512 ) ;
CRC_CCITT ( src , 512 )
# else // ENABLED(SD_CHECK_AND_RETRY)
# else
uint16_t crc = 0xFFFF ;
0xFFFF
# endif // ENABLED(SD_CHECK_AND_RETRY)
# endif
;
spiSendBlock ( token , src ) ;
spiSendBlock ( token , src ) ;
spiSend ( crc > > 8 ) ;
spiSend ( crc > > 8 ) ;
spiSend ( crc & 0XFF ) ;
spiSend ( crc & 0xFF ) ;
status_ = spiRec ( ) ;
status_ = spiRec ( ) ;
if ( ( status_ & DATA_RES_MASK ) ! = DATA_RES_ACCEPTED ) {
if ( ( status_ & DATA_RES_MASK ) ! = DATA_RES_ACCEPTED ) {
@ -643,23 +624,18 @@ bool Sd2Card::writeData(uint8_t token, const uint8_t* src) {
*
*
* \ return true for success , false for failure .
* \ return true for success , false for failure .
*/
*/
bool Sd2Card : : writeStart ( uint32_t blockNumber , uint32_t eraseCount ) {
bool Sd2Card : : writeStart ( uint32_t blockNumber , const uint32_t eraseCount ) {
// send pre-erase count
bool success = false ;
if ( cardAcmd ( ACMD23 , eraseCount ) ) {
if ( ! cardAcmd ( ACMD23 , eraseCount ) ) { // Send pre-erase count
error ( SD_CARD_ERROR_ACMD23 ) ;
if ( type ( ) ! = SD_CARD_TYPE_SDHC ) blockNumber < < = 9 ; // Use address if not SDHC card
goto FAIL ;
success = ! cardCommand ( CMD25 , blockNumber ) ;
if ( ! success ) error ( SD_CARD_ERROR_CMD25 ) ;
}
}
// use address if not SDHC card
else
if ( type ( ) ! = SD_CARD_TYPE_SDHC ) blockNumber < < = 9 ;
error ( SD_CARD_ERROR_ACMD23 ) ;
if ( cardCommand ( CMD25 , blockNumber ) ) {
error ( SD_CARD_ERROR_CMD25 ) ;
goto FAIL ;
}
chipDeselect ( ) ;
return true ;
FAIL :
chipDeselect ( ) ;
chipDeselect ( ) ;
return fal se;
return success ;
}
}
/**
/**
@ -668,16 +644,17 @@ 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 ( ) {
bool success = false ;
chipSelect ( ) ;
chipSelect ( ) ;
if ( ! waitNotBusy ( SD_WRITE_TIMEOUT ) ) goto FAIL ;
if ( waitNotBusy ( SD_WRITE_TIMEOUT ) ) {
spiSend ( STOP_TRAN_TOKEN ) ;
spiSend ( STOP_TRAN_TOKEN ) ;
if ( ! waitNotBusy ( SD_WRITE_TIMEOUT ) ) goto FAIL ;
success = waitNotBusy ( SD_WRITE_TIMEOUT ) ;
chipDeselect ( ) ;
}
return true ;
else
FAIL :
error ( SD_CARD_ERROR_STOP_TRAN ) ;
error ( SD_CARD_ERROR_STOP_TRAN ) ;
chipDeselect ( ) ;
chipDeselect ( ) ;
return fal se;
return succ ess ;
}
}
# endif // SDSUPPORT
# endif // SDSUPPORT