const uint8_t SD_CS_PIN = SDCARD_SS_PIN; | const uint8_t SD_CS_PIN = SDCARD_SS_PIN; | ||||
#endif // SDCARD_SS_PIN | #endif // SDCARD_SS_PIN | ||||
// Use SPI, SD_CS_PIN, SHARED_SPI, FULL_SPEED. | |||||
// Use SPI, SD_CS_PIN, SHARED_SPI, 50 MHz. | |||||
#define SD_CONFIG SdSpiConfig(SD_CS_PIN) | #define SD_CONFIG SdSpiConfig(SD_CS_PIN) | ||||
SdExFat sd; | SdExFat sd; |
// An example of an external chip select functions. | |||||
// Useful for port expanders or replacement of the standard GPIO functions. | |||||
// | |||||
#include "SdFat.h" | |||||
// SD_CHIP_SELECT_MODE must be set to one or two in SdFat/SdFatConfig.h. | |||||
// A value of one allows optional replacement and two requires replacement. | |||||
#if SD_CHIP_SELECT_MODE == 1 || SD_CHIP_SELECT_MODE == 2 | |||||
// SD chip select pin. | |||||
#define SD_CS_PIN SS | |||||
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SD_SCK_MHZ(50)) | |||||
SdFat sd; | |||||
// Stats to verify function calls. | |||||
uint32_t initCalls = 0; | |||||
uint32_t writeCalls = 0; | |||||
//------------------------------------------------------------------------------ | |||||
// Modify these functions for your port expander or custom GPIO library. | |||||
void sdCsInit(SdCsPin_t pin) { | |||||
initCalls++; | |||||
pinMode(pin, OUTPUT); | |||||
} | |||||
void sdCsWrite(SdCsPin_t pin, bool level) { | |||||
writeCalls++; | |||||
digitalWrite(pin, level); | |||||
} | |||||
//------------------------------------------------------------------------------ | |||||
void setup() { | |||||
Serial.begin(9600); | |||||
if (!sd.begin(SD_CONFIG)) { | |||||
sd.initErrorHalt(&Serial); | |||||
} | |||||
sd.ls(&Serial, LS_SIZE); | |||||
Serial.print(F("sdCsInit calls: ")); | |||||
Serial.println(initCalls); | |||||
Serial.print(F("sdCsWrite calls: ")); | |||||
Serial.println(writeCalls); | |||||
} | |||||
//------------------------------------------------------------------------------ | |||||
void loop() {} | |||||
#else // SD_CHIP_SELECT_MODE == 1 || SD_CHIP_SELECT_MODE == 2 | |||||
#error SD_CHIP_SELECT_MODE must be one or two in SdFat/SdFatConfig.h | |||||
#endif // SD_CHIP_SELECT_MODE == 1 || SD_CHIP_SELECT_MODE == 2 |
// An example of an external SPI driver. | |||||
// | |||||
#include "SdFat.h" | |||||
#include "SPI.h" // Only required if you use features in the SPI library. | |||||
#if SPI_DRIVER_SELECT == 3 // Must be set in SdFat/SdFatConfig.h | |||||
// SD chip select pin. | |||||
#define SD_CS_PIN SS | |||||
// This is a simple driver based on the the standard SPI.h library. | |||||
// You can write a driver entirely independent of SPI.h. | |||||
// It can be optimized for your board or a different SPI port can be used. | |||||
// The driver must be derived from SdSpiBaseClass. | |||||
// See: SdFat/src/SpiDriver/SdSpiBaseClass.h | |||||
class MySpiClass : public SdSpiBaseClass { | |||||
public: | |||||
// Activate SPI hardware with correct speed and mode. | |||||
void activate() { | |||||
SPI.beginTransaction(m_spiSettings); | |||||
} | |||||
// Initialize the SPI bus. | |||||
void begin(SdSpiConfig config) { | |||||
(void)config; | |||||
SPI.begin(); | |||||
} | |||||
// Deactivate SPI hardware. | |||||
void deactivate() { | |||||
SPI.endTransaction(); | |||||
} | |||||
// Receive a byte. | |||||
uint8_t receive() { | |||||
return SPI.transfer(0XFF); | |||||
} | |||||
// Receive multiple bytes. | |||||
// Replace this function if your board has multiple byte receive. | |||||
uint8_t receive(uint8_t* buf, size_t count) { | |||||
for (size_t i = 0; i < count; i++) { | |||||
buf[i] = SPI.transfer(0XFF); | |||||
} | |||||
return 0; | |||||
} | |||||
// Send a byte. | |||||
void send(uint8_t data) { | |||||
SPI.transfer(data); | |||||
} | |||||
// Send multiple bytes. | |||||
// Replace this function if your board has multiple byte send. | |||||
void send(const uint8_t* buf, size_t count) { | |||||
for (size_t i = 0; i < count; i++) { | |||||
SPI.transfer(buf[i]); | |||||
} | |||||
} | |||||
// Save SPISettings for new max SCK frequency | |||||
void setSckSpeed(uint32_t maxSck) { | |||||
m_spiSettings = SPISettings(maxSck, MSBFIRST, SPI_MODE0); | |||||
} | |||||
private: | |||||
SPISettings m_spiSettings; | |||||
} mySpi; | |||||
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SD_SCK_MHZ(50), &mySpi) | |||||
SdFat sd; | |||||
//------------------------------------------------------------------------------ | |||||
void setup() { | |||||
Serial.begin(9600); | |||||
if (!sd.begin(SD_CONFIG)) { | |||||
sd.initErrorHalt(&Serial); | |||||
} | |||||
sd.ls(&Serial, LS_SIZE); | |||||
} | |||||
//------------------------------------------------------------------------------ | |||||
void loop() {} | |||||
#else // SPI_DRIVER_SELECT | |||||
#error SPI_DRIVER_SELECT must be three in SdFat/SdFatConfig.h | |||||
#endif // SPI_DRIVER_SELECT |
delay(200); // Catch Due reset problem | delay(200); // Catch Due reset problem | ||||
// initialize the SD card at SPI_FULL_SPEED for best performance. | // initialize the SD card at SPI_FULL_SPEED for best performance. | ||||
// try SPI_HALF_SPEED if bus errors occur. | |||||
// try lower speed if bus errors occur. | |||||
if (!sd.begin(SD_CHIP_SELECT, SPI_FULL_SPEED)) { | if (!sd.begin(SD_CHIP_SELECT, SPI_FULL_SPEED)) { | ||||
sd.initErrorHalt(&Serial); | sd.initErrorHalt(&Serial); | ||||
} | } |
delay(200); // Catch Due reset problem | delay(200); // Catch Due reset problem | ||||
// initialize the SD card at SPI_FULL_SPEED for best performance. | // initialize the SD card at SPI_FULL_SPEED for best performance. | ||||
// try SPI_HALF_SPEED if bus errors occur. | |||||
// try lower speed if bus errors occur. | |||||
if (!sd.begin(SD_CHIP_SELECT, SPI_FULL_SPEED)) { | if (!sd.begin(SD_CHIP_SELECT, SPI_FULL_SPEED)) { | ||||
sd.initErrorHalt(&Serial); | sd.initErrorHalt(&Serial); | ||||
} | } |
2017-08-10 | |||||
2019-12-10 | |||||
Run the SdErrorCode example to produce an updated list. | Run the SdErrorCode example to produce an updated list. | ||||
C | |||||
Code,Symbol - failed operation | Code,Symbol - failed operation | ||||
0X0,SD_CARD_ERROR_NONE - No error | |||||
0X1,SD_CARD_ERROR_CMD0 - Card reset failed | |||||
0X2,SD_CARD_ERROR_CMD2 - SDIO read CID | |||||
0X3,SD_CARD_ERROR_CMD3 - SDIO publish RCA | |||||
0X4,SD_CARD_ERROR_CMD6 - Switch card function | |||||
0X5,SD_CARD_ERROR_CMD7 - SDIO card select | |||||
0X6,SD_CARD_ERROR_CMD8 - Send and check interface settings | |||||
0X7,SD_CARD_ERROR_CMD9 - Read CSD data | |||||
0X8,SD_CARD_ERROR_CMD10 - Read CID data | |||||
0X9,SD_CARD_ERROR_CMD12 - Stop multiple block read | |||||
0XA,SD_CARD_ERROR_CMD13 - Read card status | |||||
0XB,SD_CARD_ERROR_CMD17 - Read single block | |||||
0XC,SD_CARD_ERROR_CMD18 - Read multiple blocks | |||||
0XD,SD_CARD_ERROR_CMD24 - Write single block | |||||
0XE,SD_CARD_ERROR_CMD25 - Write multiple blocks | |||||
0XF,SD_CARD_ERROR_CMD32 - Set first erase block | |||||
0X00,SD_CARD_ERROR_NONE - No error | |||||
0X01,SD_CARD_ERROR_CMD0 - Card reset failed | |||||
0X02,SD_CARD_ERROR_CMD2 - SDIO read CID | |||||
0X03,SD_CARD_ERROR_CMD3 - SDIO publish RCA | |||||
0X04,SD_CARD_ERROR_CMD6 - Switch card function | |||||
0X05,SD_CARD_ERROR_CMD7 - SDIO card select | |||||
0X06,SD_CARD_ERROR_CMD8 - Send and check interface settings | |||||
0X07,SD_CARD_ERROR_CMD9 - Read CSD data | |||||
0X08,SD_CARD_ERROR_CMD10 - Read CID data | |||||
0X09,SD_CARD_ERROR_CMD12 - Stop multiple block read | |||||
0X0A,SD_CARD_ERROR_CMD13 - Read card status | |||||
0X0B,SD_CARD_ERROR_CMD17 - Read single block | |||||
0X0C,SD_CARD_ERROR_CMD18 - Read multiple blocks | |||||
0X0D,SD_CARD_ERROR_CMD24 - Write single block | |||||
0X0E,SD_CARD_ERROR_CMD25 - Write multiple blocks | |||||
0X0F,SD_CARD_ERROR_CMD32 - Set first erase block | |||||
0X10,SD_CARD_ERROR_CMD33 - Set last erase block | 0X10,SD_CARD_ERROR_CMD33 - Set last erase block | ||||
0X11,SD_CARD_ERROR_CMD38 - Erase selected blocks | 0X11,SD_CARD_ERROR_CMD38 - Erase selected blocks | ||||
0X12,SD_CARD_ERROR_CMD58 - Read OCR register | 0X12,SD_CARD_ERROR_CMD58 - Read OCR register | ||||
0X13,SD_CARD_ERROR_CMD59 - Set CRC mode | 0X13,SD_CARD_ERROR_CMD59 - Set CRC mode | ||||
0X14,SD_CARD_ERROR_ACMD6 - Set SDIO bus width | 0X14,SD_CARD_ERROR_ACMD6 - Set SDIO bus width | ||||
0X15,SD_CARD_ERROR_ACMD13 - Read extended status | 0X15,SD_CARD_ERROR_ACMD13 - Read extended status | ||||
0X16,SD_CARD_ERROR_ACMD41 - Activate card initialization | |||||
0X17,SD_CARD_ERROR_READ_TOKEN - Bad read data token | |||||
0X18,SD_CARD_ERROR_READ_CRC - Read CRC error | |||||
0X19,SD_CARD_ERROR_READ_FIFO - SDIO fifo read timeout | |||||
0X1A,SD_CARD_ERROR_READ_REG - Read CID or CSD failed. | |||||
0X1B,SD_CARD_ERROR_READ_START - Bad readStart argument | |||||
0X1C,SD_CARD_ERROR_READ_TIMEOUT - Read data timeout | |||||
0X1D,SD_CARD_ERROR_STOP_TRAN - Multiple block stop failed | |||||
0X1E,SD_CARD_ERROR_WRITE_DATA - Write data not accepted | |||||
0X1F,SD_CARD_ERROR_WRITE_FIFO - SDIO fifo write timeout | |||||
0X20,SD_CARD_ERROR_WRITE_START - Bad writeStart argument | |||||
0X21,SD_CARD_ERROR_WRITE_TIMEOUT - Flash programming timeout | |||||
0X22,SD_CARD_ERROR_DMA - DMA transfer failed | |||||
0X23,SD_CARD_ERROR_ERASE - Card did not accept erase commands | |||||
0X24,SD_CARD_ERROR_ERASE_SINGLE_SECTOR - Card does not support erase | |||||
0X25,SD_CARD_ERROR_ERASE_TIMEOUT - Erase command timeout | |||||
0X26,SD_CARD_ERROR_INIT_NOT_CALLED - Card has not been initialized | |||||
0X27,SD_CARD_ERROR_INVALID_CARD_CONFIG - Invalid card config | |||||
0X28,SD_CARD_ERROR_FUNCTION_NOT_SUPPORTED - Unsupported SDIO command | |||||
0X29,SD_CARD_ERROR_UNKNOWN - Unknown error | |||||
0X16,SD_CARD_ERROR_ACMD23 - Set pre-erased count | |||||
0X17,SD_CARD_ERROR_ACMD41 - Activate card initialization | |||||
0X18,SD_CARD_ERROR_READ_TOKEN - Bad read data token | |||||
0X19,SD_CARD_ERROR_READ_CRC - Read CRC error | |||||
0X1A,SD_CARD_ERROR_READ_FIFO - SDIO fifo read timeout | |||||
0X1B,SD_CARD_ERROR_READ_REG - Read CID or CSD failed. | |||||
0X1C,SD_CARD_ERROR_READ_START - Bad readStart argument | |||||
0X1D,SD_CARD_ERROR_READ_TIMEOUT - Read data timeout | |||||
0X1E,SD_CARD_ERROR_STOP_TRAN - Multiple block stop failed | |||||
0X1F,SD_CARD_ERROR_WRITE_DATA - Write data not accepted | |||||
0X20,SD_CARD_ERROR_WRITE_FIFO - SDIO fifo write timeout | |||||
0X21,SD_CARD_ERROR_WRITE_START - Bad writeStart argument | |||||
0X22,SD_CARD_ERROR_WRITE_PROGRAMMING - Flash programming | |||||
0X23,SD_CARD_ERROR_WRITE_TIMEOUT - Write timeout | |||||
0X24,SD_CARD_ERROR_DMA - DMA transfer failed | |||||
0X25,SD_CARD_ERROR_ERASE - Card did not accept erase commands | |||||
0X26,SD_CARD_ERROR_ERASE_SINGLE_SECTOR - Card does not support erase | |||||
0X27,SD_CARD_ERROR_ERASE_TIMEOUT - Erase command timeout | |||||
0X28,SD_CARD_ERROR_INIT_NOT_CALLED - Card has not been initialized | |||||
0X29,SD_CARD_ERROR_INVALID_CARD_CONFIG - Invalid card config | |||||
0X2A,SD_CARD_ERROR_FUNCTION_NOT_SUPPORTED - Unsupported SDIO command | |||||
0X2B,SD_CARD_ERROR_UNKNOWN - Unknown error |
name=SdFat | name=SdFat | ||||
version=2.0.0-beta.7 | |||||
version=2.0.0-beta.8 | |||||
license=MIT | license=MIT | ||||
author=Bill Greiman <fat16lib@sbcglobal.net> | author=Bill Greiman <fat16lib@sbcglobal.net> | ||||
maintainer=Bill Greiman <fat16lib@sbcglobal.net> | maintainer=Bill Greiman <fat16lib@sbcglobal.net> |
DirName_t* dn; | DirName_t* dn; | ||||
DirPos_t pos = m_dirPos; | DirPos_t pos = m_dirPos; | ||||
size_t n = 0; | size_t n = 0; | ||||
uint8_t in; | |||||
uint8_t buf[15]; | |||||
if (!isOpen()) { | if (!isOpen()) { | ||||
DBG_FAIL_MACRO; | DBG_FAIL_MACRO; | ||||
goto fail; | goto fail; | ||||
DBG_FAIL_MACRO; | DBG_FAIL_MACRO; | ||||
goto fail; | goto fail; | ||||
} | } | ||||
for (uint8_t in = 0; in < 15; in++) { | |||||
for (in = 0; in < 15; in++) { | |||||
uint16_t c = getLe16(dn->unicode + 2*in); | uint16_t c = getLe16(dn->unicode + 2*in); | ||||
if (!c) { | if (!c) { | ||||
goto done; | |||||
break;; | |||||
} | } | ||||
pr->write(c < 0X7f ? c : '?'); | |||||
buf[in] = c < 0X7f ? c : '?'; | |||||
n++; | n++; | ||||
} | } | ||||
pr->write(buf, in); | |||||
} | } | ||||
done: | |||||
return n; | return n; | ||||
fail: | fail: |
//------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
size_t FatFile::printName(print_t* pr) { | size_t FatFile::printName(print_t* pr) { | ||||
FatFile dirFile; | FatFile dirFile; | ||||
uint16_t u; | |||||
size_t n = 0; | |||||
DirLfn_t* ldir; | DirLfn_t* ldir; | ||||
size_t n = 0; | |||||
uint16_t u; | |||||
uint8_t buf[13]; | |||||
uint8_t i; | |||||
if (!isLFN()) { | if (!isLFN()) { | ||||
return printSFN(pr); | return printSFN(pr); | ||||
DBG_FAIL_MACRO; | DBG_FAIL_MACRO; | ||||
goto fail; | goto fail; | ||||
} | } | ||||
for (uint8_t i = 0; i < 13; i++) { | |||||
for (i = 0; i < 13; i++) { | |||||
u = lfnGetChar(ldir, i); | u = lfnGetChar(ldir, i); | ||||
if (u == 0) { | if (u == 0) { | ||||
// End of name. | // End of name. | ||||
break; | break; | ||||
} | } | ||||
if (u > 0X7E) { | |||||
u = '?'; | |||||
} | |||||
pr->write(static_cast<char>(u)); | |||||
buf[i] = u < 0X7F ? u : '?'; | |||||
n++; | n++; | ||||
} | } | ||||
if (ldir->order & FAT_ORDER_LAST_LONG_ENTRY) { | |||||
return n; | |||||
} | |||||
pr->write(buf, i); | |||||
} | } | ||||
// Fall into fail; | |||||
DBG_FAIL_MACRO; | |||||
return n; | |||||
fail: | fail: | ||||
return 0; | return 0; |
#include "FsLib.h" | #include "FsLib.h" | ||||
//------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
FsBaseFile::FsBaseFile(const FsBaseFile& from) { | FsBaseFile::FsBaseFile(const FsBaseFile& from) { | ||||
close(); | |||||
m_fFile = nullptr; | |||||
m_xFile = nullptr; | |||||
if (from.m_fFile) { | if (from.m_fFile) { | ||||
m_fFile = new (m_fileMem) FatFile; | m_fFile = new (m_fileMem) FatFile; | ||||
*m_fFile = *from.m_fFile; | *m_fFile = *from.m_fFile; |
* \return generic card pointer. | * \return generic card pointer. | ||||
*/ | */ | ||||
SdCard* newCard(SdSpiConfig config) { | SdCard* newCard(SdSpiConfig config) { | ||||
m_spiCard.begin(&m_spi, config); | |||||
m_spiCard.begin(config); | |||||
return &m_spiCard; | return &m_spiCard; | ||||
} | } | ||||
/** Initialize SDIO card. | /** Initialize SDIO card. | ||||
SdioCard m_sdioCard; | SdioCard m_sdioCard; | ||||
#endif // HAS_SDIO_CLASS | #endif // HAS_SDIO_CLASS | ||||
SdSpiCard m_spiCard; | SdSpiCard m_spiCard; | ||||
SdSpiDriver m_spi; | |||||
}; | }; | ||||
#endif // SdCard_h | #endif // SdCard_h |
//============================================================================== | //============================================================================== | ||||
// SdSpiCard member functions | // SdSpiCard member functions | ||||
//------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
bool SdSpiCard::begin(SdSpiDriver* spi, SdSpiConfig spiConfig) { | |||||
bool SdSpiCard::begin(SdSpiConfig spiConfig) { | |||||
SdMillis_t t0 = SysCall::curTimeMS(); | |||||
m_errorCode = SD_CARD_ERROR_NONE; | m_errorCode = SD_CARD_ERROR_NONE; | ||||
m_type = 0; | m_type = 0; | ||||
m_csPin = spiConfig.csPin; | m_csPin = spiConfig.csPin; | ||||
#if SPI_DRIVER_SELECT >= 2 | |||||
m_spiDriverPtr = spiConfig.spiPort; | |||||
if (!m_spiDriverPtr) { | |||||
error(SD_CARD_ERROR_INVALID_CARD_CONFIG); | |||||
goto fail; | |||||
} | |||||
#endif // SPI_DRIVER_SELECT | |||||
sdCsInit(m_csPin); | sdCsInit(m_csPin); | ||||
spiUnselect(); | spiUnselect(); | ||||
m_spiDriver = spi; | |||||
m_spiDriver->setSckSpeed(1000UL*SD_MAX_INIT_RATE_KHZ); | |||||
m_spiDriver->begin(spiConfig); | |||||
SdMillis_t t0 = SysCall::curTimeMS(); | |||||
spiSetSckSpeed(1000UL*SD_MAX_INIT_RATE_KHZ); | |||||
spiBegin(spiConfig); | |||||
uint32_t arg; | uint32_t arg; | ||||
#if ENABLE_DEDICATED_SPI | #if ENABLE_DEDICATED_SPI | ||||
m_sharedSpi = !(spiConfig.options & DEDICATED_SPI); | m_sharedSpi = !(spiConfig.options & DEDICATED_SPI); | ||||
} | } | ||||
} | } | ||||
spiStop(); | spiStop(); | ||||
m_spiDriver->setSckSpeed(spiConfig.maxSck); | |||||
spiSetSckSpeed(spiConfig.maxSck); | |||||
return true; | return true; | ||||
fail: | fail: |
* \param[in] spiConfig SPI card configuration. | * \param[in] spiConfig SPI card configuration. | ||||
* \return true for success or false for failure. | * \return true for success or false for failure. | ||||
*/ | */ | ||||
bool begin(SdSpiDriver* spi, SdSpiConfig spiConfig); | |||||
bool begin(SdSpiConfig spiConfig); | |||||
/** Clear debug stats. */ | /** Clear debug stats. */ | ||||
void dbgClearStats(); | void dbgClearStats(); | ||||
/** Print debug stats. */ | /** Print debug stats. */ | ||||
bool isTimedOut(SdMillis_t startMS, SdMillis_t timeoutMS); | bool isTimedOut(SdMillis_t startMS, SdMillis_t timeoutMS); | ||||
bool readData(uint8_t* dst, size_t count); | bool readData(uint8_t* dst, size_t count); | ||||
bool readRegister(uint8_t cmd, void* buf); | bool readRegister(uint8_t cmd, void* buf); | ||||
void spiSelect() { | |||||
sdCsWrite(m_csPin, false); | |||||
} | |||||
void type(uint8_t value) { | void type(uint8_t value) { | ||||
m_type = value; | m_type = value; | ||||
} | } | ||||
void spiUnselect() { | |||||
sdCsWrite(m_csPin, true); | |||||
} | |||||
bool waitNotBusy(SdMillis_t timeoutMS); | bool waitNotBusy(SdMillis_t timeoutMS); | ||||
bool writeData(uint8_t token, const uint8_t* src); | bool writeData(uint8_t token, const uint8_t* src); | ||||
//--------------------------------------------------------------------------- | |||||
// functions defined in SdSpiDriver.h | |||||
#if SPI_DRIVER_SELECT < 2 | |||||
void spiActivate() { | void spiActivate() { | ||||
m_spiDriver->activate(); | |||||
m_spiDriver.activate(); | |||||
} | |||||
void spiBegin(SdSpiConfig spiConfig) { | |||||
m_spiDriver.begin(spiConfig); | |||||
} | } | ||||
void spiDeactivate() { | void spiDeactivate() { | ||||
m_spiDriver->deactivate(); | |||||
m_spiDriver.deactivate(); | |||||
} | } | ||||
uint8_t spiReceive() { | uint8_t spiReceive() { | ||||
return m_spiDriver->receive(); | |||||
return m_spiDriver.receive(); | |||||
} | } | ||||
uint8_t spiReceive(uint8_t* buf, size_t n) { | uint8_t spiReceive(uint8_t* buf, size_t n) { | ||||
return m_spiDriver->receive(buf, n); | |||||
return m_spiDriver.receive(buf, n); | |||||
} | } | ||||
void spiSend(uint8_t data) { | void spiSend(uint8_t data) { | ||||
m_spiDriver->send(data); | |||||
m_spiDriver.send(data); | |||||
} | } | ||||
void spiSend(const uint8_t* buf, size_t n) { | void spiSend(const uint8_t* buf, size_t n) { | ||||
m_spiDriver->send(buf, n); | |||||
m_spiDriver.send(buf, n); | |||||
} | } | ||||
void spiSelect() { | |||||
sdCsWrite(m_csPin, false); | |||||
void spiSetSckSpeed(uint32_t maxSck) { | |||||
m_spiDriver.setSckSpeed(maxSck); | |||||
} | } | ||||
void spiUnselect() { | |||||
sdCsWrite(m_csPin, true); | |||||
SdSpiDriver m_spiDriver; | |||||
#else // SPI_DRIVER_SELECT < 2 | |||||
void spiActivate() { | |||||
m_spiDriverPtr->activate(); | |||||
} | |||||
void spiBegin(SdSpiConfig spiConfig) { | |||||
m_spiDriverPtr->begin(spiConfig); | |||||
} | |||||
void spiDeactivate() { | |||||
m_spiDriverPtr->deactivate(); | |||||
} | |||||
uint8_t spiReceive() { | |||||
return m_spiDriverPtr->receive(); | |||||
} | |||||
uint8_t spiReceive(uint8_t* buf, size_t n) { | |||||
return m_spiDriverPtr->receive(buf, n); | |||||
} | |||||
void spiSend(uint8_t data) { | |||||
m_spiDriverPtr->send(data); | |||||
} | |||||
void spiSend(const uint8_t* buf, size_t n) { | |||||
m_spiDriverPtr->send(buf, n); | |||||
} | |||||
void spiSetSckSpeed(uint32_t maxSck) { | |||||
m_spiDriverPtr->setSckSpeed(maxSck); | |||||
} | } | ||||
SdSpiDriver* m_spiDriverPtr; | |||||
#endif // SPI_DRIVER_SELECT < 2 | |||||
#if ENABLE_DEDICATED_SPI | #if ENABLE_DEDICATED_SPI | ||||
static const uint8_t IDLE_STATE = 0; | static const uint8_t IDLE_STATE = 0; | ||||
static const uint8_t READ_STATE = 1; | static const uint8_t READ_STATE = 1; | ||||
uint8_t m_curState; | uint8_t m_curState; | ||||
bool m_sharedSpi; | bool m_sharedSpi; | ||||
#endif // ENABLE_DEDICATED_SPI | #endif // ENABLE_DEDICATED_SPI | ||||
SdSpiDriver *m_spiDriver; | |||||
SdCsPin_t m_csPin; | SdCsPin_t m_csPin; | ||||
uint8_t m_errorCode; | uint8_t m_errorCode; | ||||
bool m_spiActive; | bool m_spiActive; |
#define ENABLE_ARDUINO_SERIAL 1 | #define ENABLE_ARDUINO_SERIAL 1 | ||||
/** For Debug - must be one */ | /** For Debug - must be one */ | ||||
#define ENABLE_ARDUINO_STRING 1 | #define ENABLE_ARDUINO_STRING 1 | ||||
/** Set USE_BLOCK_DEVICE_INTERFACE nonzero to use generic of block device */ | |||||
/** Set USE_BLOCK_DEVICE_INTERFACE nonzero to use generic block device */ | |||||
#define USE_BLOCK_DEVICE_INTERFACE 0 | #define USE_BLOCK_DEVICE_INTERFACE 0 | ||||
//------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
#if ENABLE_ARDUINO_FEATURES | #if ENABLE_ARDUINO_FEATURES | ||||
#include "Arduino.h" | #include "Arduino.h" | ||||
#ifdef PLATFORM_ID | #ifdef PLATFORM_ID | ||||
// Only defined if a Particle device | |||||
// Only defined if a Particle device. | |||||
#include "application.h" | #include "application.h" | ||||
#endif // PLATFORM_ID | #endif // PLATFORM_ID | ||||
#endif // ENABLE_ARDUINO_FEATURES | #endif // ENABLE_ARDUINO_FEATURES | ||||
#define INCLUDE_SDIOS 0 | #define INCLUDE_SDIOS 0 | ||||
//------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
/** | /** | ||||
* Optimize access to contiguous files. | |||||
* Experimental - set nonzero to enable. | |||||
* Set USE_FAT_FILE_FLAG_CONTIGUOUS nonzero to optimize access to | |||||
* contiguous files. | |||||
*/ | */ | ||||
#define USE_FAT_FILE_FLAG_CONTIGUOUS 1 | #define USE_FAT_FILE_FLAG_CONTIGUOUS 1 | ||||
//------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
* | * | ||||
* 1 - The standard library driver is always used. | * 1 - The standard library driver is always used. | ||||
* | * | ||||
* 2 - The software SPI driver is always used. | |||||
* 2 - An external SPI driver of SoftSpiDriver template class is always used. | |||||
* | * | ||||
* 3 - Experimental external SPI driver hook. | |||||
* 3 - An external SPI driver derived from SdSpiBaseClass is always used. | |||||
*/ | */ | ||||
#define SPI_DRIVER_SELECT 0 | #define SPI_DRIVER_SELECT 0 | ||||
//------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ |
} | } | ||||
//------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
void SdSpiArduinoDriver::send(const uint8_t *buf, size_t count) { | void SdSpiArduinoDriver::send(const uint8_t *buf, size_t count) { | ||||
// Convert byte array to 4 byte array | |||||
// If not a multiple of four. Command with CRC used six byte send. | |||||
while (count%4) { | |||||
send(*buf++); | |||||
count--; | |||||
} | |||||
// Convert byte array to 4 byte array. | |||||
uint32_t myArray[count/4]; // NOLINT | uint32_t myArray[count/4]; // NOLINT | ||||
for (int x = 0; x < count/4; x++) { | for (int x = 0; x < count/4; x++) { | ||||
myArray[x] = ((uint32_t)buf[(x * 4) + 3] << (8 * 3)) | | myArray[x] = ((uint32_t)buf[(x * 4) + 3] << (8 * 3)) | |
/** Activate SPI hardware. */ | /** Activate SPI hardware. */ | ||||
virtual void activate() {} | virtual void activate() {} | ||||
/** Initialize the SPI bus. */ | /** Initialize the SPI bus. */ | ||||
virtual void begin() = 0; | |||||
virtual void begin(SdSpiConfig config) = 0; | |||||
/** Deactivate SPI hardware. */ | /** Deactivate SPI hardware. */ | ||||
virtual void deactivate() {} | virtual void deactivate() {} | ||||
/** Receive a byte. | /** Receive a byte. | ||||
*/ | */ | ||||
virtual void setSckSpeed(uint32_t maxSck) {(void)maxSck;} | virtual void setSckSpeed(uint32_t maxSck) {(void)maxSck;} | ||||
}; | }; | ||||
#include "SPI.h" | |||||
/** | |||||
* \class MySpiClass | |||||
* \brief Sample external SPI class. | |||||
*/ | |||||
class MySpiClass : public SdSpiBaseClass { | |||||
public: | |||||
/** Activate SPI hardware. */ | |||||
void activate() { | |||||
SPI.beginTransaction(m_spiSettings); | |||||
} | |||||
/** Initialize the SPI bus. */ | |||||
void begin() {SPI.begin();} | |||||
/** Deactivate SPI hardware. */ | |||||
void deactivate() {SPI.endTransaction();} | |||||
/** Receive a byte. | |||||
* | |||||
* \return The byte. | |||||
*/ | |||||
uint8_t receive() {return SPI.transfer(0XFF);} | |||||
/** Receive multiple bytes. | |||||
* | |||||
* \param[out] buf Buffer to receive the data. | |||||
* \param[in] count Number of bytes to receive. | |||||
* | |||||
* \return Zero for no error or nonzero error code. | |||||
*/ | |||||
uint8_t receive(uint8_t* buf, size_t count) { | |||||
for (size_t i = 0; i < count; i++) { | |||||
buf[i] = SPI.transfer(0XFF); | |||||
} | |||||
return 0; | |||||
} | |||||
/** Send a byte. | |||||
* | |||||
* \param[in] data Byte to send | |||||
*/ | |||||
void send(uint8_t data) {SPI.transfer(data);} | |||||
/** Send multiple bytes. | |||||
* | |||||
* \param[in] buf Buffer for data to be sent. | |||||
* \param[in] count Number of bytes to send. | |||||
*/ | |||||
void send(const uint8_t* buf, size_t count) { | |||||
for (size_t i = 0; i < count; i++) { | |||||
SPI.transfer(buf[i]); | |||||
} | |||||
} | |||||
/** Save high speed SPISettings after SD initialization. | |||||
* | |||||
* \param[in] maxSck Maximum SCK frequency. | |||||
*/ | |||||
void setSckSpeed(uint32_t maxSck) { | |||||
m_spiSettings = SPISettings(maxSck, MSBFIRST, SPI_MODE0); | |||||
} | |||||
private: | |||||
SPISettings m_spiSettings; | |||||
}; | |||||
#endif // SdSpiBaseClass_h | #endif // SdSpiBaseClass_h |
void sdCsWrite(SdCsPin_t pin, bool level) { | void sdCsWrite(SdCsPin_t pin, bool level) { | ||||
digitalWrite(pin, level); | digitalWrite(pin, level); | ||||
} | } | ||||
//------------------------------------------------------------------------------ | |||||
#elif SD_CHIP_SELECT_MODE == 1 | #elif SD_CHIP_SELECT_MODE == 1 | ||||
//------------------------------------------------------------------------------ | |||||
__attribute__((weak)) | __attribute__((weak)) | ||||
void sdCsInit(SdCsPin_t pin) { | void sdCsInit(SdCsPin_t pin) { | ||||
pinMode(pin, OUTPUT); | pinMode(pin, OUTPUT); |
#define SD_SCK_HZ(maxSpeed) (maxSpeed) | #define SD_SCK_HZ(maxSpeed) (maxSpeed) | ||||
/** SPISettings for SCK frequency in MHz. */ | /** SPISettings for SCK frequency in MHz. */ | ||||
#define SD_SCK_MHZ(maxMhz) (1000000UL*(maxMhz)) | #define SD_SCK_MHZ(maxMhz) (1000000UL*(maxMhz)) | ||||
// SPI divisor constants | |||||
// SPI divisor constants - obsolete. | |||||
/** Set SCK to max rate. */ | /** Set SCK to max rate. */ | ||||
#define SPI_FULL_SPEED SD_SCK_MHZ(50) | #define SPI_FULL_SPEED SD_SCK_MHZ(50) | ||||
/** Set SCK rate to F_CPU/3 for Due */ | |||||
#define SPI_DIV3_SPEED SD_SCK_HZ(F_CPU/3) | |||||
/** Set SCK rate to F_CPU/4. */ | |||||
#define SPI_HALF_SPEED SD_SCK_HZ(F_CPU/4) | |||||
/** Set SCK rate to F_CPU/6 for Due */ | |||||
#define SPI_DIV6_SPEED SD_SCK_HZ(F_CPU/6) | |||||
/** Set SCK rate to F_CPU/8. */ | |||||
#define SPI_QUARTER_SPEED SD_SCK_HZ(F_CPU/8) | |||||
/** Set SCK rate to F_CPU/16. */ | |||||
#define SPI_EIGHTH_SPEED SD_SCK_HZ(F_CPU/16) | |||||
/** Set SCK rate to F_CPU/32. */ | |||||
#define SPI_SIXTEENTH_SPEED SD_SCK_HZ(F_CPU/32) | |||||
/** Set SCK rate to 16 MHz for Due */ | |||||
#define SPI_DIV3_SPEED SD_SCK_MHZ(16) | |||||
/** Set SCK rate to 4 MHz for AVR. */ | |||||
#define SPI_HALF_SPEED SD_SCK_MHZ(4) | |||||
/** Set SCK rate to 8 MHz for Due */ | |||||
#define SPI_DIV6_SPEED SD_SCK_MHZ(8) | |||||
/** Set SCK rate to 2 MHz for AVR. */ | |||||
#define SPI_QUARTER_SPEED SD_SCK_MHZ(2) | |||||
/** Set SCK rate to 1 MHz for AVR. */ | |||||
#define SPI_EIGHTH_SPEED SD_SCK_MHZ(1) | |||||
/** Set SCK rate to 500 kHz for AVR. */ | |||||
#define SPI_SIXTEENTH_SPEED SD_SCK_HZ(500000) | |||||
//------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
/** The SD is the only device on the SPI bus. */ | /** The SD is the only device on the SPI bus. */ | ||||
#define DEDICATED_SPI 0X80 | #define DEDICATED_SPI 0X80 | ||||
#define SHARED_SPI 0 | #define SHARED_SPI 0 | ||||
#if SPI_DRIVER_SELECT < 2 | #if SPI_DRIVER_SELECT < 2 | ||||
#include "SPI.h" | #include "SPI.h" | ||||
/** Port type for SPI hardware driver. */ | |||||
/** Port type for Arduino SPI hardware driver. */ | |||||
typedef SPIClass SpiPort_t; | typedef SPIClass SpiPort_t; | ||||
#elif SPI_DRIVER_SELECT == 2 | #elif SPI_DRIVER_SELECT == 2 | ||||
class SoftSPIClass; | |||||
class SdSpiSoftDriver; | |||||
/** Port type for software SPI driver. */ | /** Port type for software SPI driver. */ | ||||
typedef SoftSPIClass SpiPort_t; | |||||
#else // SPI_DRIVER_SELECT | |||||
#include "SdSpiBaseClass.h" | |||||
typedef SdSpiSoftDriver SpiPort_t; | |||||
#elif SPI_DRIVER_SELECT == 3 | |||||
class SdSpiBaseClass; | |||||
/** Port type for extrernal SPI driver. */ | |||||
typedef SdSpiBaseClass SpiPort_t; | typedef SdSpiBaseClass SpiPort_t; | ||||
#else // SPI_DRIVER_SELECT | |||||
typedef void* SpiPort_t; | |||||
#endif // SPI_DRIVER_SELECT | #endif // SPI_DRIVER_SELECT | ||||
//------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
/** | /** | ||||
* \param[in] opt Options. | * \param[in] opt Options. | ||||
*/ | */ | ||||
SdSpiConfig(SdCsPin_t cs, uint8_t opt) : | SdSpiConfig(SdCsPin_t cs, uint8_t opt) : | ||||
csPin(cs), options(opt), maxSck(SPI_FULL_SPEED), spiPort(nullptr) {} | |||||
csPin(cs), options(opt), maxSck(SD_SCK_MHZ(50)), spiPort(nullptr) {} | |||||
/** SdSpiConfig constructor. | /** SdSpiConfig constructor. | ||||
* | * | ||||
* \param[in] cs Chip select pin. | * \param[in] cs Chip select pin. | ||||
*/ | */ | ||||
explicit SdSpiConfig(SdCsPin_t cs) : csPin(cs), options(SHARED_SPI), | explicit SdSpiConfig(SdCsPin_t cs) : csPin(cs), options(SHARED_SPI), | ||||
maxSck(SPI_FULL_SPEED), spiPort(nullptr) {} | |||||
maxSck(SD_SCK_MHZ(50)), spiPort(nullptr) {} | |||||
/** Chip select pin. */ | /** Chip select pin. */ | ||||
const SdCsPin_t csPin; | const SdCsPin_t csPin; | ||||
/** SPI port */ | /** SPI port */ | ||||
SpiPort_t* spiPort; | SpiPort_t* spiPort; | ||||
}; | }; | ||||
#if SPI_DRIVER_SELECT < 2 | #if SPI_DRIVER_SELECT < 2 | ||||
#include "SdSpiArduinoDriver.h" | #include "SdSpiArduinoDriver.h" | ||||
#elif SPI_DRIVER_SELECT == 2 | #elif SPI_DRIVER_SELECT == 2 | ||||
#include "SdSpiSoftDriver.h" | #include "SdSpiSoftDriver.h" | ||||
#elif SPI_DRIVER_SELECT == 3 | #elif SPI_DRIVER_SELECT == 3 | ||||
#include "SdSpiExternalDriver.h" | |||||
#elif SPI_DRIVER_SELECT == 4 | |||||
#include "SdSpiBareUnoDriver.h" | |||||
typedef SdSpiDriverBareUno SdSpiDriver; | |||||
#include "SdSpiBaseClass.h" | |||||
typedef SdSpiBaseClass SdSpiDriver; | |||||
#else // SPI_DRIVER_SELECT | #else // SPI_DRIVER_SELECT | ||||
#error Invalid SPI_DRIVER_SELECT | #error Invalid SPI_DRIVER_SELECT | ||||
#endif // SPI_DRIVER_SELECT | #endif // SPI_DRIVER_SELECT |
/** | |||||
* Copyright (c) 2011-2019 Bill Greiman | |||||
* This file is part of the SdFat library for SD memory cards. | |||||
* | |||||
* MIT License | |||||
* | |||||
* Permission is hereby granted, free of charge, to any person obtaining a | |||||
* copy of this software and associated documentation files (the "Software"), | |||||
* to deal in the Software without restriction, including without limitation | |||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense, | |||||
* and/or sell copies of the Software, and to permit persons to whom the | |||||
* Software is furnished to do so, subject to the following conditions: | |||||
* | |||||
* The above copyright notice and this permission notice shall be included | |||||
* in all copies or substantial portions of the Software. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |||||
* DEALINGS IN THE SOFTWARE. | |||||
*/ | |||||
/** | |||||
* \file | |||||
* \brief Class for external drivers. | |||||
*/ | |||||
#ifndef SdSpiExternalDriver_h | |||||
#define SdSpiExternalDriver_h | |||||
/** | |||||
* \class SdExternalSpiDriver | |||||
* \brief Class for external SPI. | |||||
*/ | |||||
class SdExternalSpiDriver { | |||||
public: | |||||
/** Activate SPI hardware. */ | |||||
void activate() {if (m_spi) m_spi->activate();} | |||||
/** Initialize the SPI bus. | |||||
* | |||||
* \param[in] spiConfig SD card configuration. | |||||
*/ | |||||
void begin(SdSpiConfig spiConfig) { | |||||
m_spi = spiConfig.spiPort; | |||||
if (m_spi) m_spi->begin(); | |||||
} | |||||
/** Deactivate SPI hardware. */ | |||||
void deactivate() {if (m_spi) m_spi->deactivate();} | |||||
/** Receive a byte. | |||||
* | |||||
* \return The byte. | |||||
*/ | |||||
uint8_t receive() {return m_spi ? m_spi->receive(): 0XFF;} | |||||
/** Receive multiple bytes. | |||||
* | |||||
* \param[out] buf Buffer to receive the data. | |||||
* \param[in] count Number of bytes to receive. | |||||
* | |||||
* \return Zero for no error or nonzero error code. | |||||
*/ | |||||
uint8_t receive(uint8_t* buf, size_t count) { | |||||
return m_spi ? m_spi->receive(buf, count) : 1; | |||||
} | |||||
/** Send a byte. | |||||
* | |||||
* \param[in] data Byte to send | |||||
*/ | |||||
void send(uint8_t data) {if (m_spi) m_spi->send(data);} | |||||
/** Send multiple bytes. | |||||
* | |||||
* \param[in] buf Buffer for data to be sent. | |||||
* \param[in] count Number of bytes to send. | |||||
*/ | |||||
void send(const uint8_t* buf, size_t count) { | |||||
if (m_spi) m_spi->send(buf, count); | |||||
} | |||||
/** Save high speed SPISettings after SD initialization. | |||||
* | |||||
* \param[in] maxSck Maximum SCK frequency. | |||||
*/ | |||||
void setSckSpeed(uint32_t maxSck) { | |||||
if (m_spi) m_spi->setSckSpeed(maxSck); | |||||
} | |||||
private: | |||||
SdSpiBaseClass* m_spi; | |||||
}; | |||||
/** Typedef for use of SdExternalSpiDriver */ | |||||
typedef SdExternalSpiDriver SdSpiDriver; | |||||
#endif // SdSpiExternalDriver_h |
#define SdSpiSoftDriver_h | #define SdSpiSoftDriver_h | ||||
#include "../DigitalIO/SoftSPI.h" | #include "../DigitalIO/SoftSPI.h" | ||||
/** | /** | ||||
* \class SoftSPIClass | |||||
* \class SdSpiSoftDriver | |||||
* \brief Base class for external soft SPI. | * \brief Base class for external soft SPI. | ||||
*/ | */ | ||||
class SoftSPIClass { | |||||
public: | |||||
/** Initialize the SPI bus. */ | |||||
virtual void begin() = 0; | |||||
/** Receive a byte. | |||||
* | |||||
* \return The byte. | |||||
*/ | |||||
virtual uint8_t receive() = 0; | |||||
/** Send a byte. | |||||
* | |||||
* \param[in] data Byte to send | |||||
*/ | |||||
virtual void send(uint8_t data) = 0; | |||||
}; | |||||
//------------------------------------------------------------------------------ | |||||
/** | |||||
* \class SoftSpiDriver | |||||
* \brief Class for external soft SPI. | |||||
*/ | |||||
template<uint8_t MisoPin, uint8_t MosiPin, uint8_t SckPin> | |||||
class SoftSpiDriver : public SoftSPIClass { | |||||
public: | |||||
/** Initialize the SPI bus. */ | |||||
void begin() {m_spi.begin();} | |||||
/** Receive a byte. | |||||
* | |||||
* \return The byte. | |||||
*/ | |||||
uint8_t receive() {return m_spi.receive();} | |||||
/** Send a byte. | |||||
* | |||||
* \param[in] data Byte to send | |||||
*/ | |||||
void send(uint8_t data) {m_spi.send(data);} | |||||
private: | |||||
SoftSPI<MisoPin, MosiPin, SckPin, 0> m_spi; | |||||
}; | |||||
//------------------------------------------------------------------------------ | |||||
/** | |||||
* \class SdSoftSpiDriver | |||||
* \brief Class for SdSoftSpiDriver. | |||||
*/ | |||||
class SdSoftSpiDriver { | |||||
class SdSpiSoftDriver { | |||||
public: | public: | ||||
/** Activate SPI hardware. */ | /** Activate SPI hardware. */ | ||||
void activate() {} | void activate() {} | ||||
/** Initialize the SPI bus. */ | |||||
virtual void begin() = 0; | |||||
/** Initialize the SPI bus. | /** Initialize the SPI bus. | ||||
* | * | ||||
* \param[in] spiConfig SD card configuration. | * \param[in] spiConfig SD card configuration. | ||||
*/ | */ | ||||
void begin(SdSpiConfig spiConfig) { | void begin(SdSpiConfig spiConfig) { | ||||
m_spi = spiConfig.spiPort; | |||||
if (m_spi) m_spi->begin(); | |||||
(void)spiConfig; | |||||
begin(); | |||||
} | } | ||||
/** Deactivate SPI hardware. */ | /** Deactivate SPI hardware. */ | ||||
void deactivate() {} | void deactivate() {} | ||||
* | * | ||||
* \return The byte. | * \return The byte. | ||||
*/ | */ | ||||
uint8_t receive() {return m_spi ? m_spi->receive() : 0XFF;} | |||||
virtual uint8_t receive() = 0; | |||||
/** Receive multiple bytes. | /** Receive multiple bytes. | ||||
* | |||||
* \param[out] buf Buffer to receive the data. | |||||
* \param[in] count Number of bytes to receive. | |||||
* | |||||
* \return Zero for no error or nonzero error code. | |||||
*/ | |||||
* | |||||
* \param[out] buf Buffer to receive the data. | |||||
* \param[in] count Number of bytes to receive. | |||||
* | |||||
* \return Zero for no error or nonzero error code. | |||||
*/ | |||||
uint8_t receive(uint8_t* buf, size_t count) { | uint8_t receive(uint8_t* buf, size_t count) { | ||||
for (size_t i = 0; i < count; i++) { | for (size_t i = 0; i < count; i++) { | ||||
buf[i] = receive(); | buf[i] = receive(); | ||||
* | * | ||||
* \param[in] data Byte to send | * \param[in] data Byte to send | ||||
*/ | */ | ||||
void send(uint8_t data) {if (m_spi) m_spi->send(data);} | |||||
virtual void send(uint8_t data) = 0; | |||||
/** Send multiple bytes. | /** Send multiple bytes. | ||||
* | * | ||||
* \param[in] buf Buffer for data to be sent. | * \param[in] buf Buffer for data to be sent. | ||||
void setSckSpeed(uint32_t maxSck) { | void setSckSpeed(uint32_t maxSck) { | ||||
(void)maxSck; | (void)maxSck; | ||||
} | } | ||||
}; | |||||
//------------------------------------------------------------------------------ | |||||
/** | |||||
* \class SoftSpiDriver | |||||
* \brief Class for external soft SPI. | |||||
*/ | |||||
template<uint8_t MisoPin, uint8_t MosiPin, uint8_t SckPin> | |||||
class SoftSpiDriver : public SdSpiSoftDriver { | |||||
public: | |||||
/** Initialize the SPI bus. */ | |||||
void begin() {m_spi.begin();} | |||||
/** Receive a byte. | |||||
* | |||||
* \return The byte. | |||||
*/ | |||||
uint8_t receive() {return m_spi.receive();} | |||||
/** Send a byte. | |||||
* | |||||
* \param[in] data Byte to send | |||||
*/ | |||||
void send(uint8_t data) {m_spi.send(data);} | |||||
private: | private: | ||||
SoftSPIClass* m_spi; | |||||
SoftSPI<MisoPin, MosiPin, SckPin, 0> m_spi; | |||||
}; | }; | ||||
/** Typedef for use of SdSoftSpiDriver */ | /** Typedef for use of SdSoftSpiDriver */ | ||||
typedef SdSoftSpiDriver SdSpiDriver; | |||||
typedef SdSpiSoftDriver SdSpiDriver; | |||||
#endif // SdSpiSoftDriver_h | #endif // SdSpiSoftDriver_h |