/** Start a write multiple blocks sequence. * * \param[in] blockNumber Address of first block in sequence. * \param[in] eraseCount The number of blocks to be pre-erased. * * \note This function is used with writeData() and writeStop() * for optimized multiple block writes. * * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. */ uint8_t Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) { #if SD_PROTECT_BLOCK_ZERO // don't allow write to first block if (blockNumber == 0) { error(SD_CARD_ERROR_WRITE_BLOCK_ZERO); goto fail; } #endif // SD_PROTECT_BLOCK_ZERO // send pre-erase count if (cardAcmd(ACMD23, eraseCount)) { error(SD_CARD_ERROR_ACMD23); goto fail; } // use address if not SDHC card if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; if (cardCommand(CMD25, blockNumber)) { error(SD_CARD_ERROR_CMD25); goto fail; } return true; fail: chipSelectHigh(); return false; }
//------------------------------------------------------------------------------ // send one block of data for write block or write multiple blocks uint8_t Sd2Card::writeData(uint8_t token, const uint8_t* src) { #ifdef OPTIMIZE_HARDWARE_SPI // send data - optimized loop SPDR = token; // send two byte per iteration for (uint16_t i = 0; i < 512; i += 2) { while (!(SPSR & (1 << SPIF))); SPDR = src[i]; while (!(SPSR & (1 << SPIF))); SPDR = src[i+1]; } // wait for last data byte while (!(SPSR & (1 << SPIF))); #else // OPTIMIZE_HARDWARE_SPI spiSend(token); for (uint16_t i = 0; i < 512; i++) { spiSend(src[i]); } #endif // OPTIMIZE_HARDWARE_SPI spiSend(0xff); // dummy crc spiSend(0xff); // dummy crc status_ = spiRec(); if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) { error(SD_CARD_ERROR_WRITE); chipSelectHigh(); return false; } return true; }
/** * Writes a 512 byte block to an 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, const 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); SerialDebug.println("Error: Write block zero"); goto fail; } #endif // SD_PROTECT_BLOCK_ZERO // use address if not SDHC card if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; if (cardCommand(CMD24, blockNumber)) { SerialDebug.println("Error: CMD24"); error(SD_CARD_ERROR_CMD24); goto fail; } if (!writeData(DATA_START_BLOCK, src)) goto fail; // wait for flash programming to complete if (!waitNotBusy(SD_WRITE_TIMEOUT)) { error(SD_CARD_ERROR_WRITE_TIMEOUT); SerialDebug.println("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); SerialDebug.println("Error: Write programming"); goto fail; } chipSelectHigh(); return true; fail: chipSelectHigh(); SerialDebug.println("Error: Sd2Card::writeBlock"); return false; }
/** Skip remaining data in a block when in partial block read mode. */ void Sd2Card::readEnd(void) { if (inBlock_) { // skip data and crc while (offset_++ < 514) spiRec(); chipSelectHigh(); inBlock_ = 0; } }
/** read CID or CSR register */ uint8_t Sd2Card::readRegister(uint8_t cmd, void* buf) { uint8_t* dst = reinterpret_cast<uint8_t*>(buf); if (cardCommand(cmd, 0)) { error(SD_CARD_ERROR_READ_REG); goto fail; } if (!waitStartBlock()) goto fail; // transfer data for (uint16_t i = 0; i < 16; i++) dst[i] = spiRec(); spiRec(); // get first crc byte spiRec(); // get second crc byte chipSelectHigh(); return true; fail: chipSelectHigh(); return false; }
/** Write one data block in a multiple block write sequence */ uint8_t Sd2Card::writeData(const uint8_t* src) { // wait for previous write to finish if (!waitNotBusy(SD_WRITE_TIMEOUT)) { error(SD_CARD_ERROR_WRITE_MULTIPLE); chipSelectHigh(); return false; } return writeData(WRITE_MULTIPLE_TOKEN, src); }
/** Start a write multiple blocks sequence. * * \param[in] blockNumber Address of first block in sequence. * \param[in] eraseCount The number of blocks to be pre-erased. * * \note This function is used with writeData() and writeStop() * for optimized multiple block writes. * * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. */ bool Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) { // send pre-erase count if (cardAcmd(ACMD23, eraseCount)) { error(SD_CARD_ERROR_ACMD23); goto fail; } // use address if not SDHC card if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; if (cardCommand(CMD25, blockNumber)) { error(SD_CARD_ERROR_CMD25); goto fail; } chipSelectHigh(); return true; fail: chipSelectHigh(); return false; }
//------------------------------------------------------------------------------ bool Sd2Card::readData(uint8_t* dst, uint16_t count) { // wait for start block token uint16_t t0 = millis(); while ((status_ = spiRec()) == 0XFF) { if (((uint16_t)millis() - t0) > SD_READ_TIMEOUT) { error(SD_CARD_ERROR_READ_TIMEOUT); goto fail; } } if (status_ != DATA_START_BLOCK) { error(SD_CARD_ERROR_READ); goto fail; } // transfer data spiRead(dst, count); #ifdef SD_CHECK_AND_RETRY { uint16_t calcCrc = CRC_CCITT(dst, count); uint16_t recvCrc = spiRec() << 8; recvCrc |= spiRec(); if (calcCrc != recvCrc) { error(SD_CARD_ERROR_CRC); goto fail; } } #else // discard CRC spiRec(); spiRec(); #endif chipSelectHigh(); // Send an additional dummy byte, required by Toshiba Flash Air SD Card spiSend(0XFF); return true; fail: chipSelectHigh(); // Send an additional dummy byte, required by Toshiba Flash Air SD Card spiSend(0XFF); return false; }
/** 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 (!waitNotBusy(SD_WRITE_TIMEOUT)) { goto fail; } spiSend(STOP_TRAN_TOKEN); if (!waitNotBusy(SD_WRITE_TIMEOUT)) { goto fail; } chipSelectHigh(); return true; fail: error(SD_CARD_ERROR_STOP_TRAN); chipSelectHigh(); return false; }
/** read CID or CSR register */ bool Sd2Card::readRegister(uint8_t cmd, void* buf) { uint8_t* dst = reinterpret_cast<uint8_t*>(buf); if (cardCommand(cmd, 0)) { error(SD_CARD_ERROR_READ_REG); goto fail; } return readData(dst, 16); fail: chipSelectHigh(); return false; }
/** * Read a 512 byte block from an SD card device. * * \param[in] block Logical block to be read. * \param[out] dst Pointer to the location that will receive the data. * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. */ int Sd2Card::readBlock(uint32_t block, uint8_t* dst) { //return readData(block, 0, 512, dst); unsigned int *idst; int i; if (!inBlock_ || block != block_) { block_ = block; // use address if not SDHC card if (type()!= SD_CARD_TYPE_SDHC) block <<= 9; if (cardCommand(CMD17, block)) { error(SD_CARD_ERROR_CMD17); goto fail; } if (!waitStartBlock()) { goto fail; } offset_ = 0; inBlock_ = 1; } /* Do fast readout */ idst = (unsigned int*)dst; for (i=128;i!=0;i--) { *idst++=spiRec32(wishboneSlot_); // USPIDATA=0xff; // USPIDATA=0xff; // USPIDATA=0xff; // USPIDATA=0xff; //*idst++=USPIDATA; } chipSelectHigh(); inBlock_ = 0; return true; fail: chipSelectHigh(); return false; }
/** * Read a 512 byte block from an SD card. * * \param[in] blockNumber Logical block to be read. * \param[out] dst Pointer to the location that will receive the data. * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. */ bool Sd2Card::readBlock(uint32_t blockNumber, uint8_t* dst) { #if ENABLED(SD_CHECK_AND_RETRY) uint8_t retryCnt = 3; // use address if not SDHC card if (type()!= SD_CARD_TYPE_SDHC) blockNumber <<= 9; retry2: retryCnt --; if (cardCommand(CMD17, blockNumber)) { error(SD_CARD_ERROR_CMD17); if (retryCnt > 0) goto retry; goto fail; } if (!readData(dst, 512)) { if (retryCnt > 0) goto retry; goto fail; } return true; retry: chipSelectHigh(); cardCommand(CMD12, 0);//Try sending a stop command, but ignore the result. errorCode_ = 0; goto retry2; #else // use address if not SDHC card if (type()!= SD_CARD_TYPE_SDHC) blockNumber <<= 9; if (cardCommand(CMD17, blockNumber)) { error(SD_CARD_ERROR_CMD17); goto fail; } return readData(dst, 512); #endif fail: chipSelectHigh(); return false; }
/** Erase a range of blocks. * * \param[in] firstBlock The address of the first block in the range. * \param[in] lastBlock The address of the last block in the range. * * \note This function requests the SD card to do a flash erase for a * range of blocks. The data on the card after an erase operation is * either 0 or 1, depends on the card vendor. The card must support * single block erase. * * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. */ uint8_t Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) { if (!eraseSingleBlockEnable()) { error(SD_CARD_ERROR_ERASE_SINGLE_BLOCK); goto fail; } if (type_ != SD_CARD_TYPE_SDHC) { firstBlock <<= 9; lastBlock <<= 9; } if (cardCommand(CMD32, firstBlock) || cardCommand(CMD33, lastBlock) || cardCommand(CMD38, 0)) { error(SD_CARD_ERROR_ERASE); goto fail; } if (!waitNotBusy(SD_ERASE_TIMEOUT)) { error(SD_CARD_ERROR_ERASE_TIMEOUT); goto fail; } chipSelectHigh(); return true; fail: chipSelectHigh(); return false; }
//------------------------------------------------------------------------------ // send one block of data for write block or write multiple blocks uint8_t Sd2Card::writeData(uint8_t token, const uint8_t* src) { spiSend(token); for (uint16_t i = 0; i < 512; i++) { spiSend(src[i]); } spiSend(0xff); // dummy crc spiSend(0xff); // dummy crc status_ = spiRec(); if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) { error(SD_CARD_ERROR_WRITE); chipSelectHigh(); return false; } return true; }
/** * Read part of a 512 byte block from an SD card. * * \param[in] block Logical block to be read. * \param[in] offset Number of bytes to skip at start of block * \param[out] dst Pointer to the location that will receive the data. * \param[in] count Number of bytes to read * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. */ uint8_t Sd2Card::readData(uint32_t block, uint16_t offset, uint16_t count, uint8_t* dst) { uint16_t n; if (count == 0) return true; if ((count + offset) > 512) { goto fail; } if (!inBlock_ || block != block_ || offset < offset_) { block_ = block; // use address if not SDHC card if (type()!= SD_CARD_TYPE_SDHC) block <<= 9; if (cardCommand(CMD17, block)) { error(SD_CARD_ERROR_CMD17); goto fail; } if (!waitStartBlock()) { goto fail; } offset_ = 0; inBlock_ = 1; } // skip data before offset for (;offset_ < offset; offset_++) { spiRec(); } n = count; // transfer data for (uint16_t i = 0; i < n; i++) { dst[i] = spiRec(); } offset_ += count; if (!partialBlockRead_ || offset_ >= 512) { // read rest of data, checksum and set chip select high readEnd(); } return true; fail: chipSelectHigh(); return false; }
//------------------------------------------------------------------------------ // send one block of data for write block or write multiple blocks bool Sd2Card::writeData(uint8_t token, const uint8_t* src) { spiSendBlock(token, src); spiSend(0xff); // dummy crc spiSend(0xff); // dummy crc status_ = spiRec(); if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) { error(SD_CARD_ERROR_WRITE); goto fail; } return true; fail: chipSelectHigh(); return false; }
/** Wait for start block token */ uint8_t Sd2Card::waitStartBlock(void) { uint16_t t0 = millis(); while ((status_ = spiRec()) == 0XFF) { if (((uint16_t) millis() - t0) > SD_READ_TIMEOUT) { error(SD_CARD_ERROR_READ_TIMEOUT); goto fail; } } if (status_ != DATA_START_BLOCK) { error(SD_CARD_ERROR_READ); goto fail; } return true; fail: chipSelectHigh(); return false; }
/** 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 chipSelectHigh(); inBlock_ = 0; } }
/** Wait for start block token */ int Sd2Card::waitStartBlock(void) { //unsigned t0 = millis(); unsigned count = 30000; while ((status_ = spiRec()) == 0XFF) { if (count-- == 0) { error(SD_CARD_ERROR_READ_TIMEOUT); goto fail; } } if (status_ != DATA_START_BLOCK) { error(SD_CARD_ERROR_READ); goto fail; } return true; fail: chipSelectHigh(); return false; }
/** Skip remaining data in a block when in partial block read mode. */ void Sd2Card::readEnd(void) { if (inBlock_) { // skip data and crc #ifdef SPI_DMA dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_8BITS, ack, DMA_SIZE_8BITS, (/*DMA_MINC_MODE | DMA_CIRC_MODE |*/ DMA_FROM_MEM | DMA_TRNS_CMPLT | DMA_TRNS_ERR)); dma_attach_interrupt(DMA1, DMA_CH3, DMAEvent); dma_set_priority(DMA1, DMA_CH3, DMA_PRIORITY_VERY_HIGH); dma_set_num_transfers(DMA1, DMA_CH3, SPI_BUFF_SIZE + 1 - offset_); dmaActive = true; dma_enable(DMA1, DMA_CH3); while(dmaActive)delayMicroseconds(1); dma_disable(DMA1, DMA_CH3); #else // SPI_DMA while (offset_++ < 514) spiRec(); #endif // SPI_DMA chipSelectHigh(); inBlock_ = 0; } }
/** Skip remaining data in a block when in partial block read mode. */ void Sd2Card::readEnd(void) { if (inBlock_) { // skip data and crc #if defined(USE_TEENSY3_SPI) if (offset_ < 514) { spiRecIgnore(514 - offset_); offset_ = 514; } #elif defined(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 chipSelectHigh(); inBlock_ = 0; } }
/** Read part of a 512 byte block from an SD card. \param[in] block Logical block to be read. \param[in] offset Number of bytes to skip at start of block \param[out] dst Pointer to the location that will receive the data. \param[in] count Number of bytes to read \return The value one, true, is returned for success and the value zero, false, is returned for failure. */ uint8_t Sd2Card::readData(uint32_t block, uint16_t offset, uint16_t count, uint8_t* dst) { // uint16_t n; if (count == 0) { return true; } if ((count + offset) > 512) { goto fail; } if (!inBlock_ || block != block_ || offset < offset_) { block_ = block; // use address if not SDHC card if (type() != SD_CARD_TYPE_SDHC) { block <<= 9; } if (cardCommand(CMD17, block)) { error(SD_CARD_ERROR_CMD17); goto fail; } if (!waitStartBlock()) { goto fail; } offset_ = 0; inBlock_ = 1; } #ifdef OPTIMIZE_HARDWARE_SPI // start first spi transfer SPDR = 0XFF; // skip data before offset for (; offset_ < offset; offset_++) { while (!(SPSR & (1 << SPIF))); SPDR = 0XFF; } // transfer data n = count - 1; for (uint16_t i = 0; i < n; i++) { while (!(SPSR & (1 << SPIF))); dst[i] = SPDR; SPDR = 0XFF; } // wait for last byte while (!(SPSR & (1 << SPIF))); dst[n] = SPDR; #else // OPTIMIZE_HARDWARE_SPI // skip data before offset for (; offset_ < offset; offset_++) { spiRec(); } // transfer data for (uint16_t i = 0; i < count; i++) { dst[i] = spiRec(); } #endif // OPTIMIZE_HARDWARE_SPI offset_ += count; if (!partialBlockRead_ || offset_ >= 512) { // read rest of data, checksum and set chip select high readEnd(); } return true; fail: chipSelectHigh(); return false; }
void Sd2Card::deselect(void) { chipSelectHigh(); }
/** * Read part of a 512 byte block from an SD card. * * \param[in] block Logical block to be read. * \param[in] offset Number of bytes to skip at start of block * \param[out] dst Pointer to the location that will receive the data. * \param[in] count Number of bytes to read * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. */ uint8_t Sd2Card::readData(uint32_t block, uint16_t offset, uint16_t count, uint8_t* dst) { //uint16_t n; if (count == 0) return true; if ((count + offset) > 512) { goto fail; } if (!inBlock_ || block != block_ || offset < offset_) { block_ = block; // use address if not SDHC card if (type()!= SD_CARD_TYPE_SDHC) block <<= 9; if (cardCommand(CMD17, block)) { error(SD_CARD_ERROR_CMD17); Serial.println("Error: CMD17"); goto fail; } if (!waitStartBlock()) { goto fail; } offset_ = 0; inBlock_ = 1; } #ifdef SPI_DMA // skip data before offset if(offset_ < offset){ dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_8BITS, ack, DMA_SIZE_8BITS, (/*DMA_MINC_MODE | DMA_CIRC_MODE |*/ DMA_FROM_MEM | DMA_TRNS_CMPLT | DMA_TRNS_ERR)); dma_attach_interrupt(DMA1, DMA_CH3, DMAEvent); dma_set_priority(DMA1, DMA_CH3, DMA_PRIORITY_VERY_HIGH); dma_set_num_transfers(DMA1, DMA_CH3, offset - offset_); dmaActive = true; dma_enable(DMA1, DMA_CH3); while(dmaActive) delayMicroseconds(1); dma_disable(DMA1, DMA_CH3); } offset_ = offset; // transfer data dma_setup_transfer(DMA1, DMA_CH2, &SPI1->regs->DR, DMA_SIZE_8BITS, dst, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_TRNS_CMPLT | DMA_TRNS_ERR)); dma_attach_interrupt(DMA1, DMA_CH2, DMAEvent); dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_8BITS, ack, DMA_SIZE_8BITS, (/*DMA_MINC_MODE | DMA_CIRC_MODE |*/ DMA_FROM_MEM)); dma_set_priority(DMA1, DMA_CH2, DMA_PRIORITY_VERY_HIGH); dma_set_priority(DMA1, DMA_CH3, DMA_PRIORITY_VERY_HIGH); dma_set_num_transfers(DMA1, DMA_CH2, count); dma_set_num_transfers(DMA1, DMA_CH3, count); dmaActive = true; dma_enable(DMA1, DMA_CH3); dma_enable(DMA1, DMA_CH2); while(dmaActive) delayMicroseconds(1); dma_disable(DMA1, DMA_CH3); dma_disable(DMA1, DMA_CH2); offset_ += count; if (!partialBlockRead_ || offset_ >= SPI_BUFF_SIZE) { readEnd(); } #else // skip data before offset for (;offset_ < offset; offset_++) { spiRec(); } // transfer data for (uint16_t i = 0; i < count; i++) { dst[i] = spiRec(); } offset_ += count; if (!partialBlockRead_ || offset_ >= 512) { // read rest of data, checksum and set chip select high readEnd(); } #endif return true; fail: chipSelectHigh(); Serial.println("Error: Sd2Card::readData()"); return false; }
/** Initialize an SD flash memory card. \param[in] sckRateID SPI clock rate selector. See setSckRate(). \param[in] chipSelectPin SD chip select pin number. \return The value one, true, is returned for success and the value zero, false, is returned for failure. The reason for failure can be determined by calling errorCode() and errorData(). */ uint8_t Sd2Card::init(uint8_t chipSelectPin, uint8_t sckRateID, int8_t SPI_Port, int8_t cardDetectionPin, int8_t level) { // Serial.println("> Sd2Card::init"); errorCode_ = inBlock_ = partialBlockRead_ = type_ = 0; chipSelectPin_ = chipSelectPin; SPI_Port_ = SPI_Port; cardDetectionPin_ = cardDetectionPin; level_ = level; // 16-bit init start time allows over a minute uint16_t t0 = (uint16_t)millis(); uint32_t arg; // set pin modes pinMode(chipSelectPin_, OUTPUT); chipSelectHigh(); if (cardDetectionPin_ >= 0) { pinMode(cardDetectionPin_, INPUT_PULLUP); } //#ifndef USE_SPI_LIB // pinMode(SPI_MISO_PIN, INPUT); // pinMode(SPI_MOSI_PIN, OUTPUT); // pinMode(SPI_SCK_PIN, OUTPUT); //#endif //#ifndef SOFTWARE_SPI //#ifndef USE_SPI_LIB // // SS must be in output mode even it is not chip select // pinMode(SS_PIN, OUTPUT); // digitalWrite(SS_PIN, HIGH); // disable any SPI device using hardware SS pin // // Enable SPI, Master, clock rate f_osc/128 // SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); // // clear double speed // SPSR &= ~(1 << SPI2X); //#else // USE_SPI_LIB /// @todo Add SPI port selection for LM4F and TM4C SPI_for_SD.begin(); #if defined(__LM4F120H5QR__) || defined(__TM4C1230C3PM__) || defined(__TM4C123GH6PM__) || defined(__TM4C129XNCZAD__) || defined(__TM4C1294NCPDT__) // LM4F and TM4C specific if (SPI_Port >= 0) { SPI_for_SD.setModule(SPI_Port); } #endif #ifdef SPI_CLOCK_DIV128 // Serial.println("> SPI_Port 128"); SPI_for_SD.setClockDivider(SPI_CLOCK_DIV128); #else // Serial.println("> SPI_Port 255"); SPI_for_SD.setClockDivider(255); #endif //#endif // USE_SPI_LIB //#endif // SOFTWARE_SPI // Hardware card detection if (cardDetectionPin_ >= 0) { // debugln("hardware card detection %i should be %i", digitalRead(cardDetectionPin_), level); if (digitalRead(cardDetectionPin_) != level_) { // Serial.println("*** hardware failure"); error(SD_CARD_ERROR_CMD0); // I don't like goto but this is how it is implemented goto fail; } } // Software card detection // must supply min of 74 clock cycles with CS high. for (uint8_t i = 0; i < 10; i++) { spiSend(0xff); } chipSelectLow(); // Serial.print("software card detection "); // command to go idle in SPI mode while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) { if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { error(SD_CARD_ERROR_CMD0); // Serial.println("*** software failure"); goto fail; } } // 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++) { status_ = spiRec(); } if (status_ != 0xaa) { error(SD_CARD_ERROR_CMD8); goto fail; } type(SD_CARD_TYPE_SD2); } // initialize card and send host supports SDHC if SD2 arg = type() == SD_CARD_TYPE_SD2 ? 0x40000000 : 0; while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) { // check for timeout if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { error(SD_CARD_ERROR_ACMD41); goto fail; } } // 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); goto fail; } if ((spiRec() & 0xc0) == 0xc0) { type(SD_CARD_TYPE_SDHC); } // discard rest of ocr - contains allowed voltage range for (uint8_t i = 0; i < 3; i++) { spiRec(); } } chipSelectHigh(); #ifndef SOFTWARE_SPI return setSckRate(sckRateID); #else // SOFTWARE_SPI return true; #endif // SOFTWARE_SPI fail: chipSelectHigh(); return false; }
/** * Initialize an SD flash memory card. * * \param[in] sckRateID SPI clock rate selector. See setSckRate(). * \param[in] chipSelectPin SD chip select pin number. * * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. The reason for failure * can be determined by calling errorCode() and errorData(). */ bool Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) { errorCode_ = type_ = 0; chipSelectPin_ = chipSelectPin; // 16-bit init start time allows over a minute uint16_t t0 = (uint16_t)millis(); uint32_t arg; // set pin modes pinMode(chipSelectPin_, OUTPUT); chipSelectHigh(); pinMode(SPI_MISO_PIN, INPUT); pinMode(SPI_MOSI_PIN, OUTPUT); pinMode(SPI_SCK_PIN, OUTPUT); // SS must be in output mode even it is not chip select pinMode(SS_PIN, OUTPUT); // set SS high - may be chip select for another SPI device #if SET_SPI_SS_HIGH digitalWrite(SS_PIN, HIGH); #endif // SET_SPI_SS_HIGH spiInit(); // set SCK rate for initialization commands setSckRate(SPI_SD_INIT_RATE); // must supply min of 74 clock cycles with CS high. for (uint8_t i = 0; i < 10; i++) spiSend(0XFF); // command to go idle in SPI mode while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) { if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { error(SD_CARD_ERROR_CMD0); goto fail; } } // 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++) status_ = spiRec(); if (status_ != 0XAA) { error(SD_CARD_ERROR_CMD8); goto fail; } type(SD_CARD_TYPE_SD2); } // initialize card and send host supports SDHC if SD2 arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0; while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) { // check for timeout if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { error(SD_CARD_ERROR_ACMD41); goto fail; } } // 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); goto fail; } if ((spiRec() & 0XC0) == 0XC0) type(SD_CARD_TYPE_SDHC); // discard rest of ocr - contains allowed voltage range for (uint8_t i = 0; i < 3; i++) spiRec(); } chipSelectHigh(); return setSckRate(sckRateID); fail: chipSelectHigh(); return false; }
uint8_t Sd2Card::init(HardwareSPI &SPIn) { errorCode_ = inBlock_ = partialBlockRead_ = type_ = 0; //chipSelectPin_ = chipSelectPin; // 16-bit init start time allows over a minute uint16_t t0 = (uint16_t)millis(); uint32_t arg; // SPIn = s; // set pin modes /* pinMode(chipSelectPin_, OUTPUT); chipSelectHigh(); pinMode(SPI_MISO_PIN, INPUT); pinMode(SPI_MOSI_PIN, OUTPUT); pinMode(SPI_SCK_PIN, OUTPUT); */ // SS must be in output mode even it is not chip select // pinMode(SS_PIN, OUTPUT); // Enable SPI, Master, clock rate f_osc/128 // SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); // clear double speed // SPSR &= ~(1 << SPI2X); // must supply min of 74 clock cycles with CS high. chipSelectHigh(); for (uint8_t i = 0; i < 10; i++) spiSend(0XFF); chipSelectLow(); // command to go idle in SPI mode while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) { if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { Serial.println("Error: CMD0"); error(SD_CARD_ERROR_CMD0); goto fail; } } // 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++) status_ = spiRec(); if (status_ != 0XAA) { error(SD_CARD_ERROR_CMD8); Serial.println("Error: CMD8"); goto fail; } type(SD_CARD_TYPE_SD2); } // initialize card and send host supports SDHC if SD2 arg = (type() == SD_CARD_TYPE_SD2) ? 0X40000000 : 0; while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) { // check for timeout if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { Serial.println("Error: ACMD41"); error(SD_CARD_ERROR_ACMD41); goto fail; } } // if SD2 read OCR register to check for SDHC card if (type() == SD_CARD_TYPE_SD2) { if (cardCommand(CMD58, 0)) { Serial.println("Error: CMD58"); error(SD_CARD_ERROR_CMD58); goto fail; } if ((spiRec() & 0XC0) == 0XC0) type(SD_CARD_TYPE_SDHC); // discard rest of ocr - contains allowed voltage range for (uint8_t i = 0; i < 3; i++) spiRec(); } chipSelectHigh(); // return setSckRate(sckRateID); return true; fail: chipSelectHigh(); Serial.println("Error: Sd2Card::init()"); return false; }
/** * Initialize an SD flash memory card. * * \param[in] sckRateID SPI clock rate selector. See setSckRate(). * \param[in] chipSelectPin SD chip select pin number. * * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. The reason for failure * can be determined by calling errorCode() and errorData(). */ uint8_t Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) { errorCode_ = inBlock_ = partialBlockRead_ = type_ = 0; // 16-bit init start time allows over a minute uint16_t t0 = (uint16_t)millis(); uint32_t arg; SPI2CON = 0; DDPCONbits.JTAGEN = 0; AD1PCFG = 0xFFFF; chipSelectPin_ = chipSelectPin; pinMode(chipSelectPin_, OUTPUT); PORTSetPinsDigitalOut(prtSCK, bnSCK); PORTSetPinsDigitalOut(prtSDO, bnSDO); PORTSetPinsDigitalIn(prtSDI, bnSDI); // set pin modes chipSelectHigh(); // must supply min of 74 clock cycles with CS high. for (uint8_t i = 0; i < 10; i++) spiSend(0XFF); chipSelectLow(); // command to go idle in SPI mode while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) { if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { error(SD_CARD_ERROR_CMD0); goto fail; } } // 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++) status_ = spiRec(); if (status_ != 0XAA) { error(SD_CARD_ERROR_CMD8); goto fail; } type(SD_CARD_TYPE_SD2); } // initialize card and send host supports SDHC if SD2 arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0; while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) { // check for timeout if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { error(SD_CARD_ERROR_ACMD41); goto fail; } } // 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); goto fail; } if ((spiRec() & 0XC0) == 0XC0) type(SD_CARD_TYPE_SDHC); // discard rest of ocr - contains allowed voltage range for (uint8_t i = 0; i < 3; i++) spiRec(); } chipSelectHigh(); #ifndef SOFTWARE_SPI return setSckRate(sckRateID); #else // SOFTWARE_SPI return true; #endif // SOFTWARE_SPI fail: chipSelectHigh(); return false; }
/** * Initialize an SD flash memory card. * * \param[in] sckRateID SPI clock rate selector. See setSckRate(). * \param[in] chipSelectPin SD chip select pin number. * * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. The reason for failure * can be determined by calling errorCode() and errorData(). */ uint8_t Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) { errorCode_ = inBlock_ = partialBlockRead_ = type_ = 0; chipSelectPin_ = chipSelectPin; // 16-bit init start time allows over a minute uint16_t t0 = (uint16_t)millis(); uint32_t arg; // set pin modes pinMode(chipSelectPin_, OUTPUT); digitalWrite(chipSelectPin_, HIGH); #ifndef USE_SPI_LIB pinMode(SPI_MISO_PIN, INPUT); pinMode(SPI_MOSI_PIN, OUTPUT); pinMode(SPI_SCK_PIN, OUTPUT); #endif #ifndef SOFTWARE_SPI #ifndef USE_SPI_LIB // SS must be in output mode even it is not chip select pinMode(SS_PIN, OUTPUT); digitalWrite(SS_PIN, HIGH); // disable any SPI device using hardware SS pin // Enable SPI, Master, clock rate f_osc/128 SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); // clear double speed SPSR &= ~(1 << SPI2X); #else // USE_SPI_LIB SPI.begin(); settings = SPISettings(250000, MSBFIRST, SPI_MODE0); #endif // USE_SPI_LIB #endif // SOFTWARE_SPI // must supply min of 74 clock cycles with CS high. #ifdef USE_SPI_LIB SPI.beginTransaction(settings); #endif for (uint8_t i = 0; i < 10; i++) spiSend(0XFF); #ifdef USE_SPI_LIB SPI.endTransaction(); #endif chipSelectLow(); // command to go idle in SPI mode while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) { if (((uint16_t)(millis() - t0)) > SD_INIT_TIMEOUT) { error(SD_CARD_ERROR_CMD0); goto fail; } } // 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++) status_ = spiRec(); if (status_ != 0XAA) { error(SD_CARD_ERROR_CMD8); goto fail; } type(SD_CARD_TYPE_SD2); } // initialize card and send host supports SDHC if SD2 arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0; while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) { // check for timeout if (((uint16_t)(millis() - t0)) > SD_INIT_TIMEOUT) { error(SD_CARD_ERROR_ACMD41); goto fail; } } // 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); goto fail; } if ((spiRec() & 0XC0) == 0XC0) type(SD_CARD_TYPE_SDHC); // discard rest of ocr - contains allowed voltage range for (uint8_t i = 0; i < 3; i++) spiRec(); } chipSelectHigh(); #ifndef SOFTWARE_SPI return setSckRate(sckRateID); #else // SOFTWARE_SPI return true; #endif // SOFTWARE_SPI fail: chipSelectHigh(); return false; }
/** * Initialize an SD flash memory card. * * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. The reason for failure * can be determined by calling errorCode() and errorData(). */ uint8_t Sd2Card::init() { errorCode_ = inBlock_ = partialBlockRead_ = type_ = 0; chipSelectPin_ = SD_CHIP_SELECT_PIN; // 16-bit init start time allows over a minute uint16_t t0 = (uint16_t)millis(); uint32_t arg; // set pin modes pinMode(chipSelectPin_, OUTPUT); chipSelectHigh(); pinMode(SPI_MISO_PIN, INPUT); pinMode(SPI_MOSI_PIN, OUTPUT); pinMode(SPI_SCK_PIN, OUTPUT); // must supply min of 74 clock cycles with CS high. for (uint8_t i = 0; i < 10; i++) spiSend(0XFF); chipSelectLow(); // command to go idle in SPI mode while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) { if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { error(SD_CARD_ERROR_CMD0); goto fail; } } // 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++) status_ = spiRec(); if (status_ != 0XAA) { error(SD_CARD_ERROR_CMD8); goto fail; } type(SD_CARD_TYPE_SD2); } // initialize card and send host supports SDHC if SD2 arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0; while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) { // check for timeout if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { error(SD_CARD_ERROR_ACMD41); goto fail; } } // 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); goto fail; } if ((spiRec() & 0XC0) == 0XC0) type(SD_CARD_TYPE_SDHC); // discard rest of ocr - contains allowed voltage range for (uint8_t i = 0; i < 3; i++) spiRec(); } chipSelectHigh(); return true; fail: chipSelectHigh(); return false; }