### Warning: This beta is for testing with Particle IoT mesh devices. | ### Warning: This beta is for testing with Particle IoT mesh devices. | ||||
This version of SdFat has been modified to use standard POSIX/Linux | |||||
definitions of open flags from fcntl.h. | |||||
Open flags are access modes, O_RDONLY, O_RDWR, O_WRONLY, and modifiers | |||||
O_APPEND, O_CREAT, O_EXCL, O_SYNC, O_TRUNC. | |||||
Rename this folder SdFat and place it in the standard place for libraries. | Rename this folder SdFat and place it in the standard place for libraries. | ||||
I tested with a particle CLI project with a SdFat in a lib | I tested with a particle CLI project with a SdFat in a lib | ||||
src: | src: | ||||
SdFatMod.ino | SdFatMod.ino | ||||
``` | ``` | ||||
Changess Version 1.0.10: | |||||
Added custom Particle driver to use DMA and allow use of SPI1. | |||||
To use SPI1 declare SdFat/SdFatEX class like this: | |||||
``` | |||||
SdFat sd1(&SPI1); | |||||
// or | |||||
SdFatEX sd1(&SPI1); | |||||
``` | |||||
Changed STM32 use of SPI ports. See STM32Test example. | |||||
To use second SPI port: | |||||
``` | |||||
// Use second SPI port | |||||
SPIClass SPI_2(2); | |||||
SdFat sd2(&SPI_2); | |||||
``` | |||||
Changes Version 1.0.9: | |||||
This version of SdFat has been modified to use standard POSIX/Linux | |||||
definitions of open flags from fcntl.h. | |||||
Open flags are access modes, O_RDONLY, O_RDWR, O_WRONLY, and modifiers | |||||
O_APPEND, O_CREAT, O_EXCL, O_SYNC, O_TRUNC. | |||||
The mods required changing the type for open flags from uint8_t to int so | The mods required changing the type for open flags from uint8_t to int so | ||||
bugs are likely if any uint8_t local variables were missed. | bugs are likely if any uint8_t local variables were missed. |
// set ENABLE_EXTENDED_TRANSFER_CLASS non-zero to use faster EX classes | // set ENABLE_EXTENDED_TRANSFER_CLASS non-zero to use faster EX classes | ||||
// Use first SPI port | // Use first SPI port | ||||
SdFat sd1(1); | |||||
// SdFatEX sd1(1); | |||||
SdFat sd1; | |||||
// SdFatEX sd1; | |||||
const uint8_t SD1_CS = PA4; // chip select for sd1 | const uint8_t SD1_CS = PA4; // chip select for sd1 | ||||
// Use second SPI port | // Use second SPI port | ||||
SdFat sd2(2); | |||||
// SdFatEX sd2(2); | |||||
SPIClass SPI_2(2); | |||||
SdFat sd2(&SPI_2); | |||||
// SdFatEX sd2(&SPI_2); | |||||
const uint8_t SD2_CS = PB12; // chip select for sd2 | const uint8_t SD2_CS = PB12; // chip select for sd2 | ||||
const uint8_t BUF_DIM = 100; | const uint8_t BUF_DIM = 100; | ||||
Serial.println(F("Done")); | Serial.println(F("Done")); | ||||
} | } | ||||
//------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
void loop() {} | |||||
void loop() {} |
while (!Serial.available()) { | while (!Serial.available()) { | ||||
SysCall::yield(); | SysCall::yield(); | ||||
} | } | ||||
cout << F("chipSelect: ") << int(chipSelect) << endl; | |||||
cout << F("FreeStack: ") << FreeStack() << endl; | cout << F("FreeStack: ") << FreeStack() << endl; | ||||
#if USE_SDIO | #if USE_SDIO |
/** | /** | ||||
* Copyright (c) 20011-2017 Bill Greiman | |||||
* Copyright (c) 20011-2018 Bill Greiman | |||||
* This file is part of the SdFat library for SD memory cards. | * This file is part of the SdFat library for SD memory cards. | ||||
* | * | ||||
* MIT License | * MIT License | ||||
*/ | */ | ||||
/** | /** | ||||
\mainpage Arduino %SdFat Library | \mainpage Arduino %SdFat Library | ||||
<CENTER>Copyright © 2012, 2013, 2014, 2015, 2016 by William Greiman | |||||
<CENTER>Copyright © 2012-2018 by William Greiman | |||||
</CENTER> | </CENTER> | ||||
\section Intro Introduction | \section Intro Introduction |
name=SdFat | name=SdFat | ||||
version=1.0.9 | |||||
version=1.0.10 | |||||
author=Bill Greiman <fat16lib@sbcglobal.net> | author=Bill Greiman <fat16lib@sbcglobal.net> | ||||
maintainer=Bill Greiman <fat16lib@sbcglobal.net> | maintainer=Bill Greiman <fat16lib@sbcglobal.net> | ||||
sentence=FAT16/FAT32 file system for SD cards. | sentence=FAT16/FAT32 file system for SD cards. |
m_attr |= FILE_ATTR_FILE; | m_attr |= FILE_ATTR_FILE; | ||||
} | } | ||||
m_lfnOrd = lfnOrd; | m_lfnOrd = lfnOrd; | ||||
switch(oflag & O_ACCMODE){ | |||||
switch (oflag & O_ACCMODE) { | |||||
case O_RDONLY: | case O_RDONLY: | ||||
if (oflag & O_TRUNC) { | if (oflag & O_TRUNC) { | ||||
DBG_FAIL_MACRO; | DBG_FAIL_MACRO; | ||||
goto fail; | |||||
goto fail; | |||||
} | } | ||||
m_flags = F_READ; | m_flags = F_READ; | ||||
break; | break; | ||||
case O_RDWR: | case O_RDWR: | ||||
m_flags = F_READ | F_WRITE; | m_flags = F_READ | F_WRITE; | ||||
break; | break; | ||||
case O_WRONLY: | case O_WRONLY: | ||||
m_flags = F_WRITE; | |||||
m_flags = F_WRITE; | |||||
break; | break; | ||||
default: | default: | ||||
DBG_FAIL_MACRO; | DBG_FAIL_MACRO; | ||||
goto fail; | goto fail; | ||||
} | } | ||||
if (m_flags & F_WRITE) { | if (m_flags & F_WRITE) { | ||||
if (isSubDir() || isReadOnly()) { | if (isSubDir() || isReadOnly()) { | ||||
DBG_FAIL_MACRO; | DBG_FAIL_MACRO; | ||||
goto fail; | goto fail; | ||||
} | } | ||||
} | } | ||||
m_flags |= (oflag & O_APPEND ? F_APPEND : 0) | (oflag & O_SYNC ? F_SYNC : 0); | m_flags |= (oflag & O_APPEND ? F_APPEND : 0) | (oflag & O_SYNC ? F_SYNC : 0); | ||||
m_dirBlock = m_vol->cacheBlockNumber(); | m_dirBlock = m_vol->cacheBlockNumber(); |
//------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
private: | private: | ||||
// Allow FatFile and FatCache access to FatVolume private functions. | // Allow FatFile and FatCache access to FatVolume private functions. | ||||
friend class FatCache; | |||||
friend class FatFile; | |||||
friend class FatFileSystem; | |||||
friend class FatCache; ///< Allow access to FatVolume. | |||||
friend class FatFile; ///< Allow access to FatVolume. | |||||
friend class FatFileSystem; ///< Allow access to FatVolume. | |||||
//------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
BlockDriver* m_blockDev; // block device | BlockDriver* m_blockDev; // block device | ||||
uint8_t m_blocksPerCluster; // Cluster size in blocks. | uint8_t m_blocksPerCluster; // Cluster size in blocks. |
case 'a': | case 'a': | ||||
m = O_WRONLY; | m = O_WRONLY; | ||||
oflag = O_CREAT | O_APPEND; | oflag = O_CREAT | O_APPEND; | ||||
m_status = S_SWR; | |||||
m_status = S_SWR; | |||||
break; | break; | ||||
case 'r': | case 'r': | ||||
m = O_RDONLY; | m = O_RDONLY; | ||||
oflag = 0; | oflag = 0; | ||||
m_status = S_SRD; | |||||
m_status = S_SRD; | |||||
break; | break; | ||||
case 'w': | case 'w': | ||||
m = O_WRONLY; | m = O_WRONLY; | ||||
oflag = O_CREAT | O_TRUNC; | oflag = O_CREAT | O_TRUNC; | ||||
m_status = S_SWR; | |||||
m_status = S_SWR; | |||||
break; | break; | ||||
default: | default: | ||||
//------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
size_t StdioStream::fwrite(const void* ptr, size_t size, size_t count) { | size_t StdioStream::fwrite(const void* ptr, size_t size, size_t count) { | ||||
return write(ptr, count*size) < 0 ? EOF : count; | return write(ptr, count*size) < 0 ? EOF : count; | ||||
#if 0 //////////////////////////////////////////////////////////////////////////////////// | |||||
const uint8_t* src = static_cast<const uint8_t*>(ptr); | |||||
size_t total = count*size; | |||||
if (total == 0) { | |||||
return 0; | |||||
} | |||||
size_t todo = total; | |||||
while (todo > m_w) { | |||||
memcpy(m_p, src, m_w); | |||||
m_p += m_w; | |||||
src += m_w; | |||||
todo -= m_w; | |||||
if (!flushBuf()) { | |||||
return (total - todo)/size; | |||||
} | |||||
} | |||||
memcpy(m_p, src, todo); | |||||
m_p += todo; | |||||
m_w -= todo; | |||||
return count; | |||||
#endif ////////////////////////////////////////////////////////////////////////////////// | |||||
} | } | ||||
//------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
int StdioStream::write(const void* buf, size_t count) { | int StdioStream::write(const void* buf, size_t count) { |
SD_CARD_ERROR_WRITE, | SD_CARD_ERROR_WRITE, | ||||
SD_CARD_ERROR_WRITE_FIFO, | SD_CARD_ERROR_WRITE_FIFO, | ||||
SD_CARD_ERROR_WRITE_START, | SD_CARD_ERROR_WRITE_START, | ||||
SD_CARD_ERROR_FLASH_PROGRAMMING, | |||||
SD_CARD_ERROR_WRITE_TIMEOUT, | SD_CARD_ERROR_WRITE_TIMEOUT, | ||||
// Misc errors. | // Misc errors. | ||||
/** erase timeout ms */ | /** erase timeout ms */ | ||||
const uint16_t SD_ERASE_TIMEOUT = 10000; | const uint16_t SD_ERASE_TIMEOUT = 10000; | ||||
/** read timeout ms */ | /** read timeout ms */ | ||||
const uint16_t SD_READ_TIMEOUT = 300; | |||||
const uint16_t SD_READ_TIMEOUT = 1000; | |||||
/** write time out ms */ | /** write time out ms */ | ||||
const uint16_t SD_WRITE_TIMEOUT = 600; | |||||
const uint16_t SD_WRITE_TIMEOUT = 2000; | |||||
//------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
// SD card commands | // SD card commands | ||||
/** GO_IDLE_STATE - init card in spi mode if CS low */ | /** GO_IDLE_STATE - init card in spi mode if CS low */ |
#if CHECK_FLASH_PROGRAMMING | #if CHECK_FLASH_PROGRAMMING | ||||
// wait for flash programming to complete | // wait for flash programming to complete | ||||
if (!waitNotBusy(SD_WRITE_TIMEOUT)) { | if (!waitNotBusy(SD_WRITE_TIMEOUT)) { | ||||
error(SD_CARD_ERROR_WRITE_TIMEOUT); | |||||
error(SD_CARD_ERROR_FLASH_PROGRAMMING); | |||||
goto fail; | goto fail; | ||||
} | } | ||||
// response is r2 so get and check two bytes for nonzero | // response is r2 so get and check two bytes for nonzero |
#endif // INCLUDE_SDIOS | #endif // INCLUDE_SDIOS | ||||
//------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
/** SdFat version */ | /** SdFat version */ | ||||
#define SD_FAT_VERSION "1.0.9" | |||||
#define SD_FAT_VERSION "1.0.10" | |||||
//============================================================================== | //============================================================================== | ||||
/** | /** | ||||
* \class SdBaseFile | * \class SdBaseFile | ||||
public: | public: | ||||
#if IMPLEMENT_SPI_PORT_SELECTION || defined(DOXYGEN) | #if IMPLEMENT_SPI_PORT_SELECTION || defined(DOXYGEN) | ||||
SdFat() { | SdFat() { | ||||
m_spi.setPortNumber(0); | |||||
m_spi.setPort(nullptr); | |||||
} | } | ||||
/** Constructor with SPI port selection. | /** Constructor with SPI port selection. | ||||
* \param[in] spiPort SPI port number. | * \param[in] spiPort SPI port number. | ||||
*/ | */ | ||||
explicit SdFat(uint8_t spiPort) { | |||||
m_spi.setPortNumber(spiPort); | |||||
explicit SdFat(SPIClass* spiPort) { | |||||
m_spi.setPort(spiPort); | |||||
} | } | ||||
#endif // IMPLEMENT_SPI_PORT_SELECTION | #endif // IMPLEMENT_SPI_PORT_SELECTION | ||||
/** Initialize SD card and file system. | /** Initialize SD card and file system. | ||||
public: | public: | ||||
#if IMPLEMENT_SPI_PORT_SELECTION || defined(DOXYGEN) | #if IMPLEMENT_SPI_PORT_SELECTION || defined(DOXYGEN) | ||||
SdFatEX() { | SdFatEX() { | ||||
m_spi.setPortNumber(0); | |||||
m_spi.setPort(nullptr); | |||||
} | } | ||||
/** Constructor with SPI port selection. | /** Constructor with SPI port selection. | ||||
* \param[in] spiPort SPI port number. | * \param[in] spiPort SPI port number. | ||||
*/ | */ | ||||
explicit SdFatEX(uint8_t spiPort) { | |||||
m_spi.setPortNumber(spiPort); | |||||
explicit SdFatEX(SPIClass* spiPort) { | |||||
m_spi.setPort(spiPort); | |||||
} | } | ||||
#endif // IMPLEMENT_SPI_PORT_SELECTION | #endif // IMPLEMENT_SPI_PORT_SELECTION | ||||
/** Initialize SD card and file system. | /** Initialize SD card and file system. |
* the SPI bus may not be shared with other devices in this mode. | * the SPI bus may not be shared with other devices in this mode. | ||||
*/ | */ | ||||
#define ENABLE_EXTENDED_TRANSFER_CLASS 0 | #define ENABLE_EXTENDED_TRANSFER_CLASS 0 | ||||
//----------------------------------------------------------------------------- | |||||
//------------------------------------------------------------------------------ | |||||
/** | /** | ||||
* If the symbol USE_STANDARD_SPI_LIBRARY is nonzero, the classes SdFat and | |||||
* SdFatEX use the standard Arduino SPI.h library. If USE_STANDARD_SPI_LIBRARY | |||||
* is zero, an optimized custom SPI driver is used if it exists. | |||||
* If the symbol USE_STANDARD_SPI_LIBRARY is zero, an optimized custom SPI | |||||
* driver is used if it exists. If the symbol USE_STANDARD_SPI_LIBRARY is | |||||
* one, the standard Arduino SPI.h library is used with SPI. If the symbol | |||||
* USE_STANDARD_SPI_LIBRARY is two, the SPI port can be selected with the | |||||
* constructors SdFat(SPIClass* spiPort) and SdFatEX(SPIClass* spiPort). | |||||
*/ | */ | ||||
#define USE_STANDARD_SPI_LIBRARY 0 | #define USE_STANDARD_SPI_LIBRARY 0 | ||||
//----------------------------------------------------------------------------- | |||||
//------------------------------------------------------------------------------ | |||||
/** | /** | ||||
* If the symbol ENABLE_SOFTWARE_SPI_CLASS is nonzero, the class SdFatSoftSpi | * If the symbol ENABLE_SOFTWARE_SPI_CLASS is nonzero, the class SdFatSoftSpi | ||||
* will be defined. If ENABLE_EXTENDED_TRANSFER_CLASS is also nonzero, | * will be defined. If ENABLE_EXTENDED_TRANSFER_CLASS is also nonzero, | ||||
//------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
/** If the symbol USE_FCNTL_H is nonzero, open flags for access modes O_RDONLY, | /** If the symbol USE_FCNTL_H is nonzero, open flags for access modes O_RDONLY, | ||||
* O_WRONLY, O_RDWR and the open modifiers O_APPEND, O_CREAT, O_EXCL, O_SYNC | * O_WRONLY, O_RDWR and the open modifiers O_APPEND, O_CREAT, O_EXCL, O_SYNC | ||||
* will be defined by including the system file fcntl.h. | |||||
* will be defined by including the system file fcntl.h. | |||||
*/ | */ | ||||
#if defined(__AVR__) | #if defined(__AVR__) | ||||
// AVR fcntl.h does not define open flags. | // AVR fcntl.h does not define open flags. | ||||
#define USE_FCNTL_H 0 | #define USE_FCNTL_H 0 | ||||
#elif defined(PLATFORM_ID) | #elif defined(PLATFORM_ID) | ||||
// Particle boards - use fcntl.h. | // Particle boards - use fcntl.h. | ||||
#define USE_FCNTL_H 1 | |||||
#define USE_FCNTL_H 1 | |||||
#elif defined(__arm__) | #elif defined(__arm__) | ||||
// ARM gcc defines open flags. | // ARM gcc defines open flags. | ||||
#define USE_FCNTL_H 1 | #define USE_FCNTL_H 1 | ||||
#endif // defined(__AVR__) | #endif // defined(__AVR__) | ||||
//------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
/** | /** | ||||
* If CHECK_FLASH_PROGRAMMING is zero, overlap of single sector flash | |||||
* If CHECK_FLASH_PROGRAMMING is zero, overlap of single sector flash | |||||
* programming and other operations will be allowed for faster write | * programming and other operations will be allowed for faster write | ||||
* performance. | * performance. | ||||
* | * | ||||
/** | /** | ||||
* Determine the default SPI configuration. | * Determine the default SPI configuration. | ||||
*/ | */ | ||||
#if defined(__STM32F1__) || defined(__STM32F4__) | |||||
#if defined(__STM32F1__) || defined(__STM32F4__) || defined(PLATFORM_ID) | |||||
// has multiple SPI ports | // has multiple SPI ports | ||||
#define SD_HAS_CUSTOM_SPI 2 | #define SD_HAS_CUSTOM_SPI 2 | ||||
#elif defined(__AVR__)\ | #elif defined(__AVR__)\ | ||||
/** | /** | ||||
* Check if API to select HW SPI port is needed. | * Check if API to select HW SPI port is needed. | ||||
*/ | */ | ||||
#if (USE_STANDARD_SPI_LIBRARY || SD_HAS_CUSTOM_SPI < 2) | |||||
#define IMPLEMENT_SPI_PORT_SELECTION 0 | |||||
#else // USE_STANDARD_SPI_LIBRARY | |||||
#if USE_STANDARD_SPI_LIBRARY > 1 || SD_HAS_CUSTOM_SPI > 1 | |||||
#define IMPLEMENT_SPI_PORT_SELECTION 1 | #define IMPLEMENT_SPI_PORT_SELECTION 1 | ||||
#endif // USE_STANDARD_SPI_LIBRARY | |||||
#else // IMPLEMENT_SPI_PORT_SELECTION | |||||
#define IMPLEMENT_SPI_PORT_SELECTION 0 | |||||
#endif // IMPLEMENT_SPI_PORT_SELECTION | |||||
#endif // SdFatConfig_h | #endif // SdFatConfig_h |
#include "SPI.h" | #include "SPI.h" | ||||
#include "SdSpiBaseDriver.h" | #include "SdSpiBaseDriver.h" | ||||
#include "SdFatConfig.h" | #include "SdFatConfig.h" | ||||
//----------------------------------------------------------------------------- | |||||
//------------------------------------------------------------------------------ | |||||
/** SDCARD_SPI is defined if board has built-in SD card socket */ | /** SDCARD_SPI is defined if board has built-in SD card socket */ | ||||
#ifndef SDCARD_SPI | #ifndef SDCARD_SPI | ||||
#define SDCARD_SPI SPI | #define SDCARD_SPI SPI | ||||
#endif // SDCARD_SPI | #endif // SDCARD_SPI | ||||
//----------------------------------------------------------------------------- | |||||
//------------------------------------------------------------------------------ | |||||
/** | /** | ||||
* \class SdSpiLibDriver | * \class SdSpiLibDriver | ||||
* \brief SdSpiLibDriver - use standard SPI library. | * \brief SdSpiLibDriver - use standard SPI library. | ||||
class SdSpiLibDriver { | class SdSpiLibDriver { | ||||
#endif // ENABLE_SOFTWARE_SPI_CLASS | #endif // ENABLE_SOFTWARE_SPI_CLASS | ||||
public: | public: | ||||
#if IMPLEMENT_SPI_PORT_SELECTION | |||||
/** Activate SPI hardware. */ | |||||
void activate() { | |||||
m_spi->beginTransaction(m_spiSettings); | |||||
} | |||||
/** Deactivate SPI hardware. */ | |||||
void deactivate() { | |||||
m_spi->endTransaction(); | |||||
} | |||||
/** Initialize the SPI bus. | |||||
* | |||||
* \param[in] csPin SD card chip select pin. | |||||
*/ | |||||
void begin(uint8_t csPin) { | |||||
m_csPin = csPin; | |||||
digitalWrite(csPin, HIGH); | |||||
pinMode(csPin, OUTPUT); | |||||
m_spi->begin(); | |||||
} | |||||
/** Receive a byte. | |||||
* | |||||
* \return The byte. | |||||
*/ | |||||
uint8_t receive() { | |||||
return m_spi->transfer( 0XFF); | |||||
} | |||||
/** Receive multiple bytes. | |||||
* | |||||
* \param[out] buf Buffer to receive the data. | |||||
* \param[in] n Number of bytes to receive. | |||||
* | |||||
* \return Zero for no error or nonzero error code. | |||||
*/ | |||||
uint8_t receive(uint8_t* buf, size_t n) { | |||||
for (size_t i = 0; i < n; i++) { | |||||
buf[i] = m_spi->transfer(0XFF); | |||||
} | |||||
return 0; | |||||
} | |||||
/** Send a byte. | |||||
* | |||||
* \param[in] data Byte to send | |||||
*/ | |||||
void send(uint8_t data) { | |||||
m_spi->transfer(data); | |||||
} | |||||
/** Send multiple bytes. | |||||
* | |||||
* \param[in] buf Buffer for data to be sent. | |||||
* \param[in] n Number of bytes to send. | |||||
*/ | |||||
void send(const uint8_t* buf, size_t n) { | |||||
for (size_t i = 0; i < n; i++) { | |||||
m_spi->transfer(buf[i]); | |||||
} | |||||
} | |||||
#else // IMPLEMENT_SPI_PORT_SELECTION | |||||
/** Activate SPI hardware. */ | /** Activate SPI hardware. */ | ||||
void activate() { | void activate() { | ||||
SDCARD_SPI.beginTransaction(m_spiSettings); | SDCARD_SPI.beginTransaction(m_spiSettings); | ||||
SDCARD_SPI.transfer(buf[i]); | SDCARD_SPI.transfer(buf[i]); | ||||
} | } | ||||
} | } | ||||
#endif // IMPLEMENT_SPI_PORT_SELECTION | |||||
/** Set CS low. */ | /** Set CS low. */ | ||||
void select() { | void select() { | ||||
digitalWrite(m_csPin, LOW); | digitalWrite(m_csPin, LOW); | ||||
void unselect() { | void unselect() { | ||||
digitalWrite(m_csPin, HIGH); | digitalWrite(m_csPin, HIGH); | ||||
} | } | ||||
#if IMPLEMENT_SPI_PORT_SELECTION || defined(DOXYGEN) | |||||
/** Set SPI port. | |||||
* \param[in] spiPort Hardware SPI port. | |||||
*/ | |||||
void setPort(SPIClass* spiPort) { | |||||
m_spi = spiPort ? spiPort : &SDCARD_SPI; | |||||
} | |||||
private: | private: | ||||
SPIClass* m_spi; | |||||
#else // IMPLEMENT_SPI_PORT_SELECTION | |||||
private: | |||||
#endif // IMPLEMENT_SPI_PORT_SELECTION | |||||
SPISettings m_spiSettings; | SPISettings m_spiSettings; | ||||
uint8_t m_csPin; | uint8_t m_csPin; | ||||
}; | }; | ||||
//----------------------------------------------------------------------------- | |||||
//------------------------------------------------------------------------------ | |||||
/** | /** | ||||
* \class SdSpiAltDriver | * \class SdSpiAltDriver | ||||
* \brief Optimized SPI class for access to SD and SDHC flash memory cards. | * \brief Optimized SPI class for access to SD and SDHC flash memory cards. | ||||
} | } | ||||
#if IMPLEMENT_SPI_PORT_SELECTION || defined(DOXYGEN) | #if IMPLEMENT_SPI_PORT_SELECTION || defined(DOXYGEN) | ||||
/** Set SPI port number. | /** Set SPI port number. | ||||
* \param[in] portNumber Hardware SPI port number. | |||||
* \param[in] spiPort Hardware SPI port. | |||||
*/ | */ | ||||
void setPortNumber(uint8_t portNumber); | |||||
void setPort(SPIClass* spiPort) { | |||||
m_spi = spiPort ? spiPort : &SDCARD_SPI; | |||||
} | |||||
private: | private: | ||||
SPIClass* m_spi; | SPIClass* m_spi; | ||||
#else // IMPLEMENT_SPI_PORT_SELECTION | #else // IMPLEMENT_SPI_PORT_SELECTION | ||||
SoftSPI<MisoPin, MosiPin, SckPin, 0> m_spi; | SoftSPI<MisoPin, MosiPin, SckPin, 0> m_spi; | ||||
}; | }; | ||||
#endif // ENABLE_SOFTWARE_SPI_CLASS || defined(DOXYGEN) | #endif // ENABLE_SOFTWARE_SPI_CLASS || defined(DOXYGEN) | ||||
//----------------------------------------------------------------------------- | |||||
//------------------------------------------------------------------------------ | |||||
// Choose SPI driver for SdFat and SdFatEX classes. | // Choose SPI driver for SdFat and SdFatEX classes. | ||||
#if USE_STANDARD_SPI_LIBRARY || !SD_HAS_CUSTOM_SPI | #if USE_STANDARD_SPI_LIBRARY || !SD_HAS_CUSTOM_SPI | ||||
/** SdFat uses Arduino library SPI. */ | /** SdFat uses Arduino library SPI. */ | ||||
// Don't need virtual driver. | // Don't need virtual driver. | ||||
typedef SdFatSpiDriver SdSpiDriver; | typedef SdFatSpiDriver SdSpiDriver; | ||||
#endif // ENABLE_SOFTWARE_SPI_CLASS | #endif // ENABLE_SOFTWARE_SPI_CLASS | ||||
//============================================================================= | |||||
//============================================================================== | |||||
// Use of in-line for AVR to save flash. | // Use of in-line for AVR to save flash. | ||||
#ifdef __AVR__ | #ifdef __AVR__ | ||||
//------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ |
/** | |||||
* Copyright (c) 2011-2018 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. | |||||
*/ | |||||
#if defined(PLATFORM_ID) | |||||
#include "SdSpiDriver.h" | |||||
static volatile bool SPI_DMA_TransferCompleted = false; | |||||
//----------------------------------------------------------------------------- | |||||
static void SD_SPI_DMA_TransferComplete_Callback(void) { | |||||
SPI_DMA_TransferCompleted = true; | |||||
} | |||||
//------------------------------------------------------------------------------ | |||||
/** Set SPI options for access to SD/SDHC cards. | |||||
* | |||||
* \param[in] divisor SCK clock divider relative to the APB1 or APB2 clock. | |||||
*/ | |||||
void SdSpiAltDriver::activate() { | |||||
m_spi->beginTransaction(m_spiSettings); | |||||
} | |||||
//------------------------------------------------------------------------------ | |||||
/** Initialize the SPI bus. | |||||
* | |||||
* \param[in] chipSelectPin SD card chip select pin. | |||||
*/ | |||||
void SdSpiAltDriver::begin(uint8_t csPin) { | |||||
m_csPin = csPin; | |||||
pinMode(m_csPin, OUTPUT); | |||||
digitalWrite(m_csPin, HIGH); | |||||
m_spi->begin(); | |||||
} | |||||
//------------------------------------------------------------------------------ | |||||
/** | |||||
* End SPI transaction. | |||||
*/ | |||||
void SdSpiAltDriver::deactivate() { | |||||
m_spi->endTransaction(); | |||||
} | |||||
//------------------------------------------------------------------------------ | |||||
/** Receive a byte. | |||||
* | |||||
* \return The byte. | |||||
*/ | |||||
uint8_t SdSpiAltDriver::receive() { | |||||
return m_spi->transfer(0XFF); | |||||
} | |||||
//------------------------------------------------------------------------------ | |||||
/** Receive multiple bytes. | |||||
* | |||||
* \param[out] buf Buffer to receive the data. | |||||
* \param[in] n Number of bytes to receive. | |||||
* | |||||
* \return Zero for no error or nonzero error code. | |||||
*/ | |||||
uint8_t SdSpiAltDriver::receive(uint8_t* buf, size_t n) { | |||||
SPI_DMA_TransferCompleted = false; | |||||
m_spi->transfer(0, buf, n, SD_SPI_DMA_TransferComplete_Callback); | |||||
while (!SPI_DMA_TransferCompleted) {} | |||||
return 0; | |||||
} | |||||
//------------------------------------------------------------------------------ | |||||
/** Send a byte. | |||||
* | |||||
* \param[in] b Byte to send | |||||
*/ | |||||
void SdSpiAltDriver::send(uint8_t b) { | |||||
m_spi->transfer(b); | |||||
} | |||||
//------------------------------------------------------------------------------ | |||||
/** Send multiple bytes. | |||||
* | |||||
* \param[in] buf Buffer for data to be sent. | |||||
* \param[in] n Number of bytes to send. | |||||
*/ | |||||
void SdSpiAltDriver::send(const uint8_t* buf , size_t n) { | |||||
SPI_DMA_TransferCompleted = false; | |||||
m_spi->transfer(const_cast<uint8_t*>(buf), 0, n, | |||||
SD_SPI_DMA_TransferComplete_Callback); | |||||
while (!SPI_DMA_TransferCompleted) {} | |||||
} | |||||
#endif // defined(PLATFORM_ID) |
int rtn = 0; | int rtn = 0; | ||||
#if USE_SAM3X_DMAC | #if USE_SAM3X_DMAC | ||||
// clear overrun error | // clear overrun error | ||||
uint32_t s = pSpi->SPI_SR; | |||||
pSpi->SPI_SR; | |||||
spiDmaRX(buf, n); | spiDmaRX(buf, n); | ||||
spiDmaTX(0, n); | spiDmaTX(0, n); | ||||
#endif // #if USE_SAM3X_DMAC | #endif // #if USE_SAM3X_DMAC | ||||
while ((pSpi->SPI_SR & SPI_SR_TXEMPTY) == 0) {} | while ((pSpi->SPI_SR & SPI_SR_TXEMPTY) == 0) {} | ||||
// leave RDR empty | // leave RDR empty | ||||
uint8_t b = pSpi->SPI_RDR; | |||||
pSpi->SPI_RDR; | |||||
} | } | ||||
#endif // defined(__SAM3X8E__) || defined(__SAM3X8H__) | #endif // defined(__SAM3X8E__) || defined(__SAM3X8H__) |
#error Unknown STM32 type | #error Unknown STM32 type | ||||
#endif // defined(__STM32F1__) | #endif // defined(__STM32F1__) | ||||
//------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
static SPIClass m_SPI1(1); | |||||
#if BOARD_NR_SPI >= 2 | |||||
static SPIClass m_SPI2(2); | |||||
#endif // BOARD_NR_SPI >= 2 | |||||
#if BOARD_NR_SPI >= 3 | |||||
static SPIClass m_SPI3(3); | |||||
#endif // BOARD_NR_SPI >= 3 | |||||
#if BOARD_NR_SPI > 3 | |||||
#error BOARD_NR_SPI too large | |||||
#endif | |||||
//------------------------------------------------------------------------------ | |||||
/** Set SPI options for access to SD/SDHC cards. | /** Set SPI options for access to SD/SDHC cards. | ||||
* | * | ||||
* \param[in] divisor SCK clock divider relative to the APB1 or APB2 clock. | * \param[in] divisor SCK clock divider relative to the APB1 or APB2 clock. | ||||
m_spi->write(const_cast<uint8*>(buf), n); | m_spi->write(const_cast<uint8*>(buf), n); | ||||
#endif // USE_STM32_DMA | #endif // USE_STM32_DMA | ||||
} | } | ||||
//------------------------------------------------------------------------------ | |||||
void SdSpiAltDriver::setPortNumber(uint8_t portNumber) { | |||||
m_spi = &m_SPI1; | |||||
#if BOARD_NR_SPI >= 2 | |||||
if (portNumber == 2) { | |||||
m_spi = &m_SPI2; | |||||
} | |||||
#endif // BOARD_NR_SPI >= 2 | |||||
#if BOARD_NR_SPI >= 3 | |||||
if (portNumber == 3) { | |||||
m_spi = &m_SPI3; | |||||
} | |||||
#endif // BOARD_NR_SPI >= 2 | |||||
} | |||||
#endif // defined(__STM32F1__) || defined(__STM32F4__) | #endif // defined(__STM32F1__) || defined(__STM32F4__) |