@@ -13,7 +13,7 @@ const uint8_t SD_CS_PIN = SS; | |||
const uint8_t SD_CS_PIN = 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) | |||
SdExFat sd; |
@@ -0,0 +1,47 @@ | |||
// 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 |
@@ -0,0 +1,78 @@ | |||
// 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 |
@@ -109,7 +109,7 @@ void setup() { | |||
delay(200); // Catch Due reset problem | |||
// 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)) { | |||
sd.initErrorHalt(&Serial); | |||
} |
@@ -62,7 +62,7 @@ void setup() { | |||
delay(200); // Catch Due reset problem | |||
// 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)) { | |||
sd.initErrorHalt(&Serial); | |||
} |
@@ -1,47 +1,50 @@ | |||
2017-08-10 | |||
2019-12-10 | |||
Run the SdErrorCode example to produce an updated list. | |||
C | |||
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 | |||
0X11,SD_CARD_ERROR_CMD38 - Erase selected blocks | |||
0X12,SD_CARD_ERROR_CMD58 - Read OCR register | |||
0X13,SD_CARD_ERROR_CMD59 - Set CRC mode | |||
0X14,SD_CARD_ERROR_ACMD6 - Set SDIO bus width | |||
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 |
@@ -1,5 +1,5 @@ | |||
name=SdFat | |||
version=2.0.0-beta.7 | |||
version=2.0.0-beta.8 | |||
license=MIT | |||
author=Bill Greiman <fat16lib@sbcglobal.net> | |||
maintainer=Bill Greiman <fat16lib@sbcglobal.net> |
@@ -508,6 +508,8 @@ size_t ExFatFile::printName(print_t* pr) { | |||
DirName_t* dn; | |||
DirPos_t pos = m_dirPos; | |||
size_t n = 0; | |||
uint8_t in; | |||
uint8_t buf[15]; | |||
if (!isOpen()) { | |||
DBG_FAIL_MACRO; | |||
goto fail; | |||
@@ -523,16 +525,16 @@ size_t ExFatFile::printName(print_t* pr) { | |||
DBG_FAIL_MACRO; | |||
goto fail; | |||
} | |||
for (uint8_t in = 0; in < 15; in++) { | |||
for (in = 0; in < 15; in++) { | |||
uint16_t c = getLe16(dn->unicode + 2*in); | |||
if (!c) { | |||
goto done; | |||
break;; | |||
} | |||
pr->write(c < 0X7f ? c : '?'); | |||
buf[in] = c < 0X7f ? c : '?'; | |||
n++; | |||
} | |||
pr->write(buf, in); | |||
} | |||
done: | |||
return n; | |||
fail: |
@@ -506,9 +506,11 @@ fail: | |||
//------------------------------------------------------------------------------ | |||
size_t FatFile::printName(print_t* pr) { | |||
FatFile dirFile; | |||
uint16_t u; | |||
size_t n = 0; | |||
DirLfn_t* ldir; | |||
size_t n = 0; | |||
uint16_t u; | |||
uint8_t buf[13]; | |||
uint8_t i; | |||
if (!isLFN()) { | |||
return printSFN(pr); | |||
@@ -532,24 +534,18 @@ size_t FatFile::printName(print_t* pr) { | |||
DBG_FAIL_MACRO; | |||
goto fail; | |||
} | |||
for (uint8_t i = 0; i < 13; i++) { | |||
for (i = 0; i < 13; i++) { | |||
u = lfnGetChar(ldir, i); | |||
if (u == 0) { | |||
// End of name. | |||
break; | |||
} | |||
if (u > 0X7E) { | |||
u = '?'; | |||
} | |||
pr->write(static_cast<char>(u)); | |||
buf[i] = u < 0X7F ? u : '?'; | |||
n++; | |||
} | |||
if (ldir->order & FAT_ORDER_LAST_LONG_ENTRY) { | |||
return n; | |||
} | |||
pr->write(buf, i); | |||
} | |||
// Fall into fail; | |||
DBG_FAIL_MACRO; | |||
return n; | |||
fail: | |||
return 0; |
@@ -25,7 +25,8 @@ | |||
#include "FsLib.h" | |||
//------------------------------------------------------------------------------ | |||
FsBaseFile::FsBaseFile(const FsBaseFile& from) { | |||
close(); | |||
m_fFile = nullptr; | |||
m_xFile = nullptr; | |||
if (from.m_fFile) { | |||
m_fFile = new (m_fileMem) FatFile; | |||
*m_fFile = *from.m_fFile; |
@@ -55,7 +55,7 @@ class SdCardFactory { | |||
* \return generic card pointer. | |||
*/ | |||
SdCard* newCard(SdSpiConfig config) { | |||
m_spiCard.begin(&m_spi, config); | |||
m_spiCard.begin(config); | |||
return &m_spiCard; | |||
} | |||
/** Initialize SDIO card. | |||
@@ -78,6 +78,5 @@ class SdCardFactory { | |||
SdioCard m_sdioCard; | |||
#endif // HAS_SDIO_CLASS | |||
SdSpiCard m_spiCard; | |||
SdSpiDriver m_spi; | |||
}; | |||
#endif // SdCard_h |
@@ -220,16 +220,22 @@ static uint16_t CRC_CCITT(const uint8_t* data, size_t n) { | |||
//============================================================================== | |||
// 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_type = 0; | |||
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); | |||
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; | |||
#if ENABLE_DEDICATED_SPI | |||
m_sharedSpi = !(spiConfig.options & DEDICATED_SPI); | |||
@@ -317,7 +323,7 @@ bool SdSpiCard::begin(SdSpiDriver* spi, SdSpiConfig spiConfig) { | |||
} | |||
} | |||
spiStop(); | |||
m_spiDriver->setSckSpeed(spiConfig.maxSck); | |||
spiSetSckSpeed(spiConfig.maxSck); | |||
return true; | |||
fail: |
@@ -53,7 +53,7 @@ class SdSpiCard { | |||
* \param[in] spiConfig SPI card configuration. | |||
* \return true for success or false for failure. | |||
*/ | |||
bool begin(SdSpiDriver* spi, SdSpiConfig spiConfig); | |||
bool begin(SdSpiConfig spiConfig); | |||
/** Clear debug stats. */ | |||
void dbgClearStats(); | |||
/** Print debug stats. */ | |||
@@ -285,40 +285,71 @@ class SdSpiCard { | |||
bool isTimedOut(SdMillis_t startMS, SdMillis_t timeoutMS); | |||
bool readData(uint8_t* dst, size_t count); | |||
bool readRegister(uint8_t cmd, void* buf); | |||
void spiSelect() { | |||
sdCsWrite(m_csPin, false); | |||
} | |||
void type(uint8_t value) { | |||
m_type = value; | |||
} | |||
void spiUnselect() { | |||
sdCsWrite(m_csPin, true); | |||
} | |||
bool waitNotBusy(SdMillis_t timeoutMS); | |||
bool writeData(uint8_t token, const uint8_t* src); | |||
//--------------------------------------------------------------------------- | |||
// functions defined in SdSpiDriver.h | |||
#if SPI_DRIVER_SELECT < 2 | |||
void spiActivate() { | |||
m_spiDriver->activate(); | |||
m_spiDriver.activate(); | |||
} | |||
void spiBegin(SdSpiConfig spiConfig) { | |||
m_spiDriver.begin(spiConfig); | |||
} | |||
void spiDeactivate() { | |||
m_spiDriver->deactivate(); | |||
m_spiDriver.deactivate(); | |||
} | |||
uint8_t spiReceive() { | |||
return m_spiDriver->receive(); | |||
return m_spiDriver.receive(); | |||
} | |||
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) { | |||
m_spiDriver->send(data); | |||
m_spiDriver.send(data); | |||
} | |||
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 | |||
static const uint8_t IDLE_STATE = 0; | |||
static const uint8_t READ_STATE = 1; | |||
@@ -327,7 +358,6 @@ class SdSpiCard { | |||
uint8_t m_curState; | |||
bool m_sharedSpi; | |||
#endif // ENABLE_DEDICATED_SPI | |||
SdSpiDriver *m_spiDriver; | |||
SdCsPin_t m_csPin; | |||
uint8_t m_errorCode; | |||
bool m_spiActive; |
@@ -38,13 +38,13 @@ | |||
#define ENABLE_ARDUINO_SERIAL 1 | |||
/** For Debug - must be one */ | |||
#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 | |||
//------------------------------------------------------------------------------ | |||
#if ENABLE_ARDUINO_FEATURES | |||
#include "Arduino.h" | |||
#ifdef PLATFORM_ID | |||
// Only defined if a Particle device | |||
// Only defined if a Particle device. | |||
#include "application.h" | |||
#endif // PLATFORM_ID | |||
#endif // ENABLE_ARDUINO_FEATURES | |||
@@ -56,8 +56,8 @@ | |||
#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 | |||
//------------------------------------------------------------------------------ | |||
@@ -101,9 +101,9 @@ | |||
* | |||
* 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 | |||
//------------------------------------------------------------------------------ |
@@ -56,7 +56,12 @@ void SdSpiArduinoDriver::send(uint8_t data) { | |||
} | |||
//------------------------------------------------------------------------------ | |||
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 | |||
for (int x = 0; x < count/4; x++) { | |||
myArray[x] = ((uint32_t)buf[(x * 4) + 3] << (8 * 3)) | |
@@ -37,7 +37,7 @@ class SdSpiBaseClass { | |||
/** Activate SPI hardware. */ | |||
virtual void activate() {} | |||
/** Initialize the SPI bus. */ | |||
virtual void begin() = 0; | |||
virtual void begin(SdSpiConfig config) = 0; | |||
/** Deactivate SPI hardware. */ | |||
virtual void deactivate() {} | |||
/** Receive a byte. | |||
@@ -70,63 +70,4 @@ class SdSpiBaseClass { | |||
*/ | |||
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 |
@@ -33,8 +33,8 @@ void sdCsInit(SdCsPin_t pin) { | |||
void sdCsWrite(SdCsPin_t pin, bool level) { | |||
digitalWrite(pin, level); | |||
} | |||
//------------------------------------------------------------------------------ | |||
#elif SD_CHIP_SELECT_MODE == 1 | |||
//------------------------------------------------------------------------------ | |||
__attribute__((weak)) | |||
void sdCsInit(SdCsPin_t pin) { | |||
pinMode(pin, OUTPUT); |
@@ -47,21 +47,21 @@ void sdCsWrite(SdCsPin_t pin, bool level); | |||
#define SD_SCK_HZ(maxSpeed) (maxSpeed) | |||
/** SPISettings for SCK frequency in MHz. */ | |||
#define SD_SCK_MHZ(maxMhz) (1000000UL*(maxMhz)) | |||
// SPI divisor constants | |||
// SPI divisor constants - obsolete. | |||
/** Set SCK to max rate. */ | |||
#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. */ | |||
#define DEDICATED_SPI 0X80 | |||
@@ -69,15 +69,18 @@ void sdCsWrite(SdCsPin_t pin, bool level); | |||
#define SHARED_SPI 0 | |||
#if SPI_DRIVER_SELECT < 2 | |||
#include "SPI.h" | |||
/** Port type for SPI hardware driver. */ | |||
/** Port type for Arduino SPI hardware driver. */ | |||
typedef SPIClass SpiPort_t; | |||
#elif SPI_DRIVER_SELECT == 2 | |||
class SoftSPIClass; | |||
class SdSpiSoftDriver; | |||
/** 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; | |||
#else // SPI_DRIVER_SELECT | |||
typedef void* SpiPort_t; | |||
#endif // SPI_DRIVER_SELECT | |||
//------------------------------------------------------------------------------ | |||
/** | |||
@@ -110,13 +113,13 @@ class SdSpiConfig { | |||
* \param[in] opt Options. | |||
*/ | |||
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. | |||
* | |||
* \param[in] cs Chip select pin. | |||
*/ | |||
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. */ | |||
const SdCsPin_t csPin; | |||
@@ -127,16 +130,13 @@ class SdSpiConfig { | |||
/** SPI port */ | |||
SpiPort_t* spiPort; | |||
}; | |||
#if SPI_DRIVER_SELECT < 2 | |||
#include "SdSpiArduinoDriver.h" | |||
#elif SPI_DRIVER_SELECT == 2 | |||
#include "SdSpiSoftDriver.h" | |||
#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 | |||
#error Invalid SPI_DRIVER_SELECT | |||
#endif // SPI_DRIVER_SELECT |
@@ -1,90 +0,0 @@ | |||
/** | |||
* 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 |
@@ -30,64 +30,22 @@ | |||
#define SdSpiSoftDriver_h | |||
#include "../DigitalIO/SoftSPI.h" | |||
/** | |||
* \class SoftSPIClass | |||
* \class SdSpiSoftDriver | |||
* \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: | |||
/** Activate SPI hardware. */ | |||
void activate() {} | |||
/** Initialize the SPI bus. */ | |||
virtual void begin() = 0; | |||
/** Initialize the SPI bus. | |||
* | |||
* \param[in] spiConfig SD card configuration. | |||
*/ | |||
void begin(SdSpiConfig spiConfig) { | |||
m_spi = spiConfig.spiPort; | |||
if (m_spi) m_spi->begin(); | |||
(void)spiConfig; | |||
begin(); | |||
} | |||
/** Deactivate SPI hardware. */ | |||
void deactivate() {} | |||
@@ -95,14 +53,14 @@ class SdSoftSpiDriver { | |||
* | |||
* \return The byte. | |||
*/ | |||
uint8_t receive() {return m_spi ? m_spi->receive() : 0XFF;} | |||
virtual uint8_t receive() = 0; | |||
/** 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) { | |||
for (size_t i = 0; i < count; i++) { | |||
buf[i] = receive(); | |||
@@ -113,7 +71,7 @@ class SdSoftSpiDriver { | |||
* | |||
* \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. | |||
* | |||
* \param[in] buf Buffer for data to be sent. | |||
@@ -131,10 +89,31 @@ class SdSoftSpiDriver { | |||
void setSckSpeed(uint32_t 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: | |||
SoftSPIClass* m_spi; | |||
SoftSPI<MisoPin, MosiPin, SckPin, 0> m_spi; | |||
}; | |||
/** Typedef for use of SdSoftSpiDriver */ | |||
typedef SdSoftSpiDriver SdSpiDriver; | |||
typedef SdSpiSoftDriver SdSpiDriver; | |||
#endif // SdSpiSoftDriver_h |