/** 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; }
//----------------------------------------------------------------------------- bool SdSpiCard::readStatus(uint8_t* status) { // retrun is R2 so read extra status byte. if (cardAcmd(ACMD13, 0) || spiReceive()) { error(SD_CARD_ERROR_ACMD13); goto fail; } if (!readData(status, 64)) { goto fail; } spiStop(); return true; fail: spiStop(); return false; }
/** 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 SdSpiCard::writeStart(uint32_t blockNumber, uint32_t eraseCount) { SD_TRACE("WS", blockNumber); // 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: spiStop(); 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(). */ 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; }
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; }
//============================================================================== // SdSpiCard member functions //------------------------------------------------------------------------------ bool SdSpiCard::begin(SdSpiDriver* spi, uint8_t csPin, SPISettings settings) { m_spiActive = false; m_errorCode = SD_CARD_ERROR_NONE; m_type = 0; m_spiDriver = spi; uint16_t t0 = curTimeMS(); uint32_t arg; m_spiDriver->begin(csPin); m_spiDriver->setSpiSettings(SD_SCK_HZ(250000)); spiStart(); // must supply min of 74 clock cycles with CS high. spiUnselect(); for (uint8_t i = 0; i < 10; i++) { spiSend(0XFF); } spiSelect(); // command to go idle in SPI mode while (cardCommand(CMD0, 0) != R1_IDLE_STATE) { if (isTimedOut(t0, SD_INIT_TIMEOUT)) { error(SD_CARD_ERROR_CMD0); goto fail; } } #if USE_SD_CRC if (cardCommand(CMD59, 1) != R1_IDLE_STATE) { error(SD_CARD_ERROR_CMD59); goto fail; } #endif // USE_SD_CRC // check SD version while (1) { if (cardCommand(CMD8, 0x1AA) == (R1_ILLEGAL_COMMAND | R1_IDLE_STATE)) { type(SD_CARD_TYPE_SD1); break; } for (uint8_t i = 0; i < 4; i++) { m_status = spiReceive(); } if (m_status == 0XAA) { type(SD_CARD_TYPE_SD2); break; } if (isTimedOut(t0, SD_INIT_TIMEOUT)) { error(SD_CARD_ERROR_CMD8); goto fail; } } // initialize card and send host supports SDHC if SD2 arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0; while (cardAcmd(ACMD41, arg) != R1_READY_STATE) { // check for timeout if (isTimedOut(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 ((spiReceive() & 0XC0) == 0XC0) { type(SD_CARD_TYPE_SDHC); } // Discard rest of ocr - contains allowed voltage range. for (uint8_t i = 0; i < 3; i++) { spiReceive(); } } spiStop(); m_spiDriver->setSpiSettings(settings); return true; fail: spiStop(); return false; }
//============================================================================= bool SdioCard::begin() { uint32_t kHzSdClk; uint32_t arg; m_initDone = false; m_errorCode = SD_CARD_ERROR_NONE; m_highCapacity = false; m_version2 = false; // initialize controller. initSDHC(); if (!cardCommand(CMD0_XFERTYP, 0)) { return sdError(SD_CARD_ERROR_CMD0); } // Try several times for case of reset delay. for (uint32_t i = 0; i < CMD8_RETRIES; i++) { if (cardCommand(CMD8_XFERTYP, 0X1AA)) { if (SDHC_CMDRSP0 != 0X1AA) { return sdError(SD_CARD_ERROR_CMD8); } m_version2 = true; break; } } arg = m_version2 ? 0X40300000 : 0x00300000; uint32_t m = micros(); do { if (!cardAcmd(0, ACMD41_XFERTYP, arg) || ((micros() - m) > BUSY_TIMEOUT_MICROS)) { return sdError(SD_CARD_ERROR_ACMD41); } } while ((SDHC_CMDRSP0 & 0x80000000) == 0); m_ocr = SDHC_CMDRSP0; if (SDHC_CMDRSP0 & 0x40000000) { // Is high capacity. m_highCapacity = true; } if (!cardCommand(CMD2_XFERTYP, 0)) { return sdError(SD_CARD_ERROR_CMD2); } if (!cardCommand(CMD3_XFERTYP, 0)) { return sdError(SD_CARD_ERROR_CMD3); } m_rca = SDHC_CMDRSP0 & 0xFFFF0000; if (!readReg16(CMD9_XFERTYP, &m_csd)) { return sdError(SD_CARD_ERROR_CMD9); } if (!readReg16(CMD10_XFERTYP, &m_cid)) { return sdError(SD_CARD_ERROR_CMD10); } if (!cardCommand(CMD7_XFERTYP, m_rca)) { return sdError(SD_CARD_ERROR_CMD7); } // Set card to bus width four. if (!cardAcmd(m_rca, ACMD6_XFERTYP, 2)) { return sdError(SD_CARD_ERROR_ACMD6); } // Set SDHC to bus width four. SDHC_PROCTL &= ~SDHC_PROCTL_DTW_MASK; SDHC_PROCTL |= SDHC_PROCTL_DTW(SDHC_PROCTL_DTW_4BIT); SDHC_WML = SDHC_WML_RDWML(FIFO_WML) | SDHC_WML_WRWML(FIFO_WML); // Determine if High Speed mode is supported and set frequency. uint8_t status[64]; if (cardCMD6(0X00FFFFFF, status) && (2 & status[13]) && cardCMD6(0X80FFFFF1, status) && (status[16] & 0XF) == 1) { kHzSdClk = 50000; } else { kHzSdClk = 25000; } // disable GPIO enableGPIO(false); // Set the SDHC SCK frequency. setSdclk(kHzSdClk); // enable GPIO enableGPIO(true); m_initDone = true; return true; }
/** * 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; }
/** * 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); pinMode(SS_PIN, OUTPUT); digitalWrite(SS_PIN, HIGH); // disable any SPI device using hardware SS pin SPI.begin(chipSelectPin_); SPI.setFrequency(chipSelectPin_, 4000000); // 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(); } #ifndef SOFTWARE_SPI return setSckRate(sckRateID); #else // SOFTWARE_SPI return true; #endif // SOFTWARE_SPI fail: return false; }
/** * 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; }