/* Arduino SdSpiCard Library * Copyright (C) 2012 by William Greiman * * This file is part of the Arduino SdSpiCard Library * * This Library is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This Library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with the Arduino SdSpiCard Library. If not, see * . */ #ifndef SpiCard_h #define SpiCard_h /** * \file * \brief SdSpiCard class for V2 SD/SDHC cards */ #include #include #include #include //============================================================================== /** * \class SdSpiCard * \brief Raw access to SD and SDHC flash memory cards via SPI protocol. */ class SdSpiCard { public: /** typedef for SPI class. */ #if USE_MULTIPLE_SPI_TYPES typedef SdSpiBase m_spi_t; #else // USE_MULTIPLE_SPI_TYPES typedef SpiDefault_t m_spi_t; #endif // USE_MULTIPLE_SPI_TYPES /** Construct an instance of SdSpiCard. */ SdSpiCard() : m_errorCode(SD_CARD_ERROR_INIT_NOT_CALLED), m_type(0) {} /** Initialize the SD card. * \param[in] spi SPI object. * \param[in] chipSelectPin SD chip select pin. * \param[in] sckDivisor SPI clock divisor. * \return true for success else false. */ bool begin(m_spi_t* spi, uint8_t chipSelectPin = SS, uint8_t sckDivisor = SPI_FULL_SPEED); /** * Determine the size of an SD flash memory card. * * \return The number of 512 byte data blocks in the card * or zero if an error occurs. */ uint32_t cardSize(); /** 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 erase(uint32_t firstBlock, uint32_t lastBlock); /** Determine if card supports single block erase. * * \return true is returned if single block erase is supported. * false is returned if single block erase is not supported. */ bool eraseSingleBlockEnable(); /** * Set SD error code. * \param[in] code value for error code. */ void error(uint8_t code) {m_errorCode = code;} /** * \return code for the last error. See SdSpiCard.h for a list of error codes. */ int errorCode() const {return m_errorCode;} /** \return error data for last error. */ int errorData() const {return m_status;} /** * Check for busy. MISO low indicates the card is busy. * * \return true if busy else false. */ bool isBusy(); /** * Read a 512 byte block from an SD card. * * \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. */ bool readBlock(uint32_t block, uint8_t* dst); /** * Read multiple 512 byte blocks from an SD card. * * \param[in] block Logical block to be read. * \param[in] count Number of blocks 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 readBlocks(uint32_t block, uint8_t* dst, size_t count); /** * Read a card's CID register. The CID contains card identification * information such as Manufacturer ID, Product name, Product serial * number and Manufacturing date. * * \param[out] cid pointer to area for returned data. * * \return true for success or false for failure. */ bool readCID(cid_t* cid) { return readRegister(CMD10, cid); } /** * Read a card's CSD register. The CSD contains Card-Specific Data that * provides information regarding access to the card's contents. * * \param[out] csd pointer to area for returned data. * * \return true for success or false for failure. */ bool readCSD(csd_t* csd) { return readRegister(CMD9, csd); } /** Read one data block in a multiple block read sequence * * \param[out] dst Pointer to the location for the data to be read. * * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. */ bool readData(uint8_t *dst); /** Read OCR register. * * \param[out] ocr Value of OCR register. * \return true for success else false. */ bool readOCR(uint32_t* ocr); /** Start a read multiple blocks sequence. * * \param[in] blockNumber Address of first block in sequence. * * \note This function is used with readData() and readStop() for optimized * multiple block reads. SPI chipSelect must be low for the entire sequence. * * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. */ bool readStart(uint32_t blockNumber); /** End a read multiple blocks sequence. * * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. */ bool readStop(); /** Return SCK divisor. * * \return Requested SCK divisor. */ uint8_t sckDivisor() {return m_sckDivisor;} /** Return the card type: SD V1, SD V2 or SDHC * \return 0 - SD V1, 1 - SD V2, or 3 - SDHC. */ int type() const {return m_type;} /** * 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. */ bool writeBlock(uint32_t blockNumber, const uint8_t* src); /** * Write multiple 512 byte blocks to an SD card. * * \param[in] block Logical block to be written. * \param[in] count Number of blocks 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. */ bool writeBlocks(uint32_t block, const uint8_t* src, size_t count); /** 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 writeData(const uint8_t* 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 writeStart(uint32_t blockNumber, uint32_t eraseCount); /** End a write multiple blocks sequence. * * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. */ bool writeStop(); private: // private functions uint8_t cardAcmd(uint8_t cmd, uint32_t arg) { cardCommand(CMD55, 0); return cardCommand(cmd, arg); } uint8_t cardCommand(uint8_t cmd, uint32_t arg); bool readData(uint8_t* dst, size_t count); bool readRegister(uint8_t cmd, void* buf); void chipSelectHigh(); void chipSelectLow(); void spiYield(); void type(uint8_t value) {m_type = value;} bool waitNotBusy(uint16_t timeoutMillis); bool writeData(uint8_t token, const uint8_t* src); void spiBegin() {m_spi->begin();} void spiInit(uint8_t spiDivisor) {m_spi->init(spiDivisor);} uint8_t spiReceive() {return m_spi->receive();} uint8_t spiReceive(uint8_t* buf, size_t n) {return m_spi->receive(buf, n);} void spiSend(uint8_t data) {m_spi->send(data);} void spiSend(const uint8_t* buf, size_t n) {m_spi->send(buf, n);} bool useSpiTransactions() {return m_spi->useSpiTransactions();} m_spi_t* m_spi; uint8_t m_chipSelectPin; uint8_t m_errorCode; uint8_t m_sckDivisor; uint8_t m_status; uint8_t m_type; }; //============================================================================== /** * \class Sd2Card * \brief Raw access to SD and SDHC card using default SPI library. */ class Sd2Card : public SdSpiCard { public: /** Initialize the SD card. * \param[in] chipSelectPin SD chip select pin. * \param[in] sckDivisor SPI clock divisor. * \return true for success else false. */ bool begin(uint8_t chipSelectPin = SS, uint8_t sckDivisor = 2) { return SdSpiCard::begin(&m_spi, chipSelectPin, sckDivisor); } /** Initialize the SD card. Obsolete form. * \param[in] chipSelectPin SD chip select pin. * \param[in] sckDivisor SPI clock divisor. * \return true for success else false. */ bool init(uint8_t sckDivisor = 2, uint8_t chipSelectPin = SS) { return begin(chipSelectPin, sckDivisor); } private: bool begin(m_spi_t* spi, uint8_t chipSelectPin = SS, uint8_t sckDivisor = SPI_FULL_SPEED) {return false;} SpiDefault_t m_spi; }; #endif // SpiCard_h