Sfoglia il codice sorgente

SdFatEX and other features

main
Bill Greiman 8 anni fa
parent
commit
9c407b3e9f
100 ha cambiato i file con 3661 aggiunte e 2867 eliminazioni
  1. +0
    -8
      LowLatencyLoggerADXL345/UserDataType.h
  2. +21
    -7
      README.md
  3. +27
    -22
      SdFat/MainPage/SdFatmainpage.h
  4. +3
    -2
      SdFat/examples/#attic/AnalogLogger/AnalogLogger.ino
  5. +3
    -1
      SdFat/examples/#attic/BaseExtCaseTest/BaseExtCaseTest.ino
  6. +1
    -1
      SdFat/examples/#attic/StreamParseInt/StreamParseInt.ino
  7. +3
    -3
      SdFat/examples/#attic/append/append.ino
  8. +3
    -3
      SdFat/examples/#attic/average/average.ino
  9. +3
    -3
      SdFat/examples/#attic/eventlog/eventlog.ino
  10. +3
    -3
      SdFat/examples/#attic/fgetsRewrite/fgetsRewrite.ino
  11. +3
    -3
      SdFat/examples/#attic/readlog/readlog.ino
  12. +5
    -10
      SdFat/examples/AnalogBinLogger/AnalogBinLogger.ino
  13. +3
    -1
      SdFat/examples/LongFileName/LongFileName.ino
  14. +272
    -243
      SdFat/examples/LowLatencyLogger/LowLatencyLogger.ino
  15. +0
    -8
      SdFat/examples/LowLatencyLogger/UserDataType.h
  16. +41
    -0
      SdFat/examples/LowLatencyLogger/UserFunctions.cpp
  17. +15
    -0
      SdFat/examples/LowLatencyLogger/UserTypes.h
  18. +277
    -277
      SdFat/examples/LowLatencyLoggerADXL345/LowLatencyLogger.ino
  19. +1
    -0
      SdFat/examples/LowLatencyLoggerADXL345/LowLatencyLoggerADXL345.ino
  20. +67
    -0
      SdFat/examples/LowLatencyLoggerADXL345/UserFunctions.cpp
  21. +17
    -0
      SdFat/examples/LowLatencyLoggerADXL345/UserTypes.h
  22. +0
    -0
      SdFat/examples/LowLatencyLoggerADXL345/readme.txt
  23. +612
    -0
      SdFat/examples/LowLatencyLoggerMPU6050/LowLatencyLogger.ino
  24. +2
    -0
      SdFat/examples/LowLatencyLoggerMPU6050/LowLatencyLoggerMPU6050.ino
  25. +51
    -0
      SdFat/examples/LowLatencyLoggerMPU6050/UserFunctions.cpp
  26. +18
    -0
      SdFat/examples/LowLatencyLoggerMPU6050/UserTypes.h
  27. +3
    -3
      SdFat/examples/OpenNext/OpenNext.ino
  28. +3
    -3
      SdFat/examples/PrintBenchmark/PrintBenchmark.ino
  29. +6
    -6
      SdFat/examples/QuickStart/QuickStart.ino
  30. +58
    -60
      SdFat/examples/RawWrite/RawWrite.ino
  31. +0
    -111
      SdFat/examples/ReadCsvFields/ReadCsvFields.ino
  32. +120
    -0
      SdFat/examples/ReadCsvStream/ReadCsvStream.ino
  33. +6
    -14
      SdFat/examples/ReadWrite/ReadWrite.ino
  34. +0
    -77
      SdFat/examples/ReadWriteSdFat/ReadWriteSdFat.ino
  35. +176
    -0
      SdFat/examples/STM32Test/STM32Test.ino
  36. +7
    -9
      SdFat/examples/SdFormatter/SdFormatter.ino
  37. +8
    -21
      SdFat/examples/SdInfo/SdInfo.ino
  38. +4
    -4
      SdFat/examples/SoftwareSpi/SoftwareSpi.ino
  39. +7
    -3
      SdFat/examples/StdioBench/StdioBench.ino
  40. +0
    -231
      SdFat/examples/ThreeCards/ThreeCards.ino
  41. +3
    -3
      SdFat/examples/Timestamp/Timestamp.ino
  42. +1
    -0
      SdFat/examples/TwoCards/TwoCards.ino
  43. +4
    -3
      SdFat/examples/VolumeFreeSpace/VolumeFreeSpace.ino
  44. +9
    -5
      SdFat/examples/bench/bench.ino
  45. +3
    -3
      SdFat/examples/dataLogger/dataLogger.ino
  46. +4
    -4
      SdFat/examples/directoryFunctions/directoryFunctions.ino
  47. +3
    -3
      SdFat/examples/fgets/fgets.ino
  48. +3
    -3
      SdFat/examples/getline/getline.ino
  49. +186
    -94
      SdFat/examples/readCSV/readCSV.ino
  50. +3
    -3
      SdFat/examples/rename/rename.ino
  51. +6
    -2
      SdFat/examples/wipe/wipe.ino
  52. +1
    -1
      SdFat/library.properties
  53. +0
    -1
      SdFat/src/AltSpiDrivers/DigitalPin.h
  54. +15
    -27
      SdFat/src/AltSpiDrivers/SdSpiESP8266.cpp
  55. +21
    -37
      SdFat/src/AltSpiDrivers/SdSpiSAM3X.cpp
  56. +52
    -56
      SdFat/src/AltSpiDrivers/SdSpiSTM32F1.cpp
  57. +31
    -119
      SdFat/src/AltSpiDrivers/SdSpiTeensy3.cpp
  58. +0
    -0
      SdFat/src/AltSpiDrivers/SoftSPI.h
  59. +0
    -0
      SdFat/src/AltSpiDrivers/boards/AvrDevelopersGpioPinMap.h
  60. +0
    -0
      SdFat/src/AltSpiDrivers/boards/BobuinoGpioPinMap.h
  61. +0
    -0
      SdFat/src/AltSpiDrivers/boards/GpioPinMap.h
  62. +0
    -0
      SdFat/src/AltSpiDrivers/boards/LeonardoGpioPinMap.h
  63. +0
    -0
      SdFat/src/AltSpiDrivers/boards/MegaGpioPinMap.h
  64. +0
    -0
      SdFat/src/AltSpiDrivers/boards/SleepingBeautyGpioPinMap.h
  65. +0
    -0
      SdFat/src/AltSpiDrivers/boards/Standard1284GpioPinMap.h
  66. +0
    -0
      SdFat/src/AltSpiDrivers/boards/Teensy2GpioPinMap.h
  67. +0
    -0
      SdFat/src/AltSpiDrivers/boards/Teensy2ppGpioPinMap.h
  68. +0
    -0
      SdFat/src/AltSpiDrivers/boards/UnoGpioPinMap.h
  69. +89
    -0
      SdFat/src/BlockDriver.cpp
  70. +197
    -0
      SdFat/src/BlockDriver.h
  71. +0
    -4
      SdFat/src/FatLib/ArduinoFiles.h
  72. +1
    -2
      SdFat/src/FatLib/ArduinoStream.h
  73. +56
    -0
      SdFat/src/FatLib/BaseBlockDriver.h
  74. +19
    -19
      SdFat/src/FatLib/FatApiConstants.h
  75. +10
    -10
      SdFat/src/FatLib/FatFile.cpp
  76. +21
    -3
      SdFat/src/FatLib/FatFile.h
  77. +0
    -1
      SdFat/src/FatLib/FatFilePrint.cpp
  78. +6
    -4
      SdFat/src/FatLib/FatFileSystem.h
  79. +11
    -13
      SdFat/src/FatLib/FatLibConfig.h
  80. +27
    -27
      SdFat/src/FatLib/FatStructs.h
  81. +19
    -24
      SdFat/src/FatLib/FatVolume.cpp
  82. +29
    -17
      SdFat/src/FatLib/FatVolume.h
  83. +5
    -3
      SdFat/src/FreeStack.h
  84. +9
    -1
      SdFat/src/MinimumSerial.cpp
  85. +13
    -1
      SdFat/src/MinimumSerial.h
  86. +0
    -100
      SdFat/src/SdFat.cpp
  87. +209
    -107
      SdFat/src/SdFat.h
  88. +32
    -86
      SdFat/src/SdFatConfig.h
  89. +0
    -41
      SdFat/src/SdFatUtil.cpp
  90. +0
    -35
      SdFat/src/SdFatUtil.h
  91. +76
    -72
      SdFat/src/SdSpiCard/SdInfo.h
  92. +0
    -411
      SdFat/src/SdSpiCard/SdSpi.h
  93. +75
    -0
      SdFat/src/SdSpiCard/SdSpiBaseDriver.h
  94. +133
    -139
      SdFat/src/SdSpiCard/SdSpiCard.cpp
  95. +51
    -103
      SdFat/src/SdSpiCard/SdSpiCard.h
  96. +0
    -110
      SdFat/src/SdSpiCard/SdSpiParticle.cpp
  97. +359
    -0
      SdFat/src/SdSpiDriver.h
  98. +20
    -4
      SdFat/src/SysCall.h
  99. +0
    -29
      SdFat/src/SystemInclude.h
  100. +0
    -0
      changes.txt

+ 0
- 8
LowLatencyLoggerADXL345/UserDataType.h Vedi File

@@ -1,8 +0,0 @@
#ifndef UserDataType_h
#define UserDataType_h
const uint8_t ACCEL_DIM = 3;
struct data_t {
unsigned long time;
int16_t accel[ACCEL_DIM];
};
#endif // UserDataType_h

+ 21
- 7
README.md Vedi File

@@ -1,8 +1,22 @@
This is a beta version so there may be bugs and compatibility
problems.
### Warning: This version has major changes so it may be unstable.

Please report problems to the email address listed in the
"Bugs and Comments" section of the html documentation.
Recent versions of the Arduino IDE have bugs that may cause SdFat-beta to crash.

https://forum.arduino.cc/index.php?topic=419264.0

SdFat-beta was tested using with Arduino AVR boards 1.6.11.
If you are using IDE 1.6.11 you must also install AVR boards 1.6.11, not
1.6.12 or 1.6.13.

If you are Arduino IDE 1.6.11, do Tools > Board > Boards Manager > Arduino AVR Boards > 1.6.11 > Install > Close.

The SPI divisor has been replaced by SPISettings.

There are two new classes, SdFatEX and SdFatSoftSpiEX.

Please read changes.txt and the html documentation for more information.

Please report problems as issues.

The Arduino SdFat library provides read/write access to FAT16/FAT32
file systems on SD/SDHC flash cards.
@@ -23,9 +37,9 @@ Read changes.txt if you have used previous releases of this library.

Please read the html documentation for this library. Start with
html/index.html and read the Main Page. Next go to the Classes tab and
read the documentation for the classes SdFat, SdBaseFile, SdFile, File,
StdioStream, ifstream, ofstream, and others.
read the documentation for the classes SdFat, SdFatEX, SdBaseFile,
SdFile, File, StdioStream, ifstream, ofstream, and others.
Please continue by reading the html documentation.

Updated 23 Jan 2016
Updated 19 Aug 2016

+ 27
- 22
SdFat/MainPage/SdFatmainpage.h Vedi File

@@ -34,15 +34,17 @@ nonzero in SdFatConfig.h.
The %SdFat library supports Long %File Names or short 8.3 names.
Edit the SdFatConfig.h file to select short or long file names.

The main classes in %SdFat are SdFat, SdFatSoftSpi, SdFatLibSpi,
The main classes in %SdFat are SdFat, SdFatEX, SdFatSoftSpi, SdFatSoftSpiEX,
SdBaseFile, SdFile, File, StdioStream, \ref fstream, \ref ifstream,
and \ref ofstream.

The SdFat, SdFatLibSpi, and SdFatSoftSpi classes maintain a FAT volume,
a current working directory, and simplifies initialization of other classes.
The SdFat class uses a fast custom hardware SPI implementation. The
SdFatLibSpi class uses the standard Arduino SPI library. The SdFatSoftSpi
class uses software SPI.
The SdFat, SdFatEX, SdFatSoftSpi and SdFatSoftSpiEX classes maintain a
FAT volume, a current working directory, and simplify initialization
of other classes. The SdFat and SdFatEX classes uses a fast custom hardware SPI
implementation. The SdFatSoftSpi and SdFatSoftSpiEX classes uses software SPI.

the SdFatEX and SdFatSoftSpiEX use extended multi-block I/O for enhanced
performance. These classes must have exclusive use of the SPI bus.

The SdBaseFile class provides basic file access functions such as open(),
binary read(), binary write(), close(), remove(), and sync(). SdBaseFile
@@ -102,19 +104,22 @@ Long %File Names. Long %File names require extra flash but no extra RAM.
Opening Long %File Names can be slower than opening Short %File Names.
Data read and write performance is not changed by the type of %File Name.

Set SD_SPI_CONFIGURATION to enable various SPI options. The SdFatSoftSpi
and SdFatLibSpi classes can be enabled. SdFatLibSpi uses the standard
Arduino SPI library and SdFatSoftSpi uses software SPI.
If the symbol ENABLE_EXTENDED_TRANSFER_CLASS is nonzero, the class SdFatEX
will be defined. If the symbol ENABLE_SOFTWARE_SPI_CLASS is also nonzero,
the class SdFatSoftSpiEX will be defined.
These classes used extended multi-block SD I/O for better performance.
the SPI bus may not be shared with other devices in this mode.
Set USE_STANDARD_SPI_LIBRARY and ENABLE_SOFTWARE_SPI_CLASS to
enable various SPI options. set USE_STANDARD_SPI_LIBRARY to use the standard
Arduino SPI library. set ENABLE_SOFTWARE_SPI_CLASS to enable the SdFatSoftSpi
class which uses software SPI.

To enable SD card CRC checking set USE_SD_CRC nonzero.

Set FAT12_SUPPORT nonzero to enable use of FAT12 volumes.
FAT12 has not been well tested and requires additional flash.

Set ENABLE_SPI_TRANSACTIONS nonzero to enable the SPI transaction feature
of the standard Arduino SPI library. You must include SPI.h in your
programs when ENABLE_SPI_TRANSACTIONS is nonzero.

\section SDPath Paths and Working Directories

Relative paths in SdFat are resolved in a manner similar to Windows.
@@ -352,7 +357,11 @@ getline - Example of getline from section 27.7.1.3 of the C++ standard.

LongFileName - Example use of openNext, printName, and open by index.

LowLatencyLogger - A modifiable data logger for higher data rates.
LowLatencyLogger - A data logger for higher data rates. ADC version.

LowLatencyLoggerADXL345 - A data logger for higher data rates. ADXL345 SPI.

LowLatencyLoggerMPU6050 - A data logger for higher data rates. MPU6050 I2C.

OpenNext - Open all files in the root dir and print their filename.

@@ -362,13 +371,13 @@ QuickStart - A program to quickly test your SD card and SD shield/module.

RawWrite - A test of raw write functions for contiguous files.

readCSV - Read a comma-separated value file using iostream extractors.
ReadCsv - Function to read a CSV text file one field at a time.

ReadCsvArray - Read a two dimensional array from a CSV file.
ReadCsvStream - Read a comma-separated value file using iostream extractors.

ReadCsvFields - Function to read a CSV text file one field at a time.
ReadCsvArray - Read a two dimensional array from a CSV file.

ReadWriteSdFat - SdFat version of Arduino SD ReadWrite example.
ReadWrite - Compatibility test of Arduino SD ReadWrite example.

rename - A demo of SdFat::rename(old, new) and SdFile::rename(dirFile, newPath).

@@ -380,10 +389,6 @@ SdInfo - Initialize an SD card and analyze its structure for trouble shooting.

StdioBench - Demo and test of stdio style stream.

StreamParseInt - Demo of the SD.h API and the File class parseInt() function.

ThreeCards - Demonstrate simultaneous use of SdFat, SdFatLibSpi, SdFatSoftSpi.

Timestamp - Sets file create, modify, and access timestamps.

TwoCards - Example using two SD cards.

+ 3
- 2
SdFat/examples/#attic/AnalogLogger/AnalogLogger.ino Vedi File

@@ -97,8 +97,9 @@ void setup() {
cout << now << endl;
#endif // USE_DS1307

// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
if (!sd.begin(SD_CHIP_SELECT, SPI_HALF_SPEED)) {
// Initialize at the highest speed supported by the board that is
// not over 50 MHz. Try a lower speed if SPI errors occur.
if (!sd.begin(SD_CHIP_SELECT, SD_SCK_MHZ(50))) {
sd.initErrorHalt();
}


+ 3
- 1
SdFat/examples/#attic/BaseExtCaseTest/BaseExtCaseTest.ino Vedi File

@@ -4,6 +4,8 @@
#include <SPI.h>
#include "SdFat.h"

const uint8_t chipSelect = SS;

SdFat sd;

SdFile file;
@@ -24,7 +26,7 @@ void setup() {
while (!Serial.available()) {
SysCall::yield();
}
if (!sd.begin()) {
if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
Serial.println("begin failed");
return;
}

+ 1
- 1
SdFat/examples/#attic/StreamParseInt/StreamParseInt.ino Vedi File

@@ -5,7 +5,7 @@
SdFat SD;

// SD card chip select pin - Modify the value of csPin for your SD module.
const uint8_t csPin = 10;
const uint8_t csPin = SS;

File file;
//------------------------------------------------------------------------------

+ 3
- 3
SdFat/examples/#attic/append/append.ino Vedi File

@@ -36,9 +36,9 @@ void setup() {
SysCall::yield();
}

// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance.
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
// Initialize at the highest speed supported by the board that is
// not over 50 MHz. Try a lower speed if SPI errors occur.
if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
sd.initErrorHalt();
}


+ 3
- 3
SdFat/examples/#attic/average/average.ino Vedi File

@@ -65,9 +65,9 @@ void setup() {
SysCall::yield();
}

// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance.
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
// Initialize at the highest speed supported by the board that is
// not over 50 MHz. Try a lower speed if SPI errors occur.
if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
sd.initErrorHalt();
}


+ 3
- 3
SdFat/examples/#attic/eventlog/eventlog.ino Vedi File

@@ -47,9 +47,9 @@ void setup() {
}
delay(400); // catch Due reset problem

// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance.
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
// Initialize at the highest speed supported by the board that is
// not over 50 MHz. Try a lower speed if SPI errors occur.
if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
sd.initErrorHalt();
}


+ 3
- 3
SdFat/examples/#attic/fgetsRewrite/fgetsRewrite.ino Vedi File

@@ -95,9 +95,9 @@ void setup() {
SysCall::yield();
}

// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance.
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
// Initialize at the highest speed supported by the board that is
// not over 50 MHz. Try a lower speed if SPI errors occur.
if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
sd.initErrorHalt();
}


+ 3
- 3
SdFat/examples/#attic/readlog/readlog.ino Vedi File

@@ -22,9 +22,9 @@ void setup() {
while (!Serial) {
SysCall::yield();
}
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance.
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
// Initialize at the highest speed supported by the board that is
// not over 50 MHz. Try a lower speed if SPI errors occur.
if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
sd.initErrorHalt();
}


+ 5
- 10
SdFat/examples/AnalogBinLogger/AnalogBinLogger.ino Vedi File

@@ -256,12 +256,7 @@ ISR(TIMER1_COMPB_vect) {
}
//==============================================================================
// Error messages stored in flash.
#define error(msg) errorFlash(F(msg))
//------------------------------------------------------------------------------
void errorFlash(const __FlashStringHelper* msg) {
sd.errorPrint(msg);
fatalBlink();
}
#define error(msg) {sd.errorPrint(F(msg));fatalBlink();}
//------------------------------------------------------------------------------
//
void fatalBlink() {
@@ -625,8 +620,7 @@ void logData() {
// Create new file.
Serial.println(F("Creating new file"));
binFile.close();
if (!binFile.createContiguous(sd.vwd(),
TMP_FILE_NAME, 512 * FILE_BLOCK_COUNT)) {
if (!binFile.createContiguous(TMP_FILE_NAME, 512 * FILE_BLOCK_COUNT)) {
error("createContiguous failed");
}
// Get the address of the file on the SD.
@@ -783,8 +777,9 @@ void setup(void) {
Serial.print(F("FreeStack: "));
Serial.println(FreeStack());

// initialize file system.
if (!sd.begin(SD_CS_PIN, SPI_FULL_SPEED)) {
// Initialize at the highest speed supported by the board that is
// not over 50 MHz. Try a lower speed if SPI errors occur.
if (!sd.begin(SD_CS_PIN, SD_SCK_MHZ(50))) {
sd.initErrorPrint();
fatalBlink();
}

+ 3
- 1
SdFat/examples/LongFileName/LongFileName.ino Vedi File

@@ -31,7 +31,9 @@ void setup() {
"You can use test files located in\r\n"
"SdFat/examples/LongFileName/testFiles"));

if (!sd.begin(SD_CS_PIN)) {
// Initialize at the highest speed supported by the board that is
// not over 50 MHz. Try a lower speed if SPI errors occur.
if (!sd.begin(SD_CS_PIN, SD_SCK_MHZ(50))) {
sd.initErrorHalt();
}
Serial.print(F("FreeStack: "));

+ 272
- 243
SdFat/examples/LowLatencyLogger/LowLatencyLogger.ino Vedi File

@@ -9,65 +9,47 @@
*
* If your SD card has a long write latency, it may be necessary to use
* slower sample rates. Using a Mega Arduino helps overcome latency
* problems since 13 512 byte buffers will be used.
* problems since 12 512 byte buffers will be used.
*
* Data is written to the file using a SD multiple block write command.
*/
#include <SPI.h>
#include "SdFat.h"
#include "FreeStack.h"
#include "UserDataType.h" // Edit this include file to change data_t.
//------------------------------------------------------------------------------
// Set useSharedSpi true for use of an SPI sensor.
const bool useSharedSpi = false;

// File start time in micros.
uint32_t startMicros;
//------------------------------------------------------------------------------
// User data functions. Modify these functions for your data items.

// Acquire a data record.
void acquireData(data_t* data) {
data->time = micros();
for (int i = 0; i < ADC_DIM; i++) {
data->adc[i] = analogRead(i);
}
}

// Print a data record.
void printData(Print* pr, data_t* data) {
pr->print(data->time - startMicros);
for (int i = 0; i < ADC_DIM; i++) {
pr->write(',');
pr->print(data->adc[i]);
}
pr->println();
}
#include "UserTypes.h"

// Print data header.
void printHeader(Print* pr) {
pr->print(F("time"));
for (int i = 0; i < ADC_DIM; i++) {
pr->print(F(",adc"));
pr->print(i);
}
pr->println();
}
#ifdef __AVR_ATmega328P__
#include "MinimumSerial.h"
MinimumSerial MinSerial;
#define Serial MinSerial
#endif // __AVR_ATmega328P__
//==============================================================================
// Start of configuration constants.
//==============================================================================
// Abort run on an overrun. Data before the overrun will be saved.
#define ABORT_ON_OVERRUN 1
//------------------------------------------------------------------------------
//Interval between data records in microseconds.
const uint32_t LOG_INTERVAL_USEC = 2000;
//------------------------------------------------------------------------------
// Set USE_SHARED_SPI non-zero for use of an SPI sensor.
// May not work for some cards.
#ifndef USE_SHARED_SPI
#define USE_SHARED_SPI 0
#endif // USE_SHARED_SPI
//------------------------------------------------------------------------------
// Pin definitions.
//
// SD chip select pin.
const uint8_t SD_CS_PIN = SS;
//
// Digital pin to indicate an error, set to -1 if not used.
// The led blinks for fatal errors. The led goes on solid for SD write
// overrun errors and logging continues.
// The led blinks for fatal errors. The led goes on solid for
// overrun errors and logging continues unless ABORT_ON_OVERRUN
// is non-zero.
#ifdef ERROR_LED_PIN
#undef ERROR_LED_PIN
#endif // ERROR_LED_PIN
const int8_t ERROR_LED_PIN = -1;
//------------------------------------------------------------------------------
// File definitions.
@@ -77,32 +59,34 @@ const int8_t ERROR_LED_PIN = -1;
// This file is flash erased using special SD commands. The file will be
// truncated if logging is stopped early.
const uint32_t FILE_BLOCK_COUNT = 256000;

// log file base name. Must be six characters or less.
//
// log file base name if not defined in UserTypes.h
#ifndef FILE_BASE_NAME
#define FILE_BASE_NAME "data"
#endif // FILE_BASE_NAME
//------------------------------------------------------------------------------
// Buffer definitions.
//
// The logger will use SdFat's buffer plus BUFFER_BLOCK_COUNT additional
// The logger will use SdFat's buffer plus BUFFER_BLOCK_COUNT-1 additional
// buffers.
//
#ifndef RAMEND
// Assume ARM. Use total of nine 512 byte buffers.
const uint8_t BUFFER_BLOCK_COUNT = 8;
// Assume ARM. Use total of ten 512 byte buffers.
const uint8_t BUFFER_BLOCK_COUNT = 10;
//
#elif RAMEND < 0X8FF
#error Too little SRAM
//
#elif RAMEND < 0X10FF
// Use total of two 512 byte buffers.
const uint8_t BUFFER_BLOCK_COUNT = 1;
const uint8_t BUFFER_BLOCK_COUNT = 2;
//
#elif RAMEND < 0X20FF
// Use total of five 512 byte buffers.
// Use total of four 512 byte buffers.
const uint8_t BUFFER_BLOCK_COUNT = 4;
//
#else // RAMEND
// Use total of 13 512 byte buffers.
// Use total of 12 512 byte buffers.
const uint8_t BUFFER_BLOCK_COUNT = 12;
#endif // RAMEND
//==============================================================================
@@ -113,13 +97,13 @@ const uint8_t BUFFER_BLOCK_COUNT = 12;

// Size of file base name. Must not be larger than six.
const uint8_t BASE_NAME_SIZE = sizeof(FILE_BASE_NAME) - 1;
const uint8_t FILE_NAME_DIM = BASE_NAME_SIZE + 7;
char binName[FILE_NAME_DIM] = FILE_BASE_NAME "00.bin";

SdFat sd;

SdBaseFile binFile;

char binName[13] = FILE_BASE_NAME "00.bin";

// Number of data records in a block.
const uint16_t DATA_DIM = (512 - 4)/sizeof(data_t);

@@ -132,33 +116,14 @@ struct block_t {
data_t data[DATA_DIM];
uint8_t fill[FILL_DIM];
};

const uint8_t QUEUE_DIM = BUFFER_BLOCK_COUNT + 2;

block_t* emptyQueue[QUEUE_DIM];
uint8_t emptyHead;
uint8_t emptyTail;

block_t* fullQueue[QUEUE_DIM];
uint8_t fullHead;
uint8_t fullTail;

// Advance queue index.
inline uint8_t queueNext(uint8_t ht) {
return ht < (QUEUE_DIM - 1) ? ht + 1 : 0;
}
//==============================================================================
// Error messages stored in flash.
#define error(msg) errorFlash(F(msg))
//------------------------------------------------------------------------------
void errorFlash(const __FlashStringHelper* msg) {
sd.errorPrint(msg);
fatalBlink();
}
#define error(msg) {sd.errorPrint(&Serial, F(msg));fatalBlink();}
//------------------------------------------------------------------------------
//
void fatalBlink() {
while (true) {
SysCall::yield();
if (ERROR_LED_PIN >= 0) {
digitalWrite(ERROR_LED_PIN, HIGH);
delay(200);
@@ -167,7 +132,49 @@ void fatalBlink() {
}
}
}
//==============================================================================
//------------------------------------------------------------------------------
// read data file and check for overruns
void checkOverrun() {
bool headerPrinted = false;
block_t block;
uint32_t bn = 0;

if (!binFile.isOpen()) {
Serial.println();
Serial.println(F("No current binary file"));
return;
}
binFile.rewind();
Serial.println();
Serial.print(F("FreeStack: "));
Serial.println(FreeStack());
Serial.println(F("Checking overrun errors - type any character to stop"));
while (binFile.read(&block, 512) == 512) {
if (block.count == 0) {
break;
}
if (block.overrun) {
if (!headerPrinted) {
Serial.println();
Serial.println(F("Overruns:"));
Serial.println(F("fileBlockNumber,sdBlockNumber,overrunCount"));
headerPrinted = true;
}
Serial.print(bn);
Serial.print(',');
Serial.print(binFile.firstBlock() + bn);
Serial.print(',');
Serial.println(block.overrun);
}
bn++;
}
if (!headerPrinted) {
Serial.println(F("No errors found"));
} else {
Serial.println(F("Done"));
}
}
//-----------------------------------------------------------------------------
// Convert binary file to csv file.
void binaryToCsv() {
uint8_t lastPct = 0;
@@ -175,14 +182,17 @@ void binaryToCsv() {
uint32_t t0 = millis();
uint32_t syncCluster = 0;
SdFile csvFile;
char csvName[13];
char csvName[FILE_NAME_DIM];

if (!binFile.isOpen()) {
Serial.println();
Serial.println(F("No current binary file"));
return;
}
binFile.rewind();
Serial.println();
Serial.print(F("FreeStack: "));
Serial.println(FreeStack());
// Create a new csvFile.
strcpy(csvName, binName);
strcpy(&csvName[BASE_NAME_SIZE + 3], "csv");
@@ -190,7 +200,7 @@ void binaryToCsv() {
if (!csvFile.open(csvName, O_WRITE | O_CREAT | O_TRUNC)) {
error("open csvFile failed");
}
Serial.println();
binFile.rewind();
Serial.print(F("Writing: "));
Serial.print(csvName);
Serial.println(F(" - type any character to stop"));
@@ -230,48 +240,55 @@ void binaryToCsv() {
Serial.print(0.001*(millis() - t0));
Serial.println(F(" Seconds"));
}
//------------------------------------------------------------------------------
// read data file and check for overruns
void checkOverrun() {
bool headerPrinted = false;
block_t block;
//-----------------------------------------------------------------------------
void createBinFile() {
// max number of blocks to erase per erase call
const uint32_t ERASE_SIZE = 262144L;
uint32_t bgnBlock, endBlock;
uint32_t bn = 0;

if (!binFile.isOpen()) {
Serial.println();
Serial.println(F("No current binary file"));
return;
Serial.println();
while (sd.exists(binName)) {
if (binName[BASE_NAME_SIZE + 1] != '9') {
binName[BASE_NAME_SIZE + 1]++;
} else {
binName[BASE_NAME_SIZE + 1] = '0';
if (binName[BASE_NAME_SIZE] == '9') {
error("Can't create file name");
}
binName[BASE_NAME_SIZE]++;
}
}
// Delete old tmp file.
if (sd.exists(TMP_FILE_NAME)) {
Serial.println(F("Deleting tmp file"));
if (!sd.remove(TMP_FILE_NAME)) {
error("Can't remove tmp file");
}
}
// Create new file.
Serial.println(F("Creating new file"));
binFile.close();
if (!binFile.createContiguous(TMP_FILE_NAME, 512 * FILE_BLOCK_COUNT)) {
error("createContiguous failed");
}
// Get the address of the file on the SD.
if (!binFile.contiguousRange(&bgnBlock, &endBlock)) {
error("contiguousRange failed");
}
binFile.rewind();
Serial.println();
Serial.println(F("Checking overrun errors - type any character to stop"));
while (binFile.read(&block, 512) == 512) {
if (block.count == 0) {
break;
// Flash erase all data in the file.
Serial.println(F("Erasing all data"));
uint32_t bgnErase = bgnBlock;
uint32_t endErase;
while (bgnErase < endBlock) {
endErase = bgnErase + ERASE_SIZE;
if (endErase > endBlock) {
endErase = endBlock;
}
if (block.overrun) {
if (!headerPrinted) {
Serial.println();
Serial.println(F("Overruns:"));
Serial.println(F("fileBlockNumber,sdBlockNumber,overrunCount"));
headerPrinted = true;
}
Serial.print(bn);
Serial.print(',');
Serial.print(bgnBlock + bn);
Serial.print(',');
Serial.println(block.overrun);
if (!sd.card()->erase(bgnErase, endErase)) {
error("erase failed");
}
bn++;
}
if (!headerPrinted) {
Serial.println(F("No errors found"));
} else {
Serial.println(F("Done"));
bgnErase = endErase + 1;
}
}
//------------------------------------------------------------------------------
@@ -304,127 +321,105 @@ void dumpData() {
}
//------------------------------------------------------------------------------
// log data
// max number of blocks to erase per erase call
uint32_t const ERASE_SIZE = 262144L;
void logData() {
uint32_t bgnBlock, endBlock;

// Allocate extra buffer space.
block_t block[BUFFER_BLOCK_COUNT];
block_t* curBlock = 0;
Serial.println();

// Find unused file name.
if (BASE_NAME_SIZE > 6) {
error("FILE_BASE_NAME too long");
}
while (sd.exists(binName)) {
if (binName[BASE_NAME_SIZE + 1] != '9') {
binName[BASE_NAME_SIZE + 1]++;
} else {
binName[BASE_NAME_SIZE + 1] = '0';
if (binName[BASE_NAME_SIZE] == '9') {
error("Can't create file name");
}
binName[BASE_NAME_SIZE]++;
createBinFile();
recordBinFile();
renameBinFile();
}
//------------------------------------------------------------------------------
void openBinFile() {
char name[FILE_NAME_DIM];
strcpy(name, binName);
Serial.println(F("\nEnter two digit version"));
Serial.write(name, BASE_NAME_SIZE);
for (int i = 0; i < 2; i++) {
while (!Serial.available()) {
SysCall::yield();
}
}
// Delete old tmp file.
if (sd.exists(TMP_FILE_NAME)) {
Serial.println(F("Deleting tmp file"));
if (!sd.remove(TMP_FILE_NAME)) {
error("Can't remove tmp file");
char c = Serial.read();
Serial.write(c);
if (c < '0' || c > '9') {
Serial.println("\nInvalid digit");
return;
}
name[BASE_NAME_SIZE + i] = c;
}
// Create new file.
Serial.println(F("Creating new file"));
binFile.close();
if (!binFile.createContiguous(sd.vwd(),
TMP_FILE_NAME, 512 * FILE_BLOCK_COUNT)) {
error("createContiguous failed");
Serial.println(&name[BASE_NAME_SIZE+2]);
if (!sd.exists(name)) {
Serial.println(F("File does not exist"));
return;
}
// Get the address of the file on the SD.
if (!binFile.contiguousRange(&bgnBlock, &endBlock)) {
error("contiguousRange failed");
binFile.close();
strcpy(binName, name);
if (!binFile.open(binName, O_READ)) {
Serial.println(F("open failed"));
return;
}
Serial.println(F("File opened"));
}
//------------------------------------------------------------------------------
void recordBinFile() {
const uint8_t QUEUE_DIM = BUFFER_BLOCK_COUNT + 1;
// Index of last queue location.
const uint8_t QUEUE_LAST = QUEUE_DIM - 1;
// Allocate extra buffer space.
block_t block[BUFFER_BLOCK_COUNT - 1];
block_t* curBlock = 0;
block_t* emptyStack[BUFFER_BLOCK_COUNT];
uint8_t emptyTop;
uint8_t minTop;

block_t* fullQueue[QUEUE_DIM];
uint8_t fullHead = 0;
uint8_t fullTail = 0;

// Use SdFat's internal buffer.
uint8_t* cache = (uint8_t*)sd.vol()->cacheClear();
if (cache == 0) {
emptyStack[0] = (block_t*)sd.vol()->cacheClear();
if (emptyStack[0] == 0) {
error("cacheClear failed");
}

// Flash erase all data in the file.
Serial.println(F("Erasing all data"));
uint32_t bgnErase = bgnBlock;
uint32_t endErase;
while (bgnErase < endBlock) {
endErase = bgnErase + ERASE_SIZE;
if (endErase > endBlock) {
endErase = endBlock;
}
if (!sd.card()->erase(bgnErase, endErase)) {
error("erase failed");
}
bgnErase = endErase + 1;
// Put rest of buffers on the empty stack.
for (int i = 1; i < BUFFER_BLOCK_COUNT; i++) {
emptyStack[i] = &block[i - 1];
}
emptyTop = BUFFER_BLOCK_COUNT;
minTop = BUFFER_BLOCK_COUNT;
// Start a multiple block write.
if (!sd.card()->writeStart(bgnBlock, FILE_BLOCK_COUNT)) {
error("writeBegin failed");
}
// Set chip select high if other devices use SPI.
if (useSharedSpi) {
sd.card()->chipSelectHigh();
}
// Initialize queues.
emptyHead = emptyTail = 0;
fullHead = fullTail = 0;

// Use SdFat buffer for one block.
emptyQueue[emptyHead] = (block_t*)cache;
emptyHead = queueNext(emptyHead);

// Put rest of buffers in the empty queue.
for (uint8_t i = 0; i < BUFFER_BLOCK_COUNT; i++) {
emptyQueue[emptyHead] = &block[i];
emptyHead = queueNext(emptyHead);
if (!sd.card()->writeStart(binFile.firstBlock())) {
error("writeBStart failed");
}
Serial.print(F("FreeStack: "));
Serial.println(FreeStack());
Serial.println(F("Logging - type any character to stop"));
// Wait for Serial Idle.
Serial.flush();
delay(10);
bool closeFile = false;
uint32_t bn = 0;
uint32_t t0 = millis();
uint32_t t1 = t0;
uint32_t bn = 0;
uint32_t maxLatency = 0;
uint32_t overrun = 0;
uint32_t overrunTotal = 0;
uint32_t count = 0;
uint32_t maxDelta = 0;
uint32_t minDelta = 99999;
uint32_t maxLatency = 0;
uint32_t logTime = micros();

// Set time for first record of file.
startMicros = logTime + LOG_INTERVAL_USEC;

while (1) {
// Time for next data record.
while(1) {
// Time for next data record.
logTime += LOG_INTERVAL_USEC;
if (Serial.available()) {
closeFile = true;
}

}
if (closeFile) {
if (curBlock != 0) {
// Put buffer in full queue.
fullQueue[fullHead] = curBlock;
fullHead = queueNext(fullHead);
fullHead = fullHead < QUEUE_LAST ? fullHead + 1 : 0;
curBlock = 0;
}
} else {
if (curBlock == 0 && emptyTail != emptyHead) {
curBlock = emptyQueue[emptyTail];
emptyTail = queueNext(emptyTail);
if (curBlock == 0 && emptyTop != 0) {
curBlock = emptyStack[--emptyTop];
if (emptyTop < minTop) {
minTop = emptyTop;
}
curBlock->count = 0;
curBlock->overrun = overrun;
overrun = 0;
@@ -438,18 +433,29 @@ void logData() {
} while (delta < 0);
if (curBlock == 0) {
overrun++;
overrunTotal++;
if (ERROR_LED_PIN >= 0) {
digitalWrite(ERROR_LED_PIN, HIGH);
}
#if ABORT_ON_OVERRUN
Serial.println(F("Overrun abort"));
break;
#endif // ABORT_ON_OVERRUN
} else {
acquireData(&curBlock->data[curBlock->count++]);
#if USE_SHARED_SPI
sd.card()->spiStop();
#endif // USE_SHARED_SPI
acquireData(&curBlock->data[curBlock->count++]);
#if USE_SHARED_SPI
sd.card()->spiStart();
#endif // USE_SHARED_SPI
if (curBlock->count == DATA_DIM) {
fullQueue[fullHead] = curBlock;
fullHead = queueNext(fullHead);
fullHead = fullHead < QUEUE_LAST ? fullHead + 1 : 0;
curBlock = 0;
}
if ((uint32_t)delta > maxDelta) maxDelta = delta;
if ((uint32_t)delta < minDelta) minDelta = delta;
}
}
}

if (fullHead == fullTail) {
// Exit loop if done.
if (closeFile) {
@@ -458,29 +464,18 @@ void logData() {
} else if (!sd.card()->isBusy()) {
// Get address of block to write.
block_t* pBlock = fullQueue[fullTail];
fullTail = queueNext(fullTail);
fullTail = fullTail < QUEUE_LAST ? fullTail + 1 : 0;
// Write block to SD.
uint32_t usec = micros();
if (!sd.card()->writeData((uint8_t*)pBlock)) {
error("write data failed");
}
usec = micros() - usec;
t1 = millis();
if (usec > maxLatency) {
maxLatency = usec;
}
count += pBlock->count;

// Add overruns and possibly light LED.
if (pBlock->overrun) {
overrunTotal += pBlock->overrun;
if (ERROR_LED_PIN >= 0) {
digitalWrite(ERROR_LED_PIN, HIGH);
}
}
// Move block to empty queue.
emptyQueue[emptyHead] = pBlock;
emptyHead = queueNext(emptyHead);
emptyStack[emptyTop++] = pBlock;
bn++;
if (bn == FILE_BLOCK_COUNT) {
// File full so stop
@@ -491,6 +486,12 @@ void logData() {
if (!sd.card()->writeStop()) {
error("writeStop failed");
}
Serial.print(F("Min Free buffers: "));
Serial.println(minTop);
Serial.print(F("Max block write usec: "));
Serial.println(maxLatency);
Serial.print(F("Overruns: "));
Serial.println(overrunTotal);
// Truncate file if recording stopped early.
if (bn != FILE_BLOCK_COUNT) {
Serial.println(F("Truncating file"));
@@ -498,25 +499,38 @@ void logData() {
error("Can't truncate file");
}
}
}
//-----------------------------------------------------------------------------
void renameBinFile() {
if (!binFile.rename(sd.vwd(), binName)) {
error("Can't rename file");
}
}
Serial.print(F("File renamed: "));
Serial.println(binName);
Serial.print(F("Max block write usec: "));
Serial.println(maxLatency);
Serial.print(F("Record time sec: "));
Serial.println(0.001*(t1 - t0), 3);
Serial.print(minDelta);
Serial.print(F(" <= jitter microseconds <= "));
Serial.println(maxDelta);
Serial.print(F("Sample count: "));
Serial.println(count);
Serial.print(F("Samples/sec: "));
Serial.println((1000.0)*count/(t1-t0));
Serial.print(F("Overruns: "));
Serial.println(overrunTotal);
Serial.println(F("Done"));
Serial.print("File size: ");
Serial.print(binFile.fileSize()/512);
Serial.println(F(" blocks"));
Serial.print(F("FreeStack: "));
Serial.println(FreeStack());
}
//------------------------------------------------------------------------------
void testSensor() {
const uint32_t interval = 200000;
int32_t diff;
data_t data;
Serial.println(F("\nTesting - type any character to stop\n"));
// Wait for Serial Idle.
delay(1000);
printHeader(&Serial);
uint32_t m = micros();
while (!Serial.available()) {
m += interval;
do {
diff = m - micros();
} while (diff > 0);
acquireData(&data);
printData(&Serial, &data);
}
}
//------------------------------------------------------------------------------
void setup(void) {
@@ -529,7 +543,6 @@ void setup(void) {
while (!Serial) {
SysCall::yield();
}

Serial.print(F("FreeStack: "));
Serial.println(FreeStack());
Serial.print(F("Records/block: "));
@@ -537,11 +550,13 @@ void setup(void) {
if (sizeof(block_t) != 512) {
error("Invalid block size");
}
// initialize file system.
if (!sd.begin(SD_CS_PIN, SPI_FULL_SPEED)) {
sd.initErrorPrint();
// Initialize at the highest speed supported by the board that is
// not over 50 MHz. Try a lower speed if SPI errors occur.
if (!sd.begin(SD_CS_PIN, SD_SCK_MHZ(50))) {
sd.initErrorPrint(&Serial);
fatalBlink();
}
userSetup();
}
//------------------------------------------------------------------------------
void loop(void) {
@@ -551,14 +566,21 @@ void loop(void) {
} while (Serial.available() && Serial.read() >= 0);
Serial.println();
Serial.println(F("type:"));
Serial.println(F("b - open existing bin file"));
Serial.println(F("c - convert file to csv"));
Serial.println(F("d - dump data to Serial"));
Serial.println(F("e - overrun error details"));
Serial.println(F("l - list files"));
Serial.println(F("r - record data"));
Serial.println(F("t - test without logging"));
while(!Serial.available()) {
SysCall::yield();
}
#if WDT_YIELD_TIME_MICROS
Serial.println(F("LowLatencyLogger can not run with watchdog timer"));
SysCall::halt();
#endif
char c = tolower(Serial.read());

// Discard extra Serial data.
@@ -569,14 +591,21 @@ void loop(void) {
if (ERROR_LED_PIN >= 0) {
digitalWrite(ERROR_LED_PIN, LOW);
}
if (c == 'c') {
if (c == 'b') {
openBinFile();
} else if (c == 'c') {
binaryToCsv();
} else if (c == 'd') {
dumpData();
} else if (c == 'e') {
checkOverrun();
} else if (c == 'l') {
Serial.println(F("\nls:"));
sd.ls(&Serial, LS_SIZE);
} else if (c == 'r') {
logData();
} else if (c == 't') {
testSensor();
} else {
Serial.println(F("Invalid entry"));
}

+ 0
- 8
SdFat/examples/LowLatencyLogger/UserDataType.h Vedi File

@@ -1,8 +0,0 @@
#ifndef UserDataType_h
#define UserDataType_h
const uint8_t ADC_DIM = 4;
struct data_t {
unsigned long time;
unsigned short adc[ADC_DIM];
};
#endif // UserDataType_h

+ 41
- 0
SdFat/examples/LowLatencyLogger/UserFunctions.cpp Vedi File

@@ -0,0 +1,41 @@
#include "UserTypes.h"
// User data functions. Modify these functions for your data items.

// Start time for data
uint32_t startTime;

// Acquire a data record.
void acquireData(data_t* data) {
data->time = micros();
for (int i = 0; i < ADC_DIM; i++) {
data->adc[i] = analogRead(i);
}
}

// Print a data record.
void printData(Print* pr, data_t* data) {
if (startTime == 0) {
startTime = data->time;
}
pr->print(data->time - startTime);
for (int i = 0; i < ADC_DIM; i++) {
pr->write(',');
pr->print(data->adc[i]);
}
pr->println();
}

// Print data header.
void printHeader(Print* pr) {
startTime = 0;
pr->print(F("micros"));
for (int i = 0; i < ADC_DIM; i++) {
pr->print(F(",adc"));
pr->print(i);
}
pr->println();
}

// Sensor setup
void userSetup() {
}

+ 15
- 0
SdFat/examples/LowLatencyLogger/UserTypes.h Vedi File

@@ -0,0 +1,15 @@
#ifndef UserTypes_h
#define UserTypes_h
#include "Arduino.h"
// User data types. Modify for your data items.
#define FILE_BASE_NAME "adc4pin"
const uint8_t ADC_DIM = 4;
struct data_t {
unsigned long time;
unsigned short adc[ADC_DIM];
};
void acquireData(data_t* data);
void printData(Print* pr, data_t* data);
void printHeader(Print* pr);
void userSetup();
#endif // UserTypes_h

LowLatencyLoggerADXL345/LowLatencyLoggerADXL345.ino → SdFat/examples/LowLatencyLoggerADXL345/LowLatencyLogger.ino Vedi File

@@ -9,84 +9,34 @@
*
* If your SD card has a long write latency, it may be necessary to use
* slower sample rates. Using a Mega Arduino helps overcome latency
* problems since 13 512 byte buffers will be used.
* problems since 12 512 byte buffers will be used.
*
* Data is written to the file using a SD multiple block write command.
*/
#include <SPI.h>
#include "SdFat.h"
#include "FreeStack.h"
//------------------------------------------------------------------------------
// Set useSharedSpi true for use of an SPI sensor.
const bool useSharedSpi = true;

// File start time in micros.
uint32_t startMicros;
//------------------------------------------------------------------------------
// User data functions. Modify these functions for your data items.
#include "UserDataType.h" // Edit this include file to change data_t.

const uint8_t ADXL345_CS = 9;

const uint8_t POWER_CTL = 0x2D; //Power Control Register
const uint8_t DATA_FORMAT = 0x31;
const uint8_t DATAX0 = 0x32; //X-Axis Data 0
const uint8_t DATAX1 = 0x33; //X-Axis Data 1
const uint8_t DATAY0 = 0x34; //Y-Axis Data 0
const uint8_t DATAY1 = 0x35; //Y-Axis Data 1
const uint8_t DATAZ0 = 0x36; //Z-Axis Data 0
const uint8_t DATAZ1 = 0x37; //Z-Axis Data 1

void writeADXL345Register(const uint8_t registerAddress, const uint8_t value) {
SPI.setDataMode(SPI_MODE3);
digitalWrite(ADXL345_CS, LOW);
SPI.transfer(registerAddress);
SPI.transfer(value);
digitalWrite(ADXL345_CS, HIGH);
}

void setupADXL345() {
SPI.begin();
pinMode(ADXL345_CS, OUTPUT);
digitalWrite(ADXL345_CS, HIGH);
//Put the ADXL345 into +/- 4G range by writing the value 0x01 to the DATA_FORMAT register.
writeADXL345Register(DATA_FORMAT, 0x01);
//Put the ADXL345 into Measurement Mode by writing 0x08 to the POWER_CTL register.
writeADXL345Register(POWER_CTL, 0x08); //Measurement mode
}

// Acquire a data record.
void acquireData(data_t* data) {
data->time = micros();
SPI.setDataMode(SPI_MODE3);
digitalWrite(ADXL345_CS, LOW);
// Read multiple bytes so or 0XC0 with address.
SPI.transfer(DATAX0 | 0XC0);
data->accel[0] = SPI.transfer(0) | (SPI.transfer(0) << 8);
data->accel[1] = SPI.transfer(0) | (SPI.transfer(0) << 8);
data->accel[2] = SPI.transfer(0) | (SPI.transfer(0) << 8);
digitalWrite(ADXL345_CS, HIGH);
}

// Print a data record.
void printData(Print* pr, data_t* data) {
pr->print(data->time - startMicros);
for (int i = 0; i < ACCEL_DIM; i++) {
pr->write(',');
pr->print(data->accel[i]);
}
pr->println();
}
#include "UserTypes.h"

// Print data header.
void printHeader(Print* pr) {
pr->println(F("time,ax,ay,az"));
}
#ifdef __AVR_ATmega328P__
#include "MinimumSerial.h"
MinimumSerial MinSerial;
#define Serial MinSerial
#endif // __AVR_ATmega328P__
//==============================================================================
// Start of configuration constants.
//==============================================================================
// Abort run on an overrun. Data before the overrun will be saved.
#define ABORT_ON_OVERRUN 1
//------------------------------------------------------------------------------
//Interval between data records in microseconds.
const uint32_t LOG_INTERVAL_USEC = 10000;
const uint32_t LOG_INTERVAL_USEC = 2000;
//------------------------------------------------------------------------------
// Set USE_SHARED_SPI non-zero for use of an SPI sensor.
// May not work for some cards.
#ifndef USE_SHARED_SPI
#define USE_SHARED_SPI 0
#endif // USE_SHARED_SPI
//------------------------------------------------------------------------------
// Pin definitions.
//
@@ -94,8 +44,12 @@ const uint32_t LOG_INTERVAL_USEC = 10000;
const uint8_t SD_CS_PIN = SS;
//
// Digital pin to indicate an error, set to -1 if not used.
// The led blinks for fatal errors. The led goes on solid for SD write
// overrun errors and logging continues.
// The led blinks for fatal errors. The led goes on solid for
// overrun errors and logging continues unless ABORT_ON_OVERRUN
// is non-zero.
#ifdef ERROR_LED_PIN
#undef ERROR_LED_PIN
#endif // ERROR_LED_PIN
const int8_t ERROR_LED_PIN = -1;
//------------------------------------------------------------------------------
// File definitions.
@@ -105,32 +59,34 @@ const int8_t ERROR_LED_PIN = -1;
// This file is flash erased using special SD commands. The file will be
// truncated if logging is stopped early.
const uint32_t FILE_BLOCK_COUNT = 256000;

// log file base name. Must be six characters or less.
//
// log file base name if not defined in UserTypes.h
#ifndef FILE_BASE_NAME
#define FILE_BASE_NAME "data"
#endif // FILE_BASE_NAME
//------------------------------------------------------------------------------
// Buffer definitions.
//
// The logger will use SdFat's buffer plus BUFFER_BLOCK_COUNT additional
// The logger will use SdFat's buffer plus BUFFER_BLOCK_COUNT-1 additional
// buffers.
//
#ifndef RAMEND
// Assume ARM. Use total of nine 512 byte buffers.
const uint8_t BUFFER_BLOCK_COUNT = 8;
// Assume ARM. Use total of ten 512 byte buffers.
const uint8_t BUFFER_BLOCK_COUNT = 10;
//
#elif RAMEND < 0X8FF
#error Too little SRAM
//
#elif RAMEND < 0X10FF
// Use total of two 512 byte buffers.
const uint8_t BUFFER_BLOCK_COUNT = 1;
const uint8_t BUFFER_BLOCK_COUNT = 2;
//
#elif RAMEND < 0X20FF
// Use total of five 512 byte buffers.
// Use total of four 512 byte buffers.
const uint8_t BUFFER_BLOCK_COUNT = 4;
//
#else // RAMEND
// Use total of 13 512 byte buffers.
// Use total of 12 512 byte buffers.
const uint8_t BUFFER_BLOCK_COUNT = 12;
#endif // RAMEND
//==============================================================================
@@ -141,13 +97,13 @@ const uint8_t BUFFER_BLOCK_COUNT = 12;

// Size of file base name. Must not be larger than six.
const uint8_t BASE_NAME_SIZE = sizeof(FILE_BASE_NAME) - 1;
const uint8_t FILE_NAME_DIM = BASE_NAME_SIZE + 7;
char binName[FILE_NAME_DIM] = FILE_BASE_NAME "00.bin";

SdFat sd;

SdBaseFile binFile;

char binName[13] = FILE_BASE_NAME "00.bin";

// Number of data records in a block.
const uint16_t DATA_DIM = (512 - 4)/sizeof(data_t);

@@ -160,33 +116,14 @@ struct block_t {
data_t data[DATA_DIM];
uint8_t fill[FILL_DIM];
};

const uint8_t QUEUE_DIM = BUFFER_BLOCK_COUNT + 2;

block_t* emptyQueue[QUEUE_DIM];
uint8_t emptyHead;
uint8_t emptyTail;

block_t* fullQueue[QUEUE_DIM];
uint8_t fullHead;
uint8_t fullTail;

// Advance queue index.
inline uint8_t queueNext(uint8_t ht) {
return ht < (QUEUE_DIM - 1) ? ht + 1 : 0;
}
//==============================================================================
// Error messages stored in flash.
#define error(msg) errorFlash(F(msg))
//------------------------------------------------------------------------------
void errorFlash(const __FlashStringHelper* msg) {
sd.errorPrint(msg);
fatalBlink();
}
#define error(msg) {sd.errorPrint(&Serial, F(msg));fatalBlink();}
//------------------------------------------------------------------------------
//
void fatalBlink() {
while (true) {
SysCall::yield();
if (ERROR_LED_PIN >= 0) {
digitalWrite(ERROR_LED_PIN, HIGH);
delay(200);
@@ -195,7 +132,49 @@ void fatalBlink() {
}
}
}
//==============================================================================
//------------------------------------------------------------------------------
// read data file and check for overruns
void checkOverrun() {
bool headerPrinted = false;
block_t block;
uint32_t bn = 0;

if (!binFile.isOpen()) {
Serial.println();
Serial.println(F("No current binary file"));
return;
}
binFile.rewind();
Serial.println();
Serial.print(F("FreeStack: "));
Serial.println(FreeStack());
Serial.println(F("Checking overrun errors - type any character to stop"));
while (binFile.read(&block, 512) == 512) {
if (block.count == 0) {
break;
}
if (block.overrun) {
if (!headerPrinted) {
Serial.println();
Serial.println(F("Overruns:"));
Serial.println(F("fileBlockNumber,sdBlockNumber,overrunCount"));
headerPrinted = true;
}
Serial.print(bn);
Serial.print(',');
Serial.print(binFile.firstBlock() + bn);
Serial.print(',');
Serial.println(block.overrun);
}
bn++;
}
if (!headerPrinted) {
Serial.println(F("No errors found"));
} else {
Serial.println(F("Done"));
}
}
//-----------------------------------------------------------------------------
// Convert binary file to csv file.
void binaryToCsv() {
uint8_t lastPct = 0;
@@ -203,14 +182,17 @@ void binaryToCsv() {
uint32_t t0 = millis();
uint32_t syncCluster = 0;
SdFile csvFile;
char csvName[13];
char csvName[FILE_NAME_DIM];

if (!binFile.isOpen()) {
Serial.println();
Serial.println(F("No current binary file"));
return;
}
binFile.rewind();
Serial.println();
Serial.print(F("FreeStack: "));
Serial.println(FreeStack());
// Create a new csvFile.
strcpy(csvName, binName);
strcpy(&csvName[BASE_NAME_SIZE + 3], "csv");
@@ -218,7 +200,7 @@ void binaryToCsv() {
if (!csvFile.open(csvName, O_WRITE | O_CREAT | O_TRUNC)) {
error("open csvFile failed");
}
Serial.println();
binFile.rewind();
Serial.print(F("Writing: "));
Serial.print(csvName);
Serial.println(F(" - type any character to stop"));
@@ -258,48 +240,55 @@ void binaryToCsv() {
Serial.print(0.001*(millis() - t0));
Serial.println(F(" Seconds"));
}
//------------------------------------------------------------------------------
// read data file and check for overruns
void checkOverrun() {
bool headerPrinted = false;
block_t block;
//-----------------------------------------------------------------------------
void createBinFile() {
// max number of blocks to erase per erase call
const uint32_t ERASE_SIZE = 262144L;
uint32_t bgnBlock, endBlock;
uint32_t bn = 0;

if (!binFile.isOpen()) {
Serial.println();
Serial.println(F("No current binary file"));
return;
Serial.println();
while (sd.exists(binName)) {
if (binName[BASE_NAME_SIZE + 1] != '9') {
binName[BASE_NAME_SIZE + 1]++;
} else {
binName[BASE_NAME_SIZE + 1] = '0';
if (binName[BASE_NAME_SIZE] == '9') {
error("Can't create file name");
}
binName[BASE_NAME_SIZE]++;
}
}
// Delete old tmp file.
if (sd.exists(TMP_FILE_NAME)) {
Serial.println(F("Deleting tmp file"));
if (!sd.remove(TMP_FILE_NAME)) {
error("Can't remove tmp file");
}
}
// Create new file.
Serial.println(F("Creating new file"));
binFile.close();
if (!binFile.createContiguous(TMP_FILE_NAME, 512 * FILE_BLOCK_COUNT)) {
error("createContiguous failed");
}
// Get the address of the file on the SD.
if (!binFile.contiguousRange(&bgnBlock, &endBlock)) {
error("contiguousRange failed");
}
binFile.rewind();
Serial.println();
Serial.println(F("Checking overrun errors - type any character to stop"));
while (binFile.read(&block, 512) == 512) {
if (block.count == 0) {
break;
// Flash erase all data in the file.
Serial.println(F("Erasing all data"));
uint32_t bgnErase = bgnBlock;
uint32_t endErase;
while (bgnErase < endBlock) {
endErase = bgnErase + ERASE_SIZE;
if (endErase > endBlock) {
endErase = endBlock;
}
if (block.overrun) {
if (!headerPrinted) {
Serial.println();
Serial.println(F("Overruns:"));
Serial.println(F("fileBlockNumber,sdBlockNumber,overrunCount"));
headerPrinted = true;
}
Serial.print(bn);
Serial.print(',');
Serial.print(bgnBlock + bn);
Serial.print(',');
Serial.println(block.overrun);
if (!sd.card()->erase(bgnErase, endErase)) {
error("erase failed");
}
bn++;
}
if (!headerPrinted) {
Serial.println(F("No errors found"));
} else {
Serial.println(F("Done"));
bgnErase = endErase + 1;
}
}
//------------------------------------------------------------------------------
@@ -332,127 +321,105 @@ void dumpData() {
}
//------------------------------------------------------------------------------
// log data
// max number of blocks to erase per erase call
uint32_t const ERASE_SIZE = 262144L;
void logData() {
uint32_t bgnBlock, endBlock;

// Allocate extra buffer space.
block_t block[BUFFER_BLOCK_COUNT];
block_t* curBlock = 0;
Serial.println();

// Find unused file name.
if (BASE_NAME_SIZE > 6) {
error("FILE_BASE_NAME too long");
}
while (sd.exists(binName)) {
if (binName[BASE_NAME_SIZE + 1] != '9') {
binName[BASE_NAME_SIZE + 1]++;
} else {
binName[BASE_NAME_SIZE + 1] = '0';
if (binName[BASE_NAME_SIZE] == '9') {
error("Can't create file name");
}
binName[BASE_NAME_SIZE]++;
createBinFile();
recordBinFile();
renameBinFile();
}
//------------------------------------------------------------------------------
void openBinFile() {
char name[FILE_NAME_DIM];
strcpy(name, binName);
Serial.println(F("\nEnter two digit version"));
Serial.write(name, BASE_NAME_SIZE);
for (int i = 0; i < 2; i++) {
while (!Serial.available()) {
SysCall::yield();
}
}
// Delete old tmp file.
if (sd.exists(TMP_FILE_NAME)) {
Serial.println(F("Deleting tmp file"));
if (!sd.remove(TMP_FILE_NAME)) {
error("Can't remove tmp file");
char c = Serial.read();
Serial.write(c);
if (c < '0' || c > '9') {
Serial.println("\nInvalid digit");
return;
}
name[BASE_NAME_SIZE + i] = c;
}
// Create new file.
Serial.println(F("Creating new file"));
binFile.close();
if (!binFile.createContiguous(sd.vwd(),
TMP_FILE_NAME, 512 * FILE_BLOCK_COUNT)) {
error("createContiguous failed");
Serial.println(&name[BASE_NAME_SIZE+2]);
if (!sd.exists(name)) {
Serial.println(F("File does not exist"));
return;
}
// Get the address of the file on the SD.
if (!binFile.contiguousRange(&bgnBlock, &endBlock)) {
error("contiguousRange failed");
binFile.close();
strcpy(binName, name);
if (!binFile.open(binName, O_READ)) {
Serial.println(F("open failed"));
return;
}
Serial.println(F("File opened"));
}
//------------------------------------------------------------------------------
void recordBinFile() {
const uint8_t QUEUE_DIM = BUFFER_BLOCK_COUNT + 1;
// Index of last queue location.
const uint8_t QUEUE_LAST = QUEUE_DIM - 1;
// Allocate extra buffer space.
block_t block[BUFFER_BLOCK_COUNT - 1];
block_t* curBlock = 0;
block_t* emptyStack[BUFFER_BLOCK_COUNT];
uint8_t emptyTop;
uint8_t minTop;

block_t* fullQueue[QUEUE_DIM];
uint8_t fullHead = 0;
uint8_t fullTail = 0;

// Use SdFat's internal buffer.
uint8_t* cache = (uint8_t*)sd.vol()->cacheClear();
if (cache == 0) {
emptyStack[0] = (block_t*)sd.vol()->cacheClear();
if (emptyStack[0] == 0) {
error("cacheClear failed");
}

// Flash erase all data in the file.
Serial.println(F("Erasing all data"));
uint32_t bgnErase = bgnBlock;
uint32_t endErase;
while (bgnErase < endBlock) {
endErase = bgnErase + ERASE_SIZE;
if (endErase > endBlock) {
endErase = endBlock;
}
if (!sd.card()->erase(bgnErase, endErase)) {
error("erase failed");
}
bgnErase = endErase + 1;
// Put rest of buffers on the empty stack.
for (int i = 1; i < BUFFER_BLOCK_COUNT; i++) {
emptyStack[i] = &block[i - 1];
}
emptyTop = BUFFER_BLOCK_COUNT;
minTop = BUFFER_BLOCK_COUNT;
// Start a multiple block write.
if (!sd.card()->writeStart(bgnBlock, FILE_BLOCK_COUNT)) {
error("writeBegin failed");
}
// Set chip select high if other devices use SPI.
if (useSharedSpi) {
sd.card()->chipSelectHigh();
}
// Initialize queues.
emptyHead = emptyTail = 0;
fullHead = fullTail = 0;

// Use SdFat buffer for one block.
emptyQueue[emptyHead] = (block_t*)cache;
emptyHead = queueNext(emptyHead);

// Put rest of buffers in the empty queue.
for (uint8_t i = 0; i < BUFFER_BLOCK_COUNT; i++) {
emptyQueue[emptyHead] = &block[i];
emptyHead = queueNext(emptyHead);
if (!sd.card()->writeStart(binFile.firstBlock())) {
error("writeBStart failed");
}
Serial.print(F("FreeStack: "));
Serial.println(FreeStack());
Serial.println(F("Logging - type any character to stop"));
// Wait for Serial Idle.
Serial.flush();
delay(10);
bool closeFile = false;
uint32_t bn = 0;
uint32_t t0 = millis();
uint32_t t1 = t0;
uint32_t bn = 0;
uint32_t maxLatency = 0;
uint32_t overrun = 0;
uint32_t overrunTotal = 0;
uint32_t count = 0;
uint32_t maxDelta = 0;
uint32_t minDelta = 99999;
uint32_t maxLatency = 0;
uint32_t logTime = micros();

// Set time for first record of file.
startMicros = logTime + LOG_INTERVAL_USEC;

while (1) {
// Time for next data record.
while(1) {
// Time for next data record.
logTime += LOG_INTERVAL_USEC;
if (Serial.available()) {
closeFile = true;
}

}
if (closeFile) {
if (curBlock != 0) {
// Put buffer in full queue.
fullQueue[fullHead] = curBlock;
fullHead = queueNext(fullHead);
fullHead = fullHead < QUEUE_LAST ? fullHead + 1 : 0;
curBlock = 0;
}
} else {
if (curBlock == 0 && emptyTail != emptyHead) {
curBlock = emptyQueue[emptyTail];
emptyTail = queueNext(emptyTail);
if (curBlock == 0 && emptyTop != 0) {
curBlock = emptyStack[--emptyTop];
if (emptyTop < minTop) {
minTop = emptyTop;
}
curBlock->count = 0;
curBlock->overrun = overrun;
overrun = 0;
@@ -466,18 +433,29 @@ void logData() {
} while (delta < 0);
if (curBlock == 0) {
overrun++;
overrunTotal++;
if (ERROR_LED_PIN >= 0) {
digitalWrite(ERROR_LED_PIN, HIGH);
}
#if ABORT_ON_OVERRUN
Serial.println(F("Overrun abort"));
break;
#endif // ABORT_ON_OVERRUN
} else {
acquireData(&curBlock->data[curBlock->count++]);
#if USE_SHARED_SPI
sd.card()->spiStop();
#endif // USE_SHARED_SPI
acquireData(&curBlock->data[curBlock->count++]);
#if USE_SHARED_SPI
sd.card()->spiStart();
#endif // USE_SHARED_SPI
if (curBlock->count == DATA_DIM) {
fullQueue[fullHead] = curBlock;
fullHead = queueNext(fullHead);
fullHead = fullHead < QUEUE_LAST ? fullHead + 1 : 0;
curBlock = 0;
}
if ((uint32_t)delta > maxDelta) maxDelta = delta;
if ((uint32_t)delta < minDelta) minDelta = delta;
}
}
}

if (fullHead == fullTail) {
// Exit loop if done.
if (closeFile) {
@@ -486,29 +464,18 @@ void logData() {
} else if (!sd.card()->isBusy()) {
// Get address of block to write.
block_t* pBlock = fullQueue[fullTail];
fullTail = queueNext(fullTail);
fullTail = fullTail < QUEUE_LAST ? fullTail + 1 : 0;
// Write block to SD.
uint32_t usec = micros();
if (!sd.card()->writeData((uint8_t*)pBlock)) {
error("write data failed");
}
usec = micros() - usec;
t1 = millis();
if (usec > maxLatency) {
maxLatency = usec;
}
count += pBlock->count;

// Add overruns and possibly light LED.
if (pBlock->overrun) {
overrunTotal += pBlock->overrun;
if (ERROR_LED_PIN >= 0) {
digitalWrite(ERROR_LED_PIN, HIGH);
}
}
// Move block to empty queue.
emptyQueue[emptyHead] = pBlock;
emptyHead = queueNext(emptyHead);
emptyStack[emptyTop++] = pBlock;
bn++;
if (bn == FILE_BLOCK_COUNT) {
// File full so stop
@@ -519,6 +486,12 @@ void logData() {
if (!sd.card()->writeStop()) {
error("writeStop failed");
}
Serial.print(F("Min Free buffers: "));
Serial.println(minTop);
Serial.print(F("Max block write usec: "));
Serial.println(maxLatency);
Serial.print(F("Overruns: "));
Serial.println(overrunTotal);
// Truncate file if recording stopped early.
if (bn != FILE_BLOCK_COUNT) {
Serial.println(F("Truncating file"));
@@ -526,25 +499,38 @@ void logData() {
error("Can't truncate file");
}
}
}
//-----------------------------------------------------------------------------
void renameBinFile() {
if (!binFile.rename(sd.vwd(), binName)) {
error("Can't rename file");
}
}
Serial.print(F("File renamed: "));
Serial.println(binName);
Serial.print(F("Max block write usec: "));
Serial.println(maxLatency);
Serial.print(F("Record time sec: "));
Serial.println(0.001*(t1 - t0), 3);
Serial.print(minDelta);
Serial.print(F(" <= jitter microseconds <= "));
Serial.println(maxDelta);
Serial.print(F("Sample count: "));
Serial.println(count);
Serial.print(F("Samples/sec: "));
Serial.println((1000.0)*count/(t1-t0));
Serial.print(F("Overruns: "));
Serial.println(overrunTotal);
Serial.println(F("Done"));
Serial.print("File size: ");
Serial.print(binFile.fileSize()/512);
Serial.println(F(" blocks"));
Serial.print(F("FreeStack: "));
Serial.println(FreeStack());
}
//------------------------------------------------------------------------------
void testSensor() {
const uint32_t interval = 200000;
int32_t diff;
data_t data;
Serial.println(F("\nTesting - type any character to stop\n"));
// Wait for Serial Idle.
delay(1000);
printHeader(&Serial);
uint32_t m = micros();
while (!Serial.available()) {
m += interval;
do {
diff = m - micros();
} while (diff > 0);
acquireData(&data);
printData(&Serial, &data);
}
}
//------------------------------------------------------------------------------
void setup(void) {
@@ -557,7 +543,6 @@ void setup(void) {
while (!Serial) {
SysCall::yield();
}

Serial.print(F("FreeStack: "));
Serial.println(FreeStack());
Serial.print(F("Records/block: "));
@@ -565,47 +550,62 @@ void setup(void) {
if (sizeof(block_t) != 512) {
error("Invalid block size");
}
// initialize file system.
if (!sd.begin(SD_CS_PIN, SPI_FULL_SPEED)) {
sd.initErrorPrint();
// Initialize at the highest speed supported by the board that is
// not over 50 MHz. Try a lower speed if SPI errors occur.
if (!sd.begin(SD_CS_PIN, SD_SCK_MHZ(50))) {
sd.initErrorPrint(&Serial);
fatalBlink();
}
setupADXL345();
userSetup();
}
//------------------------------------------------------------------------------
void loop(void) {
// discard any input
// Read any Serial data.
do {
delay(10);
} while (Serial.read() >= 0);
} while (Serial.available() && Serial.read() >= 0);
Serial.println();
Serial.println(F("type:"));
Serial.println(F("b - open existing bin file"));
Serial.println(F("c - convert file to csv"));
Serial.println(F("d - dump data to Serial"));
Serial.println(F("e - overrun error details"));
Serial.println(F("l - list files"));
Serial.println(F("r - record data"));
Serial.println(F("t - test without logging"));
while(!Serial.available()) {
SysCall::yield();
}
#if WDT_YIELD_TIME_MICROS
Serial.println(F("LowLatencyLogger can not run with watchdog timer"));
SysCall::halt();
#endif
char c = tolower(Serial.read());

// Discard extra Serial data.
do {
delay(10);
} while (Serial.read() >= 0);
} while (Serial.available() && Serial.read() >= 0);

if (ERROR_LED_PIN >= 0) {
digitalWrite(ERROR_LED_PIN, LOW);
}
if (c == 'c') {
if (c == 'b') {
openBinFile();
} else if (c == 'c') {
binaryToCsv();
} else if (c == 'd') {
dumpData();
} else if (c == 'e') {
checkOverrun();
} else if (c == 'l') {
Serial.println(F("\nls:"));
sd.ls(&Serial, LS_SIZE);
} else if (c == 'r') {
logData();
} else if (c == 't') {
testSensor();
} else {
Serial.println(F("Invalid entry"));
}

+ 1
- 0
SdFat/examples/LowLatencyLoggerADXL345/LowLatencyLoggerADXL345.ino Vedi File

@@ -0,0 +1 @@
// Empty file with name LowLatencyLoggerADXL345.ino to make IDE happy.

+ 67
- 0
SdFat/examples/LowLatencyLoggerADXL345/UserFunctions.cpp Vedi File

@@ -0,0 +1,67 @@
#include "UserTypes.h"
// User data functions. Modify these functions for your data items.

// Start time for data
static uint32_t startMicros;

const uint8_t ADXL345_CS = 9;

const uint8_t POWER_CTL = 0x2D; //Power Control Register
const uint8_t DATA_FORMAT = 0x31;
const uint8_t DATAX0 = 0x32; //X-Axis Data 0
const uint8_t DATAX1 = 0x33; //X-Axis Data 1
const uint8_t DATAY0 = 0x34; //Y-Axis Data 0
const uint8_t DATAY1 = 0x35; //Y-Axis Data 1
const uint8_t DATAZ0 = 0x36; //Z-Axis Data 0
const uint8_t DATAZ1 = 0x37; //Z-Axis Data 1

void writeADXL345Register(const uint8_t registerAddress, const uint8_t value) {
digitalWrite(ADXL345_CS, LOW);
SPI.transfer(registerAddress);
SPI.transfer(value);
digitalWrite(ADXL345_CS, HIGH);
}

void userSetup() {
SPI.begin();
pinMode(ADXL345_CS, OUTPUT);
digitalWrite(ADXL345_CS, HIGH);
//Put the ADXL345 into +/- 4G range by writing the value 0x01 to the DATA_FORMAT register.
writeADXL345Register(DATA_FORMAT, 0x01);
//Put the ADXL345 into Measurement Mode by writing 0x08 to the POWER_CTL register.
writeADXL345Register(POWER_CTL, 0x08); //Measurement mode
}

// Acquire a data record.
void acquireData(data_t* data) {
// Max SPI clock frequency is 5 MHz with CPOL = 1 and CPHA = 1.
SPI.beginTransaction(SPISettings(5000000, MSBFIRST, SPI_MODE3));
data->time = micros();
digitalWrite(ADXL345_CS, LOW);
// Read multiple bytes so or 0XC0 with address.
SPI.transfer(DATAX0 | 0XC0);
data->accel[0] = SPI.transfer(0) | (SPI.transfer(0) << 8);
data->accel[1] = SPI.transfer(0) | (SPI.transfer(0) << 8);
data->accel[2] = SPI.transfer(0) | (SPI.transfer(0) << 8);
digitalWrite(ADXL345_CS, HIGH);
SPI.endTransaction();
}

// Print a data record.
void printData(Print* pr, data_t* data) {
if (startMicros == 0) {
startMicros = data->time;
}
pr->print(data->time - startMicros);
for (int i = 0; i < ACCEL_DIM; i++) {
pr->write(',');
pr->print(data->accel[i]);
}
pr->println();
}

// Print data header.
void printHeader(Print* pr) {
startMicros = 0;
pr->println(F("micros,ax,ay,az"));
}

+ 17
- 0
SdFat/examples/LowLatencyLoggerADXL345/UserTypes.h Vedi File

@@ -0,0 +1,17 @@
#ifndef UserTypes_h
#define UserTypes_h
#include "Arduino.h"
#include "SPI.h"
#define USE_SHARED_SPI 1
#define FILE_BASE_NAME "ADXL4G"
// User data types. Modify for your data items.
const uint8_t ACCEL_DIM = 3;
struct data_t {
unsigned long time;
int16_t accel[ACCEL_DIM];
};
void acquireData(data_t* data);
void printData(Print* pr, data_t* data);
void printHeader(Print* pr);
void userSetup();
#endif // UserTypes_h

LowLatencyLoggerADXL345/readme.txt → SdFat/examples/LowLatencyLoggerADXL345/readme.txt Vedi File


+ 612
- 0
SdFat/examples/LowLatencyLoggerMPU6050/LowLatencyLogger.ino Vedi File

@@ -0,0 +1,612 @@
/**
* This program logs data to a binary file. Functions are included
* to convert the binary file to a csv text file.
*
* Samples are logged at regular intervals. The maximum logging rate
* depends on the quality of your SD card and the time required to
* read sensor data. This example has been tested at 500 Hz with
* good SD card on an Uno. 4000 HZ is possible on a Due.
*
* If your SD card has a long write latency, it may be necessary to use
* slower sample rates. Using a Mega Arduino helps overcome latency
* problems since 12 512 byte buffers will be used.
*
* Data is written to the file using a SD multiple block write command.
*/
#include <SPI.h>
#include "SdFat.h"
#include "FreeStack.h"
#include "UserTypes.h"

#ifdef __AVR_ATmega328P__
#include "MinimumSerial.h"
MinimumSerial MinSerial;
#define Serial MinSerial
#endif // __AVR_ATmega328P__
//==============================================================================
// Start of configuration constants.
//==============================================================================
// Abort run on an overrun. Data before the overrun will be saved.
#define ABORT_ON_OVERRUN 1
//------------------------------------------------------------------------------
//Interval between data records in microseconds.
const uint32_t LOG_INTERVAL_USEC = 2000;
//------------------------------------------------------------------------------
// Set USE_SHARED_SPI non-zero for use of an SPI sensor.
// May not work for some cards.
#ifndef USE_SHARED_SPI
#define USE_SHARED_SPI 0
#endif // USE_SHARED_SPI
//------------------------------------------------------------------------------
// Pin definitions.
//
// SD chip select pin.
const uint8_t SD_CS_PIN = SS;
//
// Digital pin to indicate an error, set to -1 if not used.
// The led blinks for fatal errors. The led goes on solid for
// overrun errors and logging continues unless ABORT_ON_OVERRUN
// is non-zero.
#ifdef ERROR_LED_PIN
#undef ERROR_LED_PIN
#endif // ERROR_LED_PIN
const int8_t ERROR_LED_PIN = 3;
//------------------------------------------------------------------------------
// File definitions.
//
// Maximum file size in blocks.
// The program creates a contiguous file with FILE_BLOCK_COUNT 512 byte blocks.
// This file is flash erased using special SD commands. The file will be
// truncated if logging is stopped early.
const uint32_t FILE_BLOCK_COUNT = 256000;
//
// log file base name if not defined in UserTypes.h
#ifndef FILE_BASE_NAME
#define FILE_BASE_NAME "data"
#endif // FILE_BASE_NAME
//------------------------------------------------------------------------------
// Buffer definitions.
//
// The logger will use SdFat's buffer plus BUFFER_BLOCK_COUNT-1 additional
// buffers.
//
#ifndef RAMEND
// Assume ARM. Use total of ten 512 byte buffers.
const uint8_t BUFFER_BLOCK_COUNT = 10;
//
#elif RAMEND < 0X8FF
#error Too little SRAM
//
#elif RAMEND < 0X10FF
// Use total of two 512 byte buffers.
const uint8_t BUFFER_BLOCK_COUNT = 2;
//
#elif RAMEND < 0X20FF
// Use total of four 512 byte buffers.
const uint8_t BUFFER_BLOCK_COUNT = 4;
//
#else // RAMEND
// Use total of 12 512 byte buffers.
const uint8_t BUFFER_BLOCK_COUNT = 12;
#endif // RAMEND
//==============================================================================
// End of configuration constants.
//==============================================================================
// Temporary log file. Will be deleted if a reset or power failure occurs.
#define TMP_FILE_NAME "tmp_log.bin"

// Size of file base name. Must not be larger than six.
const uint8_t BASE_NAME_SIZE = sizeof(FILE_BASE_NAME) - 1;
const uint8_t FILE_NAME_DIM = BASE_NAME_SIZE + 7;
char binName[FILE_NAME_DIM] = FILE_BASE_NAME "00.bin";

SdFat sd;

SdBaseFile binFile;

// Number of data records in a block.
const uint16_t DATA_DIM = (512 - 4)/sizeof(data_t);

//Compute fill so block size is 512 bytes. FILL_DIM may be zero.
const uint16_t FILL_DIM = 512 - 4 - DATA_DIM*sizeof(data_t);

struct block_t {
uint16_t count;
uint16_t overrun;
data_t data[DATA_DIM];
uint8_t fill[FILL_DIM];
};
//==============================================================================
// Error messages stored in flash.
#define error(msg) {sd.errorPrint(&Serial, F(msg));fatalBlink();}
//------------------------------------------------------------------------------
//
void fatalBlink() {
while (true) {
SysCall::yield();
if (ERROR_LED_PIN >= 0) {
digitalWrite(ERROR_LED_PIN, HIGH);
delay(200);
digitalWrite(ERROR_LED_PIN, LOW);
delay(200);
}
}
}
//------------------------------------------------------------------------------
// read data file and check for overruns
void checkOverrun() {
bool headerPrinted = false;
block_t block;
uint32_t bn = 0;

if (!binFile.isOpen()) {
Serial.println();
Serial.println(F("No current binary file"));
return;
}
binFile.rewind();
Serial.println();
Serial.print(F("FreeStack: "));
Serial.println(FreeStack());
Serial.println(F("Checking overrun errors - type any character to stop"));
while (binFile.read(&block, 512) == 512) {
if (block.count == 0) {
break;
}
if (block.overrun) {
if (!headerPrinted) {
Serial.println();
Serial.println(F("Overruns:"));
Serial.println(F("fileBlockNumber,sdBlockNumber,overrunCount"));
headerPrinted = true;
}
Serial.print(bn);
Serial.print(',');
Serial.print(binFile.firstBlock() + bn);
Serial.print(',');
Serial.println(block.overrun);
}
bn++;
}
if (!headerPrinted) {
Serial.println(F("No errors found"));
} else {
Serial.println(F("Done"));
}
}
//-----------------------------------------------------------------------------
// Convert binary file to csv file.
void binaryToCsv() {
uint8_t lastPct = 0;
block_t block;
uint32_t t0 = millis();
uint32_t syncCluster = 0;
SdFile csvFile;
char csvName[FILE_NAME_DIM];

if (!binFile.isOpen()) {
Serial.println();
Serial.println(F("No current binary file"));
return;
}
Serial.println();
Serial.print(F("FreeStack: "));
Serial.println(FreeStack());
// Create a new csvFile.
strcpy(csvName, binName);
strcpy(&csvName[BASE_NAME_SIZE + 3], "csv");

if (!csvFile.open(csvName, O_WRITE | O_CREAT | O_TRUNC)) {
error("open csvFile failed");
}
binFile.rewind();
Serial.print(F("Writing: "));
Serial.print(csvName);
Serial.println(F(" - type any character to stop"));
printHeader(&csvFile);
uint32_t tPct = millis();
while (!Serial.available() && binFile.read(&block, 512) == 512) {
uint16_t i;
if (block.count == 0) {
break;
}
if (block.overrun) {
csvFile.print(F("OVERRUN,"));
csvFile.println(block.overrun);
}
for (i = 0; i < block.count; i++) {
printData(&csvFile, &block.data[i]);
}
if (csvFile.curCluster() != syncCluster) {
csvFile.sync();
syncCluster = csvFile.curCluster();
}
if ((millis() - tPct) > 1000) {
uint8_t pct = binFile.curPosition()/(binFile.fileSize()/100);
if (pct != lastPct) {
tPct = millis();
lastPct = pct;
Serial.print(pct, DEC);
Serial.println('%');
}
}
if (Serial.available()) {
break;
}
}
csvFile.close();
Serial.print(F("Done: "));
Serial.print(0.001*(millis() - t0));
Serial.println(F(" Seconds"));
}
//-----------------------------------------------------------------------------
void createBinFile() {
// max number of blocks to erase per erase call
const uint32_t ERASE_SIZE = 262144L;
uint32_t bgnBlock, endBlock;
Serial.println();
while (sd.exists(binName)) {
if (binName[BASE_NAME_SIZE + 1] != '9') {
binName[BASE_NAME_SIZE + 1]++;
} else {
binName[BASE_NAME_SIZE + 1] = '0';
if (binName[BASE_NAME_SIZE] == '9') {
error("Can't create file name");
}
binName[BASE_NAME_SIZE]++;
}
}
// Delete old tmp file.
if (sd.exists(TMP_FILE_NAME)) {
Serial.println(F("Deleting tmp file"));
if (!sd.remove(TMP_FILE_NAME)) {
error("Can't remove tmp file");
}
}
// Create new file.
Serial.println(F("Creating new file"));
binFile.close();
if (!binFile.createContiguous(TMP_FILE_NAME, 512 * FILE_BLOCK_COUNT)) {
error("createContiguous failed");
}
// Get the address of the file on the SD.
if (!binFile.contiguousRange(&bgnBlock, &endBlock)) {
error("contiguousRange failed");
}
// Flash erase all data in the file.
Serial.println(F("Erasing all data"));
uint32_t bgnErase = bgnBlock;
uint32_t endErase;
while (bgnErase < endBlock) {
endErase = bgnErase + ERASE_SIZE;
if (endErase > endBlock) {
endErase = endBlock;
}
if (!sd.card()->erase(bgnErase, endErase)) {
error("erase failed");
}
bgnErase = endErase + 1;
}
}
//------------------------------------------------------------------------------
// dump data file to Serial
void dumpData() {
block_t block;
if (!binFile.isOpen()) {
Serial.println();
Serial.println(F("No current binary file"));
return;
}
binFile.rewind();
Serial.println();
Serial.println(F("Type any character to stop"));
delay(1000);
printHeader(&Serial);
while (!Serial.available() && binFile.read(&block , 512) == 512) {
if (block.count == 0) {
break;
}
if (block.overrun) {
Serial.print(F("OVERRUN,"));
Serial.println(block.overrun);
}
for (uint16_t i = 0; i < block.count; i++) {
printData(&Serial, &block.data[i]);
}
}
Serial.println(F("Done"));
}
//------------------------------------------------------------------------------
// log data
void logData() {
createBinFile();
recordBinFile();
renameBinFile();
}
//------------------------------------------------------------------------------
void openBinFile() {
char name[FILE_NAME_DIM];
strcpy(name, binName);
Serial.println(F("\nEnter two digit version"));
Serial.write(name, BASE_NAME_SIZE);
for (int i = 0; i < 2; i++) {
while (!Serial.available()) {
SysCall::yield();
}
char c = Serial.read();
Serial.write(c);
if (c < '0' || c > '9') {
Serial.println("\nInvalid digit");
return;
}
name[BASE_NAME_SIZE + i] = c;
}
Serial.println(&name[BASE_NAME_SIZE+2]);
if (!sd.exists(name)) {
Serial.println(F("File does not exist"));
return;
}
binFile.close();
strcpy(binName, name);
if (!binFile.open(binName, O_READ)) {
Serial.println(F("open failed"));
return;
}
Serial.println(F("File opened"));
}
//------------------------------------------------------------------------------
void recordBinFile() {
const uint8_t QUEUE_DIM = BUFFER_BLOCK_COUNT + 1;
// Index of last queue location.
const uint8_t QUEUE_LAST = QUEUE_DIM - 1;
// Allocate extra buffer space.
block_t block[BUFFER_BLOCK_COUNT - 1];
block_t* curBlock = 0;
block_t* emptyStack[BUFFER_BLOCK_COUNT];
uint8_t emptyTop;
uint8_t minTop;

block_t* fullQueue[QUEUE_DIM];
uint8_t fullHead = 0;
uint8_t fullTail = 0;

// Use SdFat's internal buffer.
emptyStack[0] = (block_t*)sd.vol()->cacheClear();
if (emptyStack[0] == 0) {
error("cacheClear failed");
}
// Put rest of buffers on the empty stack.
for (int i = 1; i < BUFFER_BLOCK_COUNT; i++) {
emptyStack[i] = &block[i - 1];
}
emptyTop = BUFFER_BLOCK_COUNT;
minTop = BUFFER_BLOCK_COUNT;
// Start a multiple block write.
if (!sd.card()->writeStart(binFile.firstBlock())) {
error("writeBStart failed");
}
Serial.print(F("FreeStack: "));
Serial.println(FreeStack());
Serial.println(F("Logging - type any character to stop"));
bool closeFile = false;
uint32_t bn = 0;
uint32_t maxLatency = 0;
uint32_t overrun = 0;
uint32_t overrunTotal = 0;
uint32_t logTime = micros();
while(1) {
// Time for next data record.
logTime += LOG_INTERVAL_USEC;
if (Serial.available()) {
closeFile = true;
}
if (closeFile) {
if (curBlock != 0) {
// Put buffer in full queue.
fullQueue[fullHead] = curBlock;
fullHead = fullHead < QUEUE_LAST ? fullHead + 1 : 0;
curBlock = 0;
}
} else {
if (curBlock == 0 && emptyTop != 0) {
curBlock = emptyStack[--emptyTop];
if (emptyTop < minTop) {
minTop = emptyTop;
}
curBlock->count = 0;
curBlock->overrun = overrun;
overrun = 0;
}
if ((int32_t)(logTime - micros()) < 0) {
error("Rate too fast");
}
int32_t delta;
do {
delta = micros() - logTime;
} while (delta < 0);
if (curBlock == 0) {
overrun++;
overrunTotal++;
if (ERROR_LED_PIN >= 0) {
digitalWrite(ERROR_LED_PIN, HIGH);
}
#if ABORT_ON_OVERRUN
Serial.println(F("Overrun abort"));
break;
#endif // ABORT_ON_OVERRUN
} else {
#if USE_SHARED_SPI
sd.card()->spiStop();
#endif // USE_SHARED_SPI
acquireData(&curBlock->data[curBlock->count++]);
#if USE_SHARED_SPI
sd.card()->spiStart();
#endif // USE_SHARED_SPI
if (curBlock->count == DATA_DIM) {
fullQueue[fullHead] = curBlock;
fullHead = fullHead < QUEUE_LAST ? fullHead + 1 : 0;
curBlock = 0;
}
}
}
if (fullHead == fullTail) {
// Exit loop if done.
if (closeFile) {
break;
}
} else if (!sd.card()->isBusy()) {
// Get address of block to write.
block_t* pBlock = fullQueue[fullTail];
fullTail = fullTail < QUEUE_LAST ? fullTail + 1 : 0;
// Write block to SD.
uint32_t usec = micros();
if (!sd.card()->writeData((uint8_t*)pBlock)) {
error("write data failed");
}
usec = micros() - usec;
if (usec > maxLatency) {
maxLatency = usec;
}
// Move block to empty queue.
emptyStack[emptyTop++] = pBlock;
bn++;
if (bn == FILE_BLOCK_COUNT) {
// File full so stop
break;
}
}
}
if (!sd.card()->writeStop()) {
error("writeStop failed");
}
Serial.print(F("Min Free buffers: "));
Serial.println(minTop);
Serial.print(F("Max block write usec: "));
Serial.println(maxLatency);
Serial.print(F("Overruns: "));
Serial.println(overrunTotal);
// Truncate file if recording stopped early.
if (bn != FILE_BLOCK_COUNT) {
Serial.println(F("Truncating file"));
if (!binFile.truncate(512L * bn)) {
error("Can't truncate file");
}
}
}
//-----------------------------------------------------------------------------
void renameBinFile() {
if (!binFile.rename(sd.vwd(), binName)) {
error("Can't rename file");
}
Serial.print(F("File renamed: "));
Serial.println(binName);
Serial.print("File size: ");
Serial.print(binFile.fileSize()/512);
Serial.println(F(" blocks"));
Serial.print(F("FreeStack: "));
Serial.println(FreeStack());
}
//------------------------------------------------------------------------------
void testSensor() {
const uint32_t interval = 200000;
int32_t diff;
data_t data;
Serial.println(F("\nTesting - type any character to stop\n"));
// Wait for Serial Idle.
delay(1000);
printHeader(&Serial);
uint32_t m = micros();
while (!Serial.available()) {
m += interval;
do {
diff = m - micros();
} while (diff > 0);
acquireData(&data);
printData(&Serial, &data);
}
}
//------------------------------------------------------------------------------
void setup(void) {
if (ERROR_LED_PIN >= 0) {
pinMode(ERROR_LED_PIN, OUTPUT);
}
Serial.begin(9600);
// Wait for USB Serial
while (!Serial) {
SysCall::yield();
}
Serial.print(F("FreeStack: "));
Serial.println(FreeStack());
Serial.print(F("Records/block: "));
Serial.println(DATA_DIM);
if (sizeof(block_t) != 512) {
error("Invalid block size");
}
// Initialize at the highest speed supported by the board that is
// not over 50 MHz. Try a lower speed if SPI errors occur.
if (!sd.begin(SD_CS_PIN, SD_SCK_MHZ(50))) {
sd.initErrorPrint(&Serial);
fatalBlink();
}
userSetup();
}
//------------------------------------------------------------------------------
void loop(void) {
// Read any Serial data.
do {
delay(10);
} while (Serial.available() && Serial.read() >= 0);
Serial.println();
Serial.println(F("type:"));
Serial.println(F("b - open existing bin file"));
Serial.println(F("c - convert file to csv"));
Serial.println(F("d - dump data to Serial"));
Serial.println(F("e - overrun error details"));
Serial.println(F("l - list files"));
Serial.println(F("r - record data"));
Serial.println(F("t - test without logging"));
while(!Serial.available()) {
SysCall::yield();
}
#if WDT_YIELD_TIME_MICROS
Serial.println(F("LowLatencyLogger can not run with watchdog timer"));
SysCall::halt();
#endif
char c = tolower(Serial.read());

// Discard extra Serial data.
do {
delay(10);
} while (Serial.available() && Serial.read() >= 0);

if (ERROR_LED_PIN >= 0) {
digitalWrite(ERROR_LED_PIN, LOW);
}
if (c == 'b') {
openBinFile();
} else if (c == 'c') {
binaryToCsv();
} else if (c == 'd') {
dumpData();
} else if (c == 'e') {
checkOverrun();
} else if (c == 'l') {
Serial.println(F("\nls:"));
sd.ls(&Serial, LS_SIZE);
} else if (c == 'r') {
logData();
} else if (c == 't') {
testSensor();
} else {
Serial.println(F("Invalid entry"));
}
}

+ 2
- 0
SdFat/examples/LowLatencyLoggerMPU6050/LowLatencyLoggerMPU6050.ino Vedi File

@@ -0,0 +1,2 @@
// Empty file with name LowLatencyLoggerMPU6050.ino to make IDE happy.


+ 51
- 0
SdFat/examples/LowLatencyLoggerMPU6050/UserFunctions.cpp Vedi File

@@ -0,0 +1,51 @@
// User data functions. Modify these functions for your data items.
#include "UserTypes.h"
#include "Wire.h"
#include "I2Cdev.h"
#include "MPU6050.h"
//------------------------------------------------------------------------------
MPU6050 mpu;
static uint32_t startMicros;
// Acquire a data record.
void acquireData(data_t* data) {
data->time = micros();
mpu.getMotion6(&data->ax, &data->ay, &data->az,
&data->gx, &data->gy, &data->gz);
}

// setup AVR I2C
void userSetup() {
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.begin();
Wire.setClock(400000);
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif
mpu.initialize();
}

// Print a data record.
void printData(Print* pr, data_t* data) {
if (startMicros == 0) {
startMicros = data->time;
}
pr->print(data->time- startMicros);
pr->write(',');
pr->print(data->ax);
pr->write(',');
pr->print(data->ay);
pr->write(',');
pr->print(data->az);
pr->write(',');
pr->print(data->gx);
pr->write(',');
pr->print(data->gy);
pr->write(',');
pr->println(data->gz);
}

// Print data header.
void printHeader(Print* pr) {
startMicros = 0;
pr->println(F("micros,ax,ay,az,gx,gy,gz"));
}

+ 18
- 0
SdFat/examples/LowLatencyLoggerMPU6050/UserTypes.h Vedi File

@@ -0,0 +1,18 @@
#ifndef UserTypes_h
#define UserTypes_h
#include "Arduino.h"
#define FILE_BASE_NAME "mpuraw"
struct data_t {
unsigned long time;
int16_t ax;
int16_t ay;
int16_t az;
int16_t gx;
int16_t gy;
int16_t gz;
};
void acquireData(data_t* data);
void printData(Print* pr, data_t* data);
void printHeader(Print* pr);
void userSetup();
#endif // UserTypes_h

+ 3
- 3
SdFat/examples/OpenNext/OpenNext.ino Vedi File

@@ -25,9 +25,9 @@ void setup() {
SysCall::yield();
}

// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance.
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
// Initialize at the highest speed supported by the board that is
// not over 50 MHz. Try a lower speed if SPI errors occur.
if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
sd.initErrorHalt();
}


+ 3
- 3
SdFat/examples/PrintBenchmark/PrintBenchmark.ino Vedi File

@@ -49,9 +49,9 @@ void loop() {

cout << F("FreeStack: ") << FreeStack() << endl;

// initialize the SD card at SPI_FULL_SPEED for best performance.
// try SPI_HALF_SPEED if bus errors occur.
if (!sd.begin(chipSelect, SPI_FULL_SPEED)) {
// Initialize at the highest speed supported by the board that is
// not over 50 MHz. Try a lower speed if SPI errors occur.
if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
sd.initErrorHalt();
}


+ 6
- 6
SdFat/examples/QuickStart/QuickStart.ino Vedi File

@@ -8,10 +8,10 @@
// to 10 to disable the Ethernet controller.
const int8_t DISABLE_CHIP_SELECT = -1;
//
// Test with reduced SPI speed for breadboards.
// Change spiSpeed to SPI_FULL_SPEED for better performance
// Use SPI_QUARTER_SPEED for even slower SPI bus speed
const uint8_t spiSpeed = SPI_HALF_SPEED;
// Test with reduced SPI speed for breadboards. SD_SCK_MHZ(4) will select
// the highest speed supported by the board that is not over 4 MHz.
// Change SPI_SPEED to SD_SCK_MHZ(50) for best performance.
#define SPI_SPEED SD_SCK_MHZ(4)
//------------------------------------------------------------------------------
// File system object.
SdFat sd;
@@ -28,7 +28,7 @@ int chipSelect;

void cardOrSpeed() {
cout << F("Try another SD card or reduce the SPI bus speed.\n");
cout << F("Edit spiSpeed in this program to change it.\n");
cout << F("Edit SPI_SPEED in this program to change it.\n");
}

void reformatMsg() {
@@ -98,7 +98,7 @@ void loop() {
pinMode(DISABLE_CHIP_SELECT, OUTPUT);
digitalWrite(DISABLE_CHIP_SELECT, HIGH);
}
if (!sd.begin(chipSelect, spiSpeed)) {
if (!sd.begin(chipSelect, SPI_SPEED)) {
if (sd.card()->errorCode()) {
cout << F(
"\nSD initialization failed.\n"

+ 58
- 60
SdFat/examples/RawWrite/RawWrite.ino Vedi File

@@ -3,11 +3,7 @@
* can be used for high speed data logging.
*
* This program simulates logging from a source that produces
* data at a constant rate of one block every MICROS_PER_BLOCK.
*
* If a high quality SanDisk card is used with this program
* no overruns occur and the maximum block write time is
* under 2000 micros.
* data at a constant rate of RATE_KB_PER_SEC.
*
* Note: Apps should create a very large file then truncates it
* to the length that is used for a logging. It only takes
@@ -21,11 +17,15 @@
// SD chip select pin
const uint8_t chipSelect = SS;

// number of blocks in the contiguous file
const uint32_t BLOCK_COUNT = 10000UL;
const uint32_t RATE_KB_PER_SEC = 100;

const uint32_t TEST_TIME_SEC = 100;

// time to produce a block of data
const uint32_t MICROS_PER_BLOCK = 10000;
// Time between printing progress dots
const uint32_t DOT_TIME_MS = 5000UL;

// number of blocks in the contiguous file
const uint32_t BLOCK_COUNT = (1000*RATE_KB_PER_SEC*TEST_TIME_SEC + 511)/512;

// file system
SdFat sd;
@@ -42,13 +42,6 @@ ArduinoOutStream cout(Serial);
// store error strings in flash to save RAM
#define error(s) sd.errorHalt(F(s))
//------------------------------------------------------------------------------
// log of first overruns
#define OVER_DIM 20
struct {
uint32_t block;
uint32_t micros;
} over[OVER_DIM];
//------------------------------------------------------------------------------
void setup(void) {
Serial.begin(9600);
@@ -71,9 +64,9 @@ void loop(void) {

cout << F("FreeStack: ") << FreeStack() << endl;

// initialize the SD card at SPI_FULL_SPEED for best performance.
// try SPI_HALF_SPEED if bus errors occur.
if (!sd.begin(chipSelect, SPI_FULL_SPEED)) {
// Initialize at the highest speed supported by the board that is
// not over 50 MHz. Try a lower speed if SPI errors occur.
if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
sd.initErrorHalt();
}

@@ -81,7 +74,7 @@ void loop(void) {
sd.remove("RawWrite.txt");

// create a contiguous file
if (!file.createContiguous(sd.vwd(), "RawWrite.txt", 512UL*BLOCK_COUNT)) {
if (!file.createContiguous("RawWrite.txt", 512UL*BLOCK_COUNT)) {
error("createContiguous failed");
}
// get the location of the file's blocks
@@ -104,28 +97,48 @@ void loop(void) {
pCache[i + 63] = '\n';
}

cout << F("Start raw write of ") << file.fileSize() << F(" bytes at\n");
cout << 512000000UL/MICROS_PER_BLOCK << F(" bytes per second\n");
cout << F("Please wait ") << (BLOCK_COUNT*MICROS_PER_BLOCK)/1000000UL;
cout << F(" seconds\n");

cout << F("Start raw write of ") << file.fileSize()/1000UL << F(" KB\n");
cout << F("Target rate: ") << RATE_KB_PER_SEC << F(" KB/sec\n");
cout << F("Target time: ") << TEST_TIME_SEC << F(" seconds\n");
// tell card to setup for multiple block write with pre-erase
if (!sd.card()->writeStart(bgnBlock, BLOCK_COUNT)) {
error("writeStart failed");
}
// init stats
uint16_t overruns = 0;

delay(1000);
uint32_t dotCount = 0;
uint32_t maxQueuePrint = 0;
uint32_t maxWriteTime = 0;
uint32_t t = micros();
uint32_t tNext = t;
uint32_t minWriteTime = 9999999;
uint32_t totalWriteTime = 0;
uint32_t maxQueueSize = 0;
uint32_t nWrite = 0;
uint32_t b = 0;

// write data
for (uint32_t b = 0; b < BLOCK_COUNT; b++) {
// write must be done by this time
tNext += MICROS_PER_BLOCK;

uint32_t startTime = millis();
while (nWrite < BLOCK_COUNT) {
uint32_t nProduced = RATE_KB_PER_SEC*(millis() - startTime)/512UL;
uint32_t queueSize = nProduced - nWrite;
if (queueSize == 0) continue;
if (queueSize > maxQueueSize) {
maxQueueSize = queueSize;
}
if ((millis() - startTime - dotCount*DOT_TIME_MS) > DOT_TIME_MS) {
if (maxQueueSize != maxQueuePrint) {
cout << F("\nQ: ") << maxQueueSize << endl;
maxQueuePrint = maxQueueSize;
} else {
cout << ".";
if (++dotCount%10 == 0) {
cout << endl;
}
}
}
// put block number at start of first line in block
uint32_t n = b;
uint32_t n = b++;
for (int8_t d = 5; d >= 0; d--) {
pCache[d] = n || d == 5 ? n % 10 + '0' : ' ';
n /= 10;
@@ -136,45 +149,30 @@ void loop(void) {
error("writeData failed");
}
tw = micros() - tw;
totalWriteTime += tw;
// check for max write time
if (tw > maxWriteTime) {
maxWriteTime = tw;
}
// check for overrun
if (micros() > tNext) {
if (overruns < OVER_DIM) {
over[overruns].block = b;
over[overruns].micros = tw;
}
overruns++;
// advance time to reflect overrun
tNext = micros();
} else {
// wait for time to write next block
while(micros() < tNext);
if (tw < minWriteTime) {
minWriteTime = tw;
}
nWrite++;
}
// total write time
t = micros() - t;

uint32_t endTime = millis();
uint32_t avgWriteTime = totalWriteTime/BLOCK_COUNT;
// end multiple block write mode
if (!sd.card()->writeStop()) {
error("writeStop failed");
}

cout << F("Done\n");
cout << F("Elapsed time: ") << setprecision(3)<< 1.e-6*t;
cout << F("\nDone\n");
cout << F("maxQueueSize: ") << maxQueueSize << endl;
cout << F("Elapsed time: ") << setprecision(3)<< 1.e-3*(endTime - startTime);
cout << F(" seconds\n");
cout << F("Max write time: ") << maxWriteTime << F(" micros\n");
cout << F("Overruns: ") << overruns << endl;
if (overruns) {
uint8_t n = overruns > OVER_DIM ? OVER_DIM : overruns;
cout << F("fileBlock,micros") << endl;
for (uint8_t i = 0; i < n; i++) {
cout << over[i].block << ',' << over[i].micros << endl;
}
}
cout << F("Min block write time: ") << minWriteTime << F(" micros\n");
cout << F("Max block write time: ") << maxWriteTime << F(" micros\n");
cout << F("Avg block write time: ") << avgWriteTime << F(" micros\n");
// close file for next pass of loop
file.close();
Serial.println();

+ 0
- 111
SdFat/examples/ReadCsvFields/ReadCsvFields.ino Vedi File

@@ -1,111 +0,0 @@

// Function to read a CSV text file one field at a time.
//
#include <SPI.h>
#include <SdFat.h>
#define CS_PIN SS

SdFat SD;
File file;

/*
* Read a file one field at a time.
*
* file - File to read.
*
* str - Character array for the field.
*
* size - Size of str array.
*
* delim - String containing field delimiters.
*
* return - length of field including terminating delimiter.
*
* Note, the last character of str will not be a delimiter if
* a read error occurs, the field is too long, or the file
* does not end with a delimiter. Consider this an error
* if not at end-of-file.
*
*/
size_t readField(File* file, char* str, size_t size, const char* delim) {
char ch;
size_t n = 0;
while ((n + 1) < size && file->read(&ch, 1) == 1) {
// Delete CR.
if (ch == '\r') {
continue;
}
str[n++] = ch;
if (strchr(delim, ch)) {
break;
}
}
str[n] = '\0';
return n;
}
//------------------------------------------------------------------------------
#define errorHalt(msg) {Serial.println(F(msg)); SysCall::halt();}
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
// Wait for USB Serial
while (!Serial) {
SysCall::yield();
}
Serial.println("Type any character to start");
while (!Serial.available()) {
SysCall::yield();
}
// Initialize the SD.
if (!SD.begin(CS_PIN)) errorHalt("begin failed");

// Create or open the file.
file = SD.open("READTEST.TXT", FILE_WRITE);
if (!file) errorHalt("open failed");

// Rewind file so test data is not appended.
file.rewind();

// Write test data.
file.print(F(
"field_1_1,field_1_2,field_1_3\r\n"
"field_2_1,field_2_2,field_2_3\r\n"
"field_3_1,field_3_2\r\n" // missing a field
"field_4_1,field_4_2,field_4_3\r\n"
"field_5_1,field_5_2,field_5_3" // no delimiter
));

// Rewind the file for read.
file.rewind();

size_t n; // Length of returned field with delimiter.
char str[20]; // Must hold longest field with delimiter and zero byte.
// Read the file and print fields.
while (true) {
n = readField(&file, str, sizeof(str), ",\n");

// done if Error or at EOF.
if (n == 0) break;

// Print the type of delimiter.
if (str[n-1] == ',' || str[n-1] == '\n') {
Serial.print(str[n-1] == ',' ? F("comma: ") : F("endl: "));
// Remove the delimiter.
str[n-1] = 0;
} else {
// At eof, too long, or read error. Too long is error.
Serial.print(file.available() ? F("error: ") : F("eof: "));
}
// Print the field.
Serial.println(str);
}
file.close();
}
//------------------------------------------------------------------------------
void loop() {
}



+ 120
- 0
SdFat/examples/ReadCsvStream/ReadCsvStream.ino Vedi File

@@ -0,0 +1,120 @@
/*
* This example reads a simple CSV, comma-separated values, file.
* Each line of the file has a label and three values, a long and two floats.
*/
#include <SPI.h>
#include "SdFat.h"

// SD chip select pin
const uint8_t chipSelect = SS;

// file system object
SdFat sd;

// create Serial stream
ArduinoOutStream cout(Serial);

char fileName[] = "testfile.csv";
//------------------------------------------------------------------------------
// store error strings in flash to save RAM
#define error(s) sd.errorHalt(F(s))
//------------------------------------------------------------------------------
// read and print CSV test file
void readFile() {
long lg = 0;
float f1, f2;
char text[10];
char c1, c2, c3; // space for commas.

// open input file
ifstream sdin(fileName);

// check for open error
if (!sdin.is_open()) {
error("open");
}

// read until input fails
while (1) {
// Get text field.
sdin.get(text, sizeof(text), ',');

// Assume EOF if fail.
if (sdin.fail()) {
break;
}

// Get commas and numbers.
sdin >> c1 >> lg >> c2 >> f1 >> c3 >> f2;

// Skip CR/LF.
sdin.skipWhite();

if (sdin.fail()) {
error("bad input");
}

// error in line if not commas
if (c1 != ',' || c2 != ',' || c3 != ',') {
error("comma");
}

// print in six character wide columns
cout << text << setw(6) << lg << setw(6) << f1 << setw(6) << f2 << endl;
}
// Error in an input line if file is not at EOF.
if (!sdin.eof()) {
error("readFile");
}
}
//------------------------------------------------------------------------------
// write test file
void writeFile() {

// create or open and truncate output file
ofstream sdout(fileName);

// write file from string stored in flash
sdout << F(
"Line 1,1,2.3,4.5\n"
"Line 2,6,7.8,9.0\n"
"Line 3,9,8.7,6.5\n"
"Line 4,-4,-3.2,-1\n") << flush;

// check for any errors
if (!sdout) {
error("writeFile");
}

sdout.close();
}
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
// Wait for USB Serial
while (!Serial) {
SysCall::yield();
}
cout << F("Type any character to start\n");
while (!Serial.available()) {
SysCall::yield();
}

// Initialize at the highest speed supported by the board that is
// not over 50 MHz. Try a lower speed if SPI errors occur.
if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
sd.initErrorHalt();
}

// create test file
writeFile();

cout << endl;

// read and print test
readFile();

cout << "\nDone!" << endl;
}
void loop() {}

+ 6
- 14
SdFat/examples/ReadWrite/ReadWrite.ino Vedi File

@@ -7,7 +7,6 @@
** MOSI - pin 11
** MISO - pin 12
** CLK - pin 13
** CS - pin 4

created Nov 2010
by David A. Mellis
@@ -17,30 +16,24 @@
This example code is in the public domain.

*/
#define SD_CS_PIN SS
#include <SPI.h>
//#include <SD.h>
#include "SdFat.h"
SdFat SD;

#define SD_CS_PIN SS
File myFile;

void setup()
{
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
// Wait for USB Serial
while (!Serial) {
SysCall::yield();
; // wait for serial port to connect. Needed for native USB port only
}


Serial.print("Initializing SD card...");
// On the Ethernet Shield, CS is pin 4. It's set as an output by default.
// Note that even if it's not used as the CS pin, the hardware SS pin
// (10 on most Arduino boards, 53 on the Mega) must be left as an output
// or the SD library functions will not work.
pinMode(10, OUTPUT);

if (!SD.begin(SD_CS_PIN)) {
Serial.println("initialization failed!");
@@ -81,8 +74,7 @@ void setup()
}
}

void loop()
{
void loop() {
// nothing happens after setup
}


+ 0
- 77
SdFat/examples/ReadWriteSdFat/ReadWriteSdFat.ino Vedi File

@@ -1,77 +0,0 @@
// Ported to SdFat from the native Arduino SD library example by Bill Greiman
// On the Ethernet Shield, CS is pin 4. SdFat handles setting SS
const int chipSelect = 4;
/*
SD card read/write

This example shows how to read and write data to and from an SD card file
The circuit:
* SD card attached to SPI bus as follows:
** MOSI - pin 11
** MISO - pin 12
** CLK - pin 13
** CS - pin 4

created Nov 2010
by David A. Mellis
updated 2 Dec 2010
by Tom Igoe
modified by Bill Greiman 11 Apr 2011
This example code is in the public domain.

*/
#include <SPI.h>
#include "SdFat.h"
SdFat sd;
SdFile myFile;

void setup() {
Serial.begin(9600);
// Wait for USB Serial
while (!Serial) {
SysCall::yield();
}
Serial.println("Type any character to start");
while (!Serial.available()) {
SysCall::yield();
}
// Initialize SdFat or print a detailed error message and halt
// Use half speed like the native library.
// change to SPI_FULL_SPEED for more performance.
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
sd.initErrorHalt();
}

// open the file for write at end like the Native SD library
if (!myFile.open("test.txt", O_RDWR | O_CREAT | O_AT_END)) {
sd.errorHalt("opening test.txt for write failed");
}
// if the file opened okay, write to it:
Serial.print("Writing to test.txt...");
myFile.println("testing 1, 2, 3.");

// close the file:
myFile.close();
Serial.println("done.");

// re-open the file for reading:
if (!myFile.open("test.txt", O_READ)) {
sd.errorHalt("opening test.txt for read failed");
}
Serial.println("test.txt:");

// read from the file until there's nothing else in it:
int data;
while ((data = myFile.read()) >= 0) {
Serial.write(data);
}
// close the file:
myFile.close();
}

void loop() {
// nothing happens after setup
}



+ 176
- 0
SdFat/examples/STM32Test/STM32Test.ino Vedi File

@@ -0,0 +1,176 @@
/*
* Example use of two SPI ports on an STM32 board.
* Note SPI speed is limited to 18 MHz.
*/
#include <SPI.h>
#include "SdFat.h"
#include "FreeStack.h"

// set ENABLE_EXTENDED_TRANSFER_CLASS non-zero to use faster EX classes

// Use first SPI port
SdFat sd1(1);
// SdFatEX sd1(1);
const uint8_t SD1_CS = PA4; // chip select for sd1

// Use second SPI port
SdFat sd2(2);
// SdFatEX sd2(2);
const uint8_t SD2_CS = PB12; // chip select for sd2

const uint8_t BUF_DIM = 100;
uint8_t buf[BUF_DIM];

const uint32_t FILE_SIZE = 1000000;
const uint16_t NWRITE = FILE_SIZE/BUF_DIM;
//------------------------------------------------------------------------------
// print error msg, any SD error codes, and halt.
// store messages in flash
#define errorExit(msg) errorHalt(F(msg))
#define initError(msg) initErrorHalt(F(msg))
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
// Wait for USB Serial
while (!Serial) {
SysCall::yield();
}
Serial.print(F("FreeStack: "));

Serial.println(FreeStack());

// fill buffer with known data
for (size_t i = 0; i < sizeof(buf); i++) {
buf[i] = i;
}

Serial.println(F("type any character to start"));
while (!Serial.available()) {
SysCall::yield();
}

// initialize the first card
if (!sd1.begin(SD1_CS, SD_SCK_MHZ(18))) {
sd1.initError("sd1:");
}
// create Dir1 on sd1 if it does not exist
if (!sd1.exists("/Dir1")) {
if (!sd1.mkdir("/Dir1")) {
sd1.errorExit("sd1.mkdir");
}
}
// initialize the second card
if (!sd2.begin(SD2_CS, SD_SCK_MHZ(18))) {
sd2.initError("sd2:");
}
// create Dir2 on sd2 if it does not exist
if (!sd2.exists("/Dir2")) {
if (!sd2.mkdir("/Dir2")) {
sd2.errorExit("sd2.mkdir");
}
}
// list root directory on both cards
Serial.println(F("------sd1 root-------"));
sd1.ls();
Serial.println(F("------sd2 root-------"));
sd2.ls();

// make /Dir1 the default directory for sd1
if (!sd1.chdir("/Dir1")) {
sd1.errorExit("sd1.chdir");
}
// remove test.bin from /Dir1 directory of sd1
if (sd1.exists("test.bin")) {
if (!sd1.remove("test.bin")) {
sd2.errorExit("remove test.bin");
}
}
// make /Dir2 the default directory for sd2
if (!sd2.chdir("/Dir2")) {
sd2.errorExit("sd2.chdir");
}
// remove rename.bin from /Dir2 directory of sd2
if (sd2.exists("rename.bin")) {
if (!sd2.remove("rename.bin")) {
sd2.errorExit("remove rename.bin");
}
}
// list current directory on both cards
Serial.println(F("------sd1 Dir1-------"));
sd1.ls();
Serial.println(F("------sd2 Dir2-------"));
sd2.ls();
Serial.println(F("---------------------"));

// set the current working directory for open() to sd1
sd1.chvol();

// create or open /Dir1/test.bin and truncate it to zero length
SdFile file1;
if (!file1.open("test.bin", O_RDWR | O_CREAT | O_TRUNC)) {
sd1.errorExit("file1");
}
Serial.println(F("Writing test.bin to sd1"));

// write data to /Dir1/test.bin on sd1
for (uint16_t i = 0; i < NWRITE; i++) {
if (file1.write(buf, sizeof(buf)) != sizeof(buf)) {
sd1.errorExit("sd1.write");
}
}
// set the current working directory for open() to sd2
sd2.chvol();

// create or open /Dir2/copy.bin and truncate it to zero length
SdFile file2;
if (!file2.open("copy.bin", O_WRITE | O_CREAT | O_TRUNC)) {
sd2.errorExit("file2");
}
Serial.println(F("Copying test.bin to copy.bin"));

// copy file1 to file2
file1.rewind();
uint32_t t = millis();

while (1) {
int n = file1.read(buf, sizeof(buf));
if (n < 0) {
sd1.errorExit("read1");
}
if (n == 0) {
break;
}
if ((int)file2.write(buf, n) != n) {
sd2.errorExit("write2");
}
}
t = millis() - t;
Serial.print(F("File size: "));
Serial.println(file2.fileSize());
Serial.print(F("Copy time: "));
Serial.print(t);
Serial.println(F(" millis"));
// close test.bin
file1.close();
file2.close();
// list current directory on both cards
Serial.println(F("------sd1 -------"));
sd1.ls("/", LS_R | LS_DATE | LS_SIZE);
Serial.println(F("------sd2 -------"));
sd2.ls("/", LS_R | LS_DATE | LS_SIZE);
Serial.println(F("---------------------"));
Serial.println(F("Renaming copy.bin"));
// rename the copy
if (!sd2.rename("copy.bin", "rename.bin")) {
sd2.errorExit("sd2.rename");
}
// list current directory on both cards
Serial.println(F("------sd1 -------"));
sd1.ls("/", LS_R | LS_DATE | LS_SIZE);
Serial.println(F("------sd2 -------"));
sd2.ls("/", LS_R | LS_DATE | LS_SIZE);
Serial.println(F("---------------------"));
Serial.println(F("Done"));
}
//------------------------------------------------------------------------------
void loop() {}

+ 7
- 9
SdFat/examples/SdFormatter/SdFormatter.ino Vedi File

@@ -26,9 +26,9 @@
// Adafruit SD shields and modules: pin 10
const uint8_t chipSelect = SS;

// Change spiSpeed to SPI_FULL_SPEED for better performance
// Use SPI_QUARTER_SPEED for even slower SPI bus speed
const uint8_t spiSpeed = SPI_HALF_SPEED;
// Initialize at highest supported speed not over 50 MHz.
// Reduce max speed if errors occur.
#define SPI_SPEED SD_SCK_MHZ(50)

// Serial output stream
ArduinoOutStream cout(Serial);
@@ -65,11 +65,9 @@ char noName[] = "NO NAME ";
char fat16str[] = "FAT16 ";
char fat32str[] = "FAT32 ";
//------------------------------------------------------------------------------
#define sdError(msg) sdError_F(F(msg))

void sdError_F(const __FlashStringHelper* str) {
cout << F("error: ");
cout << str << endl;
#define sdError(msg) {cout << F("error: ") << F(msg) << endl; sdErrorHalt();}
//------------------------------------------------------------------------------
void sdErrorHalt() {
if (card.errorCode()) {
cout << F("SD error: ") << hex << int(card.errorCode());
cout << ',' << int(card.errorData()) << dec << endl;
@@ -499,7 +497,7 @@ void setup() {
return;
}

if (!card.begin(chipSelect, spiSpeed)) {
if (!card.begin(chipSelect, SPI_SPEED)) {
cout << F(
"\nSD initialization failure!\n"
"Is the SD card inserted correctly?\n"

+ 8
- 21
SdFat/examples/SdInfo/SdInfo.ino Vedi File

@@ -30,16 +30,7 @@ uint32_t cardSize;
uint32_t eraseSize;
//------------------------------------------------------------------------------
// store error strings in flash
#define sdErrorMsg(msg) sdErrorMsg_F(F(msg));
void sdErrorMsg_F(const __FlashStringHelper* str) {
cout << str << endl;
if (sd.card()->errorCode()) {
cout << F("SD errorCode: ");
cout << hex << int(sd.card()->errorCode()) << endl;
cout << F("SD errorData: ");
cout << int(sd.card()->errorData()) << dec << endl;
}
}
#define sdErrorMsg(msg) sd.errorPrint(F(msg));
//------------------------------------------------------------------------------
uint8_t cidDmp() {
cid_t cid;
@@ -97,17 +88,13 @@ uint8_t csdDmp() {
//------------------------------------------------------------------------------
// print partition table
uint8_t partDmp() {
cache_t *p = sd.vol()->cacheClear();
if (!p) {
sdErrorMsg("cacheClear failed");
return false;
}
if (!sd.card()->readBlock(0, p->data)) {
mbr_t mbr;
if (!sd.card()->readBlock(0, (uint8_t*)&mbr)) {
sdErrorMsg("read MBR failed");
return false;
}
for (uint8_t ip = 1; ip < 5; ip++) {
part_t *pt = &p->mbr.part[ip - 1];
part_t *pt = &mbr.part[ip - 1];
if ((pt->boot & 0X7F) != 0 || pt->firstSector > cardSize) {
cout << F("\nNo MBR. Assuming Super Floppy format.\n");
return true;
@@ -116,7 +103,7 @@ uint8_t partDmp() {
cout << F("\nSD Partition Table\n");
cout << F("part,boot,type,start,length\n");
for (uint8_t ip = 1; ip < 5; ip++) {
part_t *pt = &p->mbr.part[ip - 1];
part_t *pt = &mbr.part[ip - 1];
cout << int(ip) << ',' << hex << int(pt->boot) << ',' << int(pt->type);
cout << dec << ',' << pt->firstSector <<',' << pt->totalSectors << endl;
}
@@ -183,9 +170,9 @@ void loop() {
}

uint32_t t = millis();
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance.
if (!sd.cardBegin(SD_CHIP_SELECT, SPI_HALF_SPEED)) {
// Initialize at the highest speed supported by the board that is
// not over 50 MHz. Try a lower speed if SPI errors occur.
if (!sd.cardBegin(SD_CHIP_SELECT, SD_SCK_MHZ(50))) {
sdErrorMsg("\ncardBegin failed");
return;
}

+ 4
- 4
SdFat/examples/SoftwareSpi/SoftwareSpi.ino Vedi File

@@ -5,7 +5,7 @@
//
#include <SPI.h>
#include "SdFat.h"
#if SD_SPI_CONFIGURATION >= 3 // Must be set in SdFat/SdFatConfig.h
#if ENABLE_SOFTWARE_SPI_CLASS // Must be set in SdFat/SdFatConfig.h
//
// Pin numbers in templates must be constants.
const uint8_t SOFT_MISO_PIN = 12;
@@ -53,6 +53,6 @@ void setup() {
}
//------------------------------------------------------------------------------
void loop() {}
#else // SD_SPI_CONFIGURATION >= 3
#error SD_SPI_CONFIGURATION must be set to 3 in SdFat/SdFatConfig.h
#endif //SD_SPI_CONFIGURATION >= 3
#else // ENABLE_SOFTWARE_SPI_CLASS
#error ENABLE_SOFTWARE_SPI_CLASS must be set non-zero in SdFat/SdFatConfig.h
#endif //ENABLE_SOFTWARE_SPI_CLASS

+ 7
- 3
SdFat/examples/StdioBench/StdioBench.ino Vedi File

@@ -39,7 +39,10 @@ void setup() {
SysCall::yield();
}
Serial.println(F("Starting test"));
if (!sd.begin(SD_CS_PIN)) {

// Initialize at the highest speed supported by the board that is
// not over 50 MHz. Try a lower speed if SPI errors occur.
if (!sd.begin(SD_CS_PIN, SD_SCK_MHZ(50))) {
sd.errorHalt();
}

@@ -137,10 +140,11 @@ void setup() {

case 3:
for (uint16_t i = 0; i < 10000; i++) {
uint32_t n = i + 1000000000UL;
#if PRINT_FIELD
stdioFile.printField(i + 1000000000UL, '\n');
stdioFile.printField(n, '\n');
#else // PRINT_FIELD
stdioFile.println(i + 1000000000UL);
stdioFile.println(n);
#endif // PRINT_FIELD
}
break;

+ 0
- 231
SdFat/examples/ThreeCards/ThreeCards.ino Vedi File

@@ -1,231 +0,0 @@
/*
* Example use of three SD cards.
*/
#include <SPI.h>
#include "SdFat.h"
#include "FreeStack.h"
#if SD_SPI_CONFIGURATION >= 3 // Must be set in SdFat/SdFatConfig.h

// SD1 is a microSD on hardware SPI pins 50-52
// Using my fast custom SPI
SdFat sd1;
const uint8_t SD1_CS = 53;

// SD2 is a Catalex shield on hardware SPI pins 50-52
// Using the standard Arduino SPI library
SdFatLibSpi sd2;
const uint8_t SD2_CS = 4;

// SD3 is a Adafruit data logging shield on pins 10-13
// Using Software SPI
SdFatSoftSpi<12, 11, 13> sd3;
const uint8_t SD3_CS = 10;

const uint8_t BUF_DIM = 100;
uint8_t buf[BUF_DIM];

const uint32_t FILE_SIZE = 1000000;
const uint16_t NWRITE = FILE_SIZE/BUF_DIM;
//------------------------------------------------------------------------------
// print error msg, any SD error codes, and halt.
// store messages in flash
#define errorExit(msg) errorHalt(F(msg))
#define initError(msg) initErrorHalt(F(msg))
//------------------------------------------------------------------------------
void list() {
// list current directory on all cards
Serial.println(F("------sd1-------"));
sd1.ls("/", LS_SIZE|LS_R);
Serial.println(F("------sd2-------"));
sd2.ls("/", LS_SIZE|LS_R);
Serial.println(F("------sd3-------"));
sd3.ls("/", LS_SIZE|LS_R);
Serial.println(F("---------------------"));
}
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
// Wait for USB Serial
while (!Serial) {
SysCall::yield();
}
Serial.print(F("FreeStack: "));

Serial.println(FreeStack());

// fill buffer with known data
for (size_t i = 0; i < sizeof(buf); i++) {
buf[i] = i;
}
Serial.println(F("type any character to start"));
while (!Serial.available()) {
SysCall::yield();
}
// disable sd2 while initializing sd1
pinMode(SD2_CS, OUTPUT);
digitalWrite(SD2_CS, HIGH);

// initialize the first card
if (!sd1.begin(SD1_CS)) {
sd1.initError("sd1:");
}

// initialize the second card
if (!sd2.begin(SD2_CS)) {
sd2.initError("sd2:");
}

// initialize the third card
if (!sd3.begin(SD3_CS)) {
sd3.initError("sd3:");
}

Serial.println(F("Cards OK - creating directories"));

// create Dir1 on sd1 if it does not exist
if (!sd1.exists("/Dir1")) {
if (!sd1.mkdir("/Dir1")) {
sd1.errorExit("sd1.mkdir");
}
}
// make /Dir1 the default directory for sd1
if (!sd1.chdir("/Dir1")) {
sd1.errorExit("sd1.chdir");
}

// create Dir2 on sd2 if it does not exist
if (!sd2.exists("/Dir2")) {
if (!sd2.mkdir("/Dir2")) {
sd2.errorExit("sd2.mkdir");
}
}
// make /Dir2 the default directory for sd2
if (!sd2.chdir("/Dir2")) {
sd2.errorExit("sd2.chdir");
}

// create Dir3 on sd3 if it does not exist
if (!sd3.exists("/Dir3")) {
if (!sd3.mkdir("/Dir3")) {
sd2.errorExit("sd3.mkdir");
}
}
// make /Dir3 the default directory for sd3
if (!sd3.chdir("/Dir3")) {
sd3.errorExit("sd3.chdir");
}

Serial.println(F("Directories created - removing old files"));

if (sd1.exists("TEST1.bin")) {
if (!sd1.remove("TEST1.bin")) {
sd1.errorExit("sd1.remove");
}
}
if (sd2.exists("TEST2.bin")) {
if (!sd2.remove("TEST2.bin")) {
sd2.errorExit("sd2.remove");
}
}
if (sd3.exists("TEST3.bin")) {
if (!sd3.remove("TEST3.bin")) {
sd2.errorExit("sd3.remove");
}
}
Serial.println("Initial SD directories");
list();

// create or open /Dir1/TEST1.bin and truncate it to zero length
SdFile file1;
if (!file1.open(&sd1, "TEST1.bin", O_RDWR | O_CREAT | O_TRUNC)) {
sd1.errorExit("file1");
}
Serial.println(F("Writing SD1:/Dir1/TEST1.bin"));

// write data to /Dir1/TEST1.bin on sd1
for (uint16_t i = 0; i < NWRITE; i++) {
if (file1.write(buf, sizeof(buf)) != sizeof(buf)) {
sd1.errorExit("sd1.write");
}
}
file1.sync();
list();

// create or open /Dir2/TEST2.bin and truncate it to zero length
SdFile file2;
if (!file2.open(&sd2, "TEST2.bin", O_RDWR | O_CREAT | O_TRUNC)) {
sd2.errorExit("file2");
}
Serial.println(F("Copying SD1:/Dir1/TEST1.bin to SD2::/Dir2/TEST2.bin"));

// copy file1 to file2
file1.rewind();

uint32_t t = millis();

while (1) {
int n = file1.read(buf, sizeof(buf));
if (n < 0) {
sd1.errorExit("read1");
}
if (n == 0) {
break;
}
if ((int)file2.write(buf, n) != n) {
sd2.errorExit("write3");
}
}
t = millis() - t;
file2.sync();
Serial.print(F("File size: "));
Serial.println(file2.fileSize());
Serial.print(F("Copy time: "));
Serial.print(t);
Serial.println(F(" millis"));
list();

// create or open /Dir3/TEST3.bin and truncate it to zero length
SdFile file3;
if (!file3.open(&sd3, "TEST3.bin", O_RDWR | O_CREAT | O_TRUNC)) {
sd3.errorExit("file3");
}
file2.rewind();
Serial.println(F("Copying SD2:/Dir2/TEST2.bin to SD3:/Dir3/TEST3.bin"));
while (1) {
int n = file2.read(buf, sizeof(buf));
if (n == 0) {
break;
}
if (n != sizeof(buf)) {
sd2.errorExit("read2");
}
if ((int)file3.write(buf, n) != n) {
sd3.errorExit("write2");
}
}
file3.sync();
list();

// Verify content of file3
file3.rewind();
Serial.println(F("Verifying content of TEST3.bin"));
for (uint16_t i = 0; i < NWRITE; i++) {
if (file3.read(buf, sizeof(buf)) != sizeof(buf)) {
sd3.errorExit("sd3.read");
}
for (size_t j = 0; j < sizeof(buf); j++) {
if (j != buf[j]) {
sd3.errorExit("Verify error");
}
}
}
Serial.println(F("Done - Verify OK"));
file1.close();
file2.close();
file3.close();
}
//------------------------------------------------------------------------------
void loop() {}
#else // SD_SPI_CONFIGURATION >= 3
#error SD_SPI_CONFIGURATION must be set to 3 in SdFat/SdFatConfig.h
#endif //SD_SPI_CONFIGURATION >= 3

+ 3
- 3
SdFat/examples/Timestamp/Timestamp.ino Vedi File

@@ -83,9 +83,9 @@ void setup(void) {
while (!Serial.available()) {
SysCall::yield();
}
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance.
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
// Initialize at the highest speed supported by the board that is
// not over 50 MHz. Try a lower speed if SPI errors occur.
if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
sd.initErrorHalt();
}


+ 1
- 0
SdFat/examples/TwoCards/TwoCards.ino Vedi File

@@ -1,4 +1,5 @@
/*
* Warning This example requires extra RAM and may crash on Uno.
* Example use of two SD cards.
*/
#include <SPI.h>

+ 4
- 3
SdFat/examples/VolumeFreeSpace/VolumeFreeSpace.ino Vedi File

@@ -49,9 +49,9 @@ void setup() {
while (!Serial.available()) {
SysCall::yield();
}
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance.
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
// Initialize at the highest speed supported by the board that is
// not over 50 MHz. Try a lower speed if SPI errors occur.
if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
sd.initErrorHalt();
}
// Insure no TEST_FILE.
@@ -75,6 +75,7 @@ void setup() {
cout << F("Remove ") << TEST_FILE << endl << endl;
sd.remove(TEST_FILE);
printFreeSpace();
cout << F("Done") << endl;
}
//------------------------------------------------------------------------------
void loop() {}

+ 9
- 5
SdFat/examples/bench/bench.ino Vedi File

@@ -29,8 +29,12 @@ uint8_t buf[BUF_SIZE];

// file system
SdFat sd;
// Set SD_SPI_CONFIGURATION to three to test next two definitions.
// SdFatLibSpi sd;

// Set ENABLE_EXTENDED_TRANSFER_CLASS to use extended SD I/O.
// Requires dedicated use of the SPI bus.
// SdFatEX sd;

// Set ENABLE_SOFTWARE_SPI_CLASS to use software SPI.
// Args are misoPin, mosiPin, sckPin.
// SdFatSoftSpi<6, 7, 5> sd;

@@ -98,9 +102,9 @@ void loop() {

cout << F("FreeStack: ") << FreeStack() << endl;

// initialize the SD card at SPI_FULL_SPEED for best performance.
// try SPI_HALF_SPEED if bus errors occur.
if (!sd.begin(chipSelect, SPI_FULL_SPEED)) {
// Initialize at the highest speed supported by the board that is
// not over 50 MHz. Try a lower speed if SPI errors occur.
if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
sd.initErrorHalt();
}


+ 3
- 3
SdFat/examples/dataLogger/dataLogger.ino Vedi File

@@ -79,9 +79,9 @@ void setup() {
SysCall::yield();
}
// Initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance.
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
// Initialize at the highest speed supported by the board that is
// not over 50 MHz. Try a lower speed if SPI errors occur.
if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
sd.initErrorHalt();
}


+ 4
- 4
SdFat/examples/directoryFunctions/directoryFunctions.ino Vedi File

@@ -5,7 +5,7 @@
#include "SdFat.h"

// SD card chip select pin.
const uint8_t SD_CHIP_SELECT = SS;
const uint8_t chipSelect = SS;
//------------------------------------------------------------------------------

// File system object.
@@ -40,9 +40,9 @@ void setup() {
cin.readline();
cout << endl;
// Initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance.
if (!sd.begin(SD_CHIP_SELECT, SPI_HALF_SPEED)) {
// Initialize at the highest speed supported by the board that is
// not over 50 MHz. Try a lower speed if SPI errors occur.
if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
sd.initErrorHalt();
}
if (sd.exists("Folder1")

+ 3
- 3
SdFat/examples/fgets/fgets.ino Vedi File

@@ -72,9 +72,9 @@ void setup(void) {
}
delay(400); // catch Due reset problem

// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance.
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
// Initialize at the highest speed supported by the board that is
// not over 50 MHz. Try a lower speed if SPI errors occur.
if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
sd.initErrorHalt();
}


+ 3
- 3
SdFat/examples/getline/getline.ino Vedi File

@@ -66,9 +66,9 @@ void setup(void) {
SysCall::yield();
}

// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance.
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
// Initialize at the highest speed supported by the board that is
// not over 50 MHz. Try a lower speed if SPI errors occur.
if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
sd.initErrorHalt();
}


+ 186
- 94
SdFat/examples/readCSV/readCSV.ino Vedi File

@@ -1,92 +1,130 @@
/*
* This example reads a simple CSV, comma-separated values, file.
* Each line of the file has a label and three values, a long and two floats.
*/
#include <SPI.h>
#include "SdFat.h"

// SD chip select pin
const uint8_t chipSelect = SS;

// file system object
SdFat sd;
// Functions to read a CSV text file one field at a time.
//
#include <limits.h>
#include <SPI.h>

// create Serial stream
ArduinoOutStream cout(Serial);
// next line for SD.h
//#include <SD.h>

char fileName[] = "testfile.csv";
//------------------------------------------------------------------------------
// store error strings in flash to save RAM
#define error(s) sd.errorHalt(F(s))
//------------------------------------------------------------------------------
// read and print CSV test file
void readFile() {
long lg = 0;
float f1, f2;
char text[10];
char c1, c2, c3; // space for commas.
// next two lines for SdFat
#include <SdFat.h>
SdFat SD;

// open input file
ifstream sdin(fileName);
#define CS_PIN SS

// check for open error
if (!sdin.is_open()) {
error("open");
}
// example can use comma or semicolon
#define CSV_DELIM ','

// read until input fails
while (1) {
// Get text field.
sdin.get(text, sizeof(text), ',');
File file;

// Assume EOF if fail.
if (sdin.fail()) {
/*
* Read a file one field at a time.
*
* file - File to read.
*
* str - Character array for the field.
*
* size - Size of str array.
*
* delim - csv delimiter.
*
* return - negative value for failure.
* delimiter, '\n' or zero(EOF) for success.
*/
int csvReadText(File* file, char* str, size_t size, char delim) {
char ch;
int rtn;
size_t n = 0;
while (true) {
// check for EOF
if (!file->available()) {
rtn = 0;
break;
}

// Get commas and numbers.
sdin >> c1 >> lg >> c2 >> f1 >> c3 >> f2;

// Skip CR/LF.
sdin.skipWhite();

if (sdin.fail()) {
error("bad input");
if (file->read(&ch, 1) != 1) {
// read error
rtn = -1;
break;
}

// error in line if not commas
if (c1 != ',' || c2 != ',' || c3 != ',') {
error("comma");
// Delete CR.
if (ch == '\r') {
continue;
}

// print in six character wide columns
cout << text << setw(6) << lg << setw(6) << f1 << setw(6) << f2 << endl;
}
// Error in an input line if file is not at EOF.
if (!sdin.eof()) {
error("readFile");
if (ch == delim || ch == '\n') {
rtn = ch;
break;
}
if ((n+1) >= size) {
// string too long
rtn = -2;
n--;
break;
}
str[n++] = ch;
}
str[n] = '\0';
return rtn;
}
//------------------------------------------------------------------------------
// write test file
void writeFile() {

// create or open and truncate output file
ofstream sdout(fileName);

// write file from string stored in flash
sdout << F(
"Line 1,1,2.3,4.5\n"
"Line 2,6,7.8,9.0\n"
"Line 3,9,8.7,6.5\n"
"Line 4,-4,-3.2,-1\n") << flush;

// check for any errors
if (!sdout) {
error("writeFile");
}

sdout.close();
int csvReadInt32(File* file, int32_t* num, char delim) {
char buf[20];
char* ptr;
int rtn = csvReadText(file, buf, sizeof(buf), delim);
if (rtn < 0) return rtn;
*num = strtol(buf, &ptr, 10);
if (buf == ptr) return -3;
while(isspace(*ptr)) ptr++;
return *ptr == 0 ? rtn : -4;
}
//------------------------------------------------------------------------------
int csvReadInt16(File* file, int16_t* num, char delim) {
int32_t tmp;
int rtn = csvReadInt32(file, &tmp, delim);
if (rtn < 0) return rtn;
if (tmp < INT_MIN || tmp > INT_MAX) return -5;
*num = tmp;
return rtn;
}
//------------------------------------------------------------------------------
int csvReadUint32(File* file, uint32_t* num, char delim) {
char buf[20];
char* ptr;
int rtn = csvReadText(file, buf, sizeof(buf), delim);
if (rtn < 0) return rtn;
*num = strtoul(buf, &ptr, 10);
if (buf == ptr) return -3;
while(isspace(*ptr)) ptr++;
return *ptr == 0 ? rtn : -4;
}
//------------------------------------------------------------------------------
int csvReadUint16(File* file, uint16_t* num, char delim) {
uint32_t tmp;
int rtn = csvReadUint32(file, &tmp, delim);
if (rtn < 0) return rtn;
if (tmp > UINT_MAX) return -5;
*num = tmp;
return rtn;
}
//------------------------------------------------------------------------------
int csvReadDouble(File* file, double* num, char delim) {
char buf[20];
char* ptr;
int rtn = csvReadText(file, buf, sizeof(buf), delim);
if (rtn < 0) return rtn;
*num = strtod(buf, &ptr);
if (buf == ptr) return -3;
while(isspace(*ptr)) ptr++;
return *ptr == 0 ? rtn : -4;
}
//------------------------------------------------------------------------------
int csvReadFloat(File* file, float* num, char delim) {
double tmp;
int rtn = csvReadDouble(file, &tmp, delim);
if (rtn < 0)return rtn;
// could test for too large.
*num = tmp;
return rtn;
}
//------------------------------------------------------------------------------
void setup() {
@@ -94,27 +132,81 @@ void setup() {
// Wait for USB Serial
while (!Serial) {
SysCall::yield();
yield();
}
cout << F("Type any character to start\n");
Serial.println("Type any character to start");
while (!Serial.available()) {
SysCall::yield();
yield();
}

// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
sd.initErrorHalt();
// Initialize the SD.
if (!SD.begin(CS_PIN)) {
Serial.println("begin failed");
return;
}

// create test file
writeFile();

cout << endl;

// read and print test
readFile();

cout << "\nDone!" << endl;
// Remove existing file.
SD.remove("READTEST.TXT");
// Create the file.
file = SD.open("READTEST.TXT", FILE_WRITE);
if (!file) {
Serial.println("open failed");
return;
}
// Write test data.
file.print(F(
#if CSV_DELIM == ','
"36,23.20,20.70,57.60,79.50,01:08:14,23.06.16\r\n"
"37,23.21,20.71,57.61,79.51,02:08:14,23.07.16\r\n"
#elif CSV_DELIM == ';'
"36;23.20;20.70;57.60;79.50;01:08:14;23.06.16\r\n"
"37;23.21;20.71;57.61;79.51;02:08:14;23.07.16\r\n"
#else
#error "Bad CSV_DELIM"
#endif
));

// Rewind the file for read.
file.seek(0);

// Read the file and print fields.
int16_t tcalc;
float t1, t2, h1, h2;
// Must be dim 9 to allow for zero byte.
char timeS[9], dateS[9];
while (file.available()) {
if (csvReadInt16(&file, &tcalc, CSV_DELIM) != CSV_DELIM
|| csvReadFloat(&file, &t1, CSV_DELIM) != CSV_DELIM
|| csvReadFloat(&file, &t2, CSV_DELIM) != CSV_DELIM
|| csvReadFloat(&file, &h1, CSV_DELIM) != CSV_DELIM
|| csvReadFloat(&file, &h2, CSV_DELIM) != CSV_DELIM
|| csvReadText(&file, timeS, sizeof(timeS), CSV_DELIM) != CSV_DELIM
|| csvReadText(&file, dateS, sizeof(dateS), CSV_DELIM) != '\n') {
Serial.println("read error");
int ch;
int nr = 0;
// print part of file after error.
while ((ch = file.read()) > 0 && nr++ < 100) {
Serial.write(ch);
}
break;
}
Serial.print(tcalc);
Serial.print(CSV_DELIM);
Serial.print(t1);
Serial.print(CSV_DELIM);
Serial.print(t2);
Serial.print(CSV_DELIM);
Serial.print(h1);
Serial.print(CSV_DELIM);
Serial.print(h2);
Serial.print(CSV_DELIM);
Serial.print(timeS);
Serial.print(CSV_DELIM);
Serial.println(dateS);
}
file.close();
}
void loop() {}
//------------------------------------------------------------------------------
void loop() {
}


+ 3
- 3
SdFat/examples/rename/rename.ino Vedi File

@@ -29,9 +29,9 @@ void setup() {
SysCall::yield();
}

// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance.
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
// Initialize at the highest speed supported by the board that is
// not over 50 MHz. Try a lower speed if SPI errors occur.
if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
sd.initErrorHalt();
}


+ 6
- 2
SdFat/examples/wipe/wipe.ino Vedi File

@@ -20,7 +20,9 @@ void setup() {
if (c != 'Y') {
sd.errorHalt("Quitting, you did not type 'Y'.");
}
if (!sd.begin(chipSelect)) {
// Initialize at the highest speed supported by the board that is
// not over 50 MHz. Try a lower speed if SPI errors occur.
if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
sd.initErrorHalt();
}
// Use wipe() for no dot progress indicator.
@@ -28,7 +30,9 @@ void setup() {
sd.errorHalt("Wipe failed.");
}
// Must reinitialize after wipe.
if (!sd.begin(chipSelect)) {
// Initialize at the highest speed supported by the board that is
// not over 50 MHz. Try a lower speed if SPI errors occur.
if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
sd.errorHalt("Second init failed.");
}
Serial.println("Done");

+ 1
- 1
SdFat/library.properties Vedi File

@@ -1,5 +1,5 @@
name=SdFat
version=2015.4.26
version=2016.7.24
author=
maintainer=
sentence=FAT16/FAT32 file system for SD cards.

SdFat/src/SdSpiCard/DigitalPin.h → SdFat/src/AltSpiDrivers/DigitalPin.h Vedi File

@@ -27,7 +27,6 @@
*/
#ifndef DigitalPin_h
#define DigitalPin_h
#include "SystemInclude.h"
#if defined(__AVR__)
#include <avr/io.h>
/** GpioPinMap type */

SdFat/src/SdSpiCard/SdSpiESP8266.cpp → SdFat/src/AltSpiDrivers/SdSpiESP8266.cpp Vedi File

@@ -1,9 +1,9 @@
/* Arduino SdSpi Library
/* Arduino SdSpiAltDriver Library
* Copyright (C) 2016 by William Greiman
*
* STM32F1 code for Maple and Maple Mini support, 2015 by Victor Perez
*
* This file is part of the Arduino SdSpi Library
* This file is part of the Arduino SdSpiAltDriver Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,52 +16,40 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino SdSpi Library. If not, see
* along with the Arduino SdSpiAltDriver Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#if defined(ESP8266)
#include "SdSpi.h"
#include "SdSpiDriver.h"
//------------------------------------------------------------------------------
/** Initialize the SPI bus.
*
* \param[in] chipSelectPin SD card chip select pin.
*/
void SdSpi::begin(uint8_t chipSelectPin) {
pinMode(chipSelectPin, OUTPUT);
digitalWrite(chipSelectPin, HIGH);
void SdSpiAltDriver::begin(uint8_t csPin) {
m_csPin = csPin;
pinMode(m_csPin, OUTPUT);
digitalWrite(m_csPin, HIGH);
SPI.begin();
}
//------------------------------------------------------------------------------
/** Set SPI options for access to SD/SDHC cards.
*
* \param[in] divisor SCK clock divider relative to the max SPI clock.
*/
void SdSpi::beginTransaction(uint8_t divisor) {
const uint32_t F_SPI_MAX = 80000000;
#if ENABLE_SPI_TRANSACTIONS
// Note: ESP8266 beginTransaction does not protect for interrupts.
SPISettings settings(F_SPI_MAX/(divisor ? divisor : 1), MSBFIRST, SPI_MODE0);
SPI.beginTransaction(settings);
#else // ENABLE_SPI_TRANSACTIONS
// Note: ESP8266 beginTransaction is the same as following code.
SPI.setFrequency(F_SPI_MAX/(divisor ? divisor : 1));
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
#endif // ENABLE_SPI_TRANSACTIONS
void SdSpiAltDriver::activate() {
SPI.beginTransaction(m_spiSettings);
}
//------------------------------------------------------------------------------
void SdSpi::endTransaction() {
#if ENABLE_SPI_TRANSACTIONS
void SdSpiAltDriver::deactivate() {
// Note: endTransaction is an empty function on ESP8266.
SPI.endTransaction();
#endif // ENABLE_SPI_TRANSACTIONS
}
//------------------------------------------------------------------------------
/** Receive a byte.
*
* \return The byte.
*/
uint8_t SdSpi::receive() {
uint8_t SdSpiAltDriver::receive() {
return SPI.transfer(0XFF);
}
//------------------------------------------------------------------------------
@@ -72,7 +60,7 @@ uint8_t SdSpi::receive() {
*
* \return Zero for no error or nonzero error code.
*/
uint8_t SdSpi::receive(uint8_t* buf, size_t n) {
uint8_t SdSpiAltDriver::receive(uint8_t* buf, size_t n) {
// Works without 32-bit alignment of buf.
SPI.transferBytes(0, buf, n);
return 0;
@@ -82,7 +70,7 @@ uint8_t SdSpi::receive(uint8_t* buf, size_t n) {
*
* \param[in] b Byte to send
*/
void SdSpi::send(uint8_t b) {
void SdSpiAltDriver::send(uint8_t b) {
SPI.transfer(b);
}
//------------------------------------------------------------------------------
@@ -91,7 +79,7 @@ void SdSpi::send(uint8_t b) {
* \param[in] buf Buffer for data to be sent.
* \param[in] n Number of bytes to send.
*/
void SdSpi::send(const uint8_t* buf , size_t n) {
void SdSpiAltDriver::send(const uint8_t* buf , size_t n) {
// Adjust to 32-bit alignment.
while ((reinterpret_cast<uintptr_t>(buf) & 0X3) && n) {
SPI.transfer(*buf++);

SdFat/src/SdSpiCard/SdSpiSAM3X.cpp → SdFat/src/AltSpiDrivers/SdSpiSAM3X.cpp Vedi File

@@ -1,7 +1,7 @@
/* Arduino SdSpi Library
/* Arduino SdSpiAltDriver Library
* Copyright (C) 2013 by William Greiman
*
* This file is part of the Arduino SdSpi Library
* This file is part of the Arduino SdSpiAltDriver Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -14,10 +14,10 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino SdSpi Library. If not, see
* along with the Arduino SdSpiAltDriver Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include "SdSpi.h"
#include "SdSpiDriver.h"
#if defined(__SAM3X8E__) || defined(__SAM3X8H__)
/** Use SAM3X DMAC if nonzero */
#define USE_SAM3X_DMAC 1
@@ -57,25 +57,11 @@ static bool dmac_channel_transfer_done(uint32_t ul_num) {
return (DMAC->DMAC_CHSR & (DMAC_CHSR_ENA0 << ul_num)) ? false : true;
}
//------------------------------------------------------------------------------
void SdSpi::begin(uint8_t chipSelectPin) {
pinMode(chipSelectPin, OUTPUT);
digitalWrite(chipSelectPin, HIGH);
PIO_Configure(
g_APinDescription[PIN_SPI_MOSI].pPort,
g_APinDescription[PIN_SPI_MOSI].ulPinType,
g_APinDescription[PIN_SPI_MOSI].ulPin,
g_APinDescription[PIN_SPI_MOSI].ulPinConfiguration);
PIO_Configure(
g_APinDescription[PIN_SPI_MISO].pPort,
g_APinDescription[PIN_SPI_MISO].ulPinType,
g_APinDescription[PIN_SPI_MISO].ulPin,
g_APinDescription[PIN_SPI_MISO].ulPinConfiguration);
PIO_Configure(
g_APinDescription[PIN_SPI_SCK].pPort,
g_APinDescription[PIN_SPI_SCK].ulPinType,
g_APinDescription[PIN_SPI_SCK].ulPin,
g_APinDescription[PIN_SPI_SCK].ulPinConfiguration);
pmc_enable_periph_clk(ID_SPI0);
void SdSpiAltDriver::begin(uint8_t csPin) {
m_csPin = csPin;
pinMode(m_csPin, OUTPUT);
digitalWrite(m_csPin, HIGH);
SPI.begin();
#if USE_SAM3X_DMAC
pmc_enable_periph_clk(ID_DMAC);
dmac_disable();
@@ -134,28 +120,26 @@ static void spiDmaTX(const uint8_t* src, uint16_t count) {
}
//------------------------------------------------------------------------------
// initialize SPI controller
void SdSpi::beginTransaction(uint8_t sckDivisor) {
#if ENABLE_SPI_TRANSACTIONS
SPI.beginTransaction(SPISettings());
#endif // ENABLE_SPI_TRANSACTIONS
uint8_t scbr = sckDivisor;
void SdSpiAltDriver::activate() {
SPI.beginTransaction(m_spiSettings);

Spi* pSpi = SPI0;
// disable SPI
// Save the divisor
uint32_t scbr = pSpi->SPI_CSR[SPI_CHIP_SEL] & 0XFF00;
// Disable SPI
pSpi->SPI_CR = SPI_CR_SPIDIS;
// reset SPI
pSpi->SPI_CR = SPI_CR_SWRST;
// no mode fault detection, set master mode
pSpi->SPI_MR = SPI_PCS(SPI_CHIP_SEL) | SPI_MR_MODFDIS | SPI_MR_MSTR;
// mode 0, 8-bit,
pSpi->SPI_CSR[SPI_CHIP_SEL] = SPI_CSR_SCBR(scbr) | SPI_CSR_NCPHA;
pSpi->SPI_CSR[SPI_CHIP_SEL] = scbr | SPI_CSR_CSAAT | SPI_CSR_NCPHA;
// enable SPI
pSpi->SPI_CR |= SPI_CR_SPIEN;
}
//------------------------------------------------------------------------------
void SdSpi::endTransaction() {
#if ENABLE_SPI_TRANSACTIONS
void SdSpiAltDriver::deactivate() {
SPI.endTransaction();
#endif // ENABLE_SPI_TRANSACTIONS
}
//------------------------------------------------------------------------------
static inline uint8_t spiTransfer(uint8_t b) {
@@ -168,12 +152,12 @@ static inline uint8_t spiTransfer(uint8_t b) {
}
//------------------------------------------------------------------------------
/** SPI receive a byte */
uint8_t SdSpi::receive() {
uint8_t SdSpiAltDriver::receive() {
return spiTransfer(0XFF);
}
//------------------------------------------------------------------------------
/** SPI receive multiple bytes */
uint8_t SdSpi::receive(uint8_t* buf, size_t n) {
uint8_t SdSpiAltDriver::receive(uint8_t* buf, size_t n) {
Spi* pSpi = SPI0;
int rtn = 0;
#if USE_SAM3X_DMAC
@@ -206,11 +190,11 @@ uint8_t SdSpi::receive(uint8_t* buf, size_t n) {
}
//------------------------------------------------------------------------------
/** SPI send a byte */
void SdSpi::send(uint8_t b) {
void SdSpiAltDriver::send(uint8_t b) {
spiTransfer(b);
}
//------------------------------------------------------------------------------
void SdSpi::send(const uint8_t* buf , size_t n) {
void SdSpiAltDriver::send(const uint8_t* buf , size_t n) {
Spi* pSpi = SPI0;
#if USE_SAM3X_DMAC
spiDmaTX(buf, n);

SdFat/src/SdSpiCard/SdSpiSTM32F1.cpp → SdFat/src/AltSpiDrivers/SdSpiSTM32F1.cpp Vedi File

@@ -1,7 +1,7 @@
/* Arduino SdSpi Library
/* Arduino SdSpiAltDriver Library
* Copyright (C) 2013 by William Greiman
*
* This file is part of the Arduino SdSpi Library
* This file is part of the Arduino SdSpiAltDriver Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -14,72 +14,64 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino SdSpi Library. If not, see
* along with the Arduino SdSpiAltDriver Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#if defined(__STM32F1__)
#include "SdSpi.h"
#include "SdSpiDriver.h"
#define USE_STM32F1_DMAC 1
//------------------------------------------------------------------------------
/** Initialize the SPI bus.
static SPIClass m_SPI1(1);
#if BOARD_NR_SPI > 1
static SPIClass m_SPI2(2);
#endif // BOARD_NR_SPI > 1
#if BOARD_NR_SPI > 2
static SPIClass m_SPI2(3);
#endif // BOARD_NR_SPI > 2
//
static SPIClass* pSpi[] =
#if BOARD_NR_SPI == 1
{&m_SPI1};
#elif BOARD_NR_SPI == 2
{&m_SPI1, &m_SPI2};
#elif BOARD_NR_SPI == 3
{&m_SPI1, &m_SPI2, &m_SPI3};
#else // BOARD_NR_SPI
#error "BOARD_NR_SPI too large"
#endif // BOARD_NR_SPI
//------------------------------------------------------------------------------
/** Set SPI options for access to SD/SDHC cards.
*
* \param[in] chipSelectPin SD card chip select pin.
* \param[in] divisor SCK clock divider relative to the APB1 or APB2 clock.
*/
void SdSpi::begin(uint8_t chipSelectPin) {
pinMode(chipSelectPin, OUTPUT);
digitalWrite(chipSelectPin, HIGH);
SPI.begin();
void SdSpiAltDriver::activate() {
pSpi[m_spiPort]->beginTransaction(m_spiSettings);
}
//------------------------------------------------------------------------------
/** Set SPI options for access to SD/SDHC cards.
/** Initialize the SPI bus.
*
* \param[in] divisor SCK clock divider relative to the APB1 or APB2 clock.
* \param[in] chipSelectPin SD card chip select pin.
*/
void SdSpi::beginTransaction(uint8_t divisor) {
#if ENABLE_SPI_TRANSACTIONS
// Correct divisor will be set below.
SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
#endif // ENABLE_SPI_TRANSACTIONS
uint32_t br; // Baud rate control field in SPI_CR1.
if (divisor <= 2) {
br = SPI_CLOCK_DIV2;
} else if (divisor <= 4) {
br = SPI_CLOCK_DIV4;
} else if (divisor <= 8) {
br = SPI_CLOCK_DIV8;
} else if (divisor <= 16) {
br = SPI_CLOCK_DIV16;
} else if (divisor <= 32) {
br = SPI_CLOCK_DIV32;
} else if (divisor <= 64) {
br = SPI_CLOCK_DIV64;
} else if (divisor <= 128) {
br = SPI_CLOCK_DIV128;
} else {
br = SPI_CLOCK_DIV256;
}
SPI.setClockDivider(br);
#if !ENABLE_SPI_TRANSACTIONS
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
#endif // !ENABLE_SPI_TRANSACTIONS
void SdSpiAltDriver::begin(uint8_t csPin) {
m_csPin = csPin;
pinMode(m_csPin, OUTPUT);
digitalWrite(m_csPin, HIGH);
pSpi[m_spiPort]->begin();
}
//------------------------------------------------------------------------------
/**
* End SPI transaction.
*/
void SdSpi::endTransaction() {
#if ENABLE_SPI_TRANSACTIONS
SPI.endTransaction();
#endif // ENABLE_SPI_TRANSACTIONS
void SdSpiAltDriver::deactivate() {
pSpi[m_spiPort]->endTransaction();
}
//------------------------------------------------------------------------------
/** Receive a byte.
*
* \return The byte.
*/
uint8_t SdSpi::receive() {
return SPI.transfer(0XFF);
uint8_t SdSpiAltDriver::receive() {
return pSpi[m_spiPort]->transfer(0XFF);
}
//------------------------------------------------------------------------------
/** Receive multiple bytes.
@@ -89,14 +81,14 @@ uint8_t SdSpi::receive() {
*
* \return Zero for no error or nonzero error code.
*/
uint8_t SdSpi::receive(uint8_t* buf, size_t n) {
uint8_t SdSpiAltDriver::receive(uint8_t* buf, size_t n) {
int rtn = 0;
#if USE_STM32F1_DMAC
rtn = SPI.dmaTransfer(0, const_cast<uint8*>(buf), n);
rtn = pSpi[m_spiPort]->dmaTransfer(0, const_cast<uint8*>(buf), n);
#else // USE_STM32F1_DMAC
// SPI.read(buf, n);
// pSpi[m_spiPort]->read(buf, n); fails ?? use byte transfer
for (size_t i = 0; i < n; i++) {
buf[i] = SPI.transfer(0XFF);
buf[i] = pSpi[m_spiPort]->transfer(0XFF);
}
#endif // USE_STM32F1_DMAC
return rtn;
@@ -106,8 +98,8 @@ uint8_t SdSpi::receive(uint8_t* buf, size_t n) {
*
* \param[in] b Byte to send
*/
void SdSpi::send(uint8_t b) {
SPI.transfer(b);
void SdSpiAltDriver::send(uint8_t b) {
pSpi[m_spiPort]->transfer(b);
}
//------------------------------------------------------------------------------
/** Send multiple bytes.
@@ -115,11 +107,15 @@ void SdSpi::send(uint8_t b) {
* \param[in] buf Buffer for data to be sent.
* \param[in] n Number of bytes to send.
*/
void SdSpi::send(const uint8_t* buf , size_t n) {
void SdSpiAltDriver::send(const uint8_t* buf , size_t n) {
#if USE_STM32F1_DMAC
SPI.dmaSend(const_cast<uint8*>(buf), n);
pSpi[m_spiPort]->dmaSend(const_cast<uint8*>(buf), n);
#else // #if USE_STM32F1_DMAC
SPI.write(buf, n);
pSpi[m_spiPort]->write(buf, n);
#endif // USE_STM32F1_DMAC
}
#endif // USE_NATIVE_STM32F1_SPI
//-----------------------------------------------------------------------------
void SdSpiAltDriver::setPort(uint8_t portNumber) {
m_spiPort = portNumber < 1 || portNumber > BOARD_NR_SPI ? 0 : portNumber -1;
}
#endif // defined(__STM32F1__)

SdFat/src/SdSpiCard/SdSpiTeensy3.cpp → SdFat/src/AltSpiDrivers/SdSpiTeensy3.cpp Vedi File

@@ -1,7 +1,7 @@
/* Arduino SdSpi Library
/* Arduino SdSpiAltDriver Library
* Copyright (C) 2013 by William Greiman
*
* This file is part of the Arduino SdSpi Library
* This file is part of the Arduino SdSpiAltDriver Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -14,14 +14,32 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino SdSpi Library. If not, see
* along with the Arduino SdSpiAltDriver Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include "SdSpi.h"
#include "SdSpiDriver.h"
#if defined(__arm__) && defined(CORE_TEENSY)
// SPI definitions
#include "kinetis.h"

//------------------------------------------------------------------------------
void SdSpiAltDriver::activate() {
SPI.beginTransaction(m_spiSettings);
}
//------------------------------------------------------------------------------
void SdSpiAltDriver::begin(uint8_t chipSelectPin) {
m_csPin = chipSelectPin;
pinMode(m_csPin, OUTPUT);
digitalWrite(m_csPin, HIGH);
SPI.begin();
}
//------------------------------------------------------------------------------
void SdSpiAltDriver::deactivate() {
SPI.endTransaction();
}
//==============================================================================
#ifdef KINETISK

// use 16-bit frame if SPI_USE_8BIT_FRAME is zero
#define SPI_USE_8BIT_FRAME 0
// Limit initial fifo to three entries to avoid fifo overrun
@@ -37,68 +55,8 @@
#define SPI_PUSHR_CTAS(n) (((n) & 7) << 28)
#endif // SPI_PUSHR_CTAS
//------------------------------------------------------------------------------
/**
* initialize SPI pins
*/
void SdSpi::begin(uint8_t chipSelectPin) {
pinMode(chipSelectPin, OUTPUT);
digitalWrite(chipSelectPin, HIGH);
SIM_SCGC6 |= SIM_SCGC6_SPI0;
}
//------------------------------------------------------------------------------
/**
* Initialize hardware SPI
*
*/
void SdSpi::beginTransaction(uint8_t sckDivisor) {
uint32_t ctar, ctar0, ctar1;
#if ENABLE_SPI_TRANSACTIONS
SPI.beginTransaction(SPISettings());
#endif // #if ENABLE_SPI_TRANSACTIONS
if (sckDivisor <= 2) {
// 1/2 speed
ctar = SPI_CTAR_DBR | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0);
} else if (sckDivisor <= 4) {
// 1/4 speed
ctar = SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0);
} else if (sckDivisor <= 8) {
// 1/8 speed
ctar = SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1);
} else if (sckDivisor <= 12) {
// 1/12 speed
ctar = SPI_CTAR_BR(2) | SPI_CTAR_CSSCK(2);
} else if (sckDivisor <= 16) {
// 1/16 speed
ctar = SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(3);
} else if (sckDivisor <= 32) {
// 1/32 speed
ctar = SPI_CTAR_PBR(1) | SPI_CTAR_BR(4) | SPI_CTAR_CSSCK(4);
} else if (sckDivisor <= 64) {
// 1/64 speed
ctar = SPI_CTAR_PBR(1) | SPI_CTAR_BR(5) | SPI_CTAR_CSSCK(5);
} else {
// 1/128 speed
ctar = SPI_CTAR_PBR(1) | SPI_CTAR_BR(6) | SPI_CTAR_CSSCK(6);
}
// CTAR0 - 8 bit transfer
ctar0 = ctar | SPI_CTAR_FMSZ(7);

// CTAR1 - 16 bit transfer
ctar1 = ctar | SPI_CTAR_FMSZ(15);

if (SPI0_CTAR0 != ctar0 || SPI0_CTAR1 != ctar1) {
SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
SPI0_CTAR0 = ctar0;
SPI0_CTAR1 = ctar1;
}
SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x1F);
CORE_PIN11_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2);
CORE_PIN12_CONFIG = PORT_PCR_MUX(2);
CORE_PIN13_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2);
}
//------------------------------------------------------------------------------
/** SPI receive a byte */
uint8_t SdSpi::receive() {
uint8_t SdSpiAltDriver::receive() {
SPI0_MCR |= SPI_MCR_CLR_RXF;
SPI0_SR = SPI_SR_TCF;
SPI0_PUSHR = 0xFF;
@@ -107,7 +65,7 @@ uint8_t SdSpi::receive() {
}
//------------------------------------------------------------------------------
/** SPI receive multiple bytes */
uint8_t SdSpi::receive(uint8_t* buf, size_t n) {
uint8_t SdSpiAltDriver::receive(uint8_t* buf, size_t n) {
// clear any data in RX FIFO
SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_CLR_RXF | SPI_MCR_PCSIS(0x1F);
#if SPI_USE_8BIT_FRAME
@@ -162,7 +120,7 @@ uint8_t SdSpi::receive(uint8_t* buf, size_t n) {
}
//------------------------------------------------------------------------------
/** SPI send a byte */
void SdSpi::send(uint8_t b) {
void SdSpiAltDriver::send(uint8_t b) {
SPI0_MCR |= SPI_MCR_CLR_RXF;
SPI0_SR = SPI_SR_TCF;
SPI0_PUSHR = b;
@@ -170,7 +128,7 @@ void SdSpi::send(uint8_t b) {
}
//------------------------------------------------------------------------------
/** SPI send multiple bytes */
void SdSpi::send(const uint8_t* buf , size_t n) {
void SdSpiAltDriver::send(const uint8_t* buf , size_t n) {
// clear any data in RX FIFO
SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_CLR_RXF | SPI_MCR_PCSIS(0x1F);
#if SPI_USE_8BIT_FRAME
@@ -228,52 +186,12 @@ void SdSpi::send(const uint8_t* buf , size_t n) {
#else // KINETISK
//==============================================================================
// Use standard SPI library if not KINETISK
/**
* Initialize SPI pins.
*/
void SdSpi::begin(uint8_t chipSelectPin) {
pinMode(chipSelectPin, OUTPUT);
digitalWrite(chipSelectPin, HIGH);
SPI.begin();
}
/** Set SPI options for access to SD/SDHC cards.
*
* \param[in] divisor SCK clock divider relative to the system clock.
*/
void SdSpi::beginTransaction(uint8_t divisor) {
#if ENABLE_SPI_TRANSACTIONS
SPI.beginTransaction(SPISettings());
#else // #if ENABLE_SPI_TRANSACTIONS
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
#endif // #if ENABLE_SPI_TRANSACTIONS
#ifndef SPI_CLOCK_DIV128
SPI.setClockDivider(divisor);
#else // SPI_CLOCK_DIV128
int v;
if (divisor <= 2) {
v = SPI_CLOCK_DIV2;
} else if (divisor <= 4) {
v = SPI_CLOCK_DIV4;
} else if (divisor <= 8) {
v = SPI_CLOCK_DIV8;
} else if (divisor <= 16) {
v = SPI_CLOCK_DIV16;
} else if (divisor <= 32) {
v = SPI_CLOCK_DIV32;
} else if (divisor <= 64) {
v = SPI_CLOCK_DIV64;
} else {
v = SPI_CLOCK_DIV128;
}
SPI.setClockDivider(v);
#endif // SPI_CLOCK_DIV128
}
//------------------------------------------------------------------------------
/** Receive a byte.
*
* \return The byte.
*/
uint8_t SdSpi::receive() {
uint8_t SdSpiAltDriver::receive() {
return SPI.transfer(0XFF);
}
/** Receive multiple bytes.
@@ -283,7 +201,7 @@ uint8_t SdSpi::receive() {
*
* \return Zero for no error or nonzero error code.
*/
uint8_t SdSpi::receive(uint8_t* buf, size_t n) {
uint8_t SdSpiAltDriver::receive(uint8_t* buf, size_t n) {
for (size_t i = 0; i < n; i++) {
buf[i] = SPI.transfer(0XFF);
}
@@ -293,7 +211,7 @@ uint8_t SdSpi::receive(uint8_t* buf, size_t n) {
*
* \param[in] b Byte to send
*/
void SdSpi::send(uint8_t b) {
void SdSpiAltDriver::send(uint8_t b) {
SPI.transfer(b);
}
/** Send multiple bytes.
@@ -301,16 +219,10 @@ void SdSpi::send(uint8_t b) {
* \param[in] buf Buffer for data to be sent.
* \param[in] n Number of bytes to send.
*/
void SdSpi::send(const uint8_t* buf , size_t n) {
void SdSpiAltDriver::send(const uint8_t* buf , size_t n) {
for (size_t i = 0; i < n; i++) {
SPI.transfer(buf[i]);
}
}
#endif // KINETISK
//------------------------------------------------------------------------------
void SdSpi::endTransaction() {
#if ENABLE_SPI_TRANSACTIONS
SPI.endTransaction();
#endif // ENABLE_SPI_TRANSACTIONS
}
#endif // defined(__arm__) && defined(CORE_TEENSY)

SdFat/src/SdSpiCard/SoftSPI.h → SdFat/src/AltSpiDrivers/SoftSPI.h Vedi File


SdFat/src/SdSpiCard/boards/AvrDevelopersGpioPinMap.h → SdFat/src/AltSpiDrivers/boards/AvrDevelopersGpioPinMap.h Vedi File


SdFat/src/SdSpiCard/boards/BobuinoGpioPinMap.h → SdFat/src/AltSpiDrivers/boards/BobuinoGpioPinMap.h Vedi File


SdFat/src/SdSpiCard/boards/GpioPinMap.h → SdFat/src/AltSpiDrivers/boards/GpioPinMap.h Vedi File


SdFat/src/SdSpiCard/boards/LeonardoGpioPinMap.h → SdFat/src/AltSpiDrivers/boards/LeonardoGpioPinMap.h Vedi File


SdFat/src/SdSpiCard/boards/MegaGpioPinMap.h → SdFat/src/AltSpiDrivers/boards/MegaGpioPinMap.h Vedi File


SdFat/src/SdSpiCard/boards/SleepingBeautyGpioPinMap.h → SdFat/src/AltSpiDrivers/boards/SleepingBeautyGpioPinMap.h Vedi File


SdFat/src/SdSpiCard/boards/Standard1284GpioPinMap.h → SdFat/src/AltSpiDrivers/boards/Standard1284GpioPinMap.h Vedi File


SdFat/src/SdSpiCard/boards/Teensy2GpioPinMap.h → SdFat/src/AltSpiDrivers/boards/Teensy2GpioPinMap.h Vedi File


SdFat/src/SdSpiCard/boards/Teensy2ppGpioPinMap.h → SdFat/src/AltSpiDrivers/boards/Teensy2ppGpioPinMap.h Vedi File


SdFat/src/SdSpiCard/boards/UnoGpioPinMap.h → SdFat/src/AltSpiDrivers/boards/UnoGpioPinMap.h Vedi File


+ 89
- 0
SdFat/src/BlockDriver.cpp Vedi File

@@ -0,0 +1,89 @@
/* Arduino SdFat Library
* Copyright (C) 2016 by William Greiman
*
* This file is part of the Arduino SdFat Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino SdFat Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include "BlockDriver.h"
bool SdBlockDriverEX::readBlock(uint32_t block, uint8_t* dst) {
if (m_curState != READ_STATE || block != m_curBlock) {
if (!syncBlocks()) {
return false;
}
if (!SdSpiCard::readStart(block)) {
return false;
}
m_curBlock = block;
m_curState = READ_STATE;
}
if (!SdSpiCard::readData(dst)) {
return false;
}
m_curBlock++;
return true;
}
//-----------------------------------------------------------------------------
bool SdBlockDriverEX::readBlocks(uint32_t block, uint8_t* dst, size_t nb) {
for (size_t i = 0; i < nb; i++) {
if (!readBlock(block + i, dst + i*512UL)) {
return false;
}
}
return true;
}
//-----------------------------------------------------------------------------
bool SdBlockDriverEX::syncBlocks() {
if (m_curState == READ_STATE) {
m_curState = IDLE_STATE;
if (!SdSpiCard::readStop()) {
return false;
}
} else if (m_curState == WRITE_STATE) {
m_curState = IDLE_STATE;
if (!SdSpiCard::writeStop()) {
return false;
}
}
return true;
}
//-----------------------------------------------------------------------------
bool SdBlockDriverEX::writeBlock(uint32_t block, const uint8_t* src) {
if (m_curState != WRITE_STATE || m_curBlock != block) {
if (!syncBlocks()) {
return false;
}
if (!SdSpiCard::writeStart(block)) {
return false;
}
m_curBlock = block;
m_curState = WRITE_STATE;
}
if (!SdSpiCard::writeData(src)) {
return false;
}
m_curBlock++;
return true;
}
//-----------------------------------------------------------------------------
bool SdBlockDriverEX::writeBlocks(uint32_t block,
const uint8_t* src, size_t nb) {
for (size_t i = 0; i < nb; i++) {
if (!writeBlock(block + i, src + i*512UL)) {
return false;
}
}
return true;
}

+ 197
- 0
SdFat/src/BlockDriver.h Vedi File

@@ -0,0 +1,197 @@
/* Arduino SdFat Library
* Copyright (C) 2016 by William Greiman
*
* This file is part of the Arduino SdFat Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino SdFat Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
/**
* \file
* \brief Define block driver.
*/
#ifndef BlockDriver_h
#define BlockDriver_h
#ifdef ARDUINO
#include "SdSpiCard/SdSpiCard.h"
#else // ARDUINO
#include "SdSpiCard.h"
#endif // ARDUINO
#include "FatLib/BaseBlockDriver.h"
//-----------------------------------------------------------------------------
/**
* \class SdBlockDriver
* \brief Standard SD block driver.
*/
#if ENABLE_EXTENDED_TRANSFER_CLASS
class SdBlockDriver : public BaseBlockDriver, public SdSpiCard {
#else // ENABLE_EXTENDED_TRANSFER_CLASS
class SdBlockDriver : public SdSpiCard {
#endif // ENABLE_EXTENDED_TRANSFER_CLASS
public:
/** Initialize the SD card
*
* \param[in] spi SPI driver.
* \param[in] csPin Card chip select pin number.
* \param[in] spiSettings SPI speed, mode, and bit order.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool begin(SdSpiDriver* spi, uint8_t csPin, SPISettings spiSettings) {
spi->begin(csPin);
spi->setSpiSettings(SD_SCK_HZ(250000));
if (!SdSpiCard::begin(spi)) {
return false;
}
spi->setSpiSettings(spiSettings);
return true;
}
/**
* Read a 512 byte block from an SD card.
*
* \param[in] block Logical block to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readBlock(uint32_t block, uint8_t* dst) {
return SdSpiCard::readBlock(block, dst);
}
/** End multi-block transfer and go to idle state.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool syncBlocks() {
return true;
}
/**
* Writes a 512 byte block to an SD card.
*
* \param[in] block Logical block to be written.
* \param[in] src Pointer to the location of the data to be written.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeBlock(uint32_t block, const uint8_t* src) {
return SdSpiCard::writeBlock(block, src);
}
/**
* Read multiple 512 byte blocks from an SD card.
*
* \param[in] block Logical block to be read.
* \param[in] nb Number of blocks to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readBlocks(uint32_t block, uint8_t* dst, size_t nb) {
return SdSpiCard::readBlocks(block, dst, nb);
}
/**
* Write multiple 512 byte blocks to an SD card.
*
* \param[in] block Logical block to be written.
* \param[in] nb Number of blocks to be written.
* \param[in] src Pointer to the location of the data to be written.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeBlocks(uint32_t block, const uint8_t* src, size_t nb) {
return SdSpiCard::writeBlocks(block, src, nb);
}
};
//-----------------------------------------------------------------------------
/**
* \class SdBlockDriverEX
* \brief Extended SD I/O block driver.
*/
class SdBlockDriverEX : public SdSpiCard, public BaseBlockDriver {
public:
/** Initialize the SD card
*
* \param[in] spi SPI driver.
* \param[in] csPin Card chip select pin number.
* \param[in] spiSettings SPI speed, mode, and bit order.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool begin(SdSpiDriver* spi, uint8_t csPin, SPISettings spiSettings) {
m_curState = IDLE_STATE;
spi->begin(csPin);
spi->setSpiSettings(SD_SCK_HZ(250000));
if (!SdSpiCard::begin(spi)) {
return false;
}
spi->setSpiSettings(spiSettings);
return true;
}
/**
* Read a 512 byte block from an SD card.
*
* \param[in] block Logical block to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readBlock(uint32_t block, uint8_t* dst);
/** End multi-block transfer and go to idle state.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool syncBlocks();
/**
* Writes a 512 byte block to an SD card.
*
* \param[in] block Logical block to be written.
* \param[in] src Pointer to the location of the data to be written.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeBlock(uint32_t block, const uint8_t* src);
/**
* Read multiple 512 byte blocks from an SD card.
*
* \param[in] block Logical block to be read.
* \param[in] nb Number of blocks to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readBlocks(uint32_t block, uint8_t* dst, size_t nb);
/**
* Write multiple 512 byte blocks to an SD card.
*
* \param[in] block Logical block to be written.
* \param[in] nb Number of blocks to be written.
* \param[in] src Pointer to the location of the data to be written.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeBlocks(uint32_t block, const uint8_t* src, size_t nb);

private:
static const uint32_t IDLE_STATE = 0;
static const uint32_t READ_STATE = 1;
static const uint32_t WRITE_STATE = 2;
uint32_t m_curBlock;
uint8_t m_curState;
};
//-----------------------------------------------------------------------------
/** typedef for BlockDriver */
#if ENABLE_EXTENDED_TRANSFER_CLASS
typedef BaseBlockDriver BlockDriver;
#else // ENABLE_EXTENDED_TRANSFER_CLASS
typedef SdBlockDriver BlockDriver;
#endif // ENABLE_EXTENDED_TRANSFER_CLASS
#endif // BlockDriver_h

+ 0
- 4
SdFat/src/FatLib/ArduinoFiles.h Vedi File

@@ -114,11 +114,7 @@ class PrintFile : public FatFile, public Print {
* \class File
* \brief Arduino SD.h style File API
*/
#if ARDUINO_FILE_USES_STREAM
class File : public FatFile, public Stream {
#else // ARDUINO_FILE_USES_STREAM
class File : public FatFile, public Print {
#endif // ARDUINO_FILE_USES_STREAM
public:
File() {}
/** Create a file object and open it in the current working directory.

+ 1
- 2
SdFat/src/FatLib/ArduinoStream.h Vedi File

@@ -25,7 +25,6 @@
*/
#include "FatLibConfig.h"
#if ENABLE_ARDUINO_FEATURES
#include "SysCall.h"
#include "bufstream.h"
//==============================================================================
/**
@@ -51,7 +50,7 @@ class ArduinoInStream : public ibufstream {
uint32_t t;
m_line[0] = '\0';
while (!m_hw->available()) {
SysCall::yield();
yield();
}

while (1) {

+ 56
- 0
SdFat/src/FatLib/BaseBlockDriver.h Vedi File

@@ -0,0 +1,56 @@
#ifndef BaseBlockDriver_h
#define BaseBlockDriver_h
#include "FatLibConfig.h"
/**
* \class BaseBlockDriver
* \brief Base block driver.
*/
class BaseBlockDriver {
public:
/**
* Read a 512 byte block from an SD card.
*
* \param[in] block Logical block to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
virtual bool readBlock(uint32_t block, uint8_t* dst) = 0;
/** End multi-block transfer and go to idle state.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
virtual bool syncBlocks() = 0;
/**
* Writes a 512 byte block to an SD card.
*
* \param[in] block Logical block to be written.
* \param[in] src Pointer to the location of the data to be written.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
virtual bool writeBlock(uint32_t block, const uint8_t* src) = 0;
#if USE_MULTI_BLOCK_IO
/**
* Read multiple 512 byte blocks from an SD card.
*
* \param[in] block Logical block to be read.
* \param[in] nb Number of blocks to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
virtual bool readBlocks(uint32_t block, uint8_t* dst, size_t nb) = 0;
/**
* Write multiple 512 byte blocks to an SD card.
*
* \param[in] block Logical block to be written.
* \param[in] nb Number of blocks to be written.
* \param[in] src Pointer to the location of the data to be written.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
virtual bool writeBlocks(uint32_t block, const uint8_t* src, size_t nb) = 0;
#endif // USE_MULTI_BLOCK_IO
};
#endif // BaseBlockDriver_h

+ 19
- 19
SdFat/src/FatLib/FatApiConstants.h Vedi File

@@ -22,46 +22,46 @@
//------------------------------------------------------------------------------
// use the gnu style oflag in open()
/** open() oflag for reading */
uint8_t const O_READ = 0X01;
const uint8_t O_READ = 0X01;
/** open() oflag - same as O_IN */
uint8_t const O_RDONLY = O_READ;
const uint8_t O_RDONLY = O_READ;
/** open() oflag for write */
uint8_t const O_WRITE = 0X02;
const uint8_t O_WRITE = 0X02;
/** open() oflag - same as O_WRITE */
uint8_t const O_WRONLY = O_WRITE;
const uint8_t O_WRONLY = O_WRITE;
/** open() oflag for reading and writing */
uint8_t const O_RDWR = (O_READ | O_WRITE);
const uint8_t O_RDWR = (O_READ | O_WRITE);
/** open() oflag mask for access modes */
uint8_t const O_ACCMODE = (O_READ | O_WRITE);
const uint8_t O_ACCMODE = (O_READ | O_WRITE);
/** The file offset shall be set to the end of the file prior to each write. */
uint8_t const O_APPEND = 0X04;
const uint8_t O_APPEND = 0X04;
/** synchronous writes - call sync() after each write */
uint8_t const O_SYNC = 0X08;
const uint8_t O_SYNC = 0X08;
/** truncate the file to zero length */
uint8_t const O_TRUNC = 0X10;
const uint8_t O_TRUNC = 0X10;
/** set the initial position at the end of the file */
uint8_t const O_AT_END = 0X20;
const uint8_t O_AT_END = 0X20;
/** create the file if nonexistent */
uint8_t const O_CREAT = 0X40;
const uint8_t O_CREAT = 0X40;
/** If O_CREAT and O_EXCL are set, open() shall fail if the file exists */
uint8_t const O_EXCL = 0X80;
const uint8_t O_EXCL = 0X80;

// FatFile class static and const definitions
// flags for ls()
/** ls() flag for list all files including hidden. */
uint8_t const LS_A = 1;
const uint8_t LS_A = 1;
/** ls() flag to print modify. date */
uint8_t const LS_DATE = 2;
const uint8_t LS_DATE = 2;
/** ls() flag to print file size. */
uint8_t const LS_SIZE = 4;
const uint8_t LS_SIZE = 4;
/** ls() flag for recursive list of subdirectories */
uint8_t const LS_R = 8;
const uint8_t LS_R = 8;

// flags for timestamp
/** set the file's last access date */
uint8_t const T_ACCESS = 1;
const uint8_t T_ACCESS = 1;
/** set the file's creation date and time */
uint8_t const T_CREATE = 2;
const uint8_t T_CREATE = 2;
/** Set the file's write date and time */
uint8_t const T_WRITE = 4;
const uint8_t T_WRITE = 4;
#endif // FatApiConstants_h

+ 10
- 10
SdFat/src/FatLib/FatFile.cpp Vedi File

@@ -50,7 +50,7 @@ bool FatFile::addDirCluster() {
DBG_FAIL_MACRO;
goto fail;
}
block = m_vol->clusterStartBlock(m_curCluster);
block = m_vol->clusterFirstBlock(m_curCluster);
pc = m_vol->cacheFetchData(block, FatCache::CACHE_RESERVE_FOR_WRITE);
if (!pc) {
DBG_FAIL_MACRO;
@@ -113,8 +113,8 @@ bool FatFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock) {
DBG_FAIL_MACRO;
goto fail;
}
*bgnBlock = m_vol->clusterStartBlock(m_firstCluster);
*endBlock = m_vol->clusterStartBlock(c)
*bgnBlock = m_vol->clusterFirstBlock(m_firstCluster);
*endBlock = m_vol->clusterFirstBlock(c)
+ m_vol->blocksPerCluster() - 1;
return true;
}
@@ -127,6 +127,7 @@ fail:
bool FatFile::createContiguous(FatFile* dirFile,
const char* path, uint32_t size) {
uint32_t count;

// don't allow zero length file
if (size == 0) {
DBG_FAIL_MACRO;
@@ -149,7 +150,6 @@ bool FatFile::createContiguous(FatFile* dirFile,

// insure sync() will update dir entry
m_flags |= F_FILE_DIR_DIRTY;

return sync();

fail:
@@ -344,7 +344,7 @@ bool FatFile::mkdir(FatFile* parent, fname_t* fname) {
}

// cache block for '.' and '..'
block = m_vol->clusterStartBlock(m_firstCluster);
block = m_vol->clusterFirstBlock(m_firstCluster);
pc = m_vol->cacheFetchData(block, FatCache::CACHE_FOR_WRITE);
if (!pc) {
DBG_FAIL_MACRO;
@@ -612,7 +612,7 @@ bool FatFile::openParent(FatFile* dirFile) {
if (dirFile->m_dirCluster == 0) {
return openRoot(dirFile->m_vol);
}
lbn = dirFile->m_vol->clusterStartBlock(dirFile->m_dirCluster);
lbn = dirFile->m_vol->clusterFirstBlock(dirFile->m_dirCluster);
cb = dirFile->m_vol->cacheFetchData(lbn, FatCache::CACHE_FOR_READ);
if (!cb) {
DBG_FAIL_MACRO;
@@ -748,7 +748,7 @@ int FatFile::read(void* buf, size_t nbyte) {
}
}
}
block = m_vol->clusterStartBlock(m_curCluster) + blockOfCluster;
block = m_vol->clusterFirstBlock(m_curCluster) + blockOfCluster;
}
if (offset != 0 || toRead < 512 || block == m_vol->cacheBlockNumber()) {
// amount to be read from current block
@@ -941,7 +941,7 @@ bool FatFile::rename(FatFile* dirFile, const char* newPath) {
// update dot dot if directory
if (dirCluster) {
// get new dot dot
uint32_t block = m_vol->clusterStartBlock(dirCluster);
uint32_t block = m_vol->clusterFirstBlock(dirCluster);
pc = m_vol->cacheFetchData(block, FatCache::CACHE_FOR_READ);
if (!pc) {
DBG_FAIL_MACRO;
@@ -955,7 +955,7 @@ bool FatFile::rename(FatFile* dirFile, const char* newPath) {
goto fail;
}
// store new dot dot
block = m_vol->clusterStartBlock(m_firstCluster);
block = m_vol->clusterFirstBlock(m_firstCluster);
pc = m_vol->cacheFetchData(block, FatCache::CACHE_FOR_WRITE);
if (!pc) {
DBG_FAIL_MACRO;
@@ -1404,7 +1404,7 @@ int FatFile::write(const void* buf, size_t nbyte) {
}
}
// block for data write
uint32_t block = m_vol->clusterStartBlock(m_curCluster) + blockOfCluster;
uint32_t block = m_vol->clusterFirstBlock(m_curCluster) + blockOfCluster;

if (blockOffset != 0 || nToWrite < 512) {
// partial block - must use cache

+ 21
- 3
SdFat/src/FatLib/FatFile.h Vedi File

@@ -217,7 +217,7 @@ class FatFile {
/** Create and open a new contiguous file of a specified size.
*
* \param[in] dirFile The directory where the file will be created.
* \param[in] path A path with a valid DOS 8.3 file name.
* \param[in] path A path with a validfile name.
* \param[in] size The desired file size.
*
* \return The value true is returned for success and
@@ -225,6 +225,17 @@ class FatFile {
*/
bool createContiguous(FatFile* dirFile,
const char* path, uint32_t size);
/** Create and open a new contiguous file of a specified size.
*
* \param[in] path A path with a validfile name.
* \param[in] size The desired file size.
*
* \return The value true is returned for success and
* the value false, is returned for failure.
*/
bool createContiguous(const char* path, uint32_t size) {
return createContiguous(m_cwd, path, size);
}
/** \return The current cluster number for a file or directory. */
uint32_t curCluster() const {
return m_curCluster;
@@ -801,6 +812,13 @@ class FatFile {
m_cwd = dir;
return true;
}
/** \return first block of file or zero for empty file. */
uint32_t firstBlock() {
if (m_firstCluster) {
return m_vol->clusterFirstBlock(m_firstCluster);
}
return 0;
}
/** The sync() call causes all modified data and directory fields
* to be written to the storage device.
*
@@ -956,9 +974,9 @@ class FatFile {

// bits defined in m_flags
// should be 0X0F
static uint8_t const F_OFLAG = (O_ACCMODE | O_APPEND | O_SYNC);
static const uint8_t F_OFLAG = (O_ACCMODE | O_APPEND | O_SYNC);
// sync of directory entry required
static uint8_t const F_FILE_DIR_DIRTY = 0X80;
static const uint8_t F_FILE_DIR_DIRTY = 0X80;

// global pointer to cwd dir
static FatFile* m_cwd;

+ 0
- 1
SdFat/src/FatLib/FatFilePrint.cpp Vedi File

@@ -234,7 +234,6 @@ bool FatFile::printModifyDateTime(print_t* pr) {
fail:
return false;
}

//------------------------------------------------------------------------------
size_t FatFile::printFileSize(print_t* pr) {
char buf[11];

+ 6
- 4
SdFat/src/FatLib/FatFileSystem.h Vedi File

@@ -21,6 +21,7 @@
#define FatFileSystem_h
#include "FatVolume.h"
#include "FatFile.h"
#include "ArduinoStream.h"
#include "ArduinoFiles.h"
/**
* \file
@@ -35,11 +36,13 @@ class FatFileSystem : public FatVolume {
public:
/**
* Initialize an FatFileSystem object.
* \param[in] blockDev Device block driver.
* \param[in] part partition to initialize.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool begin(uint8_t part = 0) {
bool begin(BlockDriver* blockDev, uint8_t part = 0) {
m_blockDev = blockDev;
vwd()->close();
return (part ? init(part) : init(1) || init(0))
&& vwd()->openRoot(this) && FatFile::setCwd(vwd());
@@ -91,7 +94,7 @@ class FatFileSystem : public FatVolume {
* \return a File object.
*/
File open(const String &path, uint8_t mode = FILE_READ) {
return open(path.c_str(), mode );
return open(path.c_str(), mode );
}
#endif // ENABLE_ARDUINO_FEATURES
/** Change a volume's working directory to root
@@ -142,7 +145,6 @@ class FatFileSystem : public FatVolume {
if (!dir.isDir()) {
goto fail;
}
// *m_vwd = dir;
m_vwd = dir;
if (set_cwd) {
FatFile::setCwd(vwd());
@@ -189,7 +191,7 @@ fail:
*
* LS_R - Recursive list of subdirectories.
*/
void ls(print_t* pr, uint8_t flags) {
void ls(print_t* pr, uint8_t flags = 0) {
vwd()->ls(pr, flags);
}
//----------------------------------------------------------------------------

+ 11
- 13
SdFat/src/FatLib/FatLibConfig.h Vedi File

@@ -53,19 +53,6 @@
#define USE_LONG_FILE_NAMES 1
#endif // USE_LONG_FILE_NAMES
//------------------------------------------------------------------------------
/**
* Set ARDUINO_FILE_USES_STREAM nonzero to use Stream as the base class
* for the Arduino File class. If ARDUINO_FILE_USES_STREAM is zero, Print
* will be used as the base class for the Arduino File class.
*
* You can save some flash if you do not use Stream input functions such as
* find(), findUntil(), readBytesUntil(), readString(), readStringUntil(),
* parseInt(), and parsefloat().
*/
#ifndef ARDUINO_FILE_USES_STREAM
#define ARDUINO_FILE_USES_STREAM 1
#endif // ARDUINO_FILE_USES_STREAM
//------------------------------------------------------------------------------
/**
* Set USE_SEPARATE_FAT_CACHE non-zero to use a second 512 byte cache
* for FAT table entries. Improves performance for large writes that
@@ -92,6 +79,15 @@
#endif // RAMEND
#endif // USE_MULTI_BLOCK_IO
//------------------------------------------------------------------------------
/**
* Set MAINTAIN_FREE_CLUSTER_COUNT nonzero to keep the count of free clusters
* updated. This will increase the speed of the freeClusterCount() call
* after the first call. Extra flash will be required.
*/
#ifndef MAINTAIN_FREE_CLUSTER_COUNT
#define MAINTAIN_FREE_CLUSTER_COUNT 0
#endif // MAINTAIN_FREE_CLUSTER_COUNT
//------------------------------------------------------------------------------
/**
* Set DESTRUCTOR_CLOSES_FILE non-zero to close a file in its destructor.
*
@@ -133,7 +129,9 @@
/**
* Enable Extra features for Arduino.
*/
// #define ENABLE_ARDUINO_FEATURES 0 ////////////////////////FIX THIS /////////////////
#ifndef ENABLE_ARDUINO_FEATURES
#include <Arduino.h>
#if defined(ARDUINO) || defined(PLATFORM_ID) || defined(DOXYGEN)
#define ENABLE_ARDUINO_FEATURES 1
#else // #if defined(ARDUINO) || defined(DOXYGEN)

+ 27
- 27
SdFat/src/FatLib/FatStructs.h Vedi File

@@ -29,11 +29,11 @@
*/
//------------------------------------------------------------------------------
/** Value for byte 510 of boot block or MBR */
uint8_t const BOOTSIG0 = 0X55;
const uint8_t BOOTSIG0 = 0X55;
/** Value for byte 511 of boot block or MBR */
uint8_t const BOOTSIG1 = 0XAA;
const uint8_t BOOTSIG1 = 0XAA;
/** Value for bootSignature field int FAT/FAT32 boot sector */
uint8_t const EXTENDED_BOOT_SIG = 0X29;
const uint8_t EXTENDED_BOOT_SIG = 0X29;
//------------------------------------------------------------------------------
/**
* \struct partitionTable
@@ -525,9 +525,9 @@ struct fat32_boot {
typedef struct fat32_boot fat32_boot_t;
//------------------------------------------------------------------------------
/** Lead signature for a FSINFO sector */
uint32_t const FSINFO_LEAD_SIG = 0x41615252;
const uint32_t FSINFO_LEAD_SIG = 0x41615252;
/** Struct signature for a FSINFO sector */
uint32_t const FSINFO_STRUCT_SIG = 0x61417272;
const uint32_t FSINFO_STRUCT_SIG = 0x61417272;
/**
* \struct fat32_fsinfo
*
@@ -566,19 +566,19 @@ typedef struct fat32_fsinfo fat32_fsinfo_t;
//------------------------------------------------------------------------------
// End Of Chain values for FAT entries
/** FAT12 end of chain value used by Microsoft. */
uint16_t const FAT12EOC = 0XFFF;
const uint16_t FAT12EOC = 0XFFF;
/** Minimum value for FAT12 EOC. Use to test for EOC. */
uint16_t const FAT12EOC_MIN = 0XFF8;
const uint16_t FAT12EOC_MIN = 0XFF8;
/** FAT16 end of chain value used by Microsoft. */
uint16_t const FAT16EOC = 0XFFFF;
const uint16_t FAT16EOC = 0XFFFF;
/** Minimum value for FAT16 EOC. Use to test for EOC. */
uint16_t const FAT16EOC_MIN = 0XFFF8;
const uint16_t FAT16EOC_MIN = 0XFFF8;
/** FAT32 end of chain value used by Microsoft. */
uint32_t const FAT32EOC = 0X0FFFFFFF;
const uint32_t FAT32EOC = 0X0FFFFFFF;
/** Minimum value for FAT32 EOC. Use to test for EOC. */
uint32_t const FAT32EOC_MIN = 0X0FFFFFF8;
const uint32_t FAT32EOC_MIN = 0X0FFFFFF8;
/** Mask a for FAT32 entry. Entries are 28 bits. */
uint32_t const FAT32MASK = 0X0FFFFFFF;
const uint32_t FAT32MASK = 0X0FFFFFFF;
//------------------------------------------------------------------------------
/**
* \struct directoryEntry
@@ -665,33 +665,33 @@ typedef struct directoryEntry dir_t;
// Definitions for directory entries
//
/** escape for name[0] = 0XE5 */
uint8_t const DIR_NAME_0XE5 = 0X05;
const uint8_t DIR_NAME_0XE5 = 0X05;
/** name[0] value for entry that is free after being "deleted" */
uint8_t const DIR_NAME_DELETED = 0XE5;
const uint8_t DIR_NAME_DELETED = 0XE5;
/** name[0] value for entry that is free and no allocated entries follow */
uint8_t const DIR_NAME_FREE = 0X00;
const uint8_t DIR_NAME_FREE = 0X00;
/** file is read-only */
uint8_t const DIR_ATT_READ_ONLY = 0X01;
const uint8_t DIR_ATT_READ_ONLY = 0X01;
/** File should e hidden in directory listings */
uint8_t const DIR_ATT_HIDDEN = 0X02;
const uint8_t DIR_ATT_HIDDEN = 0X02;
/** Entry is for a system file */
uint8_t const DIR_ATT_SYSTEM = 0X04;
const uint8_t DIR_ATT_SYSTEM = 0X04;
/** Directory entry contains the volume label */
uint8_t const DIR_ATT_VOLUME_ID = 0X08;
const uint8_t DIR_ATT_VOLUME_ID = 0X08;
/** Entry is for a directory */
uint8_t const DIR_ATT_DIRECTORY = 0X10;
const uint8_t DIR_ATT_DIRECTORY = 0X10;
/** Old DOS archive bit for backup support */
uint8_t const DIR_ATT_ARCHIVE = 0X20;
const uint8_t DIR_ATT_ARCHIVE = 0X20;
/** Test value for long name entry. Test is
(d->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME. */
uint8_t const DIR_ATT_LONG_NAME = 0X0F;
const uint8_t DIR_ATT_LONG_NAME = 0X0F;
/** Test mask for long name entry */
uint8_t const DIR_ATT_LONG_NAME_MASK = 0X3F;
const uint8_t DIR_ATT_LONG_NAME_MASK = 0X3F;
/** defined attribute bits */
uint8_t const DIR_ATT_DEFINED_BITS = 0X3F;
const uint8_t DIR_ATT_DEFINED_BITS = 0X3F;

/** Mask for file/subdirectory tests */
uint8_t const DIR_ATT_FILE_TYPE_MASK = (DIR_ATT_VOLUME_ID | DIR_ATT_DIRECTORY);
const uint8_t DIR_ATT_FILE_TYPE_MASK = (DIR_ATT_VOLUME_ID | DIR_ATT_DIRECTORY);

/** Filename base-name is all lower case */
const uint8_t DIR_NT_LC_BASE = 0X08;
@@ -818,9 +818,9 @@ static inline uint8_t FAT_SECOND(uint16_t fatTime) {
return 2*(fatTime & 0X1F);
}
/** Default date for file timestamps is 1 Jan 2000 */
uint16_t const FAT_DEFAULT_DATE = ((2000 - 1980) << 9) | (1 << 5) | 1;
const uint16_t FAT_DEFAULT_DATE = ((2000 - 1980) << 9) | (1 << 5) | 1;
/** Default time for file timestamp is 1 am */
uint16_t const FAT_DEFAULT_TIME = (1 << 11);
const uint16_t FAT_DEFAULT_TIME = (1 << 11);
//------------------------------------------------------------------------------
/** Dimension of first name field in long directory entry */
const uint8_t LDIR_NAME1_DIM = 5;

+ 19
- 24
SdFat/src/FatLib/FatVolume.cpp Vedi File

@@ -39,6 +39,7 @@ cache_t* FatCache::read(uint32_t lbn, uint8_t option) {
return &m_block;

fail:

return 0;
}
//------------------------------------------------------------------------------
@@ -183,7 +184,7 @@ fail:
return false;
}
//------------------------------------------------------------------------------
uint32_t FatVolume::clusterStartBlock(uint32_t cluster) const {
uint32_t FatVolume::clusterFirstBlock(uint32_t cluster) const {
return m_dataStartBlock + ((cluster - 2) << m_clusterSizeShift);
}
//------------------------------------------------------------------------------
@@ -196,7 +197,7 @@ int8_t FatVolume::fatGet(uint32_t cluster, uint32_t* value) {
// error if reserved cluster of beyond FAT
DBG_HALT_IF(cluster < 2 || cluster > m_lastCluster);

if (m_fatType == 32) {
if (fatType() == 32) {
lba = m_fatStartBlock + (cluster >> 7);
pc = cacheFetchFat(lba, FatCache::CACHE_FOR_READ);
if (!pc) {
@@ -206,8 +207,7 @@ int8_t FatVolume::fatGet(uint32_t cluster, uint32_t* value) {
next = pc->fat32[cluster & 0X7F] & FAT32MASK;
goto done;
}

if (m_fatType == 16) {
if (fatType() == 16) {
lba = m_fatStartBlock + ((cluster >> 8) & 0XFF);
pc = cacheFetchFat(lba, FatCache::CACHE_FOR_READ);
if (!pc) {
@@ -217,7 +217,7 @@ int8_t FatVolume::fatGet(uint32_t cluster, uint32_t* value) {
next = pc->fat16[cluster & 0XFF];
goto done;
}
if (FAT12_SUPPORT && m_fatType == 12) {
if (FAT12_SUPPORT && fatType() == 12) {
uint16_t index = cluster;
index += index >> 1;
lba = m_fatStartBlock + (index >> 9);
@@ -263,7 +263,7 @@ bool FatVolume::fatPut(uint32_t cluster, uint32_t value) {
// error if reserved cluster of beyond FAT
DBG_HALT_IF(cluster < 2 || cluster > m_lastCluster);

if (m_fatType == 32) {
if (fatType() == 32) {
lba = m_fatStartBlock + (cluster >> 7);
pc = cacheFetchFat(lba, FatCache::CACHE_FOR_WRITE);
if (!pc) {
@@ -274,7 +274,7 @@ bool FatVolume::fatPut(uint32_t cluster, uint32_t value) {
return true;
}

if (m_fatType == 16) {
if (fatType() == 16) {
lba = m_fatStartBlock + ((cluster >> 8) & 0XFF);
pc = cacheFetchFat(lba, FatCache::CACHE_FOR_WRITE);
if (!pc) {
@@ -285,7 +285,7 @@ bool FatVolume::fatPut(uint32_t cluster, uint32_t value) {
return true;
}

if (FAT12_SUPPORT && m_fatType == 12) {
if (FAT12_SUPPORT && fatType() == 12) {
uint16_t index = cluster;
index += index >> 1;
lba = m_fatStartBlock + (index >> 9);
@@ -367,7 +367,7 @@ int32_t FatVolume::freeClusterCount() {
uint32_t todo = m_lastCluster + 1;
uint16_t n;

if (FAT12_SUPPORT && m_fatType == 12) {
if (FAT12_SUPPORT && fatType() == 12) {
for (unsigned i = 2; i < todo; i++) {
uint32_t c;
int8_t fg = fatGet(i, &c);
@@ -379,7 +379,7 @@ int32_t FatVolume::freeClusterCount() {
free++;
}
}
} else if (m_fatType == 16 || m_fatType == 32) {
} else if (fatType() == 16 || fatType() == 32) {
lba = m_fatStartBlock;
while (todo) {
cache_t* pc = cacheFetchFat(lba++, FatCache::CACHE_FOR_READ);
@@ -387,11 +387,11 @@ int32_t FatVolume::freeClusterCount() {
DBG_FAIL_MACRO;
goto fail;
}
n = m_fatType == 16 ? 256 : 128;
n = fatType() == 16 ? 256 : 128;
if (todo < n) {
n = todo;
}
if (m_fatType == 16) {
if (fatType() == 16) {
for (uint16_t i = 0; i < n; i++) {
if (pc->fat16[i] == 0) {
free++;
@@ -427,12 +427,10 @@ bool FatVolume::init(uint8_t part) {
uint8_t tmp;
m_fatType = 0;
m_allocSearchStart = 1;

m_cache.init(this);
#if USE_SEPARATE_FAT_CACHE
m_fatCache.init(this);
#endif // USE_SEPARATE_FAT_CACHE

// if part == 0 assume super floppy with FAT boot sector in block zero
// if part > 0 assume mbr volume with partition table
if (part) {
@@ -468,7 +466,6 @@ bool FatVolume::init(uint8_t part) {
}
m_blocksPerCluster = fbs->sectorsPerCluster;
m_clusterBlockMask = m_blocksPerCluster - 1;

// determine shift that is same as multiply by m_blocksPerCluster
m_clusterSizeShift = 0;
for (tmp = 1; m_blocksPerCluster != tmp; tmp <<= 1, m_clusterSizeShift++) {
@@ -477,7 +474,6 @@ bool FatVolume::init(uint8_t part) {
goto fail;
}
}

m_blocksPerFat = fbs->sectorsPerFat16 ?
fbs->sectorsPerFat16 : fbs->sectorsPerFat32;

@@ -503,7 +499,6 @@ bool FatVolume::init(uint8_t part) {

// Indicate unknown number of free clusters.
setFreeClusterCount(-1);

// FAT type is determined by cluster count
if (clusterCount < 4085) {
m_fatType = 12;
@@ -527,7 +522,7 @@ bool FatVolume::wipe(print_t* pr) {
cache_t* cache;
uint16_t count;
uint32_t lbn;
if (!m_fatType) {
if (!fatType()) {
DBG_FAIL_MACRO;
goto fail;
}
@@ -538,8 +533,8 @@ bool FatVolume::wipe(print_t* pr) {
}
memset(cache->data, 0, 512);
// Zero root.
if (m_fatType == 32) {
lbn = clusterStartBlock(m_rootDirStart);
if (fatType() == 32) {
lbn = clusterFirstBlock(m_rootDirStart);
count = m_blocksPerCluster;
} else {
lbn = m_rootDirStart;
@@ -564,13 +559,13 @@ bool FatVolume::wipe(print_t* pr) {
}
}
// Reserve first two clusters.
if (m_fatType == 32) {
if (fatType() == 32) {
cache->fat32[0] = 0x0FFFFFF8;
cache->fat32[1] = 0x0FFFFFFF;
} else if (m_fatType == 16) {
} else if (fatType() == 16) {
cache->fat16[0] = 0XFFF8;
cache->fat16[1] = 0XFFFF;
} else if (FAT12_SUPPORT && m_fatType == 12) {
} else if (FAT12_SUPPORT && fatType() == 12) {
cache->fat32[0] = 0XFFFFF8;
} else {
DBG_FAIL_MACRO;
@@ -581,7 +576,7 @@ bool FatVolume::wipe(print_t* pr) {
DBG_FAIL_MACRO;
goto fail;
}
if (m_fatType == 32) {
if (fatType() == 32) {
// Reserve root cluster.
if (!fatPutEOC(m_rootDirStart) || !cacheSync()) {
DBG_FAIL_MACRO;

+ 29
- 17
SdFat/src/FatLib/FatVolume.h Vedi File

@@ -24,18 +24,18 @@
* \brief FatVolume class
*/
#include <stddef.h>
#include "SysCall.h"
#include "FatLibConfig.h"
#include "FatStructs.h"
#include "BlockDriver.h"
//------------------------------------------------------------------------------
#ifndef DOXYGEN_SHOULD_SKIP_THIS
/** Macro for debug. */
#define DEBUG_MODE 0
#if DEBUG_MODE
#define DBG_FAIL_MACRO Serial.print(F(__FILE__)); Serial.println(__LINE__)
#define DBG_FAIL_MACRO Serial.print(F(__FILE__)); Serial.println(__LINE__);
#define DBG_PRINT_IF(b) if (b) {Serial.println(F(#b)); DBG_FAIL_MACRO;}
#define DBG_HALT_IF(b) if (b) {Serial.println(F(#b));\
DBG_FAIL_MACRO; SysCall::halt();}
DBG_FAIL_MACRO; while (1);}
#else // DEBUG_MODE
#define DBG_FAIL_MACRO
#define DBG_PRINT_IF(b)
@@ -100,11 +100,11 @@ class FatCache {
/** Sync existing block but do not read new block. */
static const uint8_t CACHE_OPTION_NO_READ = 4;
/** Cache block for read. */
static uint8_t const CACHE_FOR_READ = 0;
static const uint8_t CACHE_FOR_READ = 0;
/** Cache block for write. */
static uint8_t const CACHE_FOR_WRITE = CACHE_STATUS_DIRTY;
static const uint8_t CACHE_FOR_WRITE = CACHE_STATUS_DIRTY;
/** Reserve cache block for write - do not read from block device. */
static uint8_t const CACHE_RESERVE_FOR_WRITE
static const uint8_t CACHE_RESERVE_FOR_WRITE
= CACHE_STATUS_DIRTY | CACHE_OPTION_NO_READ;
/** \return Cache block address. */
cache_t* block() {
@@ -256,7 +256,9 @@ class FatVolume {
// Allow FatFile and FatCache access to FatVolume private functions.
friend class FatCache;
friend class FatFile;
friend class FatFileSystem;
//------------------------------------------------------------------------------
BlockDriver* m_blockDev; // block device
uint8_t m_blocksPerCluster; // Cluster size in blocks.
uint8_t m_clusterBlockMask; // Mask to extract block of cluster.
uint8_t m_clusterSizeShift; // Cluster count to block count shift.
@@ -269,6 +271,24 @@ class FatVolume {
uint32_t m_lastCluster; // Last cluster number in FAT.
uint32_t m_rootDirStart; // Start block for FAT16, cluster for FAT32.
//------------------------------------------------------------------------------
// block I/O functions.
bool readBlock(uint32_t block, uint8_t* dst) {
return m_blockDev->readBlock(block, dst);
}
bool syncBlocks() {
return m_blockDev->syncBlocks();
}
bool writeBlock(uint32_t block, const uint8_t* src) {
return m_blockDev->writeBlock(block, src);
}
#if USE_MULTI_BLOCK_IO
bool readBlocks(uint32_t block, uint8_t* dst, size_t nb) {
return m_blockDev->readBlocks(block, dst, nb);
}
bool writeBlocks(uint32_t block, const uint8_t* src, size_t nb) {
return m_blockDev->writeBlocks(block, src, nb);
}
#endif // USE_MULTI_BLOCK_IO
#if MAINTAIN_FREE_CLUSTER_COUNT
int32_t m_freeClusterCount; // Count of free clusters in volume.
void setFreeClusterCount(int32_t value) {
@@ -297,7 +317,7 @@ class FatVolume {
options | FatCache::CACHE_STATUS_MIRROR_FAT);
}
bool cacheSync() {
return m_cache.sync() && m_fatCache.sync();
return m_cache.sync() && m_fatCache.sync() && syncBlocks();
}
#else //
cache_t* cacheFetchFat(uint32_t blockNumber, uint8_t options) {
@@ -305,7 +325,7 @@ class FatVolume {
options | FatCache::CACHE_STATUS_MIRROR_FAT);
}
bool cacheSync() {
return m_cache.sync();
return m_cache.sync() && syncBlocks();
}
#endif // USE_SEPARATE_FAT_CACHE
cache_t* cacheFetchData(uint32_t blockNumber, uint8_t options) {
@@ -332,7 +352,7 @@ class FatVolume {
uint8_t blockOfCluster(uint32_t position) const {
return (position >> 9) & m_clusterBlockMask;
}
uint32_t clusterStartBlock(uint32_t cluster) const;
uint32_t clusterFirstBlock(uint32_t cluster) const;
int8_t fatGet(uint32_t cluster, uint32_t* value);
bool fatPut(uint32_t cluster, uint32_t value);
bool fatPutEOC(uint32_t cluster) {
@@ -342,13 +362,5 @@ class FatVolume {
bool isEOC(uint32_t cluster) const {
return cluster > m_lastCluster;
}
//----------------------------------------------------------------------------
// Virtual block I/O functions.
virtual bool readBlock(uint32_t block, uint8_t* dst) = 0;
virtual bool writeBlock(uint32_t block, const uint8_t* src) = 0;
#if USE_MULTI_BLOCK_IO
virtual bool readBlocks(uint32_t block, uint8_t* dst, size_t nb) = 0;
virtual bool writeBlocks(uint32_t block, const uint8_t* src, size_t nb) = 0;
#endif // USE_MULTI_BLOCK_IO
};
#endif // FatVolume

+ 5
- 3
SdFat/src/FreeStack.h Vedi File

@@ -32,8 +32,10 @@ extern char __bss_end;
* \return The number of free bytes.
*/
static int FreeStack() {
char top;
return __brkval ? &top - __brkval : &top - &__bss_end;
char* sp = reinterpret_cast<char*>(SP);
return __brkval ? sp - __brkval : sp - &__bss_end;
// char top;
// return __brkval ? &top - __brkval : &top - &__bss_end;
}
#elif defined(PLATFORM_ID) // Particle board
static int FreeStack() {
@@ -42,7 +44,7 @@ static int FreeStack() {
#elif defined(__arm__)
extern "C" char* sbrk(int incr);
static int FreeStack() {
char top;
char top = 't';
return &top - reinterpret_cast<char*>(sbrk(0));
}
#else

+ 9
- 1
SdFat/src/MinimumSerial.cpp Vedi File

@@ -17,11 +17,15 @@
* along with the Arduino SdFat Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include "SystemInclude.h"
#include "SysCall.h"
#if defined(UDR0) || defined(DOXYGEN)
#include "MinimumSerial.h"
const uint16_t MIN_2X_BAUD = F_CPU/(4*(2*0XFFF + 1)) + 1;
//------------------------------------------------------------------------------
int MinimumSerial::available() {
return UCSR0A & (1 << RXC0) ? 1 : 0;
}
//------------------------------------------------------------------------------
void MinimumSerial::begin(uint32_t baud) {
uint16_t baud_setting;
// don't worry, the compiler will squeeze out F_CPU != 16000000UL
@@ -43,6 +47,10 @@ void MinimumSerial::begin(uint32_t baud) {
UCSR0B |= (1 << TXEN0) | (1 << RXEN0);
}
//------------------------------------------------------------------------------
void MinimumSerial::flush() {
while (((1 << UDRIE0) & UCSR0B) || !(UCSR0A & (1 << UDRE0))) {}
}
//------------------------------------------------------------------------------
int MinimumSerial::read() {
if (UCSR0A & (1 << RXC0)) {
return UDR0;

+ 13
- 1
SdFat/src/MinimumSerial.h Vedi File

@@ -17,9 +17,13 @@
* along with the Arduino SdFat Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
/**
* \file
* \brief Minimal AVR Serial driver.
*/
#ifndef MinimumSerial_h
#define MinimumSerial_h
#include "SystemInclude.h"
#include "SysCall.h"
//==============================================================================
/**
* \class MinimumSerial
@@ -27,12 +31,20 @@
*/
class MinimumSerial : public Print {
public:
/** \return true for hardware serial */
operator bool() { return true; }
/**
* \return one if data is available.
*/
int available();
/**
* Set baud rate for serial port zero and enable in non interrupt mode.
* Do not call this function if you use another serial library.
* \param[in] baud rate
*/
void begin(uint32_t baud);
/** Wait for write done. */
void flush();
/**
* Unbuffered read
* \return -1 if no character is available or an available character.

+ 0
- 100
SdFat/src/SdFat.cpp Vedi File

@@ -1,100 +0,0 @@
/* Arduino SdFat Library
* Copyright (C) 2012 by William Greiman
*
* This file is part of the Arduino SdFat Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino SdFat Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include "SdFat.h"
//------------------------------------------------------------------------------
void SdFatBase::errorHalt(Print* pr) {
errorPrint(pr);
SysCall::halt();
}
//------------------------------------------------------------------------------
void SdFatBase::errorHalt(Print* pr, char const* msg) {
errorPrint(pr, msg);
SysCall::halt();
}
//------------------------------------------------------------------------------
void SdFatBase::errorPrint(Print* pr) {
if (!cardErrorCode()) {
return;
}
pr->print(F("SD errorCode: 0X"));
pr->print(cardErrorCode(), HEX);
pr->print(F(",0X"));
pr->println(cardErrorData(), HEX);
}
//------------------------------------------------------------------------------
void SdFatBase::errorPrint(Print* pr, char const* msg) {
pr->print(F("error: "));
pr->println(msg);
errorPrint(pr);
}
//------------------------------------------------------------------------------
void SdFatBase::initErrorHalt(Print* pr) {
initErrorPrint(pr);
SysCall::halt();
}
//------------------------------------------------------------------------------
void SdFatBase::initErrorHalt(Print* pr, char const *msg) {
pr->println(msg);
initErrorHalt(pr);
}
//------------------------------------------------------------------------------
void SdFatBase::initErrorPrint(Print* pr) {
if (cardErrorCode()) {
pr->println(F("Can't access SD card. Do not reformat."));
if (cardErrorCode() == SD_CARD_ERROR_CMD0) {
pr->println(F("No card, wrong chip select pin, or SPI problem?"));
}
errorPrint(pr);
} else if (vol()->fatType() == 0) {
pr->println(F("Invalid format, reformat SD."));
} else if (!vwd()->isOpen()) {
pr->println(F("Can't open root directory."));
} else {
pr->println(F("No error found."));
}
}
//------------------------------------------------------------------------------
void SdFatBase::initErrorPrint(Print* pr, char const *msg) {
pr->println(msg);
initErrorPrint(pr);
}
#if defined(ARDUINO) || defined(DOXYGEN)
//------------------------------------------------------------------------------
void SdFatBase::errorPrint(Print* pr, const __FlashStringHelper* msg) {
pr->print(F("error: "));
pr->println(msg);
errorPrint(pr);
}
//------------------------------------------------------------------------------
void SdFatBase::errorHalt(Print* pr, const __FlashStringHelper* msg) {
errorPrint(pr, msg);
SysCall::halt();
}
//------------------------------------------------------------------------------
void SdFatBase::initErrorHalt(Print* pr, const __FlashStringHelper* msg) {
pr->println(msg);
initErrorHalt(pr);
}
//------------------------------------------------------------------------------
void SdFatBase::initErrorPrint(Print* pr, const __FlashStringHelper* msg) {
pr->println(msg);
initErrorPrint(pr);
}
#endif // defined(ARDUINO) || defined(DOXYGEN)

+ 209
- 107
SdFat/src/SdFat.h Vedi File

@@ -1,5 +1,5 @@
/* Arduino SdFat Library
* Copyright (C) 2012 by William Greiman
* Copyright (C) 2016 by William Greiman
*
* This file is part of the Arduino SdFat Library
*
@@ -23,16 +23,16 @@
* \file
* \brief SdFat class
*/
#include "SysCall.h"
#include "BlockDriver.h"
#ifdef ARDUINO
#include "SdSpiCard/SdSpiCard.h"
#include "FatLib/FatLib.h"
#else // ARDUINO
#include "SdSpiCard.h"
#include "FatLib.h"
#endif // ARDUINO
//------------------------------------------------------------------------------
/** SdFat version YYYYMMDD */
#define SD_FAT_VERSION 20160430
#define SD_FAT_VERSION 20160801
//==============================================================================
/**
* \class SdBaseFile
@@ -51,6 +51,7 @@ class SdBaseFile : public FatFile {
*/
SdBaseFile(const char* path, uint8_t oflag) : FatFile(path, oflag) {}
};
//-----------------------------------------------------------------------------
#if ENABLE_ARDUINO_FEATURES
/**
* \class SdFile
@@ -70,25 +71,37 @@ class SdFile : public PrintFile {
SdFile(const char* path, uint8_t oflag) : PrintFile(path, oflag) {}
};
#endif // #if ENABLE_ARDUINO_FEATURES
//-----------------------------------------------------------------------------
/**
* \class SdFatBase
* \class SdFileSystem
* \brief Virtual base class for %SdFat library.
*/
class SdFatBase : public FatFileSystem {
template<class SdDriverClass>
class SdFileSystem : public FatFileSystem {
public:
/** Initialize SD card and file system.
* \param[in] spi SPI object for the card.
* \param[in] csPin SD card chip select pin.
* \param[in] divisor SPI divisor.
* \param[in] spiSettings SPI speed, mode, and bit order.
* \return true for success else false.
*/
bool begin(SdSpiCard::m_spi_t* spi, uint8_t csPin = SS, uint8_t divisor = 2) {
return m_sdCard.begin(spi, csPin, divisor) &&
FatFileSystem::begin();
bool begin(SdSpiDriver* spi, uint8_t csPin, SPISettings spiSettings) {
return m_card.begin(spi, csPin, spiSettings) &&
FatFileSystem::begin(&m_card);
}
/** \return Pointer to SD card object */
SdSpiCard *card() {
return &m_sdCard;
SdDriverClass *card() {
m_card.syncBlocks();
return &m_card;
}
/** Initialize SD card for diagnostic use.
* \param[in] spi SPI object for the card.
* \param[in] csPin SD card chip select pin.
* \param[in] spiSettings SPI speed, mode, and bit order.
* \return true for success else false.
*/
bool cardBegin(SdSpiDriver* spi, uint8_t csPin, SPISettings spiSettings) {
return m_card.begin(spi, csPin, spiSettings);
}
/** %Print any SD error code to Serial and halt. */
void errorHalt() {
@@ -98,7 +111,10 @@ class SdFatBase : public FatFileSystem {
*
* \param[in] pr Print destination.
*/
void errorHalt(Print* pr);
void errorHalt(Print* pr) {
errorPrint(pr);
SysCall::halt();
}
/** %Print msg, any SD error code and halt.
*
* \param[in] msg Message to print.
@@ -111,8 +127,10 @@ class SdFatBase : public FatFileSystem {
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void errorHalt(Print* pr, char const* msg);

void errorHalt(Print* pr, char const* msg) {
errorPrint(pr, msg);
SysCall::halt();
}
/** %Print any SD error code to Serial */
void errorPrint() {
errorPrint(&Serial);
@@ -120,7 +138,15 @@ class SdFatBase : public FatFileSystem {
/** %Print any SD error code.
* \param[in] pr Print device.
*/
void errorPrint(Print* pr);
void errorPrint(Print* pr) {
if (!cardErrorCode()) {
return;
}
pr->print(F("SD errorCode: 0X"));
pr->print(cardErrorCode(), HEX);
pr->print(F(",0X"));
pr->println(cardErrorData(), HEX);
}
/** %Print msg, any SD error code.
*
* \param[in] msg Message to print.
@@ -133,14 +159,10 @@ class SdFatBase : public FatFileSystem {
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void errorPrint(Print* pr, char const* msg);

/** Diagnostic call to initialize FatFileSystem - use for
* diagnostic purposes only.
* \return true for success else false.
*/
bool fsBegin() {
return FatFileSystem::begin();
void errorPrint(Print* pr, char const* msg) {
pr->print(F("error: "));
pr->println(msg);
errorPrint(pr);
}
/** %Print any SD error code and halt. */
void initErrorHalt() {
@@ -150,42 +172,65 @@ class SdFatBase : public FatFileSystem {
*
* \param[in] pr Print destination.
*/
void initErrorHalt(Print* pr);
/**Print message, error details, and halt after SdFat::init() fails.
void initErrorHalt(Print* pr) {
initErrorPrint(pr);
SysCall::halt();
}
/**Print message, error details, and halt after begin() fails.
*
* \param[in] msg Message to print.
*/
void initErrorHalt(char const *msg) {
initErrorHalt(&Serial, msg);
}
/**Print message, error details, and halt after SdFatBase::init() fails.
/**Print message, error details, and halt after begin() fails.
* \param[in] pr Print device.
* \param[in] msg Message to print.
*/
void initErrorHalt(Print* pr, char const *msg);
void initErrorHalt(Print* pr, char const *msg) {
pr->println(msg);
initErrorHalt(pr);
}

/** Print error details after SdFat::init() fails. */
/** Print error details after begin() fails. */
void initErrorPrint() {
initErrorPrint(&Serial);
}
/** Print error details after SdFatBase::init() fails.
/** Print error details after begin() fails.
*
* \param[in] pr Print destination.
*/
void initErrorPrint(Print* pr);
/**Print message and error details and halt after SdFat::init() fails.
void initErrorPrint(Print* pr) {
if (cardErrorCode()) {
pr->println(F("Can't access SD card. Do not reformat."));
if (cardErrorCode() == SD_CARD_ERROR_CMD0) {
pr->println(F("No card, wrong chip select pin, or SPI problem?"));
}
errorPrint(pr);
} else if (vol()->fatType() == 0) {
pr->println(F("Invalid format, reformat SD."));
} else if (!vwd()->isOpen()) {
pr->println(F("Can't open root directory."));
} else {
pr->println(F("No error found."));
}
}
/**Print message and error details and halt after begin() fails.
*
* \param[in] msg Message to print.
*/
void initErrorPrint(char const *msg) {
initErrorPrint(&Serial, msg);
}
/**Print message and error details and halt after SdFatBase::init() fails.
/**Print message and error details and halt after begin() fails.
*
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void initErrorPrint(Print* pr, char const *msg);
void initErrorPrint(Print* pr, char const *msg) {
pr->println(msg);
initErrorPrint(pr);
}
#if defined(ARDUINO) || defined(DOXYGEN)
/** %Print msg, any SD error code, and halt.
*
@@ -199,7 +244,11 @@ class SdFatBase : public FatFileSystem {
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void errorHalt(Print* pr, const __FlashStringHelper* msg);
void errorHalt(Print* pr, const __FlashStringHelper* msg) {
errorPrint(pr, msg);
SysCall::halt();
}

/** %Print msg, any SD error code.
*
* \param[in] msg Message to print.
@@ -212,149 +261,202 @@ class SdFatBase : public FatFileSystem {
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void errorPrint(Print* pr, const __FlashStringHelper* msg);
/**Print message, error details, and halt after SdFat::init() fails.
void errorPrint(Print* pr, const __FlashStringHelper* msg) {
pr->print(F("error: "));
pr->println(msg);
errorPrint(pr);
}
/**Print message, error details, and halt after begin() fails.
*
* \param[in] msg Message to print.
*/
void initErrorHalt(const __FlashStringHelper* msg) {
initErrorHalt(&Serial, msg);
}
/**Print message, error details, and halt after SdFatBase::init() fails.
/**Print message, error details, and halt after begin() fails.
* \param[in] pr Print device for message.
* \param[in] msg Message to print.
*/
void initErrorHalt(Print* pr, const __FlashStringHelper* msg);
/**Print message and error details and halt after SdFat::init() fails.
void initErrorHalt(Print* pr, const __FlashStringHelper* msg) {
pr->println(msg);
initErrorHalt(pr);
}
/**Print message and error details and halt after begin() fails.
*
* \param[in] msg Message to print.
*/
void initErrorPrint(const __FlashStringHelper* msg) {
initErrorPrint(&Serial, msg);
}
/**Print message and error details and halt after SdFatBase::init() fails.
/**Print message and error details and halt after begin() fails.
*
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void initErrorPrint(Print* pr, const __FlashStringHelper* msg);
void initErrorPrint(Print* pr, const __FlashStringHelper* msg) {
pr->println(msg);
initErrorPrint(pr);
}
#endif // defined(ARDUINO) || defined(DOXYGEN)

private:
/** \return The card error code */
uint8_t cardErrorCode() {
return m_sdCard.errorCode();
return m_card.errorCode();
}
/** \return the card error data */
uint8_t cardErrorData() {
return m_sdCard.errorData();
}
bool readBlock(uint32_t block, uint8_t* dst) {
return m_sdCard.readBlock(block, dst);
}
bool writeBlock(uint32_t block, const uint8_t* src) {
return m_sdCard.writeBlock(block, src);
}
bool readBlocks(uint32_t block, uint8_t* dst, size_t n) {
return m_sdCard.readBlocks(block, dst, n);
}
bool writeBlocks(uint32_t block, const uint8_t* src, size_t n) {
return m_sdCard.writeBlocks(block, src, n);
return m_card.errorData();
}
SdSpiCard m_sdCard;

private:
SdDriverClass m_card;
};
//==============================================================================
/**
* \class SdFat
* \brief Main file system class for %SdFat library.
*/
class SdFat : public SdFatBase {
class SdFat : public SdFileSystem<SdBlockDriver> {
public:
#if IMPLEMENT_SPI_INTERFACE_SELECTION
#if IMPLEMENT_SPI_PORT_SELECTION || defined(DOXYGEN)
SdFat() {
m_spi.setSpiIf(0);
m_spi.setPort(0);
}
explicit SdFat(uint8_t spiIf) {
m_spi.setSpiIf(spiIf < SPI_INTERFACE_COUNT ? spiIf : 0);
/** Constructor with SPI port selection.
* \param[in] spiPort SPI port number.
*/
explicit SdFat(uint8_t spiPort) {
m_spi.setPort(spiPort);
}
#endif // IMPLEMENT_SPI_INTERFACE_SELECTION

#endif // IMPLEMENT_SPI_PORT_SELECTION
/** Initialize SD card and file system.
*
* \param[in] csPin SD card chip select pin.
* \param[in] divisor SPI divisor.
* \param[in] spiSettings SPI speed, mode, and bit order.
* \return true for success else false.
*/
bool begin(uint8_t csPin = SS, uint8_t divisor = 2) {
return SdFatBase::begin(&m_spi, csPin, divisor);
*/
bool begin(uint8_t csPin = SS, SPISettings spiSettings = SPI_FULL_SPEED) {
return SdFileSystem::begin(&m_spi, csPin, spiSettings);
}
/** Diagnostic call to initialize SD card - use for diagnostic purposes only.
/** Initialize SD card for diagnostic use only.
*
* \param[in] csPin SD card chip select pin.
* \param[in] divisor SPI divisor.
* \param[in] settings SPI speed, mode, and bit order.
* \return true for success else false.
*/
bool cardBegin(uint8_t csPin = SS, uint8_t divisor = 2) {
return card()->begin(&m_spi, csPin, divisor);
*/
bool cardBegin(uint8_t csPin = SS, SPISettings settings = SPI_FULL_SPEED) {
return SdFileSystem::cardBegin(&m_spi, csPin, settings);
}
/** Initialize file system for diagnostic use only.
* \return true for success else false.
*/
bool fsBegin() {
return FatFileSystem::begin(card());
}

private:
SpiDefault_t m_spi;
SdFatSpiDriver m_spi;
};
//==============================================================================
#if SD_SPI_CONFIGURATION >= 3 || defined(DOXYGEN)
#if ENABLE_SOFTWARE_SPI_CLASS || defined(DOXYGEN)
/**
* \class SdFatLibSpi
* \brief SdFat class using the standard Arduino SPI library.
* \class SdFatSoftSpi
* \brief SdFat class using software SPI.
*/
class SdFatLibSpi: public SdFatBase {
template<uint8_t MisoPin, uint8_t MosiPin, uint8_t SckPin>
class SdFatSoftSpi : public SdFileSystem<SdBlockDriver> {
public:
/** Initialize SD card and file system.
*
* \param[in] csPin SD card chip select pin.
* \param[in] divisor SPI divisor.
* \return true for success else false.
*/
bool begin(uint8_t csPin = SS, uint8_t divisor = 2) {
return SdFatBase::begin(&m_spi, csPin, divisor);
}
/** Diagnostic call to initialize SD card - use for diagnostic purposes only.
*
* \param[in] csPin SD card chip select pin.
* \param[in] divisor SPI divisor.
* \param[in] spiSettings ignored for software SPI..
* \return true for success else false.
*/
bool cardBegin(uint8_t csPin = SS, uint8_t divisor = 2) {
return card()->begin(&m_spi, csPin, divisor);
bool begin(uint8_t csPin = SS, SPISettings spiSettings = SPI_FULL_SPEED) {
return SdFileSystem::begin(&m_spi, csPin, spiSettings);
}
private:
SdSpiSoftDriver<MisoPin, MosiPin, SckPin> m_spi;
};
#endif // #if ENABLE_SOFTWARE_SPI_CLASS || defined(DOXYGEN)

#if ENABLE_EXTENDED_TRANSFER_CLASS || defined(DOXYGEN)
//==============================================================================
/**
* \class SdFatEX
* \brief SdFat class with extended SD I/O.
*/
class SdFatEX : public SdFileSystem<SdBlockDriverEX> {
public:
#if IMPLEMENT_SPI_PORT_SELECTION || defined(DOXYGEN)
SdFatEX() {
m_spi.setPort(0);
}
/** Constructor with SPI port selection.
* \param[in] spiPort SPI port number.
*/
explicit SdFatEX(uint8_t spiPort) {
m_spi.setPort(spiPort);
}
#endif // IMPLEMENT_SPI_PORT_SELECTION
/** Initialize SD card and file system.
*
* \param[in] csPin SD card chip select pin.
* \param[in] spiSettings SPI speed, mode, and bit order.
* \return true for success else false.
*/
bool begin(uint8_t csPin = SS, SPISettings spiSettings = SPI_FULL_SPEED) {
return SdFileSystem::begin(&m_spi, csPin, spiSettings);
}

private:
SdSpiLib m_spi;
SdFatSpiDriver m_spi;
};
//==============================================================================
#if ENABLE_SOFTWARE_SPI_CLASS || defined(DOXYGEN)
/**
* \class SdFatSoftSpi
* \brief SdFat class using software SPI.
* \class SdFatSoftSpiEX
* \brief SdFat class using software SPI and extended SD I/O.
*/
template<uint8_t MisoPin, uint8_t MosiPin, uint8_t SckPin>
class SdFatSoftSpi : public SdFatBase {
class SdFatSoftSpiEX : public SdFileSystem<SdBlockDriverEX> {
public:
/** Initialize SD card and file system.
*
* \param[in] csPin SD card chip select pin.
* \param[in] divisor SPI divisor.
* \param[in] spiSettings ignored for software SPI.
* \return true for success else false.
*/
bool begin(uint8_t csPin = SS, uint8_t divisor = 2) {
return SdFatBase::begin(&m_spi, csPin, divisor);
bool begin(uint8_t csPin = SS, SPISettings spiSettings = 2) {
return SdFileSystem::begin(&m_spi, csPin, spiSettings);
}
/** Diagnostic call to initialize SD card - use for diagnostic purposes only.
* \param[in] csPin SD card chip select pin.
* \param[in] divisor SPI divisor.
private:
SdSpiSoftDriver<MisoPin, MosiPin, SckPin> m_spi;
};
#endif // #if ENABLE_SOFTWARE_SPI_CLASS || defined(DOXYGEN)
#endif // ENABLE_EXTENDED_TRANSFER_CLASS || defined(DOXYGEN)
//=============================================================================
/**
* \class Sd2Card
* \brief Raw access to SD and SDHC card using default SPI library.
*/
class Sd2Card : public SdSpiCard {
public:
/** Initialize the SD card.
* \param[in] chipSelectPin SD chip select pin.
* \param[in] spiSettings SPI speed, mode, and bit order.
* \return true for success else false.
*/
bool cardBegin(uint8_t csPin = SS, uint8_t divisor = 2) {
return card()->begin(&m_spi, csPin, divisor);
bool begin(uint8_t chipSelectPin = SS,
SPISettings spiSettings = SD_SCK_MHZ(50)) {
m_spi.begin(chipSelectPin);
m_spi.setSpiSettings(SD_SCK_HZ(250000));
if (!SdSpiCard::begin(&m_spi)) {
return false;
}
m_spi.setSpiSettings(spiSettings);
return true;
}

private:
SdSpiSoft<MisoPin, MosiPin, SckPin> m_spi;
SdFatSpiDriver m_spi;
};
#endif /// SD_SPI_CONFIGURATION >= 3 || defined(DOXYGEN)
#endif // SdFat_h

+ 32
- 86
SdFat/src/SdFatConfig.h Vedi File

@@ -49,50 +49,28 @@
#define USE_LONG_FILE_NAMES 1
//------------------------------------------------------------------------------
/**
* Set ARDUINO_FILE_USES_STREAM nonzero to use Stream as the base class
* for the Arduino File class. If ARDUINO_FILE_USES_STREAM is zero, Print
* will be used as the base class for the Arduino File class.
* If the symbol ENABLE_EXTENDED_TRANSFER_CLASS is nonzero, the class SdFatEX
* will be defined. If the symbol ENABLE_SOFTWARE_SPI_CLASS is also nonzero,
* the class SdFatSoftSpiEX will be defined.
*
* You can save some flash if you do not use Stream input functions such as
* find(), findUntil(), readBytesUntil(), readString(), readStringUntil(),
* parseInt(), and parseFloat().
* These classes used extended multi-block SD I/O for better performance.
* the SPI bus may not be shared with other devices in this mode.
*/
#define ARDUINO_FILE_USES_STREAM 1
//------------------------------------------------------------------------------
#define ENABLE_EXTENDED_TRANSFER_CLASS 0
//-----------------------------------------------------------------------------
/**
* The symbol SD_SPI_CONFIGURATION defines SPI access to the SD card.
*
* IF SD_SPI_CONFIGUTATION is define to be zero, only the SdFat class
* is define and SdFat uses a fast custom SPI implementation if avaiable.
* If SD_HAS_CUSTOM_SPI is zero, the standard SPI library is used.
*
* If SD_SPI_CONFIGURATION is define to be one, only the SdFat class is
* define and SdFat uses the standard Arduino SPI.h library.
*
* If SD_SPI_CONFIGURATION is define to be two, only the SdFat class is
* define and SdFat uses software SPI on the pins defined below.
*
* If SD_SPI_CONFIGURATION is define to be three, the three classes, SdFat,
* SdFatLibSpi, and SdFatSoftSpi are defined. SdFat uses the fast
* custom SPI implementation. SdFatLibSpi uses the standard Arduino SPI
* library. SdFatSoftSpi is a template class that uses Software SPI. The
* template parameters define the software SPI pins. See the ThreeCard
* example for simultaneous use of all three classes.
*/
#define SD_SPI_CONFIGURATION 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.
*/
#define USE_STANDARD_SPI_LIBRARY 0
//-----------------------------------------------------------------------------
/**
* If SD_SPI_CONFIGURATION is defined to be two, these definitions
* will define the pins used for software SPI.
*
* The default definition allows Uno shields to be used on other boards.
* If the symbol ENABLE_SOFTWARE_SPI_CLASS is nonzero, the class SdFatSoftSpi
* will be defined. If ENABLE_EXTENDED_TRANSFER_CLASS is also nonzero,
* the class SdFatSoftSpiEX will be defined.
*/
/** Software SPI Master Out Slave In pin */
uint8_t const SOFT_SPI_MOSI_PIN = 11;
/** Software SPI Master In Slave Out pin */
uint8_t const SOFT_SPI_MISO_PIN = 12;
/** Software SPI Clock pin */
uint8_t const SOFT_SPI_SCK_PIN = 13;
#define ENABLE_SOFTWARE_SPI_CLASS 0
//------------------------------------------------------------------------------
/**
* Set MAINTAIN_FREE_CLUSTER_COUNT nonzero to keep the count of free clusters
@@ -104,19 +82,14 @@ uint8_t const SOFT_SPI_SCK_PIN = 13;
/**
* To enable SD card CRC checking set USE_SD_CRC nonzero.
*
* Set USE_SD_CRC to 1 to use a smaller slower CRC-CCITT function.
* Set USE_SD_CRC to 1 to use a smaller CRC-CCITT function. This function
* is slower for AVR but may be fast for ARM and other processors.
*
* Set USE_SD_CRC to 2 to used a larger faster table driven CRC-CCITT function.
* Set USE_SD_CRC to 2 to used a larger table driven CRC-CCITT function. This
* function is faster for AVR but may be slower for ARM and other processors.
*/
#define USE_SD_CRC 0
//------------------------------------------------------------------------------
/**
* Set ENABLE_SPI_TRANSACTIONS nonzero to enable the SPI transaction feature
* of the standard Arduino SPI library. You must include SPI.h in your
* programs when ENABLE_SPI_TRANSACTIONS is nonzero.
*/
#define ENABLE_SPI_TRANSACTIONS 0
//------------------------------------------------------------------------------
/**
* Handle Watchdog Timer for WiFi modules.
*
@@ -162,16 +135,6 @@ uint8_t const SOFT_SPI_SCK_PIN = 13;
*/
#define ENDL_CALLS_FLUSH 0
//------------------------------------------------------------------------------
/**
* SPI SCK divisor for SD initialization commands.
* or greater
*/
#ifdef __AVR__
const uint8_t SPI_SCK_INIT_DIVISOR = 64;
#else
const uint8_t SPI_SCK_INIT_DIVISOR = 128;
#endif
//------------------------------------------------------------------------------
/**
* Set USE_SEPARATE_FAT_CACHE nonzero to use a second 512 byte cache
* for FAT table entries. This improves performance for large writes
@@ -197,42 +160,25 @@ const uint8_t SPI_SCK_INIT_DIVISOR = 128;
/**
* Determine the default SPI configuration.
*/
#if defined(__AVR__)\
#if defined(__STM32F1__)
// has multiple SPI ports
#define SD_HAS_CUSTOM_SPI 2
#elif defined(__AVR__)\
|| defined(__SAM3X8E__) || defined(__SAM3X8H__)\
|| (defined(__arm__) && defined(CORE_TEENSY))\
|| defined(__STM32F1__)\
|| defined(PLATFORM_ID)\
|| defined(ESP8266)\
|| defined(DOXYGEN)
// Use custom fast implementation.
|| defined(ESP8266)
#define SD_HAS_CUSTOM_SPI 1
#else // SD_HAS_CUSTOM_SPI
// Use standard SPI library.
#define SD_HAS_CUSTOM_SPI 0
#endif // SD_HAS_CUSTOM_SPI
//-----------------------------------------------------------------------------
/**
* Number of hardware interfaces.
*/
#if defined(PLATFORM_ID)
#if Wiring_SPI1 && Wiring_SPI2
#define SPI_INTERFACE_COUNT 3
#elif Wiring_SPI1
#define SPI_INTERFACE_COUNT 2
#endif // Wiring_SPI1 && Wiring_SPI2
#endif // defined(PLATFORM_ID)
// default is one
#ifndef SPI_INTERFACE_COUNT
#define SPI_INTERFACE_COUNT 1
#endif // SPI_INTERFACE_COUNT
//------------------------------------------------------------------------------
/**
* Check if API to select HW SPI interface is needed.
* Check if API to select HW SPI port is needed.
*/
#if SPI_INTERFACE_COUNT > 1 && SD_HAS_CUSTOM_SPI\
&& SD_SPI_CONFIGURATION != 1 && SD_SPI_CONFIGURATION != 2
#define IMPLEMENT_SPI_INTERFACE_SELECTION 1
#else // SPI_INTERFACE_COUNT > 1
#define IMPLEMENT_SPI_INTERFACE_SELECTION 0
#endif // SPI_INTERFACE_COUNT > 1
#if (USE_STANDARD_SPI_LIBRARY || SD_HAS_CUSTOM_SPI < 2)
#define IMPLEMENT_SPI_PORT_SELECTION 0
#else // USE_STANDARD_SPI_LIBRARY
#define IMPLEMENT_SPI_PORT_SELECTION 1
#endif // USE_STANDARD_SPI_LIBRARY
#endif // SdFatConfig_h

+ 0
- 41
SdFat/src/SdFatUtil.cpp Vedi File

@@ -1,41 +0,0 @@
/* Arduino SdFat Library
* Copyright (C) 2015 by William Greiman
*
* This file is part of the Arduino SdFat Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.

* You should have received a copy of the GNU General Public License
* along with the Arduino SdFat Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include "SdFat.h"
#include "SdFatUtil.h"
//------------------------------------------------------------------------------
#ifdef __arm__
extern "C" char* sbrk(int incr);
int SdFatUtil::FreeRam() {
char top;
return &top - reinterpret_cast<char*>(sbrk(0));
}
#else // __arm__
extern char *__brkval;
extern char __bss_end;
/** Amount of free RAM
* \return The number of free bytes.
*/
int SdFatUtil::FreeRam() {
char top;
return __brkval ? &top - __brkval : &top - &__bss_end;
}
#endif // __arm


+ 0
- 35
SdFat/src/SdFatUtil.h Vedi File

@@ -1,35 +0,0 @@
/* Arduino SdFat Library
* Copyright (C) 2012 by William Greiman
*
* This file is part of the Arduino SdFat Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino SdFat Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef SdFatUtil_h
#define SdFatUtil_h
/**
* \file
* \brief Useful utility functions.
*/
#include "SdFat.h"

namespace SdFatUtil {
/** Amount of free RAM
* \return The number of free bytes.
*/
int FreeRam();
} // namespace SdFatUtil
using namespace SdFatUtil; // NOLINT
#endif // #define SdFatUtil_h

+ 76
- 72
SdFat/src/SdSpiCard/SdInfo.h Vedi File

@@ -33,157 +33,161 @@
//------------------------------------------------------------------------------
// SD card errors
/** timeout error for command CMD0 (initialize card in SPI mode) */
uint8_t const SD_CARD_ERROR_CMD0 = 0X1;
const uint8_t SD_CARD_ERROR_CMD0 = 0X1;
/** CMD8 was not accepted - not a valid SD card*/
uint8_t const SD_CARD_ERROR_CMD8 = 0X2;
const uint8_t SD_CARD_ERROR_CMD8 = 0X2;
/** card returned an error response for CMD12 (stop multiblock read) */
uint8_t const SD_CARD_ERROR_CMD12 = 0X3;
const uint8_t SD_CARD_ERROR_CMD12 = 0X3;
/** card returned an error response for CMD17 (read block) */
uint8_t const SD_CARD_ERROR_CMD17 = 0X4;
const uint8_t SD_CARD_ERROR_CMD17 = 0X4;
/** card returned an error response for CMD18 (read multiple block) */
uint8_t const SD_CARD_ERROR_CMD18 = 0X5;
const uint8_t SD_CARD_ERROR_CMD18 = 0X5;
/** card returned an error response for CMD24 (write block) */
uint8_t const SD_CARD_ERROR_CMD24 = 0X6;
const uint8_t SD_CARD_ERROR_CMD24 = 0X6;
/** WRITE_MULTIPLE_BLOCKS command failed */
uint8_t const SD_CARD_ERROR_CMD25 = 0X7;
const uint8_t SD_CARD_ERROR_CMD25 = 0X7;
/** card returned an error response for CMD58 (read OCR) */
uint8_t const SD_CARD_ERROR_CMD58 = 0X8;
const uint8_t SD_CARD_ERROR_CMD58 = 0X8;
/** SET_WR_BLK_ERASE_COUNT failed */
uint8_t const SD_CARD_ERROR_ACMD23 = 0X9;
const uint8_t SD_CARD_ERROR_ACMD23 = 0X9;
/** ACMD41 initialization process timeout */
uint8_t const SD_CARD_ERROR_ACMD41 = 0XA;
const uint8_t SD_CARD_ERROR_ACMD41 = 0XA;
/** card returned a bad CSR version field */
uint8_t const SD_CARD_ERROR_BAD_CSD = 0XB;
const uint8_t SD_CARD_ERROR_BAD_CSD = 0XB;
/** erase block group command failed */
uint8_t const SD_CARD_ERROR_ERASE = 0XC;
const uint8_t SD_CARD_ERROR_ERASE = 0XC;
/** card not capable of single block erase */
uint8_t const SD_CARD_ERROR_ERASE_SINGLE_BLOCK = 0XD;
const uint8_t SD_CARD_ERROR_ERASE_SINGLE_BLOCK = 0XD;
/** Erase sequence timed out */
uint8_t const SD_CARD_ERROR_ERASE_TIMEOUT = 0XE;
const uint8_t SD_CARD_ERROR_ERASE_TIMEOUT = 0XE;
/** card returned an error token instead of read data */
uint8_t const SD_CARD_ERROR_READ = 0XF;
const uint8_t SD_CARD_ERROR_READ = 0XF;
/** read CID or CSD failed */
uint8_t const SD_CARD_ERROR_READ_REG = 0X10;
const uint8_t SD_CARD_ERROR_READ_REG = 0X10;
/** timeout while waiting for start of read data */
uint8_t const SD_CARD_ERROR_READ_TIMEOUT = 0X11;
const uint8_t SD_CARD_ERROR_READ_TIMEOUT = 0X11;
/** card did not accept STOP_TRAN_TOKEN */
uint8_t const SD_CARD_ERROR_STOP_TRAN = 0X12;
const uint8_t SD_CARD_ERROR_STOP_TRAN = 0X12;
/** card returned an error token as a response to a write operation */
uint8_t const SD_CARD_ERROR_WRITE = 0X13;
/** attempt to write protected block zero */
uint8_t const SD_CARD_ERROR_WRITE_BLOCK_ZERO = 0X14; // REMOVE - not used
const uint8_t SD_CARD_ERROR_WRITE = 0X13;
/** card busy for command */
const uint8_t SD_CARD_ERROR_CMD_BUSY = 0X14;
/** card did not go ready for a multiple block write */
uint8_t const SD_CARD_ERROR_WRITE_MULTIPLE = 0X15; // Not used
const uint8_t SD_CARD_ERROR_WRITE_MULTIPLE = 0X15; // Not used
/** card returned an error to a CMD13 status check after a write */
uint8_t const SD_CARD_ERROR_WRITE_PROGRAMMING = 0X16;
const uint8_t SD_CARD_ERROR_WRITE_PROGRAMMING = 0X16;
/** timeout occurred during write programming */
uint8_t const SD_CARD_ERROR_WRITE_TIMEOUT = 0X17;
const uint8_t SD_CARD_ERROR_WRITE_TIMEOUT = 0X17;
/** incorrect rate selected */
uint8_t const SD_CARD_ERROR_SCK_RATE = 0X18;
const uint8_t SD_CARD_ERROR_SCK_RATE = 0X18;
/** init() not called */
uint8_t const SD_CARD_ERROR_INIT_NOT_CALLED = 0X19;
const uint8_t SD_CARD_ERROR_INIT_NOT_CALLED = 0X19;
/** card returned an error for CMD59 (CRC_ON_OFF) */
uint8_t const SD_CARD_ERROR_CMD59 = 0X1A;
const uint8_t SD_CARD_ERROR_CMD59 = 0X1A;
/** invalid read CRC */
uint8_t const SD_CARD_ERROR_READ_CRC = 0X1B;
const uint8_t SD_CARD_ERROR_READ_CRC = 0X1B;
/** SPI DMA error */
uint8_t const SD_CARD_ERROR_SPI_DMA = 0X1C;
/** CMD6 not accepted */
uint8_t const SD_CARD_ERROR_CMD6 = 0X1D;
const uint8_t SD_CARD_ERROR_SPI_DMA = 0X1C;
/** ACMD13 not accepted */
const uint8_t SD_CARD_ERROR_ACMD13 = 0X1D;
//------------------------------------------------------------------------------
// card types
/** Standard capacity V1 SD card */
uint8_t const SD_CARD_TYPE_SD1 = 1;
const uint8_t SD_CARD_TYPE_SD1 = 1;
/** Standard capacity V2 SD card */
uint8_t const SD_CARD_TYPE_SD2 = 2;
const uint8_t SD_CARD_TYPE_SD2 = 2;
/** High Capacity SD card */
uint8_t const SD_CARD_TYPE_SDHC = 3;
const uint8_t SD_CARD_TYPE_SDHC = 3;
//------------------------------------------------------------------------------
#define SD_SCK_HZ(maxSpeed) SPISettings(maxSpeed, MSBFIRST, SPI_MODE0)
#define SD_SCK_MHZ(maxMhz) SPISettings(1000000UL*maxMhz, MSBFIRST, SPI_MODE0)
// SPI divisor constants
/** Set SCK to max rate of F_CPU/2. */
uint8_t const SPI_FULL_SPEED = 2;
#define SPI_FULL_SPEED SD_SCK_MHZ(50)
/** Set SCK rate to F_CPU/3 for Due */
uint8_t const SPI_DIV3_SPEED = 3;
#define SPI_DIV3_SPEED SD_SCK_HZ(F_CPU/3)
/** Set SCK rate to F_CPU/4. */
uint8_t const SPI_HALF_SPEED = 4;
#define SPI_HALF_SPEED SD_SCK_HZ(F_CPU/4)
/** Set SCK rate to F_CPU/6 for Due */
uint8_t const SPI_DIV6_SPEED = 6;
#define SPI_DIV6_SPEED SD_SCK_HZ(F_CPU/6)
/** Set SCK rate to F_CPU/8. */
uint8_t const SPI_QUARTER_SPEED = 8;
#define SPI_QUARTER_SPEED SD_SCK_HZ(F_CPU/8)
/** Set SCK rate to F_CPU/16. */
uint8_t const SPI_EIGHTH_SPEED = 16;
#define SPI_EIGHTH_SPEED SD_SCK_HZ(F_CPU/16)
/** Set SCK rate to F_CPU/32. */
uint8_t const SPI_SIXTEENTH_SPEED = 32;
#define SPI_SIXTEENTH_SPEED SD_SCK_HZ(F_CPU/32)
//------------------------------------------------------------------------------
// SD operation timeouts
/** init timeout ms */
unsigned const SD_INIT_TIMEOUT = 2000;
const uint16_t SD_INIT_TIMEOUT = 2000;
/** erase timeout ms */
unsigned const SD_ERASE_TIMEOUT = 10000;
const uint16_t SD_ERASE_TIMEOUT = 10000;
/** read timeout ms */
unsigned const SD_READ_TIMEOUT = 300;
const uint16_t SD_READ_TIMEOUT = 300;
/** write time out ms */
unsigned const SD_WRITE_TIMEOUT = 600;
const uint16_t SD_WRITE_TIMEOUT = 600;
//------------------------------------------------------------------------------
// SD card commands
/** GO_IDLE_STATE - init card in spi mode if CS low */
uint8_t const CMD0 = 0X00;
const uint8_t CMD0 = 0X00;
/** SWITCH_FUNC - Switch Function Command */
uint8_t const CMD6 = 0X06;
const uint8_t CMD6 = 0X06;
/** SEND_IF_COND - verify SD Memory Card interface operating condition.*/
uint8_t const CMD8 = 0X08;
const uint8_t CMD8 = 0X08;
/** SEND_CSD - read the Card Specific Data (CSD register) */
uint8_t const CMD9 = 0X09;
const uint8_t CMD9 = 0X09;
/** SEND_CID - read the card identification information (CID register) */
uint8_t const CMD10 = 0X0A;
const uint8_t CMD10 = 0X0A;
/** STOP_TRANSMISSION - end multiple block read sequence */
uint8_t const CMD12 = 0X0C;
const uint8_t CMD12 = 0X0C;
/** SEND_STATUS - read the card status register */
uint8_t const CMD13 = 0X0D;
const uint8_t CMD13 = 0X0D;
/** READ_SINGLE_BLOCK - read a single data block from the card */
uint8_t const CMD17 = 0X11;
const uint8_t CMD17 = 0X11;
/** READ_MULTIPLE_BLOCK - read a multiple data blocks from the card */
uint8_t const CMD18 = 0X12;
const uint8_t CMD18 = 0X12;
/** WRITE_BLOCK - write a single data block to the card */
uint8_t const CMD24 = 0X18;
const uint8_t CMD24 = 0X18;
/** WRITE_MULTIPLE_BLOCK - write blocks of data until a STOP_TRANSMISSION */
uint8_t const CMD25 = 0X19;
const uint8_t CMD25 = 0X19;
/** ERASE_WR_BLK_START - sets the address of the first block to be erased */
uint8_t const CMD32 = 0X20;
const uint8_t CMD32 = 0X20;
/** ERASE_WR_BLK_END - sets the address of the last block of the continuous
range to be erased*/
uint8_t const CMD33 = 0X21;
const uint8_t CMD33 = 0X21;
/** ERASE - erase all previously selected blocks */
uint8_t const CMD38 = 0X26;
const uint8_t CMD38 = 0X26;
/** APP_CMD - escape for application specific command */
uint8_t const CMD55 = 0X37;
const uint8_t CMD55 = 0X37;
/** READ_OCR - read the OCR register of a card */
uint8_t const CMD58 = 0X3A;
const uint8_t CMD58 = 0X3A;
/** CRC_ON_OFF - enable or disable CRC checking */
uint8_t const CMD59 = 0X3B;
const uint8_t CMD59 = 0X3B;
/** SD_STATUS - Send the SD Status. */
const uint8_t ACMD13 = 0X0D;
/** SET_WR_BLK_ERASE_COUNT - Set the number of write blocks to be
pre-erased before writing */
uint8_t const ACMD23 = 0X17;
const uint8_t ACMD23 = 0X17;
/** SD_SEND_OP_COMD - Sends host capacity support information and
activates the card's initialization process */
uint8_t const ACMD41 = 0X29;
const uint8_t ACMD41 = 0X29;
//==============================================================================
/** status for card in the ready state */
uint8_t const R1_READY_STATE = 0X00;
const uint8_t R1_READY_STATE = 0X00;
/** status for card in the idle state */
uint8_t const R1_IDLE_STATE = 0X01;
const uint8_t R1_IDLE_STATE = 0X01;
/** status bit for illegal command */
uint8_t const R1_ILLEGAL_COMMAND = 0X04;
const uint8_t R1_ILLEGAL_COMMAND = 0X04;
/** start data token for read or write single block*/
uint8_t const DATA_START_BLOCK = 0XFE;
const uint8_t DATA_START_BLOCK = 0XFE;
/** stop token for write multiple blocks*/
uint8_t const STOP_TRAN_TOKEN = 0XFD;
const uint8_t STOP_TRAN_TOKEN = 0XFD;
/** start data token for write multiple blocks*/
uint8_t const WRITE_MULTIPLE_TOKEN = 0XFC;
const uint8_t WRITE_MULTIPLE_TOKEN = 0XFC;
/** mask for data response tokens after a write block operation */
uint8_t const DATA_RES_MASK = 0X1F;
const uint8_t DATA_RES_MASK = 0X1F;
/** write data accepted token */
uint8_t const DATA_RES_ACCEPTED = 0X05;
const uint8_t DATA_RES_ACCEPTED = 0X05;
//==============================================================================
/**
* \class CID

+ 0
- 411
SdFat/src/SdSpiCard/SdSpi.h Vedi File

@@ -1,411 +0,0 @@
/* Arduino SdSpi Library
* Copyright (C) 2013 by William Greiman
*
* This file is part of the Arduino SdSpi Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino SdSpi Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
/**
* \file
* \brief SdSpi class for V2 SD/SDHC cards
*/
#ifndef SdSpi_h
#define SdSpi_h
#include "SystemInclude.h"
#include "SdFatConfig.h"
//------------------------------------------------------------------------------
/**
* \class SdSpiBase
* \brief Virtual SPI class for access to SD and SDHC flash memory cards.
*/
class SdSpiBase {
public:
/** Initialize the SPI bus.
*
* \param[in] chipSelectPin SD card chip select pin.
*/
virtual void begin(uint8_t chipSelectPin) = 0;
/** Set SPI options for access to SD/SDHC cards.
*
* \param[in] divisor SCK clock divider relative to the system clock.
*/
virtual void beginTransaction(uint8_t divisor);
/**
* End SPI transaction.
*/
virtual void endTransaction();
/** Receive a byte.
*
* \return The byte.
*/
virtual uint8_t receive() = 0;
/** 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.
*/
virtual uint8_t receive(uint8_t* buf, size_t n) = 0;
/** Send a byte.
*
* \param[in] data Byte to send
*/
virtual void send(uint8_t data) = 0;
/** Send multiple bytes.
*
* \param[in] buf Buffer for data to be sent.
* \param[in] n Number of bytes to send.
*/
virtual void send(const uint8_t* buf, size_t n) = 0;
};
//------------------------------------------------------------------------------
/**
* \class SdSpi
* \brief SPI class for access to SD and SDHC flash memory cards.
*/
#if SD_SPI_CONFIGURATION >= 3
class SdSpi : public SdSpiBase {
#else // SD_SPI_CONFIGURATION >= 3
class SdSpi {
#endif // SD_SPI_CONFIGURATION >= 3
public:
/** Initialize the SPI bus.
*
* \param[in] chipSelectPin SD card chip select pin.
*/
void begin(uint8_t chipSelectPin);
/** Set SPI options for access to SD/SDHC cards.
*
* \param[in] divisor SCK clock divider relative to the system clock.
*/
void beginTransaction(uint8_t divisor);
/**
* End SPI transaction
*/
void endTransaction();
/** Receive a byte.
*
* \return The byte.
*/
uint8_t receive();
/** 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);
/** Send a byte.
*
* \param[in] data Byte to send
*/
void send(uint8_t 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);
/** \return true - uses SPI transactions */
#if IMPLEMENT_SPI_INTERFACE_SELECTION
void setSpiIf(uint8_t spiIf) {
m_spiIf = spiIf;
}
private:
uint8_t m_spiIf;
#endif // IMPLEMENT_SPI_INTERFACE_SELECTION
};
//------------------------------------------------------------------------------
/**
* \class SdSpiLib
* \brief Arduino SPI library class for access to SD and SDHC flash
* memory cards.
*/
#if SD_SPI_CONFIGURATION >= 3
class SdSpiLib : public SdSpiBase {
#else // SD_SPI_CONFIGURATION >= 3
class SdSpiLib {
#endif // SD_SPI_CONFIGURATION >= 3
public:
/** Initialize the SPI bus.
*
* \param[in] chipSelectPin SD card chip select pin.
*/
void begin(uint8_t chipSelectPin) {
pinMode(chipSelectPin, OUTPUT);
digitalWrite(chipSelectPin, HIGH);
SPI.begin();
}
/** Set SPI options for access to SD/SDHC cards.
*
* \param[in] divisor SCK clock divider relative to the system clock.
*/
void beginTransaction(uint8_t divisor) {
#if ENABLE_SPI_TRANSACTIONS
SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
#else // ENABLE_SPI_TRANSACTIONS
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
#endif // ENABLE_SPI_TRANSACTIONS
#ifndef SPI_CLOCK_DIV128
SPI.setClockDivider(divisor);
#else // SPI_CLOCK_DIV128
int v;
if (divisor <= 2) {
v = SPI_CLOCK_DIV2;
} else if (divisor <= 4) {
v = SPI_CLOCK_DIV4;
} else if (divisor <= 8) {
v = SPI_CLOCK_DIV8;
} else if (divisor <= 16) {
v = SPI_CLOCK_DIV16;
} else if (divisor <= 32) {
v = SPI_CLOCK_DIV32;
} else if (divisor <= 64) {
v = SPI_CLOCK_DIV64;
} else {
v = SPI_CLOCK_DIV128;
}
SPI.setClockDivider(v);
#endif // SPI_CLOCK_DIV128
}
/**
* End SPI transaction.
*/
void endTransaction() {
#if ENABLE_SPI_TRANSACTIONS
SPI.endTransaction();
#endif // ENABLE_SPI_TRANSACTIONS
}
/** 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] 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] = SPI.transfer(0XFF);
}
return 0;
}
/** Send a byte.
*
* \param[in] b Byte to send
*/
void send(uint8_t b) {
SPI.transfer(b);
}
/** 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++) {
SPI.transfer(buf[i]);
}
}
};
//------------------------------------------------------------------------------
#if SD_SPI_CONFIGURATION > 1 || defined(DOXYGEN)
#ifdef ARDUINO
#include "SoftSPI.h"
#elif defined(PLATFORM_ID) // Only defined if a Particle device
#include "SoftSPIParticle.h"
#endif // ARDUINO
/**
* \class SdSpiSoft
* \brief Software SPI class for access to SD and SDHC flash memory cards.
*/
template<uint8_t MisoPin, uint8_t MosiPin, uint8_t SckPin>
class SdSpiSoft : public SdSpiBase {
public:
/** Initialize the SPI bus.
*
* \param[in] chipSelectPin SD card chip select pin.
*/
void begin(uint8_t chipSelectPin) {
pinMode(chipSelectPin, OUTPUT);
digitalWrite(chipSelectPin, HIGH);
m_spi.begin();
}
/**
* Initialize hardware SPI - dummy for soft SPI
* \param[in] divisor SCK divisor - ignored.
*/
void beginTransaction(uint8_t divisor) {
(void)divisor;
}
/**
* End SPI transaction - dummy for soft SPI
*/
void endTransaction() {}
/** Receive a byte.
*
* \return The byte.
*/
uint8_t receive() {
return m_spi.receive();
}
/** 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] = receive();
}
return 0;
}
/** Send a byte.
*
* \param[in] data Byte to send
*/
void send(uint8_t data) {
m_spi.send(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++) {
send(buf[i]);
}
}

private:
SoftSPI<MisoPin, MosiPin, SckPin, 0> m_spi;
};
#endif // SD_SPI_CONFIGURATION > 1 || defined(DOXYGEN)
//------------------------------------------------------------------------------
#if SD_SPI_CONFIGURATION == 2
/** Default is software SPI. */
typedef SdSpiSoft<SOFT_SPI_MISO_PIN, SOFT_SPI_MOSI_PIN, SOFT_SPI_SCK_PIN>
SpiDefault_t;
#elif SD_SPI_CONFIGURATION == 1 || !SD_HAS_CUSTOM_SPI
/** Default is Arduino library SPI. */
typedef SdSpiLib SpiDefault_t;
#else // SpiDefault_t
/** Default is custom fast SPI. */
typedef SdSpi SpiDefault_t;
#endif // SpiDefault_t
//------------------------------------------------------------------------------
// Use of in-line for AVR to save flash.
#ifdef __AVR__
//------------------------------------------------------------------------------
inline void SdSpi::begin(uint8_t chipSelectPin) {
#ifdef __AVR_ATmega328P__
// Save a few bytes for 328 CPU - gcc optimizes single bit '|' to sbi.
PORTB |= 1 << 2; // SS high
DDRB |= 1 << 2; // SS output mode
DDRB |= 1 << 3; // MOSI output mode
DDRB |= 1 << 5; // SCK output mode
#else // __AVR_ATmega328P__

// set SS high - may be chip select for another SPI device
digitalWrite(SS, HIGH);

// SS must be in output mode even it is not chip select
pinMode(SS, OUTPUT);
pinMode(MOSI, OUTPUT);
pinMode(SCK, OUTPUT);
#endif // __AVR_ATmega328P__
pinMode(chipSelectPin, OUTPUT);
digitalWrite(chipSelectPin, HIGH);
}
//------------------------------------------------------------------------------
inline void SdSpi::beginTransaction(uint8_t divisor) {
#if ENABLE_SPI_TRANSACTIONS
SPI.beginTransaction(SPISettings());
#endif // ENABLE_SPI_TRANSACTIONS
uint8_t b = 2;
uint8_t r = 0;

// See AVR processor documentation.
for (; divisor > b && r < 7; b <<= 1, r += r < 5 ? 1 : 2) {}
SPCR = (1 << SPE) | (1 << MSTR) | (r >> 1);
SPSR = r & 1 ? 0 : 1 << SPI2X;
}
//------------------------------------------------------------------------------
inline void SdSpi::endTransaction() {
#if ENABLE_SPI_TRANSACTIONS
SPI.endTransaction();
#endif // ENABLE_SPI_TRANSACTIONS
}
//------------------------------------------------------------------------------
inline uint8_t SdSpi::receive() {
SPDR = 0XFF;
while (!(SPSR & (1 << SPIF))) {}
return SPDR;
}
//------------------------------------------------------------------------------
inline uint8_t SdSpi::receive(uint8_t* buf, size_t n) {
if (n-- == 0) {
return 0;
}
SPDR = 0XFF;
for (size_t i = 0; i < n; i++) {
while (!(SPSR & (1 << SPIF))) {}
uint8_t b = SPDR;
SPDR = 0XFF;
buf[i] = b;
}
while (!(SPSR & (1 << SPIF))) {}
buf[n] = SPDR;
return 0;
}
//------------------------------------------------------------------------------
inline void SdSpi::send(uint8_t data) {
SPDR = data;
while (!(SPSR & (1 << SPIF))) {}
}
//------------------------------------------------------------------------------
inline void SdSpi::send(const uint8_t* buf , size_t n) {
if (n == 0) {
return;
}
SPDR = buf[0];
if (n > 1) {
uint8_t b = buf[1];
size_t i = 2;
while (1) {
while (!(SPSR & (1 << SPIF))) {}
SPDR = b;
if (i == n) {
break;
}
b = buf[i++];
}
}
while (!(SPSR & (1 << SPIF))) {}
}
#endif // __AVR__
#endif // SdSpi_h

+ 75
- 0
SdFat/src/SdSpiCard/SdSpiBaseDriver.h Vedi File

@@ -0,0 +1,75 @@
/* Arduino SdSpiCard Library
* Copyright (C) 2016 by William Greiman
*
* This file is part of the Arduino SdSpiCard Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino SdSpiCard Library. If not, see
* <http://www.gnu.org/licenses/>.
*/

#ifndef SdSpiBaseDriver_h
#define SdSpiBaseDriver_h
/**
* \class SdSpiBaseDriver
* \brief SPI base driver.
*/
class SdSpiBaseDriver {
public:
/** Set SPI options for access to SD/SDHC cards.
*
*/
virtual void activate() = 0;
/** Initialize the SPI bus.
*
* \param[in] chipSelectPin SD card chip select pin.
*/
virtual void begin(uint8_t chipSelectPin) = 0;
/**
* End SPI transaction.
*/
virtual void deactivate() = 0;
/** Receive a byte.
*
* \return The byte.
*/
virtual uint8_t receive() = 0;
/** 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.
*/
virtual uint8_t receive(uint8_t* buf, size_t n) = 0;
/** Send a byte.
*
* \param[in] data Byte to send
*/
virtual void send(uint8_t data) = 0;
/** Send multiple bytes.
*
* \param[in] buf Buffer for data to be sent.
* \param[in] n Number of bytes to send.
*/
virtual void send(const uint8_t* buf, size_t n) = 0;
/** Set CS low. */
virtual void select() = 0;
/** Save SPI settings.
* \param[in] spiSettings SPI speed, mode, and bit order.
*/
virtual void setSpiSettings(SPISettings spiSettings) = 0;
/** Set CS high. */
virtual void unselect() = 0;
};
#endif // SdSpiBaseDriver_h

+ 133
- 139
SdFat/src/SdSpiCard/SdSpiCard.cpp Vedi File

@@ -18,7 +18,6 @@
* <http://www.gnu.org/licenses/>.
*/
#include "SdSpiCard.h"
#include "SdSpi.h"
// debug trace macro
#define SD_TRACE(m, b)
// #define SD_TRACE(m, b) Serial.print(m);Serial.println(b);
@@ -44,7 +43,7 @@ static uint8_t CRC7(const uint8_t* data, uint8_t n) {
}
//------------------------------------------------------------------------------
#if USE_SD_CRC == 1
// slower CRC-CCITT
// Shift based CRC-CCITT
// uses the x^16,x^12,x^5,x^1 polynomial.
static uint16_t CRC_CCITT(const uint8_t *data, size_t n) {
uint16_t crc = 0;
@@ -59,7 +58,7 @@ static uint16_t CRC_CCITT(const uint8_t *data, size_t n) {
}
#elif USE_SD_CRC > 1 // CRC_CCITT
//------------------------------------------------------------------------------
// faster CRC-CCITT
// Table based CRC-CCITT
// uses the x^16,x^12,x^5,x^1 polynomial.
#ifdef __AVR__
static const uint16_t crctab[] PROGMEM = {
@@ -115,29 +114,24 @@ static uint16_t CRC_CCITT(const uint8_t* data, size_t n) {
//==============================================================================
// SdSpiCard member functions
//------------------------------------------------------------------------------
bool SdSpiCard::begin(m_spi_t* spi, uint8_t chipSelectPin, uint8_t sckDivisor) {
bool SdSpiCard::begin(SdSpiDriver* spiDriver) {
m_spiActive = false;
m_errorCode = m_type = 0;
m_spi = spi;
m_chipSelectPin = chipSelectPin;
// 16-bit init start time allows over a minute
unsigned t0 = (unsigned)millis();
m_spiDriver = spiDriver;
uint16_t t0 = curTimeMS();
uint32_t arg;

// initialize SPI bus and chip select pin.
spiBegin(m_chipSelectPin);

// set SCK rate for initialization commands.
m_sckDivisor = SPI_SCK_INIT_DIVISOR;
spiBeginTransaction(m_sckDivisor);
spiStart();

// must supply min of 74 clock cycles with CS high.
spiUnselect();
for (uint8_t i = 0; i < 10; i++) {
spiSend(0XFF);
}
spiEndTransaction();
spiSelect();
// command to go idle in SPI mode
while (cardCommand(CMD0, 0) != R1_IDLE_STATE) {
if (((unsigned)millis() - t0) > SD_INIT_TIMEOUT) {
if (isTimedOut(t0, SD_INIT_TIMEOUT)) {
error(SD_CARD_ERROR_CMD0);
goto fail;
}
@@ -161,7 +155,7 @@ bool SdSpiCard::begin(m_spi_t* spi, uint8_t chipSelectPin, uint8_t sckDivisor) {
type(SD_CARD_TYPE_SD2);
break;
}
if (((unsigned)millis() - t0) > SD_INIT_TIMEOUT) {
if (isTimedOut(t0, SD_INIT_TIMEOUT)) {
error(SD_CARD_ERROR_CMD8);
goto fail;
}
@@ -171,7 +165,7 @@ bool SdSpiCard::begin(m_spi_t* spi, uint8_t chipSelectPin, uint8_t sckDivisor) {

while (cardAcmd(ACMD41, arg) != R1_READY_STATE) {
// check for timeout
if (((unsigned)millis() - t0) > SD_INIT_TIMEOUT) {
if (isTimedOut(t0, SD_INIT_TIMEOUT)) {
error(SD_CARD_ERROR_ACMD41);
goto fail;
}
@@ -190,43 +184,43 @@ bool SdSpiCard::begin(m_spi_t* spi, uint8_t chipSelectPin, uint8_t sckDivisor) {
spiReceive();
}
}
chipSelectHigh();
m_sckDivisor = sckDivisor;
spiStop();
return true;

fail:
chipSelectHigh();
spiStop();
return false;
}
//------------------------------------------------------------------------------
// send command and return error code. Return zero for OK
uint8_t SdSpiCard::cardCommand(uint8_t cmd, uint32_t arg) {
// select card
if (!m_selected) {
chipSelectLow();
if (!m_spiActive) {
spiStart();
}
// wait if busy
waitNotBusy(SD_WRITE_TIMEOUT);

uint8_t *pa = reinterpret_cast<uint8_t *>(&arg);

#if USE_SD_CRC
// form message
uint8_t buf[6];
buf[0] = (uint8_t)0x40U | cmd;
buf[1] = (uint8_t)(arg >> 24U);
buf[2] = (uint8_t)(arg >> 16U);
buf[3] = (uint8_t)(arg >> 8U);
buf[4] = (uint8_t)arg;

uint8_t d[6] = {cmd , pa[3], pa[2], pa[1], pa[0]};
d[0] |= 0X40;
// add crc
d[5] = CRC7(d, 5);
// add CRC
buf[5] = CRC7(buf, 5);

// send message
for (uint8_t k = 0; k < 6; k++) {
spiSend(d[k]);
}
spiSend(buf, 6);
#else // USE_SD_CRC
// send command
spiSend(cmd | 0x40);

// send argument
uint8_t *pa = reinterpret_cast<uint8_t *>(&arg);
for (int8_t i = 3; i >= 0; i--) {
spiSend(pa[i]);
}
@@ -268,35 +262,6 @@ uint32_t SdSpiCard::cardSize() {
}
}
//------------------------------------------------------------------------------
void SdSpiCard::chipSelectHigh() {
if (!m_selected) {
SD_CS_DBG("chipSelectHigh error");
return;
}
digitalWrite(m_chipSelectPin, HIGH);
// insure MISO goes high impedance
spiSend(0XFF);
spiEndTransaction();
m_selected = false;
}
//------------------------------------------------------------------------------
void SdSpiCard::chipSelectLow() {
#if WDT_YIELD_TIME_MICROS
static uint32_t last;
if ((micros() - last) > WDT_YIELD_TIME_MICROS) {
SysCall::yield();
last = micros();
}
#endif // WDT_YIELD_TIME_MICROS
if (m_selected) {
SD_CS_DBG("chipSelectLow error");
return;
}
spiBeginTransaction(m_sckDivisor);
digitalWrite(m_chipSelectPin, LOW);
m_selected = true;
}
//------------------------------------------------------------------------------
bool SdSpiCard::erase(uint32_t firstBlock, uint32_t lastBlock) {
csd_t csd;
if (!readCSD(&csd)) {
@@ -326,11 +291,11 @@ bool SdSpiCard::erase(uint32_t firstBlock, uint32_t lastBlock) {
error(SD_CARD_ERROR_ERASE_TIMEOUT);
goto fail;
}
chipSelectHigh();
spiStop();
return true;

fail:
chipSelectHigh();
spiStop();
return false;
}
//------------------------------------------------------------------------------
@@ -341,21 +306,33 @@ bool SdSpiCard::eraseSingleBlockEnable() {
//------------------------------------------------------------------------------
bool SdSpiCard::isBusy() {
bool rtn = true;
bool selected = m_selected;
chipSelectLow();

bool spiActive = m_spiActive;
if (!spiActive) {
spiStart();
}
for (uint8_t i = 0; i < 8; i++) {
if (0XFF == spiReceive()) {
rtn = false;
break;
}
}
if (!selected) {
chipSelectHigh();
if (!spiActive) {
spiStop();
}
return rtn;
}
//------------------------------------------------------------------------------
bool SdSpiCard::isTimedOut(uint16_t startMS, uint16_t timeoutMS) {
#if WDT_YIELD_TIME_MICROS
static uint32_t last;
if ((micros() - last) > WDT_YIELD_TIME_MICROS) {
SysCall::yield();
last = micros();
}
#endif // WDT_YIELD_TIME_MICROS
return (curTimeMS() - startMS) > timeoutMS;
}
//------------------------------------------------------------------------------
bool SdSpiCard::readBlock(uint32_t blockNumber, uint8_t* dst) {
SD_TRACE("RB", blockNumber);
// use address if not SDHC card
@@ -369,11 +346,11 @@ bool SdSpiCard::readBlock(uint32_t blockNumber, uint8_t* dst) {
if (!readData(dst, 512)) {
goto fail;
}
chipSelectHigh();
spiStop();
return true;

fail:
chipSelectHigh();
spiStop();
return false;
}
//------------------------------------------------------------------------------
@@ -390,15 +367,7 @@ bool SdSpiCard::readBlocks(uint32_t block, uint8_t* dst, size_t count) {
}
//------------------------------------------------------------------------------
bool SdSpiCard::readData(uint8_t *dst) {
bool selected = m_selected;
chipSelectLow();
if (!readData(dst, 512)) {
return false;
}
if (!selected) {
chipSelectHigh();
}
return true;
return readData(dst, 512);
}
//------------------------------------------------------------------------------
bool SdSpiCard::readData(uint8_t* dst, size_t count) {
@@ -406,9 +375,9 @@ bool SdSpiCard::readData(uint8_t* dst, size_t count) {
uint16_t crc;
#endif // USE_SD_CRC
// wait for start block token
unsigned t0 = millis();
uint16_t t0 = curTimeMS();
while ((m_status = spiReceive()) == 0XFF) {
if (((unsigned)millis() - t0) > SD_READ_TIMEOUT) {
if (isTimedOut(t0, SD_READ_TIMEOUT)) {
error(SD_CARD_ERROR_READ_TIMEOUT);
goto fail;
}
@@ -438,7 +407,7 @@ bool SdSpiCard::readData(uint8_t* dst, size_t count) {
return true;

fail:
chipSelectHigh();
spiStop();
return false;
}
//------------------------------------------------------------------------------
@@ -452,11 +421,11 @@ bool SdSpiCard::readOCR(uint32_t* ocr) {
p[3 - i] = spiReceive();
}

chipSelectHigh();
spiStop();
return true;

fail:
chipSelectHigh();
spiStop();
return false;
}
//------------------------------------------------------------------------------
@@ -467,10 +436,14 @@ bool SdSpiCard::readRegister(uint8_t cmd, void* buf) {
error(SD_CARD_ERROR_READ_REG);
goto fail;
}
return readData(dst, 16);
if (!readData(dst, 16)) {
goto fail;
}
spiStop();
return true;

fail:
chipSelectHigh();
spiStop();
return false;
}
//------------------------------------------------------------------------------
@@ -483,67 +456,81 @@ bool SdSpiCard::readStart(uint32_t blockNumber) {
error(SD_CARD_ERROR_CMD18);
goto fail;
}
// spiStop();
return true;

fail:
chipSelectHigh();
spiStop();
return false;
}
//------------------------------------------------------------------------------
bool SdSpiCard::readStop() {
if (cardCommand(CMD12, 0)) {
error(SD_CARD_ERROR_CMD12);
//-----------------------------------------------------------------------------
bool SdSpiCard::readStatus(uint8_t* status) {
// retrun is R2 so read extra status byte.
if (cardAcmd(ACMD13, 0) || spiReceive()) {
error(SD_CARD_ERROR_ACMD13);
goto fail;
}
chipSelectHigh();
if (!readData(status, 64)) {
goto fail;
}
spiStop();
return true;

fail:
chipSelectHigh();
spiStop();
return false;
}
//------------------------------------------------------------------------------
bool SdSpiCard::sendCmd6(uint32_t arg, uint8_t* status) {
if (cardCommand(CMD6, arg)) {
error(SD_CARD_ERROR_CMD6);
goto fail;
//-----------------------------------------------------------------------------
void SdSpiCard::spiStart() {
if (!m_spiActive) {
spiActivate();
spiSelect();
m_spiActive = true;
}
if (!readData(status, 64)) {
}
//-----------------------------------------------------------------------------
void SdSpiCard::spiStop() {
if (m_spiActive) {
spiUnselect();
spiSend(0XFF);
spiDeactivate();
m_spiActive = false;
}
}
//------------------------------------------------------------------------------
bool SdSpiCard::readStop() {
if (cardCommand(CMD12, 0)) {
error(SD_CARD_ERROR_CMD12);
goto fail;
}
chipSelectHigh();
spiStop();
return true;

fail:
chipSelectHigh();
spiStop();
return false;
}
//------------------------------------------------------------------------------
bool SdSpiCard::setHighSpeedMode(uint8_t divisor) {
uint8_t status[64];
uint8_t saveDivisor = m_sckDivisor;
setSckDivisor(128);
if (!sendCmd6(0X00FFFFFF, status) || (2 & status[13]) == 0 ||
!sendCmd6(0X80FFFFF1, status) || (status[16] & 0XF) != 1) {
setSckDivisor(saveDivisor);
return false;
}
setSckDivisor(divisor);
return true;
}
//------------------------------------------------------------------------------
// wait for card to go not busy
bool SdSpiCard::waitNotBusy(uint16_t timeoutMillis) {
unsigned t0 = millis();
bool SdSpiCard::waitNotBusy(uint16_t timeoutMS) {
uint16_t t0 = curTimeMS();
#if WDT_YIELD_TIME_MICROS
// Call isTimedOut first to insure yield is called.
while (!isTimedOut(t0, timeoutMS)) {
if (spiReceive() == 0XFF) {
return true;
}
}
return false;
#else // WDT_YIELD_TIME_MICROS
// Check not busy first since yield is not called in isTimedOut.
while (spiReceive() != 0XFF) {
if (((unsigned)millis() - t0) >= timeoutMillis) {
goto fail;
if (isTimedOut(t0, timeoutMS)) {
return false;
}
}
return true;

fail:
return false;
#endif // WDT_YIELD_TIME_MICROS
}
//------------------------------------------------------------------------------
bool SdSpiCard::writeBlock(uint32_t blockNumber, const uint8_t* src) {
@@ -574,16 +561,16 @@ bool SdSpiCard::writeBlock(uint32_t blockNumber, const uint8_t* src) {
}
#endif // CHECK_PROGRAMMING

chipSelectHigh();
spiStop();
return true;

fail:
chipSelectHigh();
spiStop();
return false;
}
//------------------------------------------------------------------------------
bool SdSpiCard::writeBlocks(uint32_t block, const uint8_t* src, size_t count) {
if (!writeStart(block, count)) {
if (!writeStart(block)) {
goto fail;
}
for (size_t b = 0; b < count; b++, src += 512) {
@@ -594,13 +581,11 @@ bool SdSpiCard::writeBlocks(uint32_t block, const uint8_t* src, size_t count) {
return writeStop();

fail:
chipSelectHigh();
spiStop();
return false;
}
//------------------------------------------------------------------------------
bool SdSpiCard::writeData(const uint8_t* src) {
bool selected = m_selected;
chipSelectLow();
// wait for previous write to finish
if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
error(SD_CARD_ERROR_WRITE_TIMEOUT);
@@ -609,13 +594,10 @@ bool SdSpiCard::writeData(const uint8_t* src) {
if (!writeData(WRITE_MULTIPLE_TOKEN, src)) {
goto fail;
}
if (!selected) {
chipSelectHigh();
}
return true;

fail:
chipSelectHigh();
spiStop();
return false;
}
//------------------------------------------------------------------------------
@@ -639,7 +621,23 @@ bool SdSpiCard::writeData(uint8_t token, const uint8_t* src) {
return true;

fail:
chipSelectHigh();
spiStop();
return false;
}
//------------------------------------------------------------------------------
bool SdSpiCard::writeStart(uint32_t blockNumber) {
// use address if not SDHC card
if (type() != SD_CARD_TYPE_SDHC) {
blockNumber <<= 9;
}
if (cardCommand(CMD25, blockNumber)) {
error(SD_CARD_ERROR_CMD25);
goto fail;
}
return true;

fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
@@ -661,24 +659,20 @@ bool SdSpiCard::writeStart(uint32_t blockNumber, uint32_t eraseCount) {
return true;

fail:
chipSelectHigh();
spiStop();
return false;
}
//------------------------------------------------------------------------------
bool SdSpiCard::writeStop() {
chipSelectLow();
if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
goto fail;
}
spiSend(STOP_TRAN_TOKEN);
if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
goto fail;
}
chipSelectHigh();
spiStop();
return true;

fail:
error(SD_CARD_ERROR_STOP_TRAN);
chipSelectHigh();
spiStop();
return false;
}

+ 51
- 103
SdFat/src/SdSpiCard/SdSpiCard.h Vedi File

@@ -23,10 +23,10 @@
* \file
* \brief SdSpiCard class for V2 SD/SDHC cards
*/
#include "SystemInclude.h"
#include "SdFatConfig.h"
#include <stddef.h>
#include "SysCall.h"
#include "SdInfo.h"
#include "SdSpi.h"
#include "SdSpiDriver.h"
//==============================================================================
/**
* \class SdSpiCard
@@ -34,23 +34,13 @@
*/
class SdSpiCard {
public:
/** typedef for SPI class. */
#if SD_SPI_CONFIGURATION < 3
typedef SpiDefault_t m_spi_t;
#else // SD_SPI_CONFIGURATION < 3
typedef SdSpiBase m_spi_t;
#endif // SD_SPI_CONFIGURATION < 3
/** Construct an instance of SdSpiCard. */
SdSpiCard() : m_selected(false),
m_errorCode(SD_CARD_ERROR_INIT_NOT_CALLED), m_type(0) {}
SdSpiCard() : m_errorCode(SD_CARD_ERROR_INIT_NOT_CALLED), m_type(0) {}
/** Initialize the SD card.
* \param[in] spi SPI object.
* \param[in] chipSelectPin SD chip select pin.
* \param[in] sckDivisor SPI clock divisor.
* \param[in] spiDriver SPI driver for card.
* \return true for success else false.
*/
bool begin(m_spi_t* spi, uint8_t chipSelectPin = SS,
uint8_t sckDivisor = SPI_FULL_SPEED);
bool begin(SdSpiDriver* spiDriver);
/**
* Determine the size of an SD flash memory card.
*
@@ -58,16 +48,6 @@ class SdSpiCard {
* or zero if an error occurs.
*/
uint32_t cardSize();
/** Set the SD chip select pin high, send a dummy byte, and call SPI endTransaction.
*
* This function should only be called by programs doing raw I/O to the SD.
*/
void chipSelectHigh();
/** Set the SD chip select pin low and call SPI beginTransaction.
*
* This function should only be called by programs doing raw I/O to the SD.
*/
void chipSelectLow();
/** Erase a range of blocks.
*
* \param[in] firstBlock The address of the first block in the range.
@@ -178,40 +158,18 @@ class SdSpiCard {
* the value false is returned for failure.
*/
bool readStart(uint32_t blockNumber);
/** Return the 64 byte card status
* \param[out] status location for 64 status bytes.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readStatus(uint8_t* status);
/** End a read multiple blocks sequence.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readStop();
/** Return SCK divisor.
*
* \return Requested SCK divisor.
*/
uint8_t sckDivisor() {
return m_sckDivisor;
}
/** \return the SD chip select status, true if slected else false. */
bool selected() {return m_selected;}
/** Send CMD6 - Switch Function Command
*
* param[in] arg 32-bit argument to CMD6.
* param[out] status - 64 byte status returned by CMD6.
* \return true if the command was accepted else false.
*/
bool sendCmd6(uint32_t arg, uint8_t* status);
/** Set High Speed Bus Mode.
*
* param[in] divisor new value for SPI SCK divisor.
* \return true if successful else false.
*/
bool setHighSpeedMode(uint8_t divisor);
/** Set SCK divisor.
* param[in] sckDivisor value for divisor.
*/
void setSckDivisor(uint8_t sckDivisor) {
m_sckDivisor = sckDivisor;
}
/** Return the card type: SD V1, SD V2 or SDHC
* \return 0 - SD V1, 1 - SD V2, or 3 - SDHC.
*/
@@ -244,6 +202,18 @@ class SdSpiCard {
*/
bool writeData(const uint8_t* src);
/** Start a write multiple blocks sequence.
*
* \param[in] blockNumber Address of first block in sequence.
*
* \note This function is used with writeData() and writeStop()
* for optimized multiple block writes.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeStart(uint32_t blockNumber);

/** Start a write multiple blocks sequence with pre-erase.
*
* \param[in] blockNumber Address of first block in sequence.
* \param[in] eraseCount The number of blocks to be pre-erased.
@@ -261,6 +231,10 @@ class SdSpiCard {
* the value false is returned for failure.
*/
bool writeStop();
/** Set CS low and activate the card. */
void spiStart();
/** Set CS high and deactivate the card. */
void spiStop();

private:
// private functions
@@ -269,74 +243,48 @@ class SdSpiCard {
return cardCommand(cmd, arg);
}
uint8_t cardCommand(uint8_t cmd, uint32_t arg);
bool isTimedOut(uint16_t startMS, uint16_t timeoutMS);
bool readData(uint8_t* dst, size_t count);
bool readRegister(uint8_t cmd, void* buf);

void type(uint8_t value) {
m_type = value;
}
bool waitNotBusy(uint16_t timeoutMillis);

bool waitNotBusy(uint16_t timeoutMS);
bool writeData(uint8_t token, const uint8_t* src);
void spiBegin(uint8_t chipSelectPin) {
m_spi->begin(chipSelectPin);
}
void spiBeginTransaction(uint8_t spiDivisor) {
m_spi->beginTransaction(spiDivisor);
//---------------------------------------------------------------------------
// functions defined in SdSpiDriver.h
void spiActivate() {
m_spiDriver->activate();
}
void spiEndTransaction() {
m_spi->endTransaction();
void spiDeactivate() {
m_spiDriver->deactivate();
}
uint8_t spiReceive() {
return m_spi->receive();
return m_spiDriver->receive();
}
uint8_t spiReceive(uint8_t* buf, size_t n) {
return m_spi->receive(buf, n);
return m_spiDriver->receive(buf, n);
}
void spiSend(uint8_t data) {
m_spi->send(data);
m_spiDriver->send(data);
}
void spiSend(const uint8_t* buf, size_t n) {
m_spi->send(buf, n);
m_spiDriver->send(buf, n);
}
void spiSelect() {
m_spiDriver->select();
}
void spiUnselect() {
m_spiDriver->unselect();
}
m_spi_t* m_spi;
bool m_selected;
uint8_t m_chipSelectPin;
uint8_t m_errorCode;
uint8_t m_sckDivisor;
SdSpiDriver *m_spiDriver;
bool m_spiActive;
uint8_t m_status;
uint8_t m_type;
};
//==============================================================================
/**
* \class Sd2Card
* \brief Raw access to SD and SDHC card using default SPI library.
*/
class Sd2Card : public SdSpiCard {
public:
/** Initialize the SD card.
* \param[in] chipSelectPin SD chip select pin.
* \param[in] sckDivisor SPI clock divisor.
* \return true for success else false.
*/
bool begin(uint8_t chipSelectPin = SS, uint8_t sckDivisor = 2) {
return SdSpiCard::begin(&m_spi, chipSelectPin, sckDivisor);
}
/** Initialize the SD card. Obsolete form.
* \param[in] chipSelectPin SD chip select pin.
* \param[in] sckDivisor SPI clock divisor.
* \return true for success else false.
*/
bool init(uint8_t sckDivisor = 2, uint8_t chipSelectPin = SS) {
return begin(chipSelectPin, sckDivisor);
}

private:
bool begin(m_spi_t* spi, uint8_t chipSelectPin = SS,
uint8_t sckDivisor = SPI_FULL_SPEED) {
(void)spi;
(void)chipSelectPin;
(void)sckDivisor;
return false;
}
SpiDefault_t m_spi;
};
#endif // SpiCard_h

+ 0
- 110
SdFat/src/SdSpiCard/SdSpiParticle.cpp Vedi File

@@ -1,110 +0,0 @@
/* Arduino SdFat Library
* Copyright (C) 2016 by William Greiman
*
* This file is part of the Arduino SdFat Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino SdFat Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include "SdSpi.h"
#if defined(PLATFORM_ID)

static uint32_t bugDelay = 0; // fix for SPI DMA bug.

static volatile bool SPI_DMA_TransferCompleted = false;

static SPIClass* const spiPtr[] = {
&SPI
#if Wiring_SPI1
, &SPI1
#if Wiring_SPI2
, &SPI2
#endif // Wiring_SPI2
#endif // Wiring_SPI1
};
#if SPI_INTERFACE_COUNT == 1
const uint8_t m_spiIf = 0;
#endif
//-----------------------------------------------------------------------------
void SD_SPI_DMA_TransferComplete_Callback(void) {
SPI_DMA_TransferCompleted = true;
}
//------------------------------------------------------------------------------
void SdSpi::begin(uint8_t chipSelectPin) {
spiPtr[m_spiIf]->begin(chipSelectPin);
}
//------------------------------------------------------------------------------
void SdSpi::beginTransaction(uint8_t divisor) {
spiPtr[m_spiIf]->setBitOrder(MSBFIRST);
spiPtr[m_spiIf]->setDataMode(SPI_MODE0);
#ifndef SPI_CLOCK_DIV128
spiPtr[m_spiIf]->setClockDivider(divisor);
#else // SPI_CLOCK_DIV128
int v;
if (divisor <= 2) {
v = SPI_CLOCK_DIV2;
} else if (divisor <= 4) {
v = SPI_CLOCK_DIV4;
} else if (divisor <= 8) {
v = SPI_CLOCK_DIV8;
} else if (divisor <= 16) {
v = SPI_CLOCK_DIV16;
} else if (divisor <= 32) {
v = SPI_CLOCK_DIV32;
} else if (divisor <= 64) {
v = SPI_CLOCK_DIV64;
} else {
v = SPI_CLOCK_DIV128;
}
spiPtr[m_spiIf]->setClockDivider(v);
#endif // SPI_CLOCK_DIV128
// delay for SPI transfer done callback too soon bug.
bugDelay = 24*divisor*(1 + m_spiIf)/60;
}
//-----------------------------------------------------------------------------
void SdSpi::endTransaction() {
}
//-----------------------------------------------------------------------------
/** SPI receive a byte */
uint8_t SdSpi::receive() {
return spiPtr[m_spiIf]->transfer(0xFF);
}
//-----------------------------------------------------------------------------
uint8_t SdSpi::receive(uint8_t* buf, size_t n) {
SPI_DMA_TransferCompleted = false;
spiPtr[m_spiIf]->transfer(0, buf, n, SD_SPI_DMA_TransferComplete_Callback);
while (!SPI_DMA_TransferCompleted) {}
if (bugDelay) {
delayMicroseconds(bugDelay);
}
return 0;
}
//-----------------------------------------------------------------------------
/** SPI send a byte */
void SdSpi::send(uint8_t b) {
spiPtr[m_spiIf]->transfer(b);
}
//-----------------------------------------------------------------------------
void SdSpi::send(const uint8_t* buf , size_t n) {
SPI_DMA_TransferCompleted = false;

spiPtr[m_spiIf]->transfer(const_cast<uint8_t*>(buf), 0, n,
SD_SPI_DMA_TransferComplete_Callback);

while (!SPI_DMA_TransferCompleted) {}
if (bugDelay) {
delayMicroseconds(bugDelay);
}
}
#endif // defined(PLATFORM_ID)

+ 359
- 0
SdFat/src/SdSpiDriver.h Vedi File

@@ -0,0 +1,359 @@
/* SdFat Library
* Copyright (C) 2016 by William Greiman
*
* This file is part of the FatLib Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the FatLib Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
/**
* \file
* \brief SpiDriver classes
*/
#ifndef SdSpiDriver_h
#define SdSpiDriver_h
#include <Arduino.h>
#include "SPI.h"
#include "SdSpiCard/SdSpiBaseDriver.h"
#include "SdFatConfig.h"
//-----------------------------------------------------------------------------
/**
* \class SdSpiLibDriver
* \brief SdSpiLibDriver - use standard SPI library.
*/
#if ENABLE_SOFTWARE_SPI_CLASS
class SdSpiLibDriver : public SdSpiBaseDriver {
#else // ENABLE_SOFTWARE_SPI_CLASS
class SdSpiLibDriver {
#endif // ENABLE_SOFTWARE_SPI_CLASS
public:
/** Activate SPI hardware. */
void activate() {
SPI.beginTransaction(m_spiSettings);
}
/** Deactivate SPI hardware. */
void deactivate() {
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);
SPI.begin();
}
/** 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] 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] = 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] n Number of bytes to send.
*/
void send(const uint8_t* buf, size_t n) {
for (size_t i = 0; i < n; i++) {
SPI.transfer(buf[i]);
}
}
/** Set CS low. */
void select() {
digitalWrite(m_csPin, LOW);
}
/** Save SPISettings.
*
* \param[in] spiSettings SPI speed, mode, and byte order.
*/
void setSpiSettings(SPISettings spiSettings) {
m_spiSettings = spiSettings;
}
/** Set CS high. */
void unselect() {
digitalWrite(m_csPin, HIGH);
}

private:
SPISettings m_spiSettings;
uint8_t m_csPin;
};
//-----------------------------------------------------------------------------
/**
* \class SdSpiAltDriver
* \brief Optimized SPI class for access to SD and SDHC flash memory cards.
*/
#if ENABLE_SOFTWARE_SPI_CLASS
class SdSpiAltDriver : public SdSpiBaseDriver {
#else // ENABLE_SOFTWARE_SPI_CLASS
class SdSpiAltDriver {
#endif // ENABLE_SOFTWARE_SPI_CLASS
public:
/** Activate SPI hardware. */
void activate();
/** Deactivate SPI hardware. */
void deactivate();
/** Initialize the SPI bus.
*
* \param[in] csPin SD card chip select pin.
*/
void begin(uint8_t csPin);
/** Receive a byte.
*
* \return The byte.
*/
uint8_t receive();
/** 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);
/** Send a byte.
*
* \param[in] data Byte to send
*/
void send(uint8_t 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);
/** Set CS low. */
void select() {
digitalWrite(m_csPin, LOW);
}
/** Save SPISettings.
*
* \param[in] spiSettings SPI speed, mode, and byte order.
*/
void setSpiSettings(SPISettings spiSettings) {
m_spiSettings = spiSettings;
}
/** Set CS high. */
void unselect() {
digitalWrite(m_csPin, HIGH);
}
#if IMPLEMENT_SPI_PORT_SELECTION || defined(DOXYGEN)
/** Set SPI port number.
* \param[in] portNumber Hardware SPI port number.
*/
void setPort(uint8_t portNumber);

private:
uint8_t m_spiPort;
#else // IMPLEMENT_SPI_PORT_SELECTION
private:
#endif // IMPLEMENT_SPI_PORT_SELECTION
SPISettings m_spiSettings;
uint8_t m_csPin;
};
//------------------------------------------------------------------------------
#if ENABLE_SOFTWARE_SPI_CLASS || defined(DOXYGEN)
#ifdef ARDUINO
#include "AltSpiDrivers/SoftSPI.h"
#elif defined(PLATFORM_ID) // Only defined if a Particle device
#include "SoftSPIParticle.h"
#endif // ARDUINO
/**
* \class SdSpiSoftDriver
* \brief Software SPI class for access to SD and SDHC flash memory cards.
*/
template<uint8_t MisoPin, uint8_t MosiPin, uint8_t SckPin>
class SdSpiSoftDriver : public SdSpiBaseDriver {
public:
/** Dummy activate SPI hardware for software SPI */
void activate() {}
/** Dummy deactivate SPI hardware for software SPI */
void deactivate() {}
/** Initialize the SPI bus.
*
* \param[in] csPin SD card chip select pin.
*/
void begin(uint8_t csPin) {
m_csPin = csPin;
pinMode(m_csPin, OUTPUT);
digitalWrite(m_csPin, HIGH);
m_spi.begin();
}
/** Receive a byte.
*
* \return The byte.
*/
uint8_t receive() {
return m_spi.receive();
}
/** 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] = receive();
}
return 0;
}
/** Send a byte.
*
* \param[in] data Byte to send
*/
void send(uint8_t data) {
m_spi.send(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++) {
send(buf[i]);
}
}
/** Set CS low. */
void select() {
digitalWrite(m_csPin, LOW);
}
/** Save SPISettings.
*
* \param[in] spiSettings SPI speed, mode, and byte order.
*/
void setSpiSettings(SPISettings spiSettings) {
(void)spiSettings;
}
/** Set CS high. */
void unselect() {
digitalWrite(m_csPin, HIGH);
}

private:
uint8_t m_csPin;
SoftSPI<MisoPin, MosiPin, SckPin, 0> m_spi;
};
#endif // ENABLE_SOFTWARE_SPI_CLASS || defined(DOXYGEN)
//-----------------------------------------------------------------------------
// Choose SPI driver for SdFat and SdFatEX classes.
#if USE_STANDARD_SPI_LIBRARY || !SD_HAS_CUSTOM_SPI
/** SdFat uses Arduino library SPI. */
typedef SdSpiLibDriver SdFatSpiDriver;
#else // USE_STANDARD_SPI_LIBRARY || !SD_HAS_CUSTOM_SPI
/** SdFat uses custom fast SPI. */
typedef SdSpiAltDriver SdFatSpiDriver;
#endif // USE_STANDARD_SPI_LIBRARY || !SD_HAS_CUSTOM_SPI

/** typedef for for SdSpiCard class. */
#if ENABLE_SOFTWARE_SPI_CLASS
// Need virtual driver.
typedef SdSpiBaseDriver SdSpiDriver;
#else // ENABLE_SOFTWARE_SPI_CLASS
// Don't need virtual driver.
typedef SdFatSpiDriver SdSpiDriver;
#endif // ENABLE_SOFTWARE_SPI_CLASS
//=============================================================================
// Use of in-line for AVR to save flash.
#ifdef __AVR__
//------------------------------------------------------------------------------
inline void SdSpiAltDriver::begin(uint8_t csPin) {
m_csPin = csPin;
pinMode(m_csPin, OUTPUT);
digitalWrite(m_csPin, HIGH);
SPI.begin();
}
//------------------------------------------------------------------------------
inline void SdSpiAltDriver::activate() {
SPI.beginTransaction(m_spiSettings);
}
//------------------------------------------------------------------------------
inline void SdSpiAltDriver::deactivate() {
SPI.endTransaction();
}
//------------------------------------------------------------------------------
inline uint8_t SdSpiAltDriver::receive() {
SPDR = 0XFF;
while (!(SPSR & (1 << SPIF))) {}
return SPDR;
}
//------------------------------------------------------------------------------
inline uint8_t SdSpiAltDriver::receive(uint8_t* buf, size_t n) {
if (n-- == 0) {
return 0;
}
SPDR = 0XFF;
for (size_t i = 0; i < n; i++) {
while (!(SPSR & (1 << SPIF))) {}
uint8_t b = SPDR;
SPDR = 0XFF;
buf[i] = b;
}
while (!(SPSR & (1 << SPIF))) {}
buf[n] = SPDR;
return 0;
}
//------------------------------------------------------------------------------
inline void SdSpiAltDriver::send(uint8_t data) {
SPDR = data;
while (!(SPSR & (1 << SPIF))) {}
}
//------------------------------------------------------------------------------
inline void SdSpiAltDriver::send(const uint8_t* buf , size_t n) {
if (n == 0) {
return;
}
SPDR = buf[0];
if (n > 1) {
uint8_t b = buf[1];
size_t i = 2;
while (1) {
while (!(SPSR & (1 << SPIF))) {}
SPDR = b;
if (i == n) {
break;
}
b = buf[i++];
}
}
while (!(SPSR & (1 << SPIF))) {}
}
#endif // __AVR__
#endif // SdSpiDriver_h

SdFat/src/FatLib/SysCall.h → SdFat/src/SysCall.h Vedi File

@@ -31,10 +31,22 @@
#else // defined(ARDUINO)
#error "Unknown system"
#endif // defined(ARDUINO)
//-----------------------------------------------------------------------------
#ifdef ESP8266
// undefine F macro if ESP8266.
#undef F
#endif // ESP8266
//-----------------------------------------------------------------------------
#ifndef F
/** Define macro for strings stored in flash. */
#define F(str) (str)
#endif // F
//-----------------------------------------------------------------------------
/** \return the time in milliseconds. */
inline uint16_t curTimeMS() {
return millis();
}
//-----------------------------------------------------------------------------
/**
* \class SysCall
* \brief SysCall - Class to wrap system calls.
@@ -51,7 +63,12 @@ class SysCall {
static void yield();
};

#if defined(ARDUINO)
#if defined(ESP8266)
inline void SysCall::yield() {
// Avoid ESP8266 bug
delay(0);
}
#elif defined(ARDUINO)
inline void SysCall::yield() {
// Use the external Arduino yield() function.
::yield();
@@ -60,8 +77,7 @@ inline void SysCall::yield() {
inline void SysCall::yield() {
Particle.process();
}
#else // defined(ARDUINO)
#else // ESP8266
inline void SysCall::yield() {}
#endif // defined(ARDUINO)

#endif // ESP8266
#endif // SysCall_h

+ 0
- 29
SdFat/src/SystemInclude.h Vedi File

@@ -1,29 +0,0 @@
/* Arduino SdFat Library
* Copyright (C) 2016 by William Greiman
*
* This file is part of the Arduino SdFat Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino SdFat Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef SystemInclude_h
#define SystemInclude_h
#if defined(ARDUINO)
#include "FatLib/SysCall.h"
#elif defined(PLATFORM_ID) // Only defined if a Particle device
#include "SysCall.h"
#else // System type
#error Unknown System.
#endif // System type
#endif // SystemInclude_h

+ 0
- 0
changes.txt Vedi File


Dato che sono stati cambiati molti file in questo diff, alcuni di essi non verranno mostrati

Loading…
Annulla
Salva