/** * Initialize a SD flash memory card. * * \param[in] slow Set SPI Frequency F_CPU/4 if true else F_CPU/2. * * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. * */ uint8_t SdCard::init(uint8_t slow) { pinMode(SS, OUTPUT); spiSSHigh(); pinMode(MOSI, OUTPUT); pinMode(SCK, OUTPUT); //Enable SPI, Master, clock rate F_CPU/128 SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); //must supply min of 74 clock cycles with CS high. for (uint8_t i = 0; i < 10; i++) spiSend(0XFF); spiSSLow(); // next line prevent re-init hang by some cards (not sure why this works) for (uint16_t i = 0; i <= 512; i++) spiRec(); uint8_t r = cardCommand(CMD0, 0); for (uint16_t retry = 0; r != R1_IDLE_STATE; retry++){ if (retry == 10000) { error(SD_ERROR_CMD0, r); return false; } r = spiRec(); } for (uint16_t retry = 0; ; retry++) { cardCommand(CMD55, 0); if ((r = cardCommand(ACMD41, 0)) == R1_READY_STATE)break; if (retry == 1000) { error(SD_ERROR_ACMD41, r); return false; } } // set SPI frequency SPCR &= ~((1 << SPR1) | (1 << SPR0)); // F_CPU/4 if (!slow) SPSR |= (1 << SPI2X); // Doubled Clock Frequency to F_CPU/2 spiSSHigh(); return true; }
/** * Writes a 512 byte block to a SD card. * * \param[in] blockNumber Logical block to be written. * \param[in] src Pointer to the location of the data to be written. * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. */ uint8_t Sd2Card::writeBlock(uint32_t blockNumber, uint8_t *src) { #if SD_PROTECT_BLOCK_ZERO //don't allow write to first block if (blockNumber == 0) { error(SD_CARD_ERROR_WRITE_BLOCK_ZERO); return false; } #endif //SD_PROTECT_BLOCK_ZERO //use address if not SDHC card if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; if (cardCommand(CMD24, blockNumber)) { error(SD_CARD_ERROR_CMD24); return false; } if(!writeData(DATA_START_BLOCK, src)) return false; // wait for flash programming to complete if (!waitWriteDone()) return false; // response is r2 so get and check byte two for nonzero if (cardCommand(CMD13, 0) || spiRec()) { error(SD_CARD_ERROR_WRITE_PROGRAMMING); return false; } spiSSHigh(); return true; }
uint8_t SdCard::readReg(uint8_t cmd, uint8_t *dst) { if (cardCommand(cmd, 0)) { spiSSHigh(); return false; } return readTransfer(dst, 16); }
/** End a write multiple blocks sequence. * * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. */ uint8_t Sd2Card::writeStop(void) { if (!waitWriteDone()) return false; spiSend(STOP_TRAN_TOKEN); if (!waitWriteDone()) return false; spiSSHigh(); return true; }
/** Skip remaining data in a block when in partial block read mode. */ void SdReader::readEnd(void) { if (inBlock_) { // skip data and crc SPDR = 0XFF; while (offset_++ < 513) { while(!(SPSR & (1 << SPIF))); SPDR = 0XFF; } // wait for last crc byte while(!(SPSR & (1 << SPIF))); spiSSHigh(); inBlock_ = 0; } }
/** read CID or CSR register */ uint8_t Sd2Card::readRegister(uint8_t cmd, uint8_t *dst) { if (cardCommand(cmd, 0)) { error(SD_CARD_ERROR_READ_REG); return false; } if(!waitStartBlock()) return false; //transfer data for (uint16_t i = 0; i < 16; i++) dst[i] = spiRec(); spiRec();// get first crc byte spiRec();// get second crc byte spiSSHigh(); return true; }
/** read CID or CSR register */ uint8_t sdReadRegister(uint8_t cmd, uint8_t *dst) { uint16_t i; if (sdCardCommand(cmd, 0)) { error1(SD_CARD_ERROR_READ_REG); return 0; } if(!sdWaitStartBlock()) return 0; //transfer data for (i = 0; i < 16; i++) dst[i] = spiRec(); spiRec();// get first crc byte spiRec();// get second crc byte spiSSHigh(); return 1; }
//------------------------------------------------------------------------------ uint8_t SdCard::readTransfer(uint8_t *dst, uint16_t count) { //wait for start of data for (uint16_t retry = 0; spiRec() != DATA_START_BLOCK; retry++) { if (retry == 0XFFFF) { error(SD_ERROR_READ_TIMEOUT); return false; } } //start first spi transfer SPDR = 0XFF; for (uint16_t i = 0; i < count; i++) { while(!(SPSR & (1 << SPIF))); dst[i] = SPDR; SPDR = 0XFF; } // wait for first CRC byte while(!(SPSR & (1 << SPIF))); spiRec();//second CRC byte spiSSHigh(); return true; }
/** * Writes a 512 byte block to a storage device. * * \param[in] blockNumber Logical block to be written. * \param[in] src Pointer to the location of the data to be written. * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. */ uint8_t SdCard::writeBlock(uint32_t blockNumber, uint8_t *src) { uint32_t address = blockNumber << 9; #if SD_PROTECT_BLOCK_ZERO //don't allow write to first block if (address == 0) { error(SD_ERROR_BLOCK_ZERO_WRITE); return false; } #endif //SD_PROTECT_BLOCK_ZERO if (cardCommand(CMD24, address)) { error(SD_ERROR_CMD24); return false; } // optimize write loop SPDR = DATA_START_BLOCK; for (uint16_t i = 0; i < 512; i++) { while(!(SPSR & (1 << SPIF))); SPDR = src[i]; } while(!(SPSR & (1 << SPIF)));// wait for last data byte spiSend(0xFF);// dummy crc spiSend(0xFF);// dummy crc uint8_t r1 = spiRec(); if ((r1 & DATA_RES_MASK) != DATA_RES_ACCEPTED) { error(SD_ERROR_WRITE_RESPONSE, r1); return false; } // wait for card to complete write programming for (uint16_t retry = 0; spiRec() != 0XFF ; retry++) { if (retry == 0XFFFF) { error(SD_ERROR_WRITE_TIMEOUT); return false; } } spiSSHigh(); return true; }
/** Skip remaining data in a block when in partial block read mode. */ void Sd2Card::readEnd(void) { if (inBlock_) { // skip data and crc #ifdef OPTIMIZE_HARDWARE_SPI // optimize skip for hardware SPDR = 0XFF; while (offset_++ < 513) { while(!(SPSR & (1 << SPIF))); SPDR = 0XFF; } // wait for last crc byte while(!(SPSR & (1 << SPIF))); #else // OPTIMIZE_HARDWARE_SPI while (offset_++ < 514) spiRec(); #endif // OPTIMIZE_HARDWARE_SPI spiSSHigh(); inBlock_ = 0; } }
/** * Initialize a SD flash memory card. * * \param[in] slow If \a slow is false (zero) the SPI bus will * be initialize at a speed of 8 Mhz. If \a slow is true (nonzero) * the SPI bus will be initialize a speed of 4 Mhz. This may be helpful * for some SD cards with Version 1.0 of the Adafruit Wave Shield. * * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. * */ uint8_t SdReader::init(uint8_t slow) { uint8_t ocr[4]; uint8_t r; pinMode(SS, OUTPUT); digitalWrite(SS, HIGH); pinMode(MOSI, OUTPUT); pinMode(MISO_PIN, INPUT); pinMode(SCK, OUTPUT); #if SPI_INIT_SLOW // Enable SPI, Master, clock rate f_osc/128 SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); #else // SPI_INIT_SLOW // Enable SPI, Master, clock rate f_osc/64 SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1); #endif // SPI_INIT_SLOW // must supply min of 74 clock cycles with CS high. for (uint8_t i = 0; i < 10; i++) spiSend(0XFF); // next two lines prevent re-init hang by cards that were in partial read spiSSLow(); for (uint16_t i = 0; i <= 512; i++) spiRec(); // command to go idle in SPI mode for (uint8_t retry = 0; ; retry++) { if ((r = cardCommand(CMD0, 0)) == R1_IDLE_STATE) break; if (retry == 10) { error(SD_CARD_ERROR_CMD0, r); return false; } } // check SD version r = cardCommand(CMD8, 0x1AA); if (r == R1_IDLE_STATE) { for(uint8_t i = 0; i < 4; i++) { r = spiRec(); } if (r != 0XAA) { error(SD_CARD_ERROR_CMD8_ECHO, r); return false; } type(SD_CARD_TYPE_SD2); } else if (r & R1_ILLEGAL_COMMAND) { type(SD_CARD_TYPE_SD1); } else { error(SD_CARD_ERROR_CMD8, r); } // initialize card and send host supports SDHC if SD2 for (uint16_t t0 = millis();;) { cardCommand(CMD55, 0); r = cardCommand(ACMD41, type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0); if (r == R1_READY_STATE) break; // timeout after 2 seconds if (((uint16_t)millis() - t0) > 2000) { error(SD_CARD_ERROR_ACMD41); return false; } } // if SD2 read OCR register to check for SDHC card if (type() == SD_CARD_TYPE_SD2) { if(cardCommand(CMD58, 0)) { error(SD_CARD_ERROR_CMD58); return false; } if ((spiRec() & 0XC0) == 0XC0) type(SD_CARD_TYPE_SDHC); // discard rest of ocr for (uint8_t i = 0; i < 3; i++) spiRec(); } // use max SPI frequency unless slow is true SPCR &= ~((1 << SPR1) | (1 << SPR0)); // f_OSC/4 if (!slow) SPSR |= (1 << SPI2X); // Doubled Clock Frequency: f_OSC/2 spiSSHigh(); return true; }
//------------------------------------------------------------------------------ void SdCard::error(uint8_t code) { errorCode = code; spiSSHigh(); }
/** * Initialize a SD flash memory card. * * \param[in] slow Set SPI Frequency F_CPU/4 if true else F_CPU/2. * * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. */ uint8_t Sd2Card::init(uint8_t slow) { uint8_t r; errorCode_ = inBlock_ = partialBlockRead_ = type_ = 0; // set pin modes spiSSOutputMode(); spiSSHigh(); spiMISOInputMode(); spiMOSIOutputMode(); spiSCKOutputMode(); #ifndef SOFTWARE_SPI //Enable SPI, Master, clock rate f_osc/128 SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); #endif //SOFTWARE_SPI //must supply min of 74 clock cycles with CS high. for (uint8_t i = 0; i < 10; i++) spiSend(0XFF); // next two lines prevent re-init hang by cards that were in partial read spiSSLow(); for (uint16_t i = 0; i <= 512; i++) spiRec(); // command to go idle in SPI mode for (uint8_t retry = 0; ; retry++) { if ((r = cardCommand(CMD0, 0)) == R1_IDLE_STATE) break; if (retry == 10) { error(SD_CARD_ERROR_CMD0, r); return false; } } // check SD version if ((cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND)) { type(SD_CARD_TYPE_SD1); } else { // only need last byte of r7 response for(uint8_t i = 0; i < 4; i++) r = spiRec(); if (r != 0XAA) { error(SD_CARD_ERROR_CMD8, r); return false; } type(SD_CARD_TYPE_SD2); } // initialize card and send host supports SDHC if SD2 for (uint16_t t0 = millis();;) { r = cardAcmd(ACMD41, type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0); if (r == R1_READY_STATE) break; // timeout after 2 seconds if (((uint16_t)millis() - t0) > 2000) { error(SD_CARD_ERROR_ACMD41); return false; } } // if SD2 read OCR register to check for SDHC card if (type() == SD_CARD_TYPE_SD2) { if(cardCommand(CMD58, 0)) { error(SD_CARD_ERROR_CMD58); return false; } if ((spiRec() & 0XC0) == 0XC0) type(SD_CARD_TYPE_SDHC); // discard rest of ocr for (uint8_t i = 0; i < 3; i++) spiRec(); } #ifndef SOFTWARE_SPI // set SPI frequency to f_OSC/4 SPCR &= ~((1 << SPR1) | (1 << SPR0)); // if !slow set SPI frequency to f_OSC/2 if (!slow) SPSR |= (1 << SPI2X); #endif // SOFTWARE_SPI spiSSHigh(); return true; }