| ### 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__) |