Bläddra i källkod

New version for library manager

Bill Greiman 8 år sedan
förälder
incheckning
6bb055d415
100 ändrade filer med 2444 tillägg och 1799 borttagningar
  1. 40 21
      README.md
  2. 0 8
      SdFat/examples/LowLatencyLogger/UserDataType.h
  3. 0 77
      SdFat/examples/ReadWriteSdFat/ReadWriteSdFat.ino
  4. 0 231
      SdFat/examples/ThreeCards/ThreeCards.ino
  5. 0 9
      SdFat/library.properties
  6. 0 100
      SdFat/src/SdFat.cpp
  7. 0 360
      SdFat/src/SdFat.h
  8. 0 35
      SdFat/src/SdFatUtil.h
  9. 0 411
      SdFat/src/SdSpiCard/SdSpi.h
  10. 0 110
      SdFat/src/SdSpiCard/SdSpiParticle.cpp
  11. 0 29
      SdFat/src/SystemInclude.h
  12. 3 2
      examples/#attic/AnalogLogger/AnalogLogger.ino
  13. 3 1
      examples/#attic/BaseExtCaseTest/BaseExtCaseTest.ino
  14. 0 0
      examples/#attic/HelloWorld/HelloWorld.ino
  15. 0 0
      examples/#attic/MiniSerial/MiniSerial.ino
  16. 0 0
      examples/#attic/PrintBenchmarkSD/PrintBenchmarkSD.ino
  17. 0 0
      examples/#attic/SD_Size/SD_Size.ino
  18. 0 0
      examples/#attic/SdFatSize/SdFatSize.ino
  19. 1 1
      examples/#attic/StreamParseInt/StreamParseInt.ino
  20. 3 3
      examples/#attic/append/append.ino
  21. 3 3
      examples/#attic/average/average.ino
  22. 0 0
      examples/#attic/benchSD/benchSD.ino
  23. 0 0
      examples/#attic/bufstream/bufstream.ino
  24. 0 0
      examples/#attic/cin_cout/cin_cout.ino
  25. 3 3
      examples/#attic/eventlog/eventlog.ino
  26. 3 3
      examples/#attic/fgetsRewrite/fgetsRewrite.ino
  27. 3 3
      examples/#attic/readlog/readlog.ino
  28. 0 0
      examples/#attic/readme.txt
  29. 0 0
      examples/AnalogBinLogger/AnalogBinLogger.h
  30. 5 10
      examples/AnalogBinLogger/AnalogBinLogger.ino
  31. 4 4
      examples/DirectoryFunctions/DirectoryFunctions.ino
  32. 3 1
      examples/LongFileName/LongFileName.ino
  33. 0 0
      examples/LongFileName/testFiles/A long name can be 255 characters.txt
  34. 0 0
      examples/LongFileName/testFiles/LFN,NAME.TXT
  35. 0 0
      examples/LongFileName/testFiles/MIXCASE.txt
  36. 0 0
      examples/LongFileName/testFiles/Not_8_3.txt
  37. 0 0
      examples/LongFileName/testFiles/OK%83.TXT
  38. 0 0
      examples/LongFileName/testFiles/STD_8_3.TXT
  39. 0 0
      examples/LongFileName/testFiles/With Blank.txt
  40. 0 0
      examples/LongFileName/testFiles/With.Two dots.txt
  41. 0 0
      examples/LongFileName/testFiles/lower.txt
  42. 0 0
      examples/LongFileName/testFiles/mixed.TXT
  43. 319 250
      examples/LowLatencyLogger/LowLatencyLogger.ino
  44. 41 0
      examples/LowLatencyLogger/UserFunctions.cpp
  45. 15 0
      examples/LowLatencyLogger/UserTypes.h
  46. 655 0
      examples/LowLatencyLoggerADXL345/LowLatencyLogger.ino
  47. 1 0
      examples/LowLatencyLoggerADXL345/LowLatencyLoggerADXL345.ino
  48. 70 0
      examples/LowLatencyLoggerADXL345/UserFunctions.cpp
  49. 17 0
      examples/LowLatencyLoggerADXL345/UserTypes.h
  50. 1 0
      examples/LowLatencyLoggerADXL345/readme.txt
  51. 655 0
      examples/LowLatencyLoggerMPU6050/LowLatencyLogger.ino
  52. 2 0
      examples/LowLatencyLoggerMPU6050/LowLatencyLoggerMPU6050.ino
  53. 51 0
      examples/LowLatencyLoggerMPU6050/UserFunctions.cpp
  54. 18 0
      examples/LowLatencyLoggerMPU6050/UserTypes.h
  55. 3 3
      examples/OpenNext/OpenNext.ino
  56. 3 3
      examples/PrintBenchmark/PrintBenchmark.ino
  57. 7 7
      examples/QuickStart/QuickStart.ino
  58. 4 4
      examples/RawWrite/RawWrite.ino
  59. 0 0
      examples/ReadCsv/ReadCsv.ino
  60. 0 0
      examples/ReadCsvArray/ReadCsvArray.ino
  61. 3 3
      examples/ReadCsvStream/ReadCsvStream.ino
  62. 6 14
      examples/ReadWrite/ReadWrite.ino
  63. 176 0
      examples/STM32Test/STM32Test.ino
  64. 43 18
      examples/SdFormatter/SdFormatter.ino
  65. 27 21
      examples/SdInfo/SdInfo.ino
  66. 4 4
      examples/SoftwareSpi/SoftwareSpi.ino
  67. 7 3
      examples/StdioBench/StdioBench.ino
  68. 169 0
      examples/TeensySdioDemo/TeensySdioDemo.ino
  69. 3 3
      examples/Timestamp/Timestamp.ino
  70. 1 0
      examples/TwoCards/TwoCards.ino
  71. 3 3
      examples/VolumeFreeSpace/VolumeFreeSpace.ino
  72. 25 6
      examples/bench/bench.ino
  73. 3 3
      examples/dataLogger/dataLogger.ino
  74. 3 3
      examples/fgets/fgets.ino
  75. 0 0
      examples/formatting/formatting.ino
  76. 3 3
      examples/getline/getline.ino
  77. 3 3
      examples/rename/rename.ino
  78. 6 2
      examples/wipe/wipe.ino
  79. 0 0
      extras/AnalogBinLoggerExtras/ADC_ENOB.PNG
  80. 0 0
      extras/AnalogBinLoggerExtras/ADCdocs/ATmegaADCAccuracy.pdf
  81. 0 0
      extras/AnalogBinLoggerExtras/ADCdocs/ExcelFFT.pdf
  82. 0 0
      extras/AnalogBinLoggerExtras/AdcErrorStudy.txt
  83. 0 0
      extras/AnalogBinLoggerExtras/DATA.png
  84. 0 0
      extras/AnalogBinLoggerExtras/FFT.png
  85. 0 0
      extras/AnalogBinLoggerExtras/RateTable.txt
  86. 0 0
      extras/AnalogBinLoggerExtras/bintocsv/AnalogBinLogger.h
  87. 0 0
      extras/AnalogBinLoggerExtras/bintocsv/bintocsv.cpp
  88. 0 0
      extras/AnalogBinLoggerExtras/bintocsv/bintocsv.exe
  89. 0 0
      extras/AnalogBinLoggerExtras/readme.txt
  90. 23 18
      extras/MainPage/SdFatmainpage.h
  91. 0 0
      extras/SdFat.html
  92. 0 0
      extras/SdFatTestSuite/SdFatTestSuite.cpp
  93. 0 0
      extras/SdFatTestSuite/SdFatTestSuite.h
  94. 0 0
      extras/SdFatTestSuite/examples/ATS_SD_File/ATS_SD_File.ino
  95. 0 0
      extras/SdFatTestSuite/examples/ATS_SD_Files/ATS_SD_Files.ino
  96. 0 0
      extras/SdFatTestSuite/examples/ATS_SD_Seek/ATS_SD_Seek.ino
  97. 0 0
      extras/SdFatTestSuite/examples/StressTest/StressTest.ino
  98. 0 0
      extras/SdFatTestSuite/examples/TestMkdir/TestMkdir.ino
  99. 0 0
      extras/SdFatTestSuite/examples/TestRmdir/TestRmdir.ino
  100. 0 0
      extras/SdFatTestSuite/examples/fstreamTest/fstreamTest.ino

+ 40 - 21
README.md

@@ -3,37 +3,56 @@ file systems on SD/SDHC flash cards.
 
 
 SdFat requires Arduino 1.6x or greater.
 SdFat requires Arduino 1.6x or greater.
 
 
-To use SdFat, clone the repository or unzip the ZIP file and place the SdFat
-folder into the libraries sub-folder in your main sketch folder.
+Key changes:
 
 
-For more information see the Manual installation section of this guide:
+The SPI divisor has been replaced by SPISettings in the begin() call.
 
 
-http://arduino.cc/en/Guide/Libraries 
-
-A number of configuration options can be set by editing SdFatConfig.h
-\#define macros.  See the html documentation for details
+```
+bool begin(uint8_t csPin = SS, SPISettings spiSettings = SPI_FULL_SPEED);
+```
 
 
-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.
- 
-A new class, "File", has been added to provide compatibility with the Arduino
-SD.h library. To use SdFat with programs written for SD.h replace
+Several macros have been defined for backward compatibility. 
 
 
 ```
 ```
-#include <SD.h>
+#define SD_SCK_MHZ(maxMhz) SPISettings(1000000UL*maxMhz, MSBFIRST, SPI_MODE0)
+// SPI divisor constants
+/** Set SCK to max possible rate. */
+#define SPI_FULL_SPEED SD_SCK_MHZ(50)
+/** Set SCK rate to F_CPU/3 for Due */
+#define SPI_DIV3_SPEED SD_SCK_HZ(F_CPU/3)
+/** Set SCK rate to F_CPU/4. */
+#define SPI_HALF_SPEED SD_SCK_HZ(F_CPU/4)
+// ...
 ```
 ```
 
 
-with these two lines:
+There are two new classes, SdFatEX and SdFatSoftSpiEX.
+
+Teensy 3.5/3.6 SDIO support has been added.  Try the TeensySdioDemo example.
+Many other example will work with Teensy SDIO if you use the SdFatSdio classes
+and call begin with no parameters.
 
 
 ```
 ```
-#include "SdFat.h"
-SdFat SD;
+ SdFatSdio sd;
+ 
+ ....
+ 
+  if (!sd.begin()) {
+    // Handle failure.
+  }
+ 
 ```
 ```
+Please read changes.txt and the html documentation in the extras folder for more information.
 
 
+Please report problems as issues.
+
+A number of configuration options can be set by editing SdFatConfig.h
+define macros.  See the html documentation for details
+
+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, SdFatEX, SdBaseFile,
+SdFile, File, StdioStream, ifstream, ofstream, and others.
+ 
 Please continue by reading the html documentation.
 Please continue by reading the html documentation.
 
 
-Updated 19 Jul 2016
+Updated 26 Apr 2017

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

@@ -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

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

@@ -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
-}
-
-

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

@@ -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

+ 0 - 9
SdFat/library.properties

@@ -1,9 +0,0 @@
-name=SdFat
-version=2015.4.26
-author=
-maintainer=
-sentence=FAT16/FAT32 file system for SD cards.
-paragraph=
-category=Uncategorized
-url=
-architectures=*

+ 0 - 100
SdFat/src/SdFat.cpp

@@ -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)

+ 0 - 360
SdFat/src/SdFat.h

@@ -1,360 +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 SdFat_h
-#define SdFat_h
-/**
- * \file
- * \brief SdFat class
- */
-#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 20160719
-//==============================================================================
-/**
- * \class SdBaseFile
- * \brief Class for backward compatibility.
- */
-class SdBaseFile : public FatFile {
- public:
-  SdBaseFile() {}
-  /**  Create a file object and open it in the current working directory.
-   *
-   * \param[in] path A path for a file to be opened.
-   *
-   * \param[in] oflag Values for \a oflag are constructed by a
-   * bitwise-inclusive OR of open flags. see
-   * FatFile::open(FatFile*, const char*, uint8_t).
-   */
-  SdBaseFile(const char* path, uint8_t oflag) : FatFile(path, oflag) {}
-};
-#if ENABLE_ARDUINO_FEATURES
-/**
- * \class SdFile
- * \brief Class for backward compatibility.
- */
-class SdFile : public PrintFile {
- public:
-  SdFile() {}
-  /**  Create a file object and open it in the current working directory.
-   *
-   * \param[in] path A path for a file to be opened.
-   *
-   * \param[in] oflag Values for \a oflag are constructed by a
-   * bitwise-inclusive OR of open flags. see
-   * FatFile::open(FatFile*, const char*, uint8_t).
-   */
-  SdFile(const char* path, uint8_t oflag) : PrintFile(path, oflag) {}
-};
-#endif  // #if ENABLE_ARDUINO_FEATURES
-/**
- * \class SdFatBase
- * \brief Virtual base class for %SdFat library.
- */
-class SdFatBase : 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.
-   * \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();
-  }
-  /** \return Pointer to SD card object */
-  SdSpiCard *card() {
-    return &m_sdCard;
-  }
-  /** %Print any SD error code to Serial and halt. */
-  void errorHalt() {
-    errorHalt(&Serial);
-  }
-  /** %Print any SD error code and halt.
-   *
-   * \param[in] pr Print destination.
-   */
-  void errorHalt(Print* pr);
-  /** %Print msg, any SD error code and halt.
-   *
-   * \param[in] msg Message to print.
-   */
-  void errorHalt(char const* msg) {
-    errorHalt(&Serial, msg);
-  }
-  /** %Print msg, any SD error code, and halt.
-   *
-   * \param[in] pr Print destination.
-   * \param[in] msg Message to print.
-   */
-  void errorHalt(Print* pr, char const* msg);
-
-  /** %Print any SD error code to Serial */
-  void errorPrint() {
-    errorPrint(&Serial);
-  }
-  /** %Print any SD error code.
-   * \param[in] pr Print device.
-   */
-  void errorPrint(Print* pr);
-  /** %Print msg, any SD error code.
-   *
-   * \param[in] msg Message to print.
-   */
-  void errorPrint(const char* msg) {
-    errorPrint(&Serial, msg);
-  }
-  /** %Print msg, any SD error code.
-   *
-   * \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();
-  }
-  /** %Print any SD error code and halt. */
-  void initErrorHalt() {
-    initErrorHalt(&Serial);
-  }
-  /** %Print error details and halt after begin fails.
-   *
-   * \param[in] pr Print destination.
-   */
-  void initErrorHalt(Print* pr);
-  /**Print message, error details, and halt after SdFat::init() 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.
-   * \param[in] pr Print device.
-   * \param[in] msg Message to print.
-   */
-  void initErrorHalt(Print* pr, char const *msg);
-
-  /** Print error details after SdFat::init() fails. */
-  void initErrorPrint() {
-    initErrorPrint(&Serial);
-  }
-  /** Print error details after SdFatBase::init() fails.
-   *
-   * \param[in] pr Print destination.
-   */
-  void initErrorPrint(Print* pr);
-  /**Print message and error details and halt after SdFat::init() 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.
-   *
-   * \param[in] pr Print destination.
-   * \param[in] msg Message to print.
-   */
-  void initErrorPrint(Print* pr, char const *msg);
-#if defined(ARDUINO) || defined(DOXYGEN)
-  /** %Print msg, any SD error code, and halt.
-   *
-   * \param[in] msg Message to print.
-   */
-  void errorHalt(const __FlashStringHelper* msg) {
-    errorHalt(&Serial, msg);
-  }
-  /** %Print msg, any SD error code, and halt.
-   *
-   * \param[in] pr Print destination.
-   * \param[in] msg Message to print.
-   */
-  void errorHalt(Print* pr, const __FlashStringHelper* msg);
-  /** %Print msg, any SD error code.
-   *
-   * \param[in] msg Message to print.
-   */
-  void errorPrint(const __FlashStringHelper* msg) {
-    errorPrint(&Serial, msg);
-  }
-  /** %Print msg, any SD error code.
-   *
-   * \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.
-    *
-    * \param[in] msg Message to print.
-    */
-  void initErrorHalt(const __FlashStringHelper* msg) {
-    initErrorHalt(&Serial, msg);
-  }
-  /**Print message, error details, and halt after SdFatBase::init() 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.
-   *
-   * \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.
-   *
-   * \param[in] pr Print destination.
-   * \param[in] msg Message to print.
-   */
-  void initErrorPrint(Print* pr, const __FlashStringHelper* msg);
-#endif  // defined(ARDUINO) || defined(DOXYGEN)
-
- private:
-  uint8_t cardErrorCode() {
-    return m_sdCard.errorCode();
-  }
-  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);
-  }
-  SdSpiCard m_sdCard;
-};
-//==============================================================================
-/**
- * \class SdFat
- * \brief Main file system class for %SdFat library.
- */
-class SdFat : public SdFatBase {
- public:
-#if IMPLEMENT_SPI_INTERFACE_SELECTION
-  SdFat() {
-    m_spi.setSpiIf(0);
-  }
-  explicit SdFat(uint8_t spiIf) {
-    m_spi.setSpiIf(spiIf < SPI_INTERFACE_COUNT ? spiIf : 0);
-  }
-#endif  // IMPLEMENT_SPI_INTERFACE_SELECTION
-
-  /** 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.
-   * \return true for success else false.
-   */
-  bool cardBegin(uint8_t csPin = SS, uint8_t divisor = 2) {
-    return card()->begin(&m_spi, csPin, divisor);
-  }
-
- private:
-  SpiDefault_t m_spi;
-};
-//==============================================================================
-#if SD_SPI_CONFIGURATION >= 3 || defined(DOXYGEN)
-/**
- * \class SdFatLibSpi
- * \brief SdFat class using the standard Arduino SPI library.
- */
-class SdFatLibSpi: public SdFatBase {
- 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.
-   * \return true for success else false.
-   */
-  bool cardBegin(uint8_t csPin = SS, uint8_t divisor = 2) {
-    return card()->begin(&m_spi, csPin, divisor);
-  }
-
- private:
-  SdSpiLib m_spi;
-};
-//==============================================================================
-/**
- * \class SdFatSoftSpi
- * \brief SdFat class using software SPI.
- */
-template<uint8_t MisoPin, uint8_t MosiPin, uint8_t SckPin>
-class SdFatSoftSpi : public SdFatBase {
- 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.
-   * \return true for success else false.
-   */
-  bool cardBegin(uint8_t csPin = SS, uint8_t divisor = 2) {
-    return card()->begin(&m_spi, csPin, divisor);
-  }
-
- private:
-  SdSpiSoft<MisoPin, MosiPin, SckPin> m_spi;
-};
-#endif  /// SD_SPI_CONFIGURATION >= 3 || defined(DOXYGEN)
-#endif  // SdFat_h

+ 0 - 35
SdFat/src/SdFatUtil.h

@@ -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

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

@@ -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

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

@@ -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)

+ 0 - 29
SdFat/src/SystemInclude.h

@@ -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

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

@@ -97,8 +97,9 @@ void setup() {
   cout  << now << endl;
   cout  << now << endl;
 #endif  // USE_DS1307
 #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();
     sd.initErrorHalt();
   }
   }
 
 

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

@@ -4,6 +4,8 @@
 #include <SPI.h>
 #include <SPI.h>
 #include "SdFat.h"
 #include "SdFat.h"
 
 
+const uint8_t chipSelect = SS;
+
 SdFat sd;
 SdFat sd;
 
 
 SdFile file;
 SdFile file;
@@ -24,7 +26,7 @@ void setup() {
   while (!Serial.available()) {
   while (!Serial.available()) {
     SysCall::yield();
     SysCall::yield();
   }
   }
-  if (!sd.begin()) {
+  if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
     Serial.println("begin failed");
     Serial.println("begin failed");
     return;
     return;
   }
   }

+ 0 - 0
SdFat/examples/#attic/HelloWorld/HelloWorld.ino → examples/#attic/HelloWorld/HelloWorld.ino


+ 0 - 0
SdFat/examples/#attic/MiniSerial/MiniSerial.ino → examples/#attic/MiniSerial/MiniSerial.ino


+ 0 - 0
SdFat/examples/#attic/PrintBenchmarkSD/PrintBenchmarkSD.ino → examples/#attic/PrintBenchmarkSD/PrintBenchmarkSD.ino


+ 0 - 0
SdFat/examples/#attic/SD_Size/SD_Size.ino → examples/#attic/SD_Size/SD_Size.ino


+ 0 - 0
SdFat/examples/#attic/SdFatSize/SdFatSize.ino → examples/#attic/SdFatSize/SdFatSize.ino


+ 1 - 1
SdFat/examples/#attic/StreamParseInt/StreamParseInt.ino → examples/#attic/StreamParseInt/StreamParseInt.ino

@@ -5,7 +5,7 @@
 SdFat SD;
 SdFat SD;
 
 
 // SD card chip select pin - Modify the value of csPin for your SD module.
 // 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;
 File file;
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------

+ 3 - 3
SdFat/examples/#attic/append/append.ino → examples/#attic/append/append.ino

@@ -36,9 +36,9 @@ void setup() {
     SysCall::yield();
     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();
     sd.initErrorHalt();
   }
   }
 
 

+ 3 - 3
SdFat/examples/#attic/average/average.ino → examples/#attic/average/average.ino

@@ -65,9 +65,9 @@ void setup() {
     SysCall::yield();
     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();
     sd.initErrorHalt();
   }
   }
 
 

+ 0 - 0
SdFat/examples/#attic/benchSD/benchSD.ino → examples/#attic/benchSD/benchSD.ino


+ 0 - 0
SdFat/examples/#attic/bufstream/bufstream.ino → examples/#attic/bufstream/bufstream.ino


+ 0 - 0
SdFat/examples/#attic/cin_cout/cin_cout.ino → examples/#attic/cin_cout/cin_cout.ino


+ 3 - 3
SdFat/examples/#attic/eventlog/eventlog.ino → examples/#attic/eventlog/eventlog.ino

@@ -47,9 +47,9 @@ void setup() {
   }
   }
   delay(400);  // catch Due reset problem
   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();
     sd.initErrorHalt();
   }
   }
 
 

+ 3 - 3
SdFat/examples/#attic/fgetsRewrite/fgetsRewrite.ino → examples/#attic/fgetsRewrite/fgetsRewrite.ino

@@ -95,9 +95,9 @@ void setup() {
     SysCall::yield();
     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();
     sd.initErrorHalt();
   }
   }
 
 

+ 3 - 3
SdFat/examples/#attic/readlog/readlog.ino → examples/#attic/readlog/readlog.ino

@@ -22,9 +22,9 @@ void setup() {
   while (!Serial) {
   while (!Serial) {
     SysCall::yield();
     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();
     sd.initErrorHalt();
   }
   }
 
 

+ 0 - 0
SdFat/examples/#attic/readme.txt → examples/#attic/readme.txt


+ 0 - 0
SdFat/examples/AnalogBinLogger/AnalogBinLogger.h → examples/AnalogBinLogger/AnalogBinLogger.h


+ 5 - 10
SdFat/examples/AnalogBinLogger/AnalogBinLogger.ino → examples/AnalogBinLogger/AnalogBinLogger.ino

@@ -256,12 +256,7 @@ ISR(TIMER1_COMPB_vect) {
 }
 }
 //==============================================================================
 //==============================================================================
 // Error messages stored in flash.
 // 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() {
 void fatalBlink() {
@@ -625,8 +620,7 @@ void logData() {
   // Create new file.
   // Create new file.
   Serial.println(F("Creating new file"));
   Serial.println(F("Creating new file"));
   binFile.close();
   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");
     error("createContiguous failed");
   }
   }
   // Get the address of the file on the SD.
   // Get the address of the file on the SD.
@@ -783,8 +777,9 @@ void setup(void) {
   Serial.print(F("FreeStack: "));
   Serial.print(F("FreeStack: "));
   Serial.println(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();
     sd.initErrorPrint();
     fatalBlink();
     fatalBlink();
   }
   }

+ 4 - 4
SdFat/examples/directoryFunctions/directoryFunctions.ino → examples/DirectoryFunctions/DirectoryFunctions.ino

@@ -5,7 +5,7 @@
 #include "SdFat.h"
 #include "SdFat.h"
 
 
 // SD card chip select pin.
 // SD card chip select pin.
-const uint8_t SD_CHIP_SELECT = SS;
+const uint8_t chipSelect = SS;
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 
 
 // File system object.
 // File system object.
@@ -40,9 +40,9 @@ void setup() {
   cin.readline();
   cin.readline();
   cout << endl;
   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();
     sd.initErrorHalt();
   }
   }
   if (sd.exists("Folder1") 
   if (sd.exists("Folder1") 

+ 3 - 1
SdFat/examples/LongFileName/LongFileName.ino → examples/LongFileName/LongFileName.ino

@@ -31,7 +31,9 @@ void setup() {
                    "You can use test files located in\r\n"
                    "You can use test files located in\r\n"
                    "SdFat/examples/LongFileName/testFiles"));
                    "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();
     sd.initErrorHalt();
   }
   }
   Serial.print(F("FreeStack: "));
   Serial.print(F("FreeStack: "));

+ 0 - 0
SdFat/examples/LongFileName/testFiles/A long name can be 255 characters.txt → examples/LongFileName/testFiles/A long name can be 255 characters.txt


+ 0 - 0
SdFat/examples/LongFileName/testFiles/LFN,NAME.TXT → examples/LongFileName/testFiles/LFN,NAME.TXT


+ 0 - 0
SdFat/examples/LongFileName/testFiles/MIXCASE.txt → examples/LongFileName/testFiles/MIXCASE.txt


+ 0 - 0
SdFat/examples/LongFileName/testFiles/Not_8_3.txt → examples/LongFileName/testFiles/Not_8_3.txt


+ 0 - 0
SdFat/examples/LongFileName/testFiles/OK%83.TXT → examples/LongFileName/testFiles/OK%83.TXT


+ 0 - 0
SdFat/examples/LongFileName/testFiles/STD_8_3.TXT → examples/LongFileName/testFiles/STD_8_3.TXT


+ 0 - 0
SdFat/examples/LongFileName/testFiles/With Blank.txt → examples/LongFileName/testFiles/With Blank.txt


+ 0 - 0
SdFat/examples/LongFileName/testFiles/With.Two dots.txt → examples/LongFileName/testFiles/With.Two dots.txt


+ 0 - 0
SdFat/examples/LongFileName/testFiles/lower.txt → examples/LongFileName/testFiles/lower.txt


+ 0 - 0
SdFat/examples/LongFileName/testFiles/mixed.TXT → examples/LongFileName/testFiles/mixed.TXT


+ 319 - 250
SdFat/examples/LowLatencyLogger/LowLatencyLogger.ino → examples/LowLatencyLogger/LowLatencyLogger.ino

@@ -9,66 +9,47 @@
  *
  *
  * If your SD card has a long write latency, it may be necessary to use
  * 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
  * 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.
  * Data is written to the file using a SD multiple block write command.
  */
  */
 #include <SPI.h>
 #include <SPI.h>
 #include "SdFat.h"
 #include "SdFat.h"
 #include "FreeStack.h"
 #include "FreeStack.h"
-#include "UserDataType.h"  // Edit this include file to change data_t.
-//------------------------------------------------------------------------------
-// Set useSharedSpi true for use of an SPI sensor.
-// May not work for some cards.
-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.
 // 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.
 //Interval between data records in microseconds.
 const uint32_t LOG_INTERVAL_USEC = 2000;
 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.
 // Pin definitions.
 //
 //
 // SD chip select pin.
 // SD chip select pin.
 const uint8_t SD_CS_PIN = SS;
 const uint8_t SD_CS_PIN = SS;
 //
 //
 // Digital pin to indicate an error, set to -1 if not used.
 // 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
 #undef ERROR_LED_PIN
+#endif  // ERROR_LED_PIN
 const int8_t ERROR_LED_PIN = -1;
 const int8_t ERROR_LED_PIN = -1;
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 // File definitions.
 // File definitions.
@@ -78,49 +59,51 @@ const int8_t ERROR_LED_PIN = -1;
 // This file is flash erased using special SD commands.  The file will be
 // This file is flash erased using special SD commands.  The file will be
 // truncated if logging is stopped early.
 // truncated if logging is stopped early.
 const uint32_t FILE_BLOCK_COUNT = 256000;
 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"
 #define FILE_BASE_NAME "data"
+#endif  // FILE_BASE_NAME
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 // Buffer definitions.
 // 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.
 // buffers.
 //
 //
 #ifndef RAMEND
 #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
 #elif RAMEND < 0X8FF
 #error Too little SRAM
 #error Too little SRAM
 //
 //
 #elif RAMEND < 0X10FF
 #elif RAMEND < 0X10FF
 // Use total of two 512 byte buffers.
 // Use total of two 512 byte buffers.
-const uint8_t BUFFER_BLOCK_COUNT = 1;
+const uint8_t BUFFER_BLOCK_COUNT = 2;
 //
 //
 #elif RAMEND < 0X20FF
 #elif RAMEND < 0X20FF
-// Use total of five 512 byte buffers.
+// Use total of four 512 byte buffers.
 const uint8_t BUFFER_BLOCK_COUNT = 4;
 const uint8_t BUFFER_BLOCK_COUNT = 4;
 //
 //
 #else  // RAMEND
 #else  // RAMEND
-// Use total of 13 512 byte buffers.
+// Use total of 12 512 byte buffers.
 const uint8_t BUFFER_BLOCK_COUNT = 12;
 const uint8_t BUFFER_BLOCK_COUNT = 12;
 #endif  // RAMEND
 #endif  // RAMEND
 //==============================================================================
 //==============================================================================
 // End of configuration constants.
 // End of configuration constants.
 //==============================================================================
 //==============================================================================
 // Temporary log file.  Will be deleted if a reset or power failure occurs.
 // Temporary log file.  Will be deleted if a reset or power failure occurs.
-#define TMP_FILE_NAME "tmp_log.bin"
+#define TMP_FILE_NAME FILE_BASE_NAME "##.bin"
 
 
-// Size of file base name.  Must not be larger than six.
+// Size of file base name.
 const uint8_t BASE_NAME_SIZE = sizeof(FILE_BASE_NAME) - 1;
 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;
 SdFat sd;
 
 
 SdBaseFile binFile;
 SdBaseFile binFile;
 
 
-char binName[13] = FILE_BASE_NAME "00.bin";
-
 // Number of data records in a block.
 // Number of data records in a block.
 const uint16_t DATA_DIM = (512 - 4)/sizeof(data_t);
 const uint16_t DATA_DIM = (512 - 4)/sizeof(data_t);
 
 
@@ -133,33 +116,14 @@ struct block_t {
   data_t data[DATA_DIM];
   data_t data[DATA_DIM];
   uint8_t fill[FILL_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.
 // 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() {
 void fatalBlink() {
   while (true) {
   while (true) {
+    SysCall::yield();
     if (ERROR_LED_PIN >= 0) {
     if (ERROR_LED_PIN >= 0) {
       digitalWrite(ERROR_LED_PIN, HIGH);
       digitalWrite(ERROR_LED_PIN, HIGH);
       delay(200);
       delay(200);
@@ -168,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.
 // Convert binary file to csv file.
 void binaryToCsv() {
 void binaryToCsv() {
   uint8_t lastPct = 0;
   uint8_t lastPct = 0;
@@ -176,14 +182,17 @@ void binaryToCsv() {
   uint32_t t0 = millis();
   uint32_t t0 = millis();
   uint32_t syncCluster = 0;
   uint32_t syncCluster = 0;
   SdFile csvFile;
   SdFile csvFile;
-  char csvName[13];
+  char csvName[FILE_NAME_DIM];
 
 
   if (!binFile.isOpen()) {
   if (!binFile.isOpen()) {
     Serial.println();
     Serial.println();
     Serial.println(F("No current binary file"));
     Serial.println(F("No current binary file"));
     return;
     return;
   }
   }
-  binFile.rewind();
+  Serial.println();
+  Serial.print(F("FreeStack: "));
+  Serial.println(FreeStack());
+  
   // Create a new csvFile.
   // Create a new csvFile.
   strcpy(csvName, binName);
   strcpy(csvName, binName);
   strcpy(&csvName[BASE_NAME_SIZE + 3], "csv");
   strcpy(&csvName[BASE_NAME_SIZE + 3], "csv");
@@ -191,7 +200,7 @@ void binaryToCsv() {
   if (!csvFile.open(csvName, O_WRITE | O_CREAT | O_TRUNC)) {
   if (!csvFile.open(csvName, O_WRITE | O_CREAT | O_TRUNC)) {
     error("open csvFile failed");
     error("open csvFile failed");
   }
   }
-  Serial.println();
+  binFile.rewind();
   Serial.print(F("Writing: "));
   Serial.print(F("Writing: "));
   Serial.print(csvName);
   Serial.print(csvName);
   Serial.println(F(" - type any character to stop"));
   Serial.println(F(" - type any character to stop"));
@@ -199,7 +208,7 @@ void binaryToCsv() {
   uint32_t tPct = millis();
   uint32_t tPct = millis();
   while (!Serial.available() && binFile.read(&block, 512) == 512) {
   while (!Serial.available() && binFile.read(&block, 512) == 512) {
     uint16_t i;
     uint16_t i;
-    if (block.count == 0) {
+    if (block.count == 0 || block.count > DATA_DIM) {
       break;
       break;
     }
     }
     if (block.overrun) {
     if (block.overrun) {
@@ -231,48 +240,42 @@ void binaryToCsv() {
   Serial.print(0.001*(millis() - t0));
   Serial.print(0.001*(millis() - t0));
   Serial.println(F(" Seconds"));
   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 bgnBlock, endBlock;
-  uint32_t bn = 0;
-
-  if (!binFile.isOpen()) {
-    Serial.println();
-    Serial.println(F("No current binary file"));
-    return;
+  
+  // Delete old tmp file.
+  if (sd.exists(TMP_FILE_NAME)) {
+    Serial.println(F("Deleting tmp file " TMP_FILE_NAME));
+    if (!sd.remove(TMP_FILE_NAME)) {
+      error("Can't remove tmp file");
+    }
   }
   }
+  // Create new file.
+  Serial.println(F("\nCreating 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)) {
   if (!binFile.contiguousRange(&bgnBlock, &endBlock)) {
     error("contiguousRange failed");
     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;
   }
   }
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -305,123 +308,105 @@ void dumpData() {
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 // log data
 // log data
-// max number of blocks to erase per erase call
-uint32_t const ERASE_SIZE = 262144L;
 void logData() {
 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(F("\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.
   // 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");
     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.
   // Start a multiple block write.
-  if (!sd.card()->writeStart(bgnBlock, FILE_BLOCK_COUNT)) {
-    error("writeBegin failed");
-  }
-  // 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("writeStart failed");
   }
   }
+  Serial.print(F("FreeStack: "));
+  Serial.println(FreeStack());
   Serial.println(F("Logging - type any character to stop"));
   Serial.println(F("Logging - type any character to stop"));
-  // Wait for Serial Idle.
-  Serial.flush();
-  delay(10);
   bool closeFile = false;
   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 overrun = 0;
   uint32_t overrunTotal = 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();
   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;
     logTime += LOG_INTERVAL_USEC;
     if (Serial.available()) {
     if (Serial.available()) {
       closeFile = true;
       closeFile = true;
-    }
-
+    }  
     if (closeFile) {
     if (closeFile) {
       if (curBlock != 0) {
       if (curBlock != 0) {
         // Put buffer in full queue.
         // Put buffer in full queue.
         fullQueue[fullHead] = curBlock;
         fullQueue[fullHead] = curBlock;
-        fullHead = queueNext(fullHead);
+        fullHead = fullHead < QUEUE_LAST ? fullHead + 1 : 0;
         curBlock = 0;
         curBlock = 0;
       }
       }
     } else {
     } 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->count = 0;
         curBlock->overrun = overrun;
         curBlock->overrun = overrun;
         overrun = 0;
         overrun = 0;
@@ -435,24 +420,29 @@ void logData() {
       } while (delta < 0);
       } while (delta < 0);
       if (curBlock == 0) {
       if (curBlock == 0) {
         overrun++;
         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 {
       } else {
-        if (useSharedSpi) {
-          sd.card()->chipSelectHigh();
-        }
+#if USE_SHARED_SPI
+        sd.card()->spiStop();
+#endif  // USE_SHARED_SPI   
         acquireData(&curBlock->data[curBlock->count++]);
         acquireData(&curBlock->data[curBlock->count++]);
-        if (useSharedSpi) {
-          sd.card()->chipSelectLow();
-        }        
+#if USE_SHARED_SPI
+        sd.card()->spiStart();
+#endif  // USE_SHARED_SPI      
         if (curBlock->count == DATA_DIM) {
         if (curBlock->count == DATA_DIM) {
           fullQueue[fullHead] = curBlock;
           fullQueue[fullHead] = curBlock;
-          fullHead = queueNext(fullHead);
+          fullHead = fullHead < QUEUE_LAST ? fullHead + 1 : 0;
           curBlock = 0;
           curBlock = 0;
-        }
-        if ((uint32_t)delta > maxDelta) maxDelta = delta;
-        if ((uint32_t)delta < minDelta) minDelta = delta;          
+        } 
       }
       }
     }
     }
-
     if (fullHead == fullTail) {
     if (fullHead == fullTail) {
       // Exit loop if done.
       // Exit loop if done.
       if (closeFile) {
       if (closeFile) {
@@ -461,29 +451,18 @@ void logData() {
     } else if (!sd.card()->isBusy()) {
     } else if (!sd.card()->isBusy()) {
       // Get address of block to write.
       // Get address of block to write.
       block_t* pBlock = fullQueue[fullTail];
       block_t* pBlock = fullQueue[fullTail];
-      fullTail = queueNext(fullTail);
+      fullTail = fullTail < QUEUE_LAST ? fullTail + 1 : 0;
       // Write block to SD.
       // Write block to SD.
       uint32_t usec = micros();
       uint32_t usec = micros();
       if (!sd.card()->writeData((uint8_t*)pBlock)) {
       if (!sd.card()->writeData((uint8_t*)pBlock)) {
         error("write data failed");
         error("write data failed");
       }
       }
       usec = micros() - usec;
       usec = micros() - usec;
-      t1 = millis();
       if (usec > maxLatency) {
       if (usec > maxLatency) {
         maxLatency = usec;
         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.
       // Move block to empty queue.
-      emptyQueue[emptyHead] = pBlock;
-      emptyHead = queueNext(emptyHead);
+      emptyStack[emptyTop++] = pBlock;
       bn++;
       bn++;
       if (bn == FILE_BLOCK_COUNT) {
       if (bn == FILE_BLOCK_COUNT) {
         // File full so stop
         // File full so stop
@@ -494,6 +473,12 @@ void logData() {
   if (!sd.card()->writeStop()) {
   if (!sd.card()->writeStop()) {
     error("writeStop failed");
     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.
   // Truncate file if recording stopped early.
   if (bn != FILE_BLOCK_COUNT) {
   if (bn != FILE_BLOCK_COUNT) {
     Serial.println(F("Truncating file"));
     Serial.println(F("Truncating file"));
@@ -501,25 +486,76 @@ void logData() {
       error("Can't truncate file");
       error("Can't truncate file");
     }
     }
   }
   }
+}
+//------------------------------------------------------------------------------
+void recoverTmpFile() {
+  uint16_t count;
+  if (!binFile.open(TMP_FILE_NAME, O_RDWR)) {
+    return;
+  }
+  if (binFile.read(&count, 2) != 2 || count != DATA_DIM) {
+    error("Please delete existing " TMP_FILE_NAME);
+  }
+  Serial.println(F("\nRecovering data in tmp file " TMP_FILE_NAME));
+  uint32_t bgnBlock = 0;
+  uint32_t endBlock = binFile.fileSize()/512 - 1;
+  // find last used block.
+  while (bgnBlock < endBlock) {
+    uint32_t midBlock = (bgnBlock + endBlock + 1)/2;
+    binFile.seekSet(512*midBlock);
+    if (binFile.read(&count, 2) != 2) error("read");
+    if (count == 0 || count > DATA_DIM) {
+      endBlock = midBlock - 1;
+    } else {          
+      bgnBlock = midBlock;
+    }
+  }
+  // truncate after last used block.
+  if (!binFile.truncate(512*(bgnBlock + 1))) {
+    error("Truncate " TMP_FILE_NAME " failed");
+  }
+  renameBinFile();
+}
+//-----------------------------------------------------------------------------
+void renameBinFile() {
+  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]++;
+    }
+  }
   if (!binFile.rename(sd.vwd(), binName)) {
   if (!binFile.rename(sd.vwd(), binName)) {
     error("Can't rename file");
     error("Can't rename file");
-  }
+    }
   Serial.print(F("File renamed: "));
   Serial.print(F("File renamed: "));
   Serial.println(binName);
   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(F("File size: "));
+  Serial.print(binFile.fileSize()/512);
+  Serial.println(F(" blocks"));
+}
+//------------------------------------------------------------------------------
+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) {
 void setup(void) {
@@ -532,19 +568,38 @@ void setup(void) {
   while (!Serial) {
   while (!Serial) {
     SysCall::yield();
     SysCall::yield();
   }
   }
-
-  Serial.print(F("FreeStack: "));
+  Serial.print(F("\nFreeStack: "));
   Serial.println(FreeStack());
   Serial.println(FreeStack());
   Serial.print(F("Records/block: "));
   Serial.print(F("Records/block: "));
   Serial.println(DATA_DIM);
   Serial.println(DATA_DIM);
   if (sizeof(block_t) != 512) {
   if (sizeof(block_t) != 512) {
     error("Invalid block size");
     error("Invalid block size");
   }
   }
-  // initialize file system.
-  if (!sd.begin(SD_CS_PIN, SPI_FULL_SPEED)) {
-    sd.initErrorPrint();
+  // Allow userSetup access to SPI bus.
+  pinMode(SD_CS_PIN, OUTPUT);
+  digitalWrite(SD_CS_PIN, HIGH);
+  
+  // Setup sensors.
+  userSetup();
+  
+  // 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();
     fatalBlink();
   }
   }
+  // recover existing tmp file.
+  if (sd.exists(TMP_FILE_NAME)) {
+    Serial.println(F("\nType 'Y' to recover existing tmp file " TMP_FILE_NAME));
+    while (!Serial.available()) {
+      SysCall::yield();
+    }
+    if (Serial.read() == 'Y') {
+      recoverTmpFile();
+    } else {
+      error("'Y' not typed, please manually delete " TMP_FILE_NAME);
+    }
+  }
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void loop(void) {
 void loop(void) {
@@ -554,14 +609,21 @@ void loop(void) {
   } while (Serial.available() && Serial.read() >= 0);
   } while (Serial.available() && Serial.read() >= 0);
   Serial.println();
   Serial.println();
   Serial.println(F("type:"));
   Serial.println(F("type:"));
+  Serial.println(F("b - open existing bin file"));  
   Serial.println(F("c - convert file to csv"));
   Serial.println(F("c - convert file to csv"));
   Serial.println(F("d - dump data to Serial"));
   Serial.println(F("d - dump data to Serial"));
   Serial.println(F("e - overrun error details"));
   Serial.println(F("e - overrun error details"));
+  Serial.println(F("l - list files"));  
   Serial.println(F("r - record data"));
   Serial.println(F("r - record data"));
-
+  Serial.println(F("t - test without logging"));
   while(!Serial.available()) {
   while(!Serial.available()) {
     SysCall::yield();
     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());
   char c = tolower(Serial.read());
 
 
   // Discard extra Serial data.
   // Discard extra Serial data.
@@ -572,15 +634,22 @@ void loop(void) {
   if (ERROR_LED_PIN >= 0) {
   if (ERROR_LED_PIN >= 0) {
     digitalWrite(ERROR_LED_PIN, LOW);
     digitalWrite(ERROR_LED_PIN, LOW);
   }
   }
-  if (c == 'c') {
+  if (c == 'b') {
+    openBinFile();
+  } else if (c == 'c') {
     binaryToCsv();
     binaryToCsv();
   } else if (c == 'd') {
   } else if (c == 'd') {
     dumpData();
     dumpData();
   } else if (c == 'e') {
   } else if (c == 'e') {
     checkOverrun();
     checkOverrun();
+  } else if (c == 'l') {
+    Serial.println(F("\nls:"));  
+    sd.ls(&Serial, LS_SIZE);  
   } else if (c == 'r') {
   } else if (c == 'r') {
     logData();
     logData();
+  } else if (c == 't') {
+    testSensor();    
   } else {
   } else {
     Serial.println(F("Invalid entry"));
     Serial.println(F("Invalid entry"));
   }
   }
-}
+}

+ 41 - 0
examples/LowLatencyLogger/UserFunctions.cpp

@@ -0,0 +1,41 @@
+#include "UserTypes.h"
+// User data functions.  Modify these functions for your data items.
+
+// Start time for data
+static uint32_t startMicros;
+
+// 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 (startMicros == 0) {
+    startMicros = data->time;
+  }
+  pr->print(data->time - startMicros);
+  for (int i = 0; i < ADC_DIM; i++) {
+    pr->write(',');
+    pr->print(data->adc[i]);
+  }
+  pr->println();
+}
+
+// Print data header.
+void printHeader(Print* pr) {
+  startMicros = 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
examples/LowLatencyLogger/UserTypes.h

@@ -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 {
+  uint32_t time;
+  uint16_t adc[ADC_DIM];
+};
+void acquireData(data_t* data);
+void printData(Print* pr, data_t* data);
+void printHeader(Print* pr);
+void userSetup();
+#endif  // UserTypes_h

+ 655 - 0
examples/LowLatencyLoggerADXL345/LowLatencyLogger.ino

@@ -0,0 +1,655 @@
+/**
+ * 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 = -1;
+//------------------------------------------------------------------------------
+// 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 FILE_BASE_NAME "##.bin"
+
+// Size of file base name.
+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 || block.count > DATA_DIM) {
+      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;
+  
+  // Delete old tmp file.
+  if (sd.exists(TMP_FILE_NAME)) {
+    Serial.println(F("Deleting tmp file " TMP_FILE_NAME));
+    if (!sd.remove(TMP_FILE_NAME)) {
+      error("Can't remove tmp file");
+    }
+  }
+  // Create new file.
+  Serial.println(F("\nCreating 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(F("\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("writeStart 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 recoverTmpFile() {
+  uint16_t count;
+  if (!binFile.open(TMP_FILE_NAME, O_RDWR)) {
+    return;
+  }
+  if (binFile.read(&count, 2) != 2 || count != DATA_DIM) {
+    error("Please delete existing " TMP_FILE_NAME);
+  }
+  Serial.println(F("\nRecovering data in tmp file " TMP_FILE_NAME));
+  uint32_t bgnBlock = 0;
+  uint32_t endBlock = binFile.fileSize()/512 - 1;
+  // find last used block.
+  while (bgnBlock < endBlock) {
+    uint32_t midBlock = (bgnBlock + endBlock + 1)/2;
+    binFile.seekSet(512*midBlock);
+    if (binFile.read(&count, 2) != 2) error("read");
+    if (count == 0 || count > DATA_DIM) {
+      endBlock = midBlock - 1;
+    } else {          
+      bgnBlock = midBlock;
+    }
+  }
+  // truncate after last used block.
+  if (!binFile.truncate(512*(bgnBlock + 1))) {
+    error("Truncate " TMP_FILE_NAME " failed");
+  }
+  renameBinFile();
+}
+//-----------------------------------------------------------------------------
+void renameBinFile() {
+  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]++;
+    }
+  }
+  if (!binFile.rename(sd.vwd(), binName)) {
+    error("Can't rename file");
+    }
+  Serial.print(F("File renamed: "));
+  Serial.println(binName);
+  Serial.print(F("File size: "));
+  Serial.print(binFile.fileSize()/512);
+  Serial.println(F(" blocks"));
+}
+//------------------------------------------------------------------------------
+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("\nFreeStack: "));
+  Serial.println(FreeStack());
+  Serial.print(F("Records/block: "));
+  Serial.println(DATA_DIM);
+  if (sizeof(block_t) != 512) {
+    error("Invalid block size");
+  }
+  // Allow userSetup access to SPI bus.
+  pinMode(SD_CS_PIN, OUTPUT);
+  digitalWrite(SD_CS_PIN, HIGH);
+  
+  // Setup sensors.
+  userSetup();
+  
+  // 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();
+  }
+  // recover existing tmp file.
+  if (sd.exists(TMP_FILE_NAME)) {
+    Serial.println(F("\nType 'Y' to recover existing tmp file " TMP_FILE_NAME));
+    while (!Serial.available()) {
+      SysCall::yield();
+    }
+    if (Serial.read() == 'Y') {
+      recoverTmpFile();
+    } else {
+      error("'Y' not typed, please manually delete " TMP_FILE_NAME);
+    }
+  }
+}
+//------------------------------------------------------------------------------
+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"));
+  }
+}

+ 1 - 0
examples/LowLatencyLoggerADXL345/LowLatencyLoggerADXL345.ino

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

+ 70 - 0
examples/LowLatencyLoggerADXL345/UserFunctions.cpp

@@ -0,0 +1,70 @@
+#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) {
+  // Max SPI clock frequency is 5 MHz with CPOL = 1 and CPHA = 1.
+  SPI.beginTransaction(SPISettings(5000000, MSBFIRST, SPI_MODE3));  
+  digitalWrite(ADXL345_CS, LOW);
+  SPI.transfer(registerAddress);
+  SPI.transfer(value);
+  digitalWrite(ADXL345_CS, HIGH);
+  SPI.endTransaction();  
+}
+
+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
examples/LowLatencyLoggerADXL345/UserTypes.h

@@ -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 {
+  uint32_t 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

+ 1 - 0
examples/LowLatencyLoggerADXL345/readme.txt

@@ -0,0 +1 @@
+Test of shared SPI for LowLatencyLogger.

+ 655 - 0
examples/LowLatencyLoggerMPU6050/LowLatencyLogger.ino

@@ -0,0 +1,655 @@
+/**
+ * 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 = -1;
+//------------------------------------------------------------------------------
+// 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 FILE_BASE_NAME "##.bin"
+
+// Size of file base name.
+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 || block.count > DATA_DIM) {
+      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;
+  
+  // Delete old tmp file.
+  if (sd.exists(TMP_FILE_NAME)) {
+    Serial.println(F("Deleting tmp file " TMP_FILE_NAME));
+    if (!sd.remove(TMP_FILE_NAME)) {
+      error("Can't remove tmp file");
+    }
+  }
+  // Create new file.
+  Serial.println(F("\nCreating 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(F("\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("writeStart 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 recoverTmpFile() {
+  uint16_t count;
+  if (!binFile.open(TMP_FILE_NAME, O_RDWR)) {
+    return;
+  }
+  if (binFile.read(&count, 2) != 2 || count != DATA_DIM) {
+    error("Please delete existing " TMP_FILE_NAME);
+  }
+  Serial.println(F("\nRecovering data in tmp file " TMP_FILE_NAME));
+  uint32_t bgnBlock = 0;
+  uint32_t endBlock = binFile.fileSize()/512 - 1;
+  // find last used block.
+  while (bgnBlock < endBlock) {
+    uint32_t midBlock = (bgnBlock + endBlock + 1)/2;
+    binFile.seekSet(512*midBlock);
+    if (binFile.read(&count, 2) != 2) error("read");
+    if (count == 0 || count > DATA_DIM) {
+      endBlock = midBlock - 1;
+    } else {          
+      bgnBlock = midBlock;
+    }
+  }
+  // truncate after last used block.
+  if (!binFile.truncate(512*(bgnBlock + 1))) {
+    error("Truncate " TMP_FILE_NAME " failed");
+  }
+  renameBinFile();
+}
+//-----------------------------------------------------------------------------
+void renameBinFile() {
+  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]++;
+    }
+  }
+  if (!binFile.rename(sd.vwd(), binName)) {
+    error("Can't rename file");
+    }
+  Serial.print(F("File renamed: "));
+  Serial.println(binName);
+  Serial.print(F("File size: "));
+  Serial.print(binFile.fileSize()/512);
+  Serial.println(F(" blocks"));
+}
+//------------------------------------------------------------------------------
+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("\nFreeStack: "));
+  Serial.println(FreeStack());
+  Serial.print(F("Records/block: "));
+  Serial.println(DATA_DIM);
+  if (sizeof(block_t) != 512) {
+    error("Invalid block size");
+  }
+  // Allow userSetup access to SPI bus.
+  pinMode(SD_CS_PIN, OUTPUT);
+  digitalWrite(SD_CS_PIN, HIGH);
+  
+  // Setup sensors.
+  userSetup();
+  
+  // 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();
+  }
+  // recover existing tmp file.
+  if (sd.exists(TMP_FILE_NAME)) {
+    Serial.println(F("\nType 'Y' to recover existing tmp file " TMP_FILE_NAME));
+    while (!Serial.available()) {
+      SysCall::yield();
+    }
+    if (Serial.read() == 'Y') {
+      recoverTmpFile();
+    } else {
+      error("'Y' not typed, please manually delete " TMP_FILE_NAME);
+    }
+  }
+}
+//------------------------------------------------------------------------------
+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
examples/LowLatencyLoggerMPU6050/LowLatencyLoggerMPU6050.ino

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

+ 51 - 0
examples/LowLatencyLoggerMPU6050/UserFunctions.cpp

@@ -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
examples/LowLatencyLoggerMPU6050/UserTypes.h

@@ -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 → examples/OpenNext/OpenNext.ino

@@ -25,9 +25,9 @@ void setup() {
     SysCall::yield();
     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();
     sd.initErrorHalt();
   }
   }
 
 

+ 3 - 3
SdFat/examples/PrintBenchmark/PrintBenchmark.ino → examples/PrintBenchmark/PrintBenchmark.ino

@@ -49,9 +49,9 @@ void loop() {
 
 
   cout << F("FreeStack: ") << FreeStack() << endl;
   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();
     sd.initErrorHalt();
   }
   }
 
 

+ 7 - 7
SdFat/examples/QuickStart/QuickStart.ino → examples/QuickStart/QuickStart.ino

@@ -1,4 +1,4 @@
-// Quick hardware test.
+// Quick hardware test for SPI card access.
 //
 //
 #include <SPI.h>
 #include <SPI.h>
 #include "SdFat.h"
 #include "SdFat.h"
@@ -8,10 +8,10 @@
 // to 10 to disable the Ethernet controller.
 // to 10 to disable the Ethernet controller.
 const int8_t DISABLE_CHIP_SELECT = -1;
 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.
 // File system object.
 SdFat sd;
 SdFat sd;
@@ -28,7 +28,7 @@ int chipSelect;
 
 
 void cardOrSpeed() {
 void cardOrSpeed() {
   cout << F("Try another SD card or reduce the SPI bus speed.\n");
   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() {
 void reformatMsg() {
@@ -98,7 +98,7 @@ void loop() {
     pinMode(DISABLE_CHIP_SELECT, OUTPUT);
     pinMode(DISABLE_CHIP_SELECT, OUTPUT);
     digitalWrite(DISABLE_CHIP_SELECT, HIGH);
     digitalWrite(DISABLE_CHIP_SELECT, HIGH);
   }
   }
-  if (!sd.begin(chipSelect, spiSpeed)) {
+  if (!sd.begin(chipSelect, SPI_SPEED)) {
     if (sd.card()->errorCode()) {
     if (sd.card()->errorCode()) {
       cout << F(
       cout << F(
              "\nSD initialization failed.\n"
              "\nSD initialization failed.\n"

+ 4 - 4
SdFat/examples/RawWrite/RawWrite.ino → examples/RawWrite/RawWrite.ino

@@ -64,9 +64,9 @@ void loop(void) {
 
 
   cout << F("FreeStack: ") << FreeStack() << endl;
   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();
     sd.initErrorHalt();
   }
   }
 
 
@@ -74,7 +74,7 @@ void loop(void) {
   sd.remove("RawWrite.txt");
   sd.remove("RawWrite.txt");
 
 
   // create a contiguous file
   // 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");
     error("createContiguous failed");
   }
   }
   // get the location of the file's blocks
   // get the location of the file's blocks

+ 0 - 0
SdFat/examples/readCSV/readCSV.ino → examples/ReadCsv/ReadCsv.ino


+ 0 - 0
SdFat/examples/ReadCsvArray/ReadCsvArray.ino → examples/ReadCsvArray/ReadCsvArray.ino


+ 3 - 3
SdFat/examples/ReadCsvStream/ReadCsvStream.ino → examples/ReadCsvStream/ReadCsvStream.ino

@@ -101,9 +101,9 @@ void setup() {
     SysCall::yield();  
     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();
     sd.initErrorHalt();
   }
   }
 
 

+ 6 - 14
SdFat/examples/ReadWrite/ReadWrite.ino → examples/ReadWrite/ReadWrite.ino

@@ -7,7 +7,6 @@
  ** MOSI - pin 11
  ** MOSI - pin 11
  ** MISO - pin 12
  ** MISO - pin 12
  ** CLK - pin 13
  ** CLK - pin 13
- ** CS - pin 4
 
 
  created   Nov 2010
  created   Nov 2010
  by David A. Mellis
  by David A. Mellis
@@ -17,30 +16,24 @@
  This example code is in the public domain.
  This example code is in the public domain.
 
 
  */
  */
-#define SD_CS_PIN SS
+
 #include <SPI.h>
 #include <SPI.h>
 //#include <SD.h>
 //#include <SD.h>
 #include "SdFat.h"
 #include "SdFat.h"
 SdFat SD;
 SdFat SD;
 
 
+#define SD_CS_PIN SS
 File myFile;
 File myFile;
 
 
-void setup()
-{
+void setup() {
   // Open serial communications and wait for port to open:
   // Open serial communications and wait for port to open:
   Serial.begin(9600);
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
   while (!Serial) {
   while (!Serial) {
-    SysCall::yield();
+    ; // wait for serial port to connect. Needed for native USB port only
   }
   }
 
 
+
   Serial.print("Initializing SD card...");
   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)) {
   if (!SD.begin(SD_CS_PIN)) {
     Serial.println("initialization failed!");
     Serial.println("initialization failed!");
@@ -81,8 +74,7 @@ void setup()
   }
   }
 }
 }
 
 
-void loop()
-{
+void loop() {
   // nothing happens after setup
   // nothing happens after setup
 }
 }
 
 

+ 176 - 0
examples/STM32Test/STM32Test.ino

@@ -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() {}

+ 43 - 18
SdFat/examples/SdFormatter/SdFormatter.ino → examples/SdFormatter/SdFormatter.ino

@@ -11,13 +11,9 @@
  * For smaller cards this program uses FAT16
  * For smaller cards this program uses FAT16
  * and SDFormatter uses FAT12.
  * and SDFormatter uses FAT12.
  */
  */
-// Print extra info for debug if DEBUG_PRINT is nonzero
-#define DEBUG_PRINT 0
-#include <SPI.h>
-#include "SdFat.h"
-#if DEBUG_PRINT
-#include "FreeStack.h"
-#endif  // DEBUG_PRINT
+
+// Set USE_SDIO to zero for SPI card access. 
+#define USE_SDIO 0
 //
 //
 // Change the value of chipSelect if your hardware does
 // Change the value of chipSelect if your hardware does
 // not use the default value, SS.  Common values are:
 // not use the default value, SS.  Common values are:
@@ -26,16 +22,31 @@
 // Adafruit SD shields and modules: pin 10
 // Adafruit SD shields and modules: pin 10
 const uint8_t chipSelect = SS;
 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)
+
+// Print extra info for debug if DEBUG_PRINT is nonzero
+#define DEBUG_PRINT 0
+#include <SPI.h>
+#include "SdFat.h"
+#if DEBUG_PRINT
+#include "FreeStack.h"
+#endif  // DEBUG_PRINT
 
 
 // Serial output stream
 // Serial output stream
 ArduinoOutStream cout(Serial);
 ArduinoOutStream cout(Serial);
 
 
+#if USE_SDIO
+// Use faster SdioCardEX
+SdioCardEX card;
+// SdioCard card;
+#else  // USE_SDIO
 Sd2Card card;
 Sd2Card card;
+#endif  // USE_SDIO
+ 
 uint32_t cardSizeBlocks;
 uint32_t cardSizeBlocks;
-uint16_t cardCapacityMB;
+uint32_t cardCapacityMB;
 
 
 // cache for SD block
 // cache for SD block
 cache_t cache;
 cache_t cache;
@@ -65,11 +76,9 @@ char noName[] = "NO NAME    ";
 char fat16str[] = "FAT16   ";
 char fat16str[] = "FAT16   ";
 char fat32str[] = "FAT32   ";
 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()) {
   if (card.errorCode()) {
     cout << F("SD error: ") << hex << int(card.errorCode());
     cout << F("SD error: ") << hex << int(card.errorCode());
     cout << ',' << int(card.errorData()) << dec << endl;
     cout << ',' << int(card.errorData()) << dec << endl;
@@ -157,6 +166,16 @@ void clearCache(uint8_t addSig) {
 // zero FAT and root dir area on SD
 // zero FAT and root dir area on SD
 void clearFatDir(uint32_t bgn, uint32_t count) {
 void clearFatDir(uint32_t bgn, uint32_t count) {
   clearCache(false);
   clearCache(false);
+#if USE_SDIO
+  for (uint32_t i = 0; i < count; i++) {
+    if (!card.writeBlock(bgn + i, cache.data)) {
+       sdError("Clear FAT/DIR writeBlock failed");
+    }     
+    if ((i & 0XFF) == 0) {
+      cout << '.';
+    }    
+  }
+#else  // USE_SDIO
   if (!card.writeStart(bgn, count)) {
   if (!card.writeStart(bgn, count)) {
     sdError("Clear FAT/DIR writeStart failed");
     sdError("Clear FAT/DIR writeStart failed");
   }
   }
@@ -171,6 +190,7 @@ void clearFatDir(uint32_t bgn, uint32_t count) {
   if (!card.writeStop()) {
   if (!card.writeStop()) {
     sdError("Clear FAT/DIR writeStop failed");
     sdError("Clear FAT/DIR writeStop failed");
   }
   }
+#endif  // USE_SDIO
   cout << endl;
   cout << endl;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -498,14 +518,19 @@ void setup() {
     cout << F("Quiting, invalid option entered.") << endl;
     cout << F("Quiting, invalid option entered.") << endl;
     return;
     return;
   }
   }
-
-  if (!card.begin(chipSelect, spiSpeed)) {
+#if USE_SDIO
+  if (!card.begin()) {
+    sdError("card.begin failed");  
+  }
+#else  // USE_SDIO
+  if (!card.begin(chipSelect, SPI_SPEED)) {
     cout << F(
     cout << F(
            "\nSD initialization failure!\n"
            "\nSD initialization failure!\n"
            "Is the SD card inserted correctly?\n"
            "Is the SD card inserted correctly?\n"
            "Is chip select correct at the top of this program?\n");
            "Is chip select correct at the top of this program?\n");
     sdError("card.begin failed");
     sdError("card.begin failed");
   }
   }
+#endif  
   cardSizeBlocks = card.cardSize();
   cardSizeBlocks = card.cardSize();
   if (cardSizeBlocks == 0) {
   if (cardSizeBlocks == 0) {
     sdError("cardSize");
     sdError("cardSize");

+ 27 - 21
SdFat/examples/SdInfo/SdInfo.ino → examples/SdInfo/SdInfo.ino

@@ -3,6 +3,9 @@
  */
  */
 #include <SPI.h>
 #include <SPI.h>
 #include "SdFat.h"
 #include "SdFat.h"
+
+// Set USE_SDIO to zero for SPI card access. 
+#define USE_SDIO 0
 /*
 /*
  * SD chip select pin.  Common values are:
  * SD chip select pin.  Common values are:
  *
  *
@@ -18,7 +21,14 @@ const uint8_t SD_CHIP_SELECT = SS;
  * to 10 to disable the Ethernet controller.
  * to 10 to disable the Ethernet controller.
  */
  */
 const int8_t DISABLE_CHIP_SELECT = -1;
 const int8_t DISABLE_CHIP_SELECT = -1;
+
+#if USE_SDIO
+// Use faster SdioCardEX
+SdFatSdioEX sd;
+// SdFatSdio sd;
+#else // USE_SDIO
 SdFat sd;
 SdFat sd;
+#endif  // USE_SDIO
 
 
 // serial output steam
 // serial output steam
 ArduinoOutStream cout(Serial);
 ArduinoOutStream cout(Serial);
@@ -30,16 +40,7 @@ uint32_t cardSize;
 uint32_t eraseSize;
 uint32_t eraseSize;
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 // store error strings in flash
 // 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() {
 uint8_t cidDmp() {
   cid_t cid;
   cid_t cid;
@@ -97,17 +98,13 @@ uint8_t csdDmp() {
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 // print partition table
 // print partition table
 uint8_t partDmp() {
 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");
     sdErrorMsg("read MBR failed");
     return false;
     return false;
   }
   }
   for (uint8_t ip = 1; ip < 5; ip++) {
   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) {
     if ((pt->boot & 0X7F) != 0 || pt->firstSector > cardSize) {
       cout << F("\nNo MBR. Assuming Super Floppy format.\n");
       cout << F("\nNo MBR. Assuming Super Floppy format.\n");
       return true;
       return true;
@@ -116,7 +113,7 @@ uint8_t partDmp() {
   cout << F("\nSD Partition Table\n");
   cout << F("\nSD Partition Table\n");
   cout << F("part,boot,type,start,length\n");
   cout << F("part,boot,type,start,length\n");
   for (uint8_t ip = 1; ip < 5; ip++) {
   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 << int(ip) << ',' << hex << int(pt->boot) << ',' << int(pt->type);
     cout << dec << ',' << pt->firstSector <<',' << pt->totalSectors << endl;
     cout << dec << ',' << pt->firstSector <<',' << pt->totalSectors << endl;
   }
   }
@@ -156,6 +153,7 @@ void setup() {
 
 
   // F stores strings in flash to save RAM
   // F stores strings in flash to save RAM
   cout << F("SdFat version: ") << SD_FAT_VERSION << endl;
   cout << F("SdFat version: ") << SD_FAT_VERSION << endl;
+#if !USE_SDIO  
   if (DISABLE_CHIP_SELECT < 0) {
   if (DISABLE_CHIP_SELECT < 0) {
     cout << F(
     cout << F(
            "\nAssuming the SD is the only SPI device.\n"
            "\nAssuming the SD is the only SPI device.\n"
@@ -168,6 +166,7 @@ void setup() {
   }
   }
   cout << F("\nAssuming the SD chip select pin is: ") <<int(SD_CHIP_SELECT);
   cout << F("\nAssuming the SD chip select pin is: ") <<int(SD_CHIP_SELECT);
   cout << F("\nEdit SD_CHIP_SELECT to change the SD chip select pin.\n");
   cout << F("\nEdit SD_CHIP_SELECT to change the SD chip select pin.\n");
+#endif  // !USE_SDIO  
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void loop() {
 void loop() {
@@ -183,12 +182,19 @@ void loop() {
   }
   }
 
 
   uint32_t t = millis();
   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)) {
+#if USE_SDIO
+  if (!sd.cardBegin()) {
     sdErrorMsg("\ncardBegin failed");
     sdErrorMsg("\ncardBegin failed");
     return;
     return;
   }
   }
+#else  // USE_SDIO
+  // 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("cardBegin failed");
+    return;
+  }
+ #endif  // USE_SDIO 
   t = millis() - t;
   t = millis() - t;
 
 
   cardSize = sd.card()->cardSize();
   cardSize = sd.card()->cardSize();

+ 4 - 4
SdFat/examples/SoftwareSpi/SoftwareSpi.ino → examples/SoftwareSpi/SoftwareSpi.ino

@@ -5,7 +5,7 @@
 //
 //
 #include <SPI.h>
 #include <SPI.h>
 #include "SdFat.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.
 // Pin numbers in templates must be constants.
 const uint8_t SOFT_MISO_PIN = 12;
 const uint8_t SOFT_MISO_PIN = 12;
@@ -53,6 +53,6 @@ void setup() {
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void loop() {}
 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 → examples/StdioBench/StdioBench.ino

@@ -39,7 +39,10 @@ void setup() {
     SysCall::yield();
     SysCall::yield();
   }
   }
   Serial.println(F("Starting test"));
   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();
     sd.errorHalt();
   }
   }
 
 
@@ -137,10 +140,11 @@ void setup() {
 
 
         case 3:
         case 3:
           for (uint16_t i = 0; i < 10000; i++) {
           for (uint16_t i = 0; i < 10000; i++) {
+            uint32_t n = i + 1000000000UL;
 #if PRINT_FIELD
 #if PRINT_FIELD
-            stdioFile.printField(i + 1000000000UL, '\n');
+            stdioFile.printField(n, '\n');
 #else  // PRINT_FIELD
 #else  // PRINT_FIELD
-            stdioFile.println(i + 1000000000UL);
+            stdioFile.println(n);
 #endif  // PRINT_FIELD      
 #endif  // PRINT_FIELD      
           }
           }
           break;
           break;

+ 169 - 0
examples/TeensySdioDemo/TeensySdioDemo.ino

@@ -0,0 +1,169 @@
+// Simple performance test for Teensy 3.5/3.6 SDHC.
+// Demonstrates yield() efficiency.
+
+// Warning SdFatSdio and SdFatSdioEX normally should 
+// not both be used in a program.
+// Each has its own cache and member variables.
+
+#include "SdFat.h"
+
+// 32 KiB buffer.
+const size_t BUF_DIM = 32768;
+
+// 8 MiB file.
+const uint32_t FILE_SIZE = 256UL*BUF_DIM;
+
+SdFatSdio sd;
+
+SdFatSdioEX sdEx;
+
+File file;
+
+uint8_t buf[BUF_DIM];
+
+// buffer as uint32_t
+uint32_t* buf32 = (uint32_t*)buf;
+
+// Total usec in read/write calls.
+uint32_t totalMicros = 0;
+// Time in yield() function.
+uint32_t yieldMicros = 0;
+// Number of yield calls.
+uint32_t yieldCalls = 0;
+// Max busy time for single yield call.
+uint32_t yieldMaxUsec = 0;
+// Control access to the two versions of SdFat.
+bool useEx = false;
+//-----------------------------------------------------------------------------
+bool sdBusy() {
+  return useEx ? sdEx.card()->isBusy() : sd.card()->isBusy();
+}
+//-----------------------------------------------------------------------------
+void errorHalt(const char* msg) {
+  if (useEx) {
+    sdEx.errorHalt(msg);
+  } else {
+    sd.errorHalt(msg);
+  }
+}
+//------------------------------------------------------------------------------
+uint32_t kHzSdClk() {
+  return useEx ? sdEx.card()->kHzSdClk() : sd.card()->kHzSdClk(); 
+}  
+//------------------------------------------------------------------------------
+// Replace "weak" system yield() function.
+void yield() {
+  // Only count cardBusy time.
+  if (!sdBusy()) {
+    return;
+  }
+  uint32_t m = micros();
+  yieldCalls++;
+  while (sdBusy()) {
+    // Do something here.
+  }
+  m = micros() - m;
+  if (m > yieldMaxUsec) {
+    yieldMaxUsec = m;
+  }
+  yieldMicros += m;
+}
+//-----------------------------------------------------------------------------
+void runTest() {
+  // Zero Stats
+  totalMicros = 0;
+  yieldMicros = 0;
+  yieldCalls = 0;
+  yieldMaxUsec = 0; 
+  if (!file.open("TeensyDemo.bin", O_RDWR | O_CREAT)) {
+    errorHalt("open failed");
+  }
+  Serial.println("\nsize,write,read");
+  Serial.println("bytes,KB/sec,KB/sec");
+  for (size_t nb = 512; nb <= BUF_DIM; nb *= 2) {
+    file.truncate(0);
+    uint32_t nRdWr = FILE_SIZE/nb;
+    Serial.print(nb);
+    Serial.print(',');
+    uint32_t t = micros();
+    for (uint32_t n = 0; n < nRdWr; n++) {
+      // Set start and end of buffer.
+      buf32[0] = n;
+      buf32[nb/4 - 1] = n;
+      if (nb != file.write(buf, nb)) {
+        errorHalt("write failed");
+      }
+    }
+    t = micros() - t;
+    totalMicros += t;
+    Serial.print(1000.0*FILE_SIZE/t);
+    Serial.print(',');
+    file.rewind();
+    t = micros();
+    
+    for (uint32_t n = 0; n < nRdWr; n++) {
+      if ((int)nb != file.read(buf, nb)) {
+        errorHalt("read failed");
+      }
+      // crude check of data.     
+      if (buf32[0] != n || buf32[nb/4 - 1] != n) {
+        errorHalt("data check");
+      }
+    }
+    t = micros() - t;
+    totalMicros += t;   
+    Serial.println(1000.0*FILE_SIZE/t);    
+  }
+  file.close();
+  Serial.print("\ntotalMicros  ");
+  Serial.println(totalMicros);
+  Serial.print("yieldMicros  ");
+  Serial.println(yieldMicros);
+  Serial.print("yieldCalls   ");
+  Serial.println(yieldCalls);
+  Serial.print("yieldMaxUsec ");
+  Serial.println(yieldMaxUsec); 
+  Serial.print("kHzSdClk     ");
+  Serial.println(kHzSdClk());
+  Serial.println("Done");
+}
+//-----------------------------------------------------------------------------
+void setup() {
+  Serial.begin(9600);
+  while (!Serial) {
+  }
+  Serial.println("SdFatSdioEX uses extended multi-block transfers without DMA.");
+  Serial.println("SdFatSdio uses a traditional DMA SDIO implementation."); 
+  Serial.println("Note the difference is speed and busy yield time.\n"); 
+}
+//-----------------------------------------------------------------------------
+void loop() {
+  do {
+    delay(10);
+  } while (Serial.available() && Serial.read());
+
+  Serial.println("Type '1' for SdFatSdioEX or '2' for SdFatSdio");
+  while (!Serial.available()) {
+  }
+  char c = Serial.read();
+  if (c != '1' && c != '2') {
+    Serial.println("Invalid input");
+    return;
+  }
+  if (c =='1') {
+    useEx = true;
+    if (!sdEx.begin()) {
+      sd.initErrorHalt("SdFatSdioEX begin() failed");
+    }
+    // make sdEx the current volume.
+    sdEx.chvol();
+  } else {
+    useEx = false;
+    if (!sd.begin()) {
+      sd.initErrorHalt("SdFatSdio begin() failed");
+    }
+    // make sd the current volume.
+    sd.chvol();  
+  }
+  runTest();
+}

+ 3 - 3
SdFat/examples/Timestamp/Timestamp.ino → examples/Timestamp/Timestamp.ino

@@ -83,9 +83,9 @@ void setup(void) {
   while (!Serial.available()) {
   while (!Serial.available()) {
     SysCall::yield();  
     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();
     sd.initErrorHalt();
   }
   }
 
 

+ 1 - 0
SdFat/examples/TwoCards/TwoCards.ino → examples/TwoCards/TwoCards.ino

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

+ 3 - 3
SdFat/examples/VolumeFreeSpace/VolumeFreeSpace.ino → examples/VolumeFreeSpace/VolumeFreeSpace.ino

@@ -49,9 +49,9 @@ void setup() {
   while (!Serial.available()) {
   while (!Serial.available()) {
     SysCall::yield();
     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();
     sd.initErrorHalt();
   }
   }
   // Insure no TEST_FILE. 
   // Insure no TEST_FILE. 

+ 25 - 6
SdFat/examples/bench/bench.ino → examples/bench/bench.ino

@@ -5,6 +5,9 @@
 #include "SdFat.h"
 #include "SdFat.h"
 #include "FreeStack.h"
 #include "FreeStack.h"
 
 
+// Set USE_SDIO to zero for SPI card access. 
+#define USE_SDIO 0
+
 // SD chip select pin
 // SD chip select pin
 const uint8_t chipSelect = SS;
 const uint8_t chipSelect = SS;
 
 
@@ -28,9 +31,20 @@ const uint32_t FILE_SIZE = 1000000UL*FILE_SIZE_MB;
 uint8_t buf[BUF_SIZE];
 uint8_t buf[BUF_SIZE];
 
 
 // file system
 // file system
+#if USE_SDIO
+// Traditional DMA version.
+// SdFatSdio sd;
+// Faster version.
+SdFatSdioEX sd;
+#else  // USE_SDIO
 SdFat sd;
 SdFat sd;
-// Set SD_SPI_CONFIGURATION to three to test next two definitions.
-// SdFatLibSpi sd;
+#endif  // USE_SDIO
+
+// 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.
 // Args are misoPin, mosiPin, sckPin.
 // SdFatSoftSpi<6, 7, 5> sd;
 // SdFatSoftSpi<6, 7, 5> sd;
 
 
@@ -98,12 +112,17 @@ void loop() {
 
 
   cout << F("FreeStack: ") << FreeStack() << endl;
   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)) {
+#if USE_SDIO
+  if (!sd.begin()) {
     sd.initErrorHalt();
     sd.initErrorHalt();
   }
   }
-
+#else  // USE_SDIO  
+  // 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();
+  }
+#endif  // USE_SDIO  
   cout << F("Type is FAT") << int(sd.vol()->fatType()) << endl;
   cout << F("Type is FAT") << int(sd.vol()->fatType()) << endl;
   cout << F("Card size: ") << sd.card()->cardSize()*512E-9;
   cout << F("Card size: ") << sd.card()->cardSize()*512E-9;
   cout << F(" GB (GB = 1E9 bytes)") << endl;
   cout << F(" GB (GB = 1E9 bytes)") << endl;

+ 3 - 3
SdFat/examples/dataLogger/dataLogger.ino → examples/dataLogger/dataLogger.ino

@@ -79,9 +79,9 @@ void setup() {
     SysCall::yield();
     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();
     sd.initErrorHalt();
   }
   }
 
 

+ 3 - 3
SdFat/examples/fgets/fgets.ino → examples/fgets/fgets.ino

@@ -72,9 +72,9 @@ void setup(void) {
   }
   }
   delay(400);  // catch Due reset problem
   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();
     sd.initErrorHalt();
   }
   }
 
 

+ 0 - 0
SdFat/examples/formatting/formatting.ino → examples/formatting/formatting.ino


+ 3 - 3
SdFat/examples/getline/getline.ino → examples/getline/getline.ino

@@ -66,9 +66,9 @@ void setup(void) {
     SysCall::yield();
     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();
     sd.initErrorHalt();
   }
   }
 
 

+ 3 - 3
SdFat/examples/rename/rename.ino → examples/rename/rename.ino

@@ -29,9 +29,9 @@ void setup() {
     SysCall::yield();
     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();
     sd.initErrorHalt();
   }
   }
 
 

+ 6 - 2
SdFat/examples/wipe/wipe.ino → examples/wipe/wipe.ino

@@ -20,7 +20,9 @@ void setup() {
   if (c != 'Y') {
   if (c != 'Y') {
     sd.errorHalt("Quitting, you did not type '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();
     sd.initErrorHalt();
   }
   }
   // Use wipe() for no dot progress indicator.
   // Use wipe() for no dot progress indicator.
@@ -28,7 +30,9 @@ void setup() {
     sd.errorHalt("Wipe failed.");
     sd.errorHalt("Wipe failed.");
   }
   }
   // Must reinitialize after wipe.
   // 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.");
     sd.errorHalt("Second init failed.");
   }
   }
   Serial.println("Done");
   Serial.println("Done");

+ 0 - 0
AnalogBinLoggerExtras/ADC_ENOB.PNG → extras/AnalogBinLoggerExtras/ADC_ENOB.PNG


+ 0 - 0
AnalogBinLoggerExtras/ADCdocs/ATmegaADCAccuracy.pdf → extras/AnalogBinLoggerExtras/ADCdocs/ATmegaADCAccuracy.pdf


+ 0 - 0
AnalogBinLoggerExtras/ADCdocs/ExcelFFT.pdf → extras/AnalogBinLoggerExtras/ADCdocs/ExcelFFT.pdf


+ 0 - 0
AnalogBinLoggerExtras/AdcErrorStudy.txt → extras/AnalogBinLoggerExtras/AdcErrorStudy.txt


+ 0 - 0
AnalogBinLoggerExtras/DATA.png → extras/AnalogBinLoggerExtras/DATA.png


+ 0 - 0
AnalogBinLoggerExtras/FFT.png → extras/AnalogBinLoggerExtras/FFT.png


+ 0 - 0
AnalogBinLoggerExtras/RateTable.txt → extras/AnalogBinLoggerExtras/RateTable.txt


+ 0 - 0
AnalogBinLoggerExtras/bintocsv/AnalogBinLogger.h → extras/AnalogBinLoggerExtras/bintocsv/AnalogBinLogger.h


+ 0 - 0
AnalogBinLoggerExtras/bintocsv/bintocsv.cpp → extras/AnalogBinLoggerExtras/bintocsv/bintocsv.cpp


+ 0 - 0
AnalogBinLoggerExtras/bintocsv/bintocsv.exe → extras/AnalogBinLoggerExtras/bintocsv/bintocsv.exe


+ 0 - 0
AnalogBinLoggerExtras/readme.txt → extras/AnalogBinLoggerExtras/readme.txt


+ 23 - 18
SdFat/MainPage/SdFatmainpage.h → extras/MainPage/SdFatmainpage.h

@@ -34,15 +34,17 @@ nonzero in SdFatConfig.h.
 The %SdFat library supports Long %File Names or short 8.3 names.
 The %SdFat library supports Long %File Names or short 8.3 names.
 Edit the SdFatConfig.h file to select short or long file 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,
 SdBaseFile, SdFile, File, StdioStream, \ref fstream, \ref ifstream,
 and \ref ofstream.
 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(),
 The SdBaseFile class provides basic file access functions such as open(),
 binary read(), binary write(), close(), remove(), and sync(). SdBaseFile
 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.
 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.
 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.
 To enable SD card CRC checking set USE_SD_CRC nonzero.
 
 
 Set FAT12_SUPPORT nonzero to enable use of FAT12 volumes.
 Set FAT12_SUPPORT nonzero to enable use of FAT12 volumes.
 FAT12 has not been well tested and requires additional flash.
 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
 \section SDPath Paths and Working Directories
 
 
 Relative paths in SdFat are resolved in a manner similar to Windows.
 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.
 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.
 OpenNext - Open all files in the root dir and print their filename.
 
 
@@ -370,8 +379,6 @@ ReadCsvArray - Read a two dimensional array from a CSV file.
 
 
 ReadWrite - Compatibility test of Arduino SD ReadWrite example.
 ReadWrite - Compatibility test of Arduino SD ReadWrite example.
 
 
-ReadWriteSdFat - SdFat version of Arduino SD ReadWrite example.
-
 rename - A demo of SdFat::rename(old, new) and SdFile::rename(dirFile, newPath).
 rename - A demo of SdFat::rename(old, new) and SdFile::rename(dirFile, newPath).
 
 
 SdFormatter - This program will format an SD or SDHC card.
 SdFormatter - This program will format an SD or SDHC card.
@@ -382,8 +389,6 @@ SdInfo - Initialize an SD card and analyze its structure for trouble shooting.
 
 
 StdioBench - Demo and test of stdio style stream.
 StdioBench - Demo and test of stdio style stream.
 
 
-ThreeCards - Demonstrate simultaneous use of SdFat, SdFatLibSpi, SdFatSoftSpi.
-
 Timestamp - Sets file create, modify, and access timestamps.
 Timestamp - Sets file create, modify, and access timestamps.
 
 
 TwoCards - Example using two SD cards.
 TwoCards - Example using two SD cards.

+ 0 - 0
SdFat.html → extras/SdFat.html


+ 0 - 0
SdFatTestSuite/SdFatTestSuite.cpp → extras/SdFatTestSuite/SdFatTestSuite.cpp


+ 0 - 0
SdFatTestSuite/SdFatTestSuite.h → extras/SdFatTestSuite/SdFatTestSuite.h


+ 0 - 0
SdFatTestSuite/examples/ATS_SD_File/ATS_SD_File.ino → extras/SdFatTestSuite/examples/ATS_SD_File/ATS_SD_File.ino


+ 0 - 0
SdFatTestSuite/examples/ATS_SD_Files/ATS_SD_Files.ino → extras/SdFatTestSuite/examples/ATS_SD_Files/ATS_SD_Files.ino


+ 0 - 0
SdFatTestSuite/examples/ATS_SD_Seek/ATS_SD_Seek.ino → extras/SdFatTestSuite/examples/ATS_SD_Seek/ATS_SD_Seek.ino


+ 0 - 0
SdFatTestSuite/examples/StressTest/StressTest.ino → extras/SdFatTestSuite/examples/StressTest/StressTest.ino


+ 0 - 0
SdFatTestSuite/examples/TestMkdir/TestMkdir.ino → extras/SdFatTestSuite/examples/TestMkdir/TestMkdir.ino


+ 0 - 0
SdFatTestSuite/examples/TestRmdir/TestRmdir.ino → extras/SdFatTestSuite/examples/TestRmdir/TestRmdir.ino


+ 0 - 0
SdFatTestSuite/examples/fstreamTest/fstreamTest.ino → extras/SdFatTestSuite/examples/fstreamTest/fstreamTest.ino


Vissa filer visades inte eftersom för många filer har ändrats