浏览代码

New version for library manager

Bill Greiman 7 年之前
父节点
当前提交
6bb055d415
共有 100 个文件被更改,包括 2444 次插入1799 次删除
  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.
 
-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.
 
-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;
 #endif  // USE_DS1307
 
-  // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
-  if (!sd.begin(SD_CHIP_SELECT, SPI_HALF_SPEED)) {
+  // Initialize at the highest speed supported by the board that is
+  // not over 50 MHz. Try a lower speed if SPI errors occur.
+  if (!sd.begin(SD_CHIP_SELECT, SD_SCK_MHZ(50))) {
     sd.initErrorHalt();
   }
 

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

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

+ 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;
 
 // SD card chip select pin - Modify the value of csPin for your SD module.
-const uint8_t csPin = 10;
+const uint8_t csPin = SS;
 
 File file;
 //------------------------------------------------------------------------------

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

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

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

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

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

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

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

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

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

+ 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.
-#define error(msg) errorFlash(F(msg))
-//------------------------------------------------------------------------------
-void errorFlash(const __FlashStringHelper* msg) {
-  sd.errorPrint(msg);
-  fatalBlink();
-}
+#define error(msg) {sd.errorPrint(F(msg));fatalBlink();}
 //------------------------------------------------------------------------------
 //
 void fatalBlink() {
@@ -625,8 +620,7 @@ void logData() {
   // Create new file.
   Serial.println(F("Creating new file"));
   binFile.close();
-  if (!binFile.createContiguous(sd.vwd(),
-                                TMP_FILE_NAME, 512 * FILE_BLOCK_COUNT)) {
+  if (!binFile.createContiguous(TMP_FILE_NAME, 512 * FILE_BLOCK_COUNT)) {
     error("createContiguous failed");
   }
   // Get the address of the file on the SD.
@@ -783,8 +777,9 @@ void setup(void) {
   Serial.print(F("FreeStack: "));
   Serial.println(FreeStack());
 
-  // initialize file system.
-  if (!sd.begin(SD_CS_PIN, SPI_FULL_SPEED)) {
+  // Initialize at the highest speed supported by the board that is
+  // not over 50 MHz. Try a lower speed if SPI errors occur.
+  if (!sd.begin(SD_CS_PIN, SD_SCK_MHZ(50))) {
     sd.initErrorPrint();
     fatalBlink();
   }

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

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

+ 3 - 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"
                    "SdFat/examples/LongFileName/testFiles"));
 
-  if (!sd.begin(SD_CS_PIN)) {
+  // Initialize at the highest speed supported by the board that is
+  // not over 50 MHz. Try a lower speed if SPI errors occur.
+  if (!sd.begin(SD_CS_PIN, SD_SCK_MHZ(50))) {
     sd.initErrorHalt();
   }
   Serial.print(F("FreeStack: "));

+ 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
  * slower sample rates.  Using a Mega Arduino helps overcome latency
- * problems since 13 512 byte buffers will be used.
+ * problems since 12 512 byte buffers will be used.
  *
  * Data is written to the file using a SD multiple block write command.
  */
 #include <SPI.h>
 #include "SdFat.h"
 #include "FreeStack.h"
-#include "UserDataType.h"  // Edit this include file to change data_t.
-//------------------------------------------------------------------------------
-// Set useSharedSpi true for use of an SPI sensor.
-// 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.
 //==============================================================================
+// Abort run on an overrun.  Data before the overrun will be saved.
+#define ABORT_ON_OVERRUN 1
+//------------------------------------------------------------------------------
 //Interval between data records in microseconds.
 const uint32_t LOG_INTERVAL_USEC = 2000;
 //------------------------------------------------------------------------------
+// Set USE_SHARED_SPI non-zero for use of an SPI sensor.
+// May not work for some cards.
+#ifndef USE_SHARED_SPI
+#define USE_SHARED_SPI 0
+#endif  // USE_SHARED_SPI
+//------------------------------------------------------------------------------
 // Pin definitions.
 //
 // SD chip select pin.
 const uint8_t SD_CS_PIN = SS;
 //
 // Digital pin to indicate an error, set to -1 if not used.
-// The led blinks for fatal errors. The led goes on solid for SD write
-// overrun errors and logging continues.
+// The led blinks for fatal errors. The led goes on solid for
+// overrun errors and logging continues unless ABORT_ON_OVERRUN
+// is non-zero.
+#ifdef ERROR_LED_PIN
 #undef ERROR_LED_PIN
+#endif  // ERROR_LED_PIN
 const int8_t ERROR_LED_PIN = -1;
 //------------------------------------------------------------------------------
 // File definitions.
@@ -78,49 +59,51 @@ const int8_t ERROR_LED_PIN = -1;
 // This file is flash erased using special SD commands.  The file will be
 // truncated if logging is stopped early.
 const uint32_t FILE_BLOCK_COUNT = 256000;
-
-// log file base name.  Must be six characters or less.
+//
+// log file base name if not defined in UserTypes.h
+#ifndef FILE_BASE_NAME
 #define FILE_BASE_NAME "data"
+#endif  // FILE_BASE_NAME
 //------------------------------------------------------------------------------
 // Buffer definitions.
 //
-// The logger will use SdFat's buffer plus BUFFER_BLOCK_COUNT additional
+// The logger will use SdFat's buffer plus BUFFER_BLOCK_COUNT-1 additional
 // buffers.
 //
 #ifndef RAMEND
-// Assume ARM. Use total of nine 512 byte buffers.
-const uint8_t BUFFER_BLOCK_COUNT = 8;
+// Assume ARM. Use total of ten 512 byte buffers.
+const uint8_t BUFFER_BLOCK_COUNT = 10;
 //
 #elif RAMEND < 0X8FF
 #error Too little SRAM
 //
 #elif RAMEND < 0X10FF
 // Use total of two 512 byte buffers.
-const uint8_t BUFFER_BLOCK_COUNT = 1;
+const uint8_t BUFFER_BLOCK_COUNT = 2;
 //
 #elif RAMEND < 0X20FF
-// Use total of five 512 byte buffers.
+// Use total of four 512 byte buffers.
 const uint8_t BUFFER_BLOCK_COUNT = 4;
 //
 #else  // RAMEND
-// Use total of 13 512 byte buffers.
+// Use total of 12 512 byte buffers.
 const uint8_t BUFFER_BLOCK_COUNT = 12;
 #endif  // RAMEND
 //==============================================================================
 // End of configuration constants.
 //==============================================================================
 // 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 FILE_NAME_DIM  = BASE_NAME_SIZE + 7;
+char binName[FILE_NAME_DIM] = FILE_BASE_NAME "00.bin";
 
 SdFat sd;
 
 SdBaseFile binFile;
 
-char binName[13] = FILE_BASE_NAME "00.bin";
-
 // Number of data records in a block.
 const uint16_t DATA_DIM = (512 - 4)/sizeof(data_t);
 
@@ -133,33 +116,14 @@ struct block_t {
   data_t data[DATA_DIM];
   uint8_t fill[FILL_DIM];
 };
-
-const uint8_t QUEUE_DIM = BUFFER_BLOCK_COUNT + 2;
-
-block_t* emptyQueue[QUEUE_DIM];
-uint8_t emptyHead;
-uint8_t emptyTail;
-
-block_t* fullQueue[QUEUE_DIM];
-uint8_t fullHead;
-uint8_t fullTail;
-
-// Advance queue index.
-inline uint8_t queueNext(uint8_t ht) {
-  return ht < (QUEUE_DIM - 1) ? ht + 1 : 0;
-}
 //==============================================================================
 // Error messages stored in flash.
-#define error(msg) errorFlash(F(msg))
-//------------------------------------------------------------------------------
-void errorFlash(const __FlashStringHelper* msg) {
-  sd.errorPrint(msg);
-  fatalBlink();
-}
+#define error(msg) {sd.errorPrint(&Serial, F(msg));fatalBlink();}
 //------------------------------------------------------------------------------
 //
 void fatalBlink() {
   while (true) {
+    SysCall::yield();
     if (ERROR_LED_PIN >= 0) {
       digitalWrite(ERROR_LED_PIN, HIGH);
       delay(200);
@@ -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.
 void binaryToCsv() {
   uint8_t lastPct = 0;
@@ -176,14 +182,17 @@ void binaryToCsv() {
   uint32_t t0 = millis();
   uint32_t syncCluster = 0;
   SdFile csvFile;
-  char csvName[13];
+  char csvName[FILE_NAME_DIM];
 
   if (!binFile.isOpen()) {
     Serial.println();
     Serial.println(F("No current binary file"));
     return;
   }
-  binFile.rewind();
+  Serial.println();
+  Serial.print(F("FreeStack: "));
+  Serial.println(FreeStack());
+  
   // Create a new csvFile.
   strcpy(csvName, binName);
   strcpy(&csvName[BASE_NAME_SIZE + 3], "csv");
@@ -191,7 +200,7 @@ void binaryToCsv() {
   if (!csvFile.open(csvName, O_WRITE | O_CREAT | O_TRUNC)) {
     error("open csvFile failed");
   }
-  Serial.println();
+  binFile.rewind();
   Serial.print(F("Writing: "));
   Serial.print(csvName);
   Serial.println(F(" - type any character to stop"));
@@ -199,7 +208,7 @@ void binaryToCsv() {
   uint32_t tPct = millis();
   while (!Serial.available() && binFile.read(&block, 512) == 512) {
     uint16_t i;
-    if (block.count == 0) {
+    if (block.count == 0 || block.count > DATA_DIM) {
       break;
     }
     if (block.overrun) {
@@ -231,48 +240,42 @@ void binaryToCsv() {
   Serial.print(0.001*(millis() - t0));
   Serial.println(F(" Seconds"));
 }
-//------------------------------------------------------------------------------
-// read data file and check for overruns
-void checkOverrun() {
-  bool headerPrinted = false;
-  block_t block;
+//-----------------------------------------------------------------------------
+void createBinFile() {
+  // max number of blocks to erase per erase call
+  const uint32_t ERASE_SIZE = 262144L;
   uint32_t bgnBlock, endBlock;
-  uint32_t bn = 0;
-
-  if (!binFile.isOpen()) {
-    Serial.println();
-    Serial.println(F("No current binary file"));
-    return;
+  
+  // 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");
   }
-  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
-// max number of blocks to erase per erase call
-uint32_t const ERASE_SIZE = 262144L;
 void logData() {
-  uint32_t bgnBlock, endBlock;
-
-  // Allocate extra buffer space.
-  block_t block[BUFFER_BLOCK_COUNT];
-  block_t* curBlock = 0;
-  Serial.println();
-
-  // Find unused file name.
-  if (BASE_NAME_SIZE > 6) {
-    error("FILE_BASE_NAME too long");
-  }
-  while (sd.exists(binName)) {
-    if (binName[BASE_NAME_SIZE + 1] != '9') {
-      binName[BASE_NAME_SIZE + 1]++;
-    } else {
-      binName[BASE_NAME_SIZE + 1] = '0';
-      if (binName[BASE_NAME_SIZE] == '9') {
-        error("Can't create file name");
-      }
-      binName[BASE_NAME_SIZE]++;
+  createBinFile();
+  recordBinFile();
+  renameBinFile();
+}
+//------------------------------------------------------------------------------
+void openBinFile() {
+  char name[FILE_NAME_DIM];
+  strcpy(name, binName);
+  Serial.println(F("\nEnter two digit version"));
+  Serial.write(name, BASE_NAME_SIZE);
+  for (int i = 0; i < 2; i++) {
+    while (!Serial.available()) {
+     SysCall::yield();
     }
-  }
-  // Delete old tmp file.
-  if (sd.exists(TMP_FILE_NAME)) {
-    Serial.println(F("Deleting tmp file"));
-    if (!sd.remove(TMP_FILE_NAME)) {
-      error("Can't remove tmp file");
+    char c = Serial.read();
+    Serial.write(c);
+    if (c < '0' || c > '9') {
+      Serial.println(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.
-  uint8_t* cache = (uint8_t*)sd.vol()->cacheClear();
-  if (cache == 0) {
+  emptyStack[0] = (block_t*)sd.vol()->cacheClear();
+  if (emptyStack[0] == 0) {
     error("cacheClear failed");
   }
-
-  // Flash erase all data in the file.
-  Serial.println(F("Erasing all data"));
-  uint32_t bgnErase = bgnBlock;
-  uint32_t endErase;
-  while (bgnErase < endBlock) {
-    endErase = bgnErase + ERASE_SIZE;
-    if (endErase > endBlock) {
-      endErase = endBlock;
-    }
-    if (!sd.card()->erase(bgnErase, endErase)) {
-      error("erase failed");
-    }
-    bgnErase = endErase + 1;
+  // Put rest of buffers on the empty stack.
+  for (int i = 1; i < BUFFER_BLOCK_COUNT; i++) {
+    emptyStack[i] = &block[i - 1];
   }
+  emptyTop = BUFFER_BLOCK_COUNT;
+  minTop = BUFFER_BLOCK_COUNT;
+  
   // Start a multiple block write.
-  if (!sd.card()->writeStart(bgnBlock, FILE_BLOCK_COUNT)) {
-    error("writeBegin failed");
-  }
-  // 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"));
-  // Wait for Serial Idle.
-  Serial.flush();
-  delay(10);
   bool closeFile = false;
-  uint32_t bn = 0;
-  uint32_t t0 = millis();
-  uint32_t t1 = t0;
+  uint32_t bn = 0;  
+  uint32_t maxLatency = 0;
   uint32_t overrun = 0;
   uint32_t overrunTotal = 0;
-  uint32_t count = 0;
-  uint32_t maxDelta = 0;
-  uint32_t minDelta = 99999;
-  uint32_t maxLatency = 0;
   uint32_t logTime = micros();
-
-  // Set time for first record of file.
-  startMicros = logTime + LOG_INTERVAL_USEC;
-
-  while (1) {
-    // Time for next data record.
+  while(1) {
+     // Time for next data record.
     logTime += LOG_INTERVAL_USEC;
     if (Serial.available()) {
       closeFile = true;
-    }
-
+    }  
     if (closeFile) {
       if (curBlock != 0) {
         // Put buffer in full queue.
         fullQueue[fullHead] = curBlock;
-        fullHead = queueNext(fullHead);
+        fullHead = fullHead < QUEUE_LAST ? fullHead + 1 : 0;
         curBlock = 0;
       }
     } else {
-      if (curBlock == 0 && emptyTail != emptyHead) {
-        curBlock = emptyQueue[emptyTail];
-        emptyTail = queueNext(emptyTail);
+      if (curBlock == 0 && emptyTop != 0) {
+        curBlock = emptyStack[--emptyTop];
+        if (emptyTop < minTop) {
+          minTop = emptyTop;
+        }
         curBlock->count = 0;
         curBlock->overrun = overrun;
         overrun = 0;
@@ -435,24 +420,29 @@ void logData() {
       } while (delta < 0);
       if (curBlock == 0) {
         overrun++;
+        overrunTotal++;
+        if (ERROR_LED_PIN >= 0) {
+          digitalWrite(ERROR_LED_PIN, HIGH);
+        }        
+#if ABORT_ON_OVERRUN
+        Serial.println(F("Overrun abort"));
+        break;
+ #endif  // ABORT_ON_OVERRUN       
       } else {
-        if (useSharedSpi) {
-          sd.card()->chipSelectHigh();
-        }
+#if USE_SHARED_SPI
+        sd.card()->spiStop();
+#endif  // USE_SHARED_SPI   
         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) {
           fullQueue[fullHead] = curBlock;
-          fullHead = queueNext(fullHead);
+          fullHead = fullHead < QUEUE_LAST ? fullHead + 1 : 0;
           curBlock = 0;
-        }
-        if ((uint32_t)delta > maxDelta) maxDelta = delta;
-        if ((uint32_t)delta < minDelta) minDelta = delta;          
+        } 
       }
     }
-
     if (fullHead == fullTail) {
       // Exit loop if done.
       if (closeFile) {
@@ -461,29 +451,18 @@ void logData() {
     } else if (!sd.card()->isBusy()) {
       // Get address of block to write.
       block_t* pBlock = fullQueue[fullTail];
-      fullTail = queueNext(fullTail);
+      fullTail = fullTail < QUEUE_LAST ? fullTail + 1 : 0;
       // Write block to SD.
       uint32_t usec = micros();
       if (!sd.card()->writeData((uint8_t*)pBlock)) {
         error("write data failed");
       }
       usec = micros() - usec;
-      t1 = millis();
       if (usec > maxLatency) {
         maxLatency = usec;
       }
-      count += pBlock->count;
-
-      // Add overruns and possibly light LED.
-      if (pBlock->overrun) {
-        overrunTotal += pBlock->overrun;
-        if (ERROR_LED_PIN >= 0) {
-          digitalWrite(ERROR_LED_PIN, HIGH);
-        }
-      }
       // Move block to empty queue.
-      emptyQueue[emptyHead] = pBlock;
-      emptyHead = queueNext(emptyHead);
+      emptyStack[emptyTop++] = pBlock;
       bn++;
       if (bn == FILE_BLOCK_COUNT) {
         // File full so stop
@@ -494,6 +473,12 @@ void logData() {
   if (!sd.card()->writeStop()) {
     error("writeStop failed");
   }
+  Serial.print(F("Min Free buffers: "));
+  Serial.println(minTop);
+  Serial.print(F("Max block write usec: "));
+  Serial.println(maxLatency);
+  Serial.print(F("Overruns: "));
+  Serial.println(overrunTotal);
   // Truncate file if recording stopped early.
   if (bn != FILE_BLOCK_COUNT) {
     Serial.println(F("Truncating file"));
@@ -501,25 +486,76 @@ void logData() {
       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("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) {
@@ -532,19 +568,38 @@ void setup(void) {
   while (!Serial) {
     SysCall::yield();
   }
-
-  Serial.print(F("FreeStack: "));
+  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");
   }
-  // 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();
   }
+  // 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) {
@@ -554,14 +609,21 @@ void loop(void) {
   } while (Serial.available() && Serial.read() >= 0);
   Serial.println();
   Serial.println(F("type:"));
+  Serial.println(F("b - open existing bin file"));  
   Serial.println(F("c - convert file to csv"));
   Serial.println(F("d - dump data to Serial"));
   Serial.println(F("e - overrun error details"));
+  Serial.println(F("l - list files"));  
   Serial.println(F("r - record data"));
-
+  Serial.println(F("t - test without logging"));
   while(!Serial.available()) {
     SysCall::yield();
   }
+#if WDT_YIELD_TIME_MICROS
+  Serial.println(F("LowLatencyLogger can not run with watchdog timer"));
+  SysCall::halt();
+#endif
+  
   char c = tolower(Serial.read());
 
   // Discard extra Serial data.
@@ -572,15 +634,22 @@ void loop(void) {
   if (ERROR_LED_PIN >= 0) {
     digitalWrite(ERROR_LED_PIN, LOW);
   }
-  if (c == 'c') {
+  if (c == 'b') {
+    openBinFile();
+  } else if (c == 'c') {
     binaryToCsv();
   } else if (c == 'd') {
     dumpData();
   } else if (c == 'e') {
     checkOverrun();
+  } else if (c == 'l') {
+    Serial.println(F("\nls:"));  
+    sd.ls(&Serial, LS_SIZE);  
   } else if (c == 'r') {
     logData();
+  } else if (c == 't') {
+    testSensor();    
   } else {
     Serial.println(F("Invalid entry"));
   }
-}
+}

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

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

@@ -49,9 +49,9 @@ void loop() {
 
   cout << F("FreeStack: ") << FreeStack() << endl;
 
-  // initialize the SD card at SPI_FULL_SPEED for best performance.
-  // try SPI_HALF_SPEED if bus errors occur.
-  if (!sd.begin(chipSelect, SPI_FULL_SPEED)) {
+  // Initialize at the highest speed supported by the board that is
+  // not over 50 MHz. Try a lower speed if SPI errors occur.
+  if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
     sd.initErrorHalt();
   }
 

+ 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 "SdFat.h"
@@ -8,10 +8,10 @@
 // to 10 to disable the Ethernet controller.
 const int8_t DISABLE_CHIP_SELECT = -1;
 //
-// Test with reduced SPI speed for breadboards.
-// Change spiSpeed to SPI_FULL_SPEED for better performance
-// Use SPI_QUARTER_SPEED for even slower SPI bus speed
-const uint8_t spiSpeed = SPI_HALF_SPEED;
+// Test with reduced SPI speed for breadboards.  SD_SCK_MHZ(4) will select 
+// the highest speed supported by the board that is not over 4 MHz.
+// Change SPI_SPEED to SD_SCK_MHZ(50) for best performance.
+#define SPI_SPEED SD_SCK_MHZ(4)
 //------------------------------------------------------------------------------
 // File system object.
 SdFat sd;
@@ -28,7 +28,7 @@ int chipSelect;
 
 void cardOrSpeed() {
   cout << F("Try another SD card or reduce the SPI bus speed.\n");
-  cout << F("Edit spiSpeed in this program to change it.\n");
+  cout << F("Edit SPI_SPEED in this program to change it.\n");
 }
 
 void reformatMsg() {
@@ -98,7 +98,7 @@ void loop() {
     pinMode(DISABLE_CHIP_SELECT, OUTPUT);
     digitalWrite(DISABLE_CHIP_SELECT, HIGH);
   }
-  if (!sd.begin(chipSelect, spiSpeed)) {
+  if (!sd.begin(chipSelect, SPI_SPEED)) {
     if (sd.card()->errorCode()) {
       cout << F(
              "\nSD initialization failed.\n"

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

@@ -64,9 +64,9 @@ void loop(void) {
 
   cout << F("FreeStack: ") << FreeStack() << endl;
 
-  // initialize the SD card at SPI_FULL_SPEED for best performance.
-  // try SPI_HALF_SPEED if bus errors occur.
-  if (!sd.begin(chipSelect, SPI_FULL_SPEED)) {
+  // Initialize at the highest speed supported by the board that is
+  // not over 50 MHz. Try a lower speed if SPI errors occur.
+  if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
     sd.initErrorHalt();
   }
 
@@ -74,7 +74,7 @@ void loop(void) {
   sd.remove("RawWrite.txt");
 
   // create a contiguous file
-  if (!file.createContiguous(sd.vwd(), "RawWrite.txt", 512UL*BLOCK_COUNT)) {
+  if (!file.createContiguous("RawWrite.txt", 512UL*BLOCK_COUNT)) {
     error("createContiguous failed");
   }
   // get the location of the file's blocks

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

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

@@ -7,7 +7,6 @@
  ** MOSI - pin 11
  ** MISO - pin 12
  ** CLK - pin 13
- ** CS - pin 4
 
  created   Nov 2010
  by David A. Mellis
@@ -17,30 +16,24 @@
  This example code is in the public domain.
 
  */
-#define SD_CS_PIN SS
+
 #include <SPI.h>
 //#include <SD.h>
 #include "SdFat.h"
 SdFat SD;
 
+#define SD_CS_PIN SS
 File myFile;
 
-void setup()
-{
+void setup() {
   // Open serial communications and wait for port to open:
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
   while (!Serial) {
-    SysCall::yield();
+    ; // wait for serial port to connect. Needed for native USB port only
   }
 
+
   Serial.print("Initializing SD card...");
-  // On the Ethernet Shield, CS is pin 4. It's set as an output by default.
-  // Note that even if it's not used as the CS pin, the hardware SS pin
-  // (10 on most Arduino boards, 53 on the Mega) must be left as an output
-  // or the SD library functions will not work.
-  pinMode(10, OUTPUT);
 
   if (!SD.begin(SD_CS_PIN)) {
     Serial.println("initialization failed!");
@@ -81,8 +74,7 @@ void setup()
   }
 }
 
-void loop()
-{
+void loop() {
   // nothing happens after setup
 }
 

+ 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
  * 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
 // not use the default value, SS.  Common values are:
@@ -26,16 +22,31 @@
 // Adafruit SD shields and modules: pin 10
 const uint8_t chipSelect = SS;
 
-// Change spiSpeed to SPI_FULL_SPEED for better performance
-// Use SPI_QUARTER_SPEED for even slower SPI bus speed
-const uint8_t spiSpeed = SPI_HALF_SPEED;
+// Initialize at highest supported speed not over 50 MHz.
+// Reduce max speed if errors occur.
+#define SPI_SPEED SD_SCK_MHZ(50)
+
+// 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
 ArduinoOutStream cout(Serial);
 
+#if USE_SDIO
+// Use faster SdioCardEX
+SdioCardEX card;
+// SdioCard card;
+#else  // USE_SDIO
 Sd2Card card;
+#endif  // USE_SDIO
+ 
 uint32_t cardSizeBlocks;
-uint16_t cardCapacityMB;
+uint32_t cardCapacityMB;
 
 // cache for SD block
 cache_t cache;
@@ -65,11 +76,9 @@ char noName[] = "NO NAME    ";
 char fat16str[] = "FAT16   ";
 char fat32str[] = "FAT32   ";
 //------------------------------------------------------------------------------
-#define sdError(msg) sdError_F(F(msg))
-
-void sdError_F(const __FlashStringHelper* str) {
-  cout << F("error: ");
-  cout << str << endl;
+#define sdError(msg) {cout << F("error: ") << F(msg) << endl; sdErrorHalt();}
+//------------------------------------------------------------------------------
+void sdErrorHalt() {
   if (card.errorCode()) {
     cout << F("SD error: ") << hex << int(card.errorCode());
     cout << ',' << int(card.errorData()) << dec << endl;
@@ -157,6 +166,16 @@ void clearCache(uint8_t addSig) {
 // zero FAT and root dir area on SD
 void clearFatDir(uint32_t bgn, uint32_t count) {
   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)) {
     sdError("Clear FAT/DIR writeStart failed");
   }
@@ -171,6 +190,7 @@ void clearFatDir(uint32_t bgn, uint32_t count) {
   if (!card.writeStop()) {
     sdError("Clear FAT/DIR writeStop failed");
   }
+#endif  // USE_SDIO
   cout << endl;
 }
 //------------------------------------------------------------------------------
@@ -498,14 +518,19 @@ void setup() {
     cout << F("Quiting, invalid option entered.") << endl;
     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(
            "\nSD initialization failure!\n"
            "Is the SD card inserted correctly?\n"
            "Is chip select correct at the top of this program?\n");
     sdError("card.begin failed");
   }
+#endif  
   cardSizeBlocks = card.cardSize();
   if (cardSizeBlocks == 0) {
     sdError("cardSize");

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

@@ -3,6 +3,9 @@
  */
 #include <SPI.h>
 #include "SdFat.h"
+
+// Set USE_SDIO to zero for SPI card access. 
+#define USE_SDIO 0
 /*
  * 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.
  */
 const int8_t DISABLE_CHIP_SELECT = -1;
+
+#if USE_SDIO
+// Use faster SdioCardEX
+SdFatSdioEX sd;
+// SdFatSdio sd;
+#else // USE_SDIO
 SdFat sd;
+#endif  // USE_SDIO
 
 // serial output steam
 ArduinoOutStream cout(Serial);
@@ -30,16 +40,7 @@ uint32_t cardSize;
 uint32_t eraseSize;
 //------------------------------------------------------------------------------
 // store error strings in flash
-#define sdErrorMsg(msg) sdErrorMsg_F(F(msg));
-void sdErrorMsg_F(const __FlashStringHelper* str) {
-  cout << str << endl;
-  if (sd.card()->errorCode()) {
-    cout << F("SD errorCode: ");
-    cout << hex << int(sd.card()->errorCode()) << endl;
-    cout << F("SD errorData: ");
-    cout << int(sd.card()->errorData()) << dec << endl;
-  }
-}
+#define sdErrorMsg(msg) sd.errorPrint(F(msg));
 //------------------------------------------------------------------------------
 uint8_t cidDmp() {
   cid_t cid;
@@ -97,17 +98,13 @@ uint8_t csdDmp() {
 //------------------------------------------------------------------------------
 // print partition table
 uint8_t partDmp() {
-  cache_t *p = sd.vol()->cacheClear();
-  if (!p) {
-    sdErrorMsg("cacheClear failed");
-    return false;
-  }
-  if (!sd.card()->readBlock(0, p->data)) {
+  mbr_t mbr;
+  if (!sd.card()->readBlock(0, (uint8_t*)&mbr)) {
     sdErrorMsg("read MBR failed");
     return false;
   }
   for (uint8_t ip = 1; ip < 5; ip++) {
-    part_t *pt = &p->mbr.part[ip - 1];
+    part_t *pt = &mbr.part[ip - 1];
     if ((pt->boot & 0X7F) != 0 || pt->firstSector > cardSize) {
       cout << F("\nNo MBR. Assuming Super Floppy format.\n");
       return true;
@@ -116,7 +113,7 @@ uint8_t partDmp() {
   cout << F("\nSD Partition Table\n");
   cout << F("part,boot,type,start,length\n");
   for (uint8_t ip = 1; ip < 5; ip++) {
-    part_t *pt = &p->mbr.part[ip - 1];
+    part_t *pt = &mbr.part[ip - 1];
     cout << int(ip) << ',' << hex << int(pt->boot) << ',' << int(pt->type);
     cout << dec << ',' << pt->firstSector <<',' << pt->totalSectors << endl;
   }
@@ -156,6 +153,7 @@ void setup() {
 
   // F stores strings in flash to save RAM
   cout << F("SdFat version: ") << SD_FAT_VERSION << endl;
+#if !USE_SDIO  
   if (DISABLE_CHIP_SELECT < 0) {
     cout << F(
            "\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("\nEdit SD_CHIP_SELECT to change the SD chip select pin.\n");
+#endif  // !USE_SDIO  
 }
 //------------------------------------------------------------------------------
 void loop() {
@@ -183,12 +182,19 @@ void loop() {
   }
 
   uint32_t t = millis();
-  // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
-  // breadboards.  use SPI_FULL_SPEED for better performance.
-  if (!sd.cardBegin(SD_CHIP_SELECT, SPI_HALF_SPEED)) {
+#if USE_SDIO
+  if (!sd.cardBegin()) {
     sdErrorMsg("\ncardBegin failed");
     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;
 
   cardSize = sd.card()->cardSize();

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

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

+ 7 - 3
SdFat/examples/StdioBench/StdioBench.ino → examples/StdioBench/StdioBench.ino

@@ -39,7 +39,10 @@ void setup() {
     SysCall::yield();
   }
   Serial.println(F("Starting test"));
-  if (!sd.begin(SD_CS_PIN)) {
+
+  // Initialize at the highest speed supported by the board that is
+  // not over 50 MHz. Try a lower speed if SPI errors occur.  
+  if (!sd.begin(SD_CS_PIN, SD_SCK_MHZ(50))) {
     sd.errorHalt();
   }
 
@@ -137,10 +140,11 @@ void setup() {
 
         case 3:
           for (uint16_t i = 0; i < 10000; i++) {
+            uint32_t n = i + 1000000000UL;
 #if PRINT_FIELD
-            stdioFile.printField(i + 1000000000UL, '\n');
+            stdioFile.printField(n, '\n');
 #else  // PRINT_FIELD
-            stdioFile.println(i + 1000000000UL);
+            stdioFile.println(n);
 #endif  // PRINT_FIELD      
           }
           break;

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

+ 1 - 0
SdFat/examples/TwoCards/TwoCards.ino → 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.
  */
 #include <SPI.h>

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

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

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

@@ -5,6 +5,9 @@
 #include "SdFat.h"
 #include "FreeStack.h"
 
+// Set USE_SDIO to zero for SPI card access. 
+#define USE_SDIO 0
+
 // SD chip select pin
 const uint8_t chipSelect = SS;
 
@@ -28,9 +31,20 @@ const uint32_t FILE_SIZE = 1000000UL*FILE_SIZE_MB;
 uint8_t buf[BUF_SIZE];
 
 // file system
+#if USE_SDIO
+// Traditional DMA version.
+// SdFatSdio sd;
+// Faster version.
+SdFatSdioEX sd;
+#else  // USE_SDIO
 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.
 // SdFatSoftSpi<6, 7, 5> sd;
 
@@ -98,12 +112,17 @@ void loop() {
 
   cout << F("FreeStack: ") << FreeStack() << endl;
 
-  // initialize the SD card at SPI_FULL_SPEED for best performance.
-  // try SPI_HALF_SPEED if bus errors occur.
-  if (!sd.begin(chipSelect, SPI_FULL_SPEED)) {
+#if USE_SDIO
+  if (!sd.begin()) {
     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("Card size: ") << sd.card()->cardSize()*512E-9;
   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();
   }
   
-  // Initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
-  // breadboards.  use SPI_FULL_SPEED for better performance.
-  if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
+  // Initialize at the highest speed supported by the board that is
+  // not over 50 MHz. Try a lower speed if SPI errors occur.
+  if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
     sd.initErrorHalt();
   }
 

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

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

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

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

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

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

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

+ 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.
 Edit the SdFatConfig.h file to select short or long file names.
 
-The main classes in %SdFat are SdFat, SdFatSoftSpi, SdFatLibSpi,
+The main classes in %SdFat are SdFat, SdFatEX, SdFatSoftSpi, SdFatSoftSpiEX,
 SdBaseFile, SdFile, File, StdioStream, \ref fstream, \ref ifstream,
 and \ref ofstream.
 
-The SdFat, SdFatLibSpi, and SdFatSoftSpi classes maintain a FAT volume,
-a current working directory, and simplifies initialization of other classes.
-The SdFat class uses a fast custom hardware SPI implementation. The
-SdFatLibSpi class uses the standard Arduino SPI library.  The SdFatSoftSpi
-class uses software SPI.
+The SdFat, SdFatEX, SdFatSoftSpi and SdFatSoftSpiEX classes maintain a 
+FAT volume, a current working directory, and simplify initialization
+of other classes. The SdFat and SdFatEX classes uses a fast custom hardware SPI 
+implementation.  The SdFatSoftSpi and SdFatSoftSpiEX classes uses software SPI.
+
+the SdFatEX and SdFatSoftSpiEX use extended multi-block I/O for enhanced
+performance.  These classes must have exclusive use of the SPI bus.
 
 The SdBaseFile class provides basic file access functions such as open(),
 binary read(), binary write(), close(), remove(), and sync(). SdBaseFile
@@ -102,19 +104,22 @@ Long %File Names.  Long %File names require extra flash but no extra RAM.
 Opening Long %File Names can be slower than opening Short %File Names.
 Data read and write performance is not changed by the type of %File Name.
 
-Set SD_SPI_CONFIGURATION to enable various SPI options.  The SdFatSoftSpi
-and SdFatLibSpi classes can be enabled. SdFatLibSpi uses the standard
-Arduino SPI library and SdFatSoftSpi uses software SPI.
+If the symbol ENABLE_EXTENDED_TRANSFER_CLASS is nonzero, the class SdFatEX
+will be defined. If the symbol ENABLE_SOFTWARE_SPI_CLASS is also nonzero,
+the class SdFatSoftSpiEX will be defined.
+These classes used extended multi-block SD I/O for better performance.
+the SPI bus may not be shared with other devices in this mode.
+ 
+Set USE_STANDARD_SPI_LIBRARY and  ENABLE_SOFTWARE_SPI_CLASS to
+enable various SPI options. set USE_STANDARD_SPI_LIBRARY to use the standard
+Arduino SPI library. set ENABLE_SOFTWARE_SPI_CLASS to enable the SdFatSoftSpi
+class which uses software SPI.
 
 To enable SD card CRC checking set USE_SD_CRC nonzero.
 
 Set FAT12_SUPPORT nonzero to enable use of FAT12 volumes.
 FAT12 has not been well tested and requires additional flash.
 
-Set ENABLE_SPI_TRANSACTIONS nonzero to enable the SPI transaction feature
-of the standard Arduino SPI library.  You must include SPI.h in your
-programs when ENABLE_SPI_TRANSACTIONS is nonzero.
-
 \section SDPath Paths and Working Directories
 
 Relative paths in SdFat are resolved in a manner similar to Windows.
@@ -352,7 +357,11 @@ getline - Example of getline from section 27.7.1.3 of the C++ standard.
 
 LongFileName - Example use of openNext, printName, and open by index.
 
-LowLatencyLogger - A modifiable data logger for higher data rates.
+LowLatencyLogger - A data logger for higher data rates. ADC version.
+
+LowLatencyLoggerADXL345 - A data logger for higher data rates. ADXL345 SPI.
+
+LowLatencyLoggerMPU6050 - A data logger for higher data rates. MPU6050 I2C.
 
 OpenNext - Open all files in the root dir and print their filename.
 
@@ -370,8 +379,6 @@ ReadCsvArray - Read a two dimensional array from a CSV file.
 
 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).
 
 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.
 
-ThreeCards - Demonstrate simultaneous use of SdFat, SdFatLibSpi, SdFatSoftSpi.
-
 Timestamp - Sets file create, modify, and access timestamps.
 
 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


部分文件因为文件数量过多而无法显示