/** 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; }
/** 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 command and return error code. Return zero for OK uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) { // end read if in partialBlockRead mode readEnd(); // select card chipSelectLow(); // wait up to 300 ms if busy waitNotBusy(300); // send command spiSend(cmd | 0x40); // send argument for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s); // send CRC uint8_t crc = 0XFF; if (cmd == CMD0) crc = 0X95; // correct crc for CMD0 with arg 0 if (cmd == CMD8) crc = 0X87; // correct crc for CMD8 with arg 0X1AA spiSend(crc); // wait for response for (uint8_t i = 0; ((status_ = spiRec()) & 0X80) && i != 0XFF; i++); return status_; }
/** * 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); 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)) { 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); 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; } chipSelectHigh(); return true; fail: chipSelectHigh(); return false; }
//------------------------------------------------------------------------------ bool SdSpiCard::writeBlock(uint32_t blockNumber, const uint8_t* src) { SD_TRACE("WB", blockNumber); // 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; } #if CHECK_FLASH_PROGRAMMING // wait for flash programming to complete if (!waitNotBusy(SD_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) || spiReceive()) { error(SD_CARD_ERROR_CMD13); goto fail; } #endif // CHECK_PROGRAMMING spiStop(); return true; fail: spiStop(); return false; }
//------------------------------------------------------------------------------ // send command to card uint8_t SdReader::cardCommand(uint8_t cmd, uint32_t arg) { //Serial.print("cardCommand, cmd="); Serial.print(cmd, DEC); Serial.print(", arg="); Serial.println(arg, DEC); uint8_t r1; // end read if in partialBlockRead mode readEnd(); // select card spiSSLow(); // wait up to 300 ms if busy waitNotBusy(300); // send command spiSend(cmd | 0x40); // send argument for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s); // send CRC uint8_t crc = 0XFF; if (cmd == CMD0) crc = 0X95; // correct crc for CMD0 with arg 0 if (cmd == CMD8) crc = 0X87; // correct crc for CMD8 with arg 0X1AA spiSend(crc); // wait for response for (uint8_t retry = 0; ((r1 = spiRec()) & 0X80) && retry != 0XFF; retry++); return r1; }
//------------------------------------------------------------------------------ // send command and return error code. Return zero for OK uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) { // select card chipSelectLow(); // wait up to 300 ms if busy waitNotBusy(300); // send command spiSend(cmd | 0x40); // send argument for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s); // send CRC uint8_t crc = 0XFF; if (cmd == CMD0) crc = 0X95; // correct crc for CMD0 with arg 0 if (cmd == CMD8) crc = 0X87; // correct crc for CMD8 with arg 0X1AA spiSend(crc); // skip stuff byte for stop read if (cmd == CMD12) spiRec(); // wait for response for (uint8_t i = 0; ((status_ = spiRec()) & 0X80) && i != 0XFF; i++) { /* Intentionally left empty */ } return status_; }
/** 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. */ bool Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) { csd_t csd; if (!readCSD(&csd)) goto fail; // check for single block erase if (!csd.v1.erase_blk_en) { // erase size mask uint8_t m = (csd.v1.sector_size_high << 1) | csd.v1.sector_size_low; if ((firstBlock & m) != 0 || ((lastBlock + 1) & m) != 0) { // error card can't erase specified area 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; }
static void writeCmdLCD(uint8_t data) { waitNotBusy(); RS=0; RW=0; E=1; PORTD=data; E=0; }
void writeDataLCD(char data) { waitNotBusy(); RS=1; RW=0; E=1; PORTD=data; E=0; }
/** 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); }
//------------------------------------------------------------------------------ bool SdSpiCard::writeStop() { if (!waitNotBusy(SD_WRITE_TIMEOUT)) { goto fail; } spiSend(STOP_TRAN_TOKEN); spiStop(); return true; fail: error(SD_CARD_ERROR_STOP_TRAN); spiStop(); return false; }
/** Write one data block in a multiple block write sequence * \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. */ bool Sd2Card::writeData(const uint8_t* src) { chipSelectLow(); // wait for previous write to finish if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail; if (!writeData(WRITE_MULTIPLE_TOKEN, src)) goto fail; chipSelectHigh(); return true; fail: error(SD_CARD_ERROR_WRITE_MULTIPLE); chipSelectHigh(); return false; }
//------------------------------------------------------------------------------ bool SdSpiCard::writeData(const uint8_t* src) { // wait for previous write to finish if (!waitNotBusy(SD_WRITE_TIMEOUT)) { error(SD_CARD_ERROR_WRITE_TIMEOUT); goto fail; } if (!writeData(WRITE_MULTIPLE_TOKEN, src)) { goto fail; } return true; fail: spiStop(); return false; }
//------------------------------------------------------------------------------ // send command and return error code. Return zero for OK uint8_t SdSpiCard::cardCommand(uint8_t cmd, uint32_t arg) { // select card if (!m_spiActive) { spiStart(); } // wait if busy waitNotBusy(SD_WRITE_TIMEOUT); #if USE_SD_CRC // form message uint8_t buf[6]; buf[0] = (uint8_t)0x40U | cmd; buf[1] = (uint8_t)(arg >> 24U); buf[2] = (uint8_t)(arg >> 16U); buf[3] = (uint8_t)(arg >> 8U); buf[4] = (uint8_t)arg; // add CRC buf[5] = CRC7(buf, 5); // send message spiSend(buf, 6); #else // USE_SD_CRC // send command spiSend(cmd | 0x40); // send argument uint8_t *pa = reinterpret_cast<uint8_t *>(&arg); for (int8_t i = 3; i >= 0; i--) { spiSend(pa[i]); } // send CRC - correct for CMD0 with arg zero or CMD8 with arg 0X1AA spiSend(cmd == CMD0 ? 0X95 : 0X87); #endif // USE_SD_CRC // skip stuff byte for stop read if (cmd == CMD12) { spiReceive(); } // wait for response for (uint8_t i = 0; ((m_status = spiReceive()) & 0X80) && i != 0XFF; i++) { } return m_status; }
//------------------------------------------------------------------------------ // send command and return error code. Return zero for OK uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) { // end read if in partialBlockRead mode readEnd(); // select card chipSelectLow(); // wait up to 300 ms if busy waitNotBusy(300); // send command spiSend(cmd | 0x40); #ifdef ESP8266 // send argument SPI.write32(arg, true); #else // send argument for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s); #endif // send CRC uint8_t crc = 0xFF; if (cmd == CMD0) crc = 0x95; // correct crc for CMD0 with arg 0 if (cmd == CMD8) crc = 0x87; // correct crc for CMD8 with arg 0X1AA spiSend(crc); // wait for response for (uint8_t i = 0; ((status_ = spiRec()) & 0x80) && i != 0xFF; i++) ; #ifdef ESP8266 optimistic_yield(10000); #endif return status_; }