Bladeren bron

Version 2 beta

main
Bill Greiman 5 jaren geleden
bovenliggende
commit
3205c6919d
100 gewijzigde bestanden met toevoegingen van 5484 en 1127 verwijderingen
  1. +92
    -11
      README.md
  2. +31
    -0
      examples/AvrAdcLogger/AvrAdcLogger.h
  3. +887
    -0
      examples/AvrAdcLogger/AvrAdcLogger.ino
  4. +78
    -0
      examples/BackwardCompatibility/BackwardCompatibility.ino
  5. +232
    -0
      examples/BufferedPrint/BufferedPrint.ino
  6. +62
    -30
      examples/DirectoryFunctions/DirectoryFunctions.ino
  7. +79
    -0
      examples/ExFatFormatter/ExFatFormatter.ino
  8. +9
    -0
      examples/ExFatLogger/ExFatLogger.h
  9. +579
    -0
      examples/ExFatLogger/ExFatLogger.ino
  10. +47
    -0
      examples/ExFatUnicodeTest/ExFatUnicodeTest.ino
  11. +66
    -18
      examples/OpenNext/OpenNext.ino
  12. +24
    -13
      examples/QuickStart/QuickStart.ino
  13. +153
    -0
      examples/ReadCsvFile/ReadCsvFile.ino
  14. +141
    -0
      examples/RtcTimestampTest/RtcTimestampTest.ino
  15. +58
    -64
      examples/STM32Test/STM32Test.ino
  16. +19
    -0
      examples/SdErrorCodes/SdErrorCodes.ino
  17. +126
    -438
      examples/SdFormatter/SdFormatter.ino
  18. +179
    -169
      examples/SdInfo/SdInfo.ino
  19. +33
    -14
      examples/SoftwareSpi/SoftwareSpi.ino
  20. +136
    -0
      examples/TeensyRtcTimestamp/TeensyRtcTimestamp.ino
  21. +78
    -47
      examples/TeensySdioDemo/TeensySdioDemo.ino
  22. +108
    -67
      examples/bench/bench.ino
  23. +87
    -0
      examples/debug/CardBusyTest/CardBusyTest.ino
  24. +47
    -0
      examples/debug/ExFatDbgDmp/ExFatDbgDmp.ino
  25. +17
    -15
      examples/debug/TestMkdir/TestMkdir.ino
  26. +17
    -16
      examples/debug/TestRmdir/TestRmdir.ino
  27. +0
    -0
      examples/examplesV1/#attic/AnalogLogger/AnalogLogger.ino
  28. +0
    -0
      examples/examplesV1/#attic/BaseExtCaseTest/BaseExtCaseTest.ino
  29. +0
    -0
      examples/examplesV1/#attic/HelloWorld/HelloWorld.ino
  30. +0
    -0
      examples/examplesV1/#attic/MiniSerial/MiniSerial.ino
  31. +0
    -0
      examples/examplesV1/#attic/PrintBenchmarkSD/PrintBenchmarkSD.ino
  32. +0
    -0
      examples/examplesV1/#attic/SD_Size/SD_Size.ino
  33. +0
    -0
      examples/examplesV1/#attic/SdFatSize/SdFatSize.ino
  34. +0
    -0
      examples/examplesV1/#attic/StreamParseInt/StreamParseInt.ino
  35. +0
    -0
      examples/examplesV1/#attic/append/append.ino
  36. +0
    -0
      examples/examplesV1/#attic/average/average.ino
  37. +0
    -0
      examples/examplesV1/#attic/benchSD/benchSD.ino
  38. +0
    -0
      examples/examplesV1/#attic/bufstream/bufstream.ino
  39. +0
    -0
      examples/examplesV1/#attic/cin_cout/cin_cout.ino
  40. +0
    -0
      examples/examplesV1/#attic/eventlog/eventlog.ino
  41. +0
    -0
      examples/examplesV1/#attic/fgetsRewrite/fgetsRewrite.ino
  42. +0
    -0
      examples/examplesV1/#attic/readlog/readlog.ino
  43. +0
    -0
      examples/examplesV1/#attic/readme.txt
  44. +0
    -0
      examples/examplesV1/AnalogBinLogger/AnalogBinLogger.h
  45. +1
    -1
      examples/examplesV1/AnalogBinLogger/AnalogBinLogger.ino
  46. +129
    -0
      examples/examplesV1/DirectoryFunctions/DirectoryFunctions.ino
  47. +0
    -0
      examples/examplesV1/LongFileName/LongFileName.ino
  48. +0
    -0
      examples/examplesV1/LongFileName/testFiles/A long name can be 255 characters.txt
  49. +0
    -0
      examples/examplesV1/LongFileName/testFiles/LFN,NAME.TXT
  50. +0
    -0
      examples/examplesV1/LongFileName/testFiles/MIXCASE.txt
  51. +0
    -0
      examples/examplesV1/LongFileName/testFiles/Not_8_3.txt
  52. +0
    -0
      examples/examplesV1/LongFileName/testFiles/OK%83.TXT
  53. +0
    -0
      examples/examplesV1/LongFileName/testFiles/STD_8_3.TXT
  54. +0
    -0
      examples/examplesV1/LongFileName/testFiles/With Blank.txt
  55. +0
    -0
      examples/examplesV1/LongFileName/testFiles/With.Two dots.txt
  56. +0
    -0
      examples/examplesV1/LongFileName/testFiles/lower.txt
  57. +0
    -0
      examples/examplesV1/LongFileName/testFiles/mixed.TXT
  58. +27
    -27
      examples/examplesV1/LowLatencyLogger/LowLatencyLogger.ino
  59. +0
    -0
      examples/examplesV1/LowLatencyLogger/UserFunctions.cpp
  60. +0
    -0
      examples/examplesV1/LowLatencyLogger/UserTypes.h
  61. +27
    -27
      examples/examplesV1/LowLatencyLoggerADXL345/LowLatencyLogger.ino
  62. +0
    -0
      examples/examplesV1/LowLatencyLoggerADXL345/LowLatencyLoggerADXL345.ino
  63. +0
    -0
      examples/examplesV1/LowLatencyLoggerADXL345/UserFunctions.cpp
  64. +0
    -0
      examples/examplesV1/LowLatencyLoggerADXL345/UserTypes.h
  65. +0
    -0
      examples/examplesV1/LowLatencyLoggerADXL345/readme.txt
  66. +27
    -27
      examples/examplesV1/LowLatencyLoggerMPU6050/LowLatencyLogger.ino
  67. +0
    -0
      examples/examplesV1/LowLatencyLoggerMPU6050/LowLatencyLoggerMPU6050.ino
  68. +0
    -0
      examples/examplesV1/LowLatencyLoggerMPU6050/UserFunctions.cpp
  69. +0
    -0
      examples/examplesV1/LowLatencyLoggerMPU6050/UserTypes.h
  70. +60
    -0
      examples/examplesV1/OpenNext/OpenNext.ino
  71. +0
    -0
      examples/examplesV1/PrintBenchmark/PrintBenchmark.ino
  72. +161
    -0
      examples/examplesV1/QuickStart/QuickStart.ino
  73. +0
    -0
      examples/examplesV1/RawWrite/RawWrite.ino
  74. +0
    -0
      examples/examplesV1/ReadCsv/ReadCsv.ino
  75. +0
    -0
      examples/examplesV1/ReadCsvArray/ReadCsvArray.ino
  76. +0
    -0
      examples/examplesV1/ReadCsvStream/ReadCsvStream.ino
  77. +0
    -0
      examples/examplesV1/ReadWrite/ReadWrite.ino
  78. +175
    -0
      examples/examplesV1/STM32Test/STM32Test.ino
  79. +552
    -0
      examples/examplesV1/SdFormatter/SdFormatter.ino
  80. +248
    -0
      examples/examplesV1/SdInfo/SdInfo.ino
  81. +59
    -0
      examples/examplesV1/SoftwareSpi/SoftwareSpi.ino
  82. +3
    -2
      examples/examplesV1/StdioBench/StdioBench.ino
  83. +169
    -0
      examples/examplesV1/TeensySdioDemo/TeensySdioDemo.ino
  84. +5
    -19
      examples/examplesV1/Timestamp/Timestamp.ino
  85. +0
    -0
      examples/examplesV1/TwoCards/TwoCards.ino
  86. +6
    -6
      examples/examplesV1/VolumeFreeSpace/VolumeFreeSpace.ino
  87. +222
    -0
      examples/examplesV1/bench/bench.ino
  88. +0
    -0
      examples/examplesV1/dataLogger/dataLogger.ino
  89. +0
    -0
      examples/examplesV1/fgets/fgets.ino
  90. +0
    -0
      examples/examplesV1/formatting/formatting.ino
  91. +0
    -0
      examples/examplesV1/getline/getline.ino
  92. +106
    -0
      examples/examplesV1/rename/rename.ino
  93. +66
    -0
      examples/examplesV1/v1v2.txt
  94. +2
    -1
      examples/examplesV1/wipe/wipe.ino
  95. +54
    -17
      examples/rename/rename.ino
  96. BIN
      extras/AnalogBinLoggerExtras/ADC_ENOB.PNG
  97. BIN
      extras/AnalogBinLoggerExtras/ADCdocs/ATmegaADCAccuracy.pdf
  98. BIN
      extras/AnalogBinLoggerExtras/ADCdocs/ExcelFFT.pdf
  99. +0
    -98
      extras/AnalogBinLoggerExtras/AdcErrorStudy.txt
  100. +0
    -0
      extras/AnalogBinLoggerExtras/DATA.png

+ 92
- 11
README.md Bestand weergeven

@@ -1,20 +1,101 @@
### Warning: This beta is no longer up to date with the release SdFat.
### Warning: This is an early beta version of SdFat Version 2.

### Please use the current version of SdFat.
This library is in early development and features may change.
It will clearly have bugs. I am posting this version to get comments and
help finding bugs/compatibility problems.

Changes Version 1.0.10:
You can help by posting issues for problems you find. I am doing a great deal
of testing but actual applications make the best test cases.

Initial test version for Particle Gen3 mesh.
SdFat Version 2 supports FAT16/FAT32 and exFAT SD cards. It is mostly
backward compatible with SdFat Version 1 for FAT16/FAT32 cards.

Changes Version 1.0.9:
exFAT supports files larger than 4GB so files sizes and positions are
type uint64_t for classes that support exFAT.

This version of SdFat has been modified to use standard POSIX/Linux
definitions of open flags from fcntl.h.
exFAT has many features not available in FAT16/FAT32. exFAT has excellent
support for contiguous files on flash devices and supports preallocation.

Open flags are access modes, O_RDONLY, O_RDWR, O_WRONLY, and modifiers
O_APPEND, O_CREAT, O_EXCL, O_SYNC, O_TRUNC.
If the SD card is the only SPI device, use dedicated SPI mode. This can
greatly improve performance. See the bench example.

The mods required changing the type for open flags from uint8_t to int so
bugs are likely if any uint8_t local variables were missed.
Here is write performance for an old, 2011, card on a Due board.
```
Shared SPI:
write speed and latency
speed,max,min,avg
KB/Sec,usec,usec,usec
294.45,24944,1398,1737

Dedicated SPI:
write speed and latency
speed,max,min,avg
KB/Sec,usec,usec,usec
3965.11,16733,110,127
```
The default version of SdFatConfig.h enables support for dedicated SPI and
optimized access to contiguous files. This make SdFat Version 2 slightly
larger than Version 1. If these features are disabled, Version 2 is smaller
than Version 1.

The types for the classes SdFat and File are defined in SdFatConfig.h.
The default version of SdFatConfig.h defines SdFat to only support FAT16/FAT32.
SdFat and File are defined in terms of more basic classes by typedefs. You
can use these basic classes in applications.

Support for exFAT requires a substantial amount of flash. Here are sizes on
an UNO for a simple program that opens a file, prints one line, and closes
the file.
```
FAT16/FAT32 only: 9780 bytes flash, 875 bytes SRAM.

exFAT only: 13830 bytes flash, 938 bytes SRAM.

FAT16/FAT32/exFAT: 19326 bytes flash, 928 bytes SRAM.
```
The section below of SdFatConfig.h has been edited to uses FAT16/FAT32 for
small AVR boards and FAT16/FAT32/exFAT for all other boards.
```
/**
* File types for SdFat, File, SdFile, SdBaseFile, fstream,
* ifstream, and ofstream.
*
* Set SDFAT_FILE_TYPE to:
*
* 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
*/
#if defined(__AVR__) && FLASHEND < 0X8000
// FAT16/FAT32 for 32K AVR boards.
#define SDFAT_FILE_TYPE 1
#else // defined(__AVR__) && FLASHEND < 0X8000
// FAT16/FAT32 and exFAT for all other boards.
#define SDFAT_FILE_TYPE 3
#endif // defined(__AVR__) && FLASHEND < 0X8000
```
The SdBaseFile class has no Arduino Stream or Print support.

The File class is derived from Stream and SdBaseFile.

The SdFile class is derived from SdBaseFile and Print.

Please try the examples. Start with SdInfo, bench, and ExFatLogger.

To use SdFat Version 2, unzip the download file, rename the library folder
SdFat and place the SdFat folder into the libraries sub-folder in your main
sketch folder.

For more information see the Manual installation section of this guide:

http://arduino.cc/en/Guide/Libraries

A number of configuration options can be set by editing SdFatConfig.h
define macros. See the html documentation File tab for details.

Please read the html documentation for this library in SdFat/extras/SdFat.html.
Start with the Main Page. Next go to the Classes tab and read the
documentation for the classes SdFat32, SdExFat, SdFs, File32, ExFile, FsFile.

The SdFat and File classes are defined in terms of the above classes by
typedefs. Edit SdFatConfig.h to select class options.

Please continue by reading the html documentation in the SdFat/extras folder.

+ 31
- 0
examples/AvrAdcLogger/AvrAdcLogger.h Bestand weergeven

@@ -0,0 +1,31 @@
#ifndef AnalogBinLogger_h
#define AnalogBinLogger_h
const size_t BLOCK_SIZE = 64;
//------------------------------------------------------------------------------
// First block of file.
const size_t PIN_NUM_DIM = BLOCK_SIZE - 3*sizeof(uint32_t) - 2*sizeof(uint8_t);
struct metadata_t {
uint32_t adcFrequency; // ADC clock frequency
uint32_t cpuFrequency; // CPU clock frequency
uint32_t sampleInterval; // Sample interval in CPU cycles.
uint8_t recordEightBits; // Size of ADC values, nonzero for 8-bits.
uint8_t pinCount; // Number of analog pins in a sample.
uint8_t pinNumber[PIN_NUM_DIM]; // List of pin numbers in a sample.
};
//------------------------------------------------------------------------------
// Data block for 8-bit ADC mode.
const size_t DATA_DIM8 = (BLOCK_SIZE - 2*sizeof(uint16_t))/sizeof(uint8_t);
struct block8_t {
uint16_t count; // count of data values
uint16_t overrun; // count of overruns since last block
uint8_t data[DATA_DIM8];
};
//------------------------------------------------------------------------------
// Data block for 10-bit ADC mode.
const size_t DATA_DIM16 = (BLOCK_SIZE - 2*sizeof(uint16_t))/sizeof(uint16_t);
struct block16_t {
unsigned short count; // count of data values
unsigned short overrun; // count of overruns since last block
unsigned short data[DATA_DIM16];
};
#endif // AnalogBinLogger_h

+ 887
- 0
examples/AvrAdcLogger/AvrAdcLogger.ino Bestand weergeven

@@ -0,0 +1,887 @@
/**
* This program logs data from the Arduino ADC to a binary file.
*
* Samples are logged at regular intervals. Each Sample consists of the ADC
* values for the analog pins defined in the PIN_LIST array. The pins numbers
* may be in any order.
*
* Edit the configuration constants below to set the sample pins, sample rate,
* and other configuration values.
*
* 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 more 64 byte buffer blocks will be used.
*
* Each 64 byte data block in the file has a four byte header followed by up
* to 60 bytes of data. (60 values in 8-bit mode or 30 values in 10-bit mode)
* Each block contains an integral number of samples with unused space at the
* end of the block.
*
*/
#ifdef __AVR__
#include <SPI.h>
#include "SdFat.h"
#include "BufferedPrint.h"
#include "FreeStack.h"
#include "AvrAdcLogger.h"

// Save SRAM if 328.
#ifdef __AVR_ATmega328P__
#include "MinimumSerial.h"
MinimumSerial MinSerial;
#define Serial MinSerial
#endif // __AVR_ATmega328P__
//------------------------------------------------------------------------------
// This example was designed for exFAT but will support FAT16/FAT32.
//
// If an exFAT SD is required, the ExFatFormatter example will format
// smaller cards with an exFAT file system.
//
// Note: Uno will not support SD_FAT_TYPE = 3.
// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 2
//------------------------------------------------------------------------------
// Set USE_RTC nonzero for file timestamps.
// RAM use will be marginal on Uno with RTClib.
#define USE_RTC 0
#if USE_RTC
#include "RTClib.h"
#endif
//------------------------------------------------------------------------------
// Pin definitions.
//
// 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.
const int8_t ERROR_LED_PIN = -1;

// SD chip select pin.
const uint8_t SD_CS_PIN = SS;
//------------------------------------------------------------------------------
// Analog pin number list for a sample. Pins may be in any order and pin
// numbers may be repeated.
const uint8_t PIN_LIST[] = {0, 1, 2, 3, 4};
//------------------------------------------------------------------------------
// Sample rate in samples per second.
const float SAMPLE_RATE = 5000; // Must be 0.25 or greater.

// The interval between samples in seconds, SAMPLE_INTERVAL, may be set to a
// constant instead of being calculated from SAMPLE_RATE. SAMPLE_RATE is not
// used in the code below. For example, setting SAMPLE_INTERVAL = 2.0e-4
// will result in a 200 microsecond sample interval.
const float SAMPLE_INTERVAL = 1.0/SAMPLE_RATE;

// Setting ROUND_SAMPLE_INTERVAL non-zero will cause the sample interval to
// be rounded to a a multiple of the ADC clock period and will reduce sample
// time jitter.
#define ROUND_SAMPLE_INTERVAL 1
//------------------------------------------------------------------------------
// Reference voltage. See the processor data-sheet for reference details.
// uint8_t const ADC_REF = 0; // External Reference AREF pin.
uint8_t const ADC_REF = (1 << REFS0); // Vcc Reference.
// uint8_t const ADC_REF = (1 << REFS1); // Internal 1.1 (only 644 1284P Mega)
// uint8_t const ADC_REF = (1 << REFS1) | (1 << REFS0); // Internal 1.1 or 2.56
//------------------------------------------------------------------------------
// File definitions.
//
// Maximum file size in bytes.
// The program creates a contiguous file with MAX_FILE_SIZE_MiB bytes.
// The file will be truncated if logging is stopped early.
const uint32_t MAX_FILE_SIZE_MiB = 100; // 100 MiB file.

// log file name. Integer field before dot will be incremented.
#define LOG_FILE_NAME "AvrAdc00.bin"

// Maximum length name including zero byte.
const size_t NAME_DIM = 40;

// Set RECORD_EIGHT_BITS non-zero to record only the high 8-bits of the ADC.
#define RECORD_EIGHT_BITS 0
//------------------------------------------------------------------------------
// FIFO size definition. Use a multiple of 512 bytes for best performance.
//
#if RAMEND < 0X8FF
#error SRAM too small
#elif RAMEND < 0X10FF
const size_t FIFO_SIZE_BYTES = 512;
#elif RAMEND < 0X20FF
const size_t FIFO_SIZE_BYTES = 4*512;
#elif RAMEND < 0X40FF
const size_t FIFO_SIZE_BYTES = 12*512;
#else // RAMEND
const size_t FIFO_SIZE_BYTES = 16*512;
#endif // RAMEND
//------------------------------------------------------------------------------
// ADC clock rate.
// The ADC clock rate is normally calculated from the pin count and sample
// interval. The calculation attempts to use the lowest possible ADC clock
// rate.
//
// You can select an ADC clock rate by defining the symbol ADC_PRESCALER to
// one of these values. You must choose an appropriate ADC clock rate for
// your sample interval.
// #define ADC_PRESCALER 7 // F_CPU/128 125 kHz on an Uno
// #define ADC_PRESCALER 6 // F_CPU/64 250 kHz on an Uno
// #define ADC_PRESCALER 5 // F_CPU/32 500 kHz on an Uno
// #define ADC_PRESCALER 4 // F_CPU/16 1000 kHz on an Uno
// #define ADC_PRESCALER 3 // F_CPU/8 2000 kHz on an Uno (8-bit mode only)
//==============================================================================
// End of configuration constants.
//==============================================================================
// Temporary log file. Will be deleted if a reset or power failure occurs.
#define TMP_FILE_NAME "tmp_adc.bin"

// Number of analog pins to log.
const uint8_t PIN_COUNT = sizeof(PIN_LIST)/sizeof(PIN_LIST[0]);

// Minimum ADC clock cycles per sample interval
const uint16_t MIN_ADC_CYCLES = 15;

// Extra cpu cycles to setup ADC with more than one pin per sample.
const uint16_t ISR_SETUP_ADC = PIN_COUNT > 1 ? 100 : 0;

// Maximum cycles for timer0 system interrupt, millis, micros.
const uint16_t ISR_TIMER0 = 160;
//==============================================================================
const uint32_t MAX_FILE_SIZE = MAX_FILE_SIZE_MiB << 20;

// Select fastest interface.
#if ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI)
#else // ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI)
#endif // ENABLE_DEDICATED_SPI

#if SD_FAT_TYPE == 0
SdFat sd;
typedef File file_t;
#elif SD_FAT_TYPE == 1
SdFat32 sd;
typedef File32 file_t;
#elif SD_FAT_TYPE == 2
SdExFat sd;
typedef ExFile file_t;
#elif SD_FAT_TYPE == 3
SdFs sd;
typedef FsFile file_t;
#else // SD_FAT_TYPE
#error Invalid SD_FAT_TYPE
#endif // SD_FAT_TYPE

file_t binFile;
file_t csvFile;

char binName[] = LOG_FILE_NAME;

#if RECORD_EIGHT_BITS
const size_t BLOCK_MAX_COUNT = PIN_COUNT*(DATA_DIM8/PIN_COUNT);
typedef block8_t block_t;
#else // RECORD_EIGHT_BITS
const size_t BLOCK_MAX_COUNT = PIN_COUNT*(DATA_DIM16/PIN_COUNT);
typedef block16_t block_t;
#endif // RECORD_EIGHT_BITS

// Size of FIFO in blocks.
size_t const FIFO_DIM = FIFO_SIZE_BYTES/sizeof(block_t);
block_t* fifoData;
volatile size_t fifoCount = 0; // volatile - shared, ISR and background.
size_t fifoHead = 0; // Only accessed by ISR during logging.
size_t fifoTail = 0; // Only accessed by writer during logging.
//==============================================================================
// Interrupt Service Routines

// Disable ADC interrupt if true.
volatile bool isrStop = false;

// Pointer to current buffer.
block_t* isrBuf = nullptr;
// overrun count
uint16_t isrOver = 0;

// ADC configuration for each pin.
uint8_t adcmux[PIN_COUNT];
uint8_t adcsra[PIN_COUNT];
uint8_t adcsrb[PIN_COUNT];
uint8_t adcindex = 1;

// Insure no timer events are missed.
volatile bool timerError = false;
volatile bool timerFlag = false;
//------------------------------------------------------------------------------
// ADC done interrupt.
ISR(ADC_vect) {
// Read ADC data.
#if RECORD_EIGHT_BITS
uint8_t d = ADCH;
#else // RECORD_EIGHT_BITS
// This will access ADCL first.
uint16_t d = ADC;
#endif // RECORD_EIGHT_BITS

if (!isrBuf) {
if (fifoCount < FIFO_DIM) {
isrBuf = fifoData + fifoHead;
} else {
// no buffers - count overrun
if (isrOver < 0XFFFF) {
isrOver++;
}
// Avoid missed timer error.
timerFlag = false;
return;
}
}
// Start ADC for next pin
if (PIN_COUNT > 1) {
ADMUX = adcmux[adcindex];
ADCSRB = adcsrb[adcindex];
ADCSRA = adcsra[adcindex];
if (adcindex == 0) {
timerFlag = false;
}
adcindex = adcindex < (PIN_COUNT - 1) ? adcindex + 1 : 0;
} else {
timerFlag = false;
}
// Store ADC data.
isrBuf->data[isrBuf->count++] = d;

// Check for buffer full.
if (isrBuf->count >= BLOCK_MAX_COUNT) {
fifoHead = fifoHead < (FIFO_DIM - 1) ? fifoHead + 1 : 0;
fifoCount++;
// Check for end logging.
if (isrStop) {
adcStop();
return;
}
// Set buffer needed and clear overruns.
isrBuf = nullptr;
isrOver = 0;
}
}
//------------------------------------------------------------------------------
// timer1 interrupt to clear OCF1B
ISR(TIMER1_COMPB_vect) {
// Make sure ADC ISR responded to timer event.
if (timerFlag) {
timerError = true;
}
timerFlag = true;
}
//==============================================================================
// Error messages stored in flash.
#define error(msg) (Serial.println(F(msg)),errorHalt())
#define assert(e) ((e) ? (void)0 : error("assert: " #e))
//------------------------------------------------------------------------------
//
void fatalBlink() {
while (true) {
if (ERROR_LED_PIN >= 0) {
digitalWrite(ERROR_LED_PIN, HIGH);
delay(200);
digitalWrite(ERROR_LED_PIN, LOW);
delay(200);
}
}
}
//------------------------------------------------------------------------------
void errorHalt() {
// Print minimal error data.
// sd.errorPrint(&Serial);
// Print extended error info - uses extra bytes of flash.
sd.printSdError(&Serial);
// Try to save data.
binFile.close();
fatalBlink();
}
//------------------------------------------------------------------------------
void printUnusedStack() {
Serial.print(F("\nUnused stack: "));
Serial.println(UnusedStack());
}
//------------------------------------------------------------------------------
#if USE_RTC
RTC_DS1307 rtc;

// Call back for file timestamps. Only called for file create and sync().
void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) {
DateTime now = rtc.now();

// Return date using FS_DATE macro to format fields.
*date = FS_DATE(now.year(), now.month(), now.day());

// Return time using FS_TIME macro to format fields.
*time = FS_TIME(now.hour(), now.minute(), now.second());

// Return low time bits in units of 10 ms.
*ms10 = now.second() & 1 ? 100 : 0;
}
#endif // USE_RTC
//==============================================================================
#if ADPS0 != 0 || ADPS1 != 1 || ADPS2 != 2
#error unexpected ADC prescaler bits
#endif
//------------------------------------------------------------------------------
inline bool adcActive() {return (1 << ADIE) & ADCSRA;}
//------------------------------------------------------------------------------
// initialize ADC and timer1
void adcInit(metadata_t* meta) {
uint8_t adps; // prescaler bits for ADCSRA
uint32_t ticks = F_CPU*SAMPLE_INTERVAL + 0.5; // Sample interval cpu cycles.

if (ADC_REF & ~((1 << REFS0) | (1 << REFS1))) {
error("Invalid ADC reference");
}
#ifdef ADC_PRESCALER
if (ADC_PRESCALER > 7 || ADC_PRESCALER < 2) {
error("Invalid ADC prescaler");
}
adps = ADC_PRESCALER;
#else // ADC_PRESCALER
// Allow extra cpu cycles to change ADC settings if more than one pin.
int32_t adcCycles = (ticks - ISR_TIMER0)/PIN_COUNT - ISR_SETUP_ADC;

for (adps = 7; adps > 0; adps--) {
if (adcCycles >= (MIN_ADC_CYCLES << adps)) {
break;
}
}
#endif // ADC_PRESCALER
meta->adcFrequency = F_CPU >> adps;
if (meta->adcFrequency > (RECORD_EIGHT_BITS ? 2000000 : 1000000)) {
error("Sample Rate Too High");
}
#if ROUND_SAMPLE_INTERVAL
// Round so interval is multiple of ADC clock.
ticks += 1 << (adps - 1);
ticks >>= adps;
ticks <<= adps;
#endif // ROUND_SAMPLE_INTERVAL

if (PIN_COUNT > BLOCK_MAX_COUNT || PIN_COUNT > PIN_NUM_DIM) {
error("Too many pins");
}
meta->pinCount = PIN_COUNT;
meta->recordEightBits = RECORD_EIGHT_BITS;

for (int i = 0; i < PIN_COUNT; i++) {
uint8_t pin = PIN_LIST[i];
if (pin >= NUM_ANALOG_INPUTS) {
error("Invalid Analog pin number");
}
meta->pinNumber[i] = pin;

// Set ADC reference and low three bits of analog pin number.
adcmux[i] = (pin & 7) | ADC_REF;
if (RECORD_EIGHT_BITS) {
adcmux[i] |= 1 << ADLAR;
}

// If this is the first pin, trigger on timer/counter 1 compare match B.
adcsrb[i] = i == 0 ? (1 << ADTS2) | (1 << ADTS0) : 0;
#ifdef MUX5
if (pin > 7) {
adcsrb[i] |= (1 << MUX5);
}
#endif // MUX5
adcsra[i] = (1 << ADEN) | (1 << ADIE) | adps;
// First pin triggers on timer 1 compare match B rest are free running.
adcsra[i] |= i == 0 ? 1 << ADATE : 1 << ADSC;
}

// Setup timer1
TCCR1A = 0;
uint8_t tshift;
if (ticks < 0X10000) {
// no prescale, CTC mode
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS10);
tshift = 0;
} else if (ticks < 0X10000*8) {
// prescale 8, CTC mode
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11);
tshift = 3;
} else if (ticks < 0X10000*64) {
// prescale 64, CTC mode
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11) | (1 << CS10);
tshift = 6;
} else if (ticks < 0X10000*256) {
// prescale 256, CTC mode
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS12);
tshift = 8;
} else if (ticks < 0X10000*1024) {
// prescale 1024, CTC mode
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS12) | (1 << CS10);
tshift = 10;
} else {
error("Sample Rate Too Slow");
}
// divide by prescaler
ticks >>= tshift;
// set TOP for timer reset
ICR1 = ticks - 1;
// compare for ADC start
OCR1B = 0;

// multiply by prescaler
ticks <<= tshift;

// Sample interval in CPU clock ticks.
meta->sampleInterval = ticks;
meta->cpuFrequency = F_CPU;
float sampleRate = (float)meta->cpuFrequency/meta->sampleInterval;
Serial.print(F("Sample pins:"));
for (uint8_t i = 0; i < meta->pinCount; i++) {
Serial.print(' ');
Serial.print(meta->pinNumber[i], DEC);
}
Serial.println();
Serial.print(F("ADC bits: "));
Serial.println(meta->recordEightBits ? 8 : 10);
Serial.print(F("ADC clock kHz: "));
Serial.println(meta->adcFrequency/1000);
Serial.print(F("Sample Rate: "));
Serial.println(sampleRate);
Serial.print(F("Sample interval usec: "));
Serial.println(1000000.0/sampleRate);
}
//------------------------------------------------------------------------------
// enable ADC and timer1 interrupts
void adcStart() {
// initialize ISR
adcindex = 1;
isrBuf = nullptr;
isrOver = 0;
isrStop = false;

// Clear any pending interrupt.
ADCSRA |= 1 << ADIF;

// Setup for first pin.
ADMUX = adcmux[0];
ADCSRB = adcsrb[0];
ADCSRA = adcsra[0];

// Enable timer1 interrupts.
timerError = false;
timerFlag = false;
TCNT1 = 0;
TIFR1 = 1 << OCF1B;
TIMSK1 = 1 << OCIE1B;
}
//------------------------------------------------------------------------------
inline void adcStop() {
TIMSK1 = 0;
ADCSRA = 0;
}
//------------------------------------------------------------------------------
// Convert binary file to csv file.
void binaryToCsv() {
uint8_t lastPct = 0;
block_t* pd;
metadata_t* pm;
uint32_t t0 = millis();
// Use fast buffered print class.
BufferedPrint<file_t, 64> bp(&csvFile);
block_t binBuffer[FIFO_DIM];

assert(sizeof(block_t) == sizeof(metadata_t));
binFile.rewind();
uint32_t tPct = millis();
bool doMeta = true;
while (!Serial.available()) {
pd = binBuffer;
int nb = binFile.read(binBuffer, sizeof(binBuffer));
if (nb < 0) {
error("read binFile failed");
}
size_t nd = nb/sizeof(block_t);
if (nd < 1) {
break;
}
if (doMeta) {
doMeta = false;
pm = (metadata_t*)pd++;
if (PIN_COUNT != pm->pinCount) {
error("Invalid pinCount");
}
bp.print(F("Interval,"));
float intervalMicros = 1.0e6*pm->sampleInterval/(float)pm->cpuFrequency;
bp.print(intervalMicros, 4);
bp.println(F(",usec"));
for (uint8_t i = 0; i < PIN_COUNT; i++) {
if (i) {
bp.print(',');
}
bp.print(F("pin"));
bp.print(pm->pinNumber[i]);
}
bp.println();
if (nd-- == 1) {
break;
}
}
for (size_t i = 0; i < nd; i++, pd++) {
if (pd->overrun) {
bp.print(F("OVERRUN,"));
bp.println(pd->overrun);
}
for (size_t j = 0; j < pd->count; j += PIN_COUNT) {
for (size_t i = 0; i < PIN_COUNT; i++) {
if (!bp.printField(pd->data[i + j], i == (PIN_COUNT-1) ? '\n' : ',')) {
error("printField failed");
}
}
}
}
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 (!bp.sync() || !csvFile.close()) {
error("close csvFile failed");
}
Serial.print(F("Done: "));
Serial.print(0.001*(millis() - t0));
Serial.println(F(" Seconds"));
}
//------------------------------------------------------------------------------
void createBinFile() {
binFile.close();
while (sd.exists(binName)) {
char* p = strchr(binName, '.');
if (!p) {
error("no dot in filename");
}
while (true) {
p--;
if (p < binName || *p < '0' || *p > '9') {
error("Can't create file name");
}
if (p[0] != '9') {
p[0]++;
break;
}
p[0] = '0';
}
}
Serial.print(F("Opening: "));
Serial.println(binName);
if (!binFile.open(binName, O_RDWR | O_CREAT)) {
error("open binName failed");
}
Serial.print(F("Allocating: "));
Serial.print(MAX_FILE_SIZE_MiB);
Serial.println(F(" MiB"));
if (!binFile.preAllocate(MAX_FILE_SIZE)) {
error("preAllocate failed");
}
}
//------------------------------------------------------------------------------
bool createCsvFile() {
char csvName[NAME_DIM];

if (!binFile.isOpen()) {
Serial.println(F("No current binary file"));
return false;
}
binFile.getName(csvName, sizeof(csvName));
char* dot = strchr(csvName, '.');
if (!dot) {
error("no dot in binName");
}
strcpy(dot + 1, "csv");
if (!csvFile.open(csvName, O_WRONLY|O_CREAT|O_TRUNC)) {
error("open csvFile failed");
}
Serial.print(F("Writing: "));
Serial.print(csvName);
Serial.println(F(" - type any character to stop"));
return true;
}
//------------------------------------------------------------------------------
// log data
void logData() {
uint32_t t0;
uint32_t t1;
uint32_t overruns =0;
uint32_t count = 0;
uint32_t maxLatencyUsec = 0;
size_t maxFifoUse = 0;
block_t fifoBuffer[FIFO_DIM];

adcInit((metadata_t*)fifoBuffer);
// Write metadata.
if (sizeof(metadata_t) != binFile.write(fifoBuffer, sizeof(metadata_t))) {
error("Write metadata failed");
}
fifoCount = 0;
fifoHead = 0;
fifoTail = 0;
fifoData = fifoBuffer;
// Initialize all blocks to save ISR overhead.
memset(fifoBuffer, 0, sizeof(fifoBuffer));

Serial.println(F("Logging - type any character to stop"));
// Wait for Serial Idle.
Serial.flush();
delay(10);

t0 = millis();
t1 = t0;
// Start logging interrupts.
adcStart();
while (1) {
uint32_t m;
noInterrupts();
size_t tmpFifoCount = fifoCount;
interrupts();
if (tmpFifoCount) {
block_t* pBlock = fifoData + fifoTail;
// Write block to SD.
m = micros();
if (sizeof(block_t) != binFile.write(pBlock, sizeof(block_t))) {
error("write data failed");
}
m = micros() - m;
t1 = millis();
if (m > maxLatencyUsec) {
maxLatencyUsec = m;
}
if (tmpFifoCount >maxFifoUse) {
maxFifoUse = tmpFifoCount;
}
count += pBlock->count;

// Add overruns and possibly light LED.
if (pBlock->overrun) {
overruns += pBlock->overrun;
if (ERROR_LED_PIN >= 0) {
digitalWrite(ERROR_LED_PIN, HIGH);
}
}
// Initialize empty block to save ISR overhead.
pBlock->count = 0;
pBlock->overrun = 0;
fifoTail = fifoTail < (FIFO_DIM - 1) ? fifoTail + 1 : 0;

noInterrupts();
fifoCount--;
interrupts();

if (binFile.curPosition() >= MAX_FILE_SIZE) {
// File full so stop ISR calls.
adcStop();
break;
}
}
if (timerError) {
error("Missed timer event - rate too high");
}
if (Serial.available()) {
// Stop ISR interrupts.
isrStop = true;
}
if (fifoCount == 0 && !adcActive()) {
break;
}
}
Serial.println();
// Truncate file if recording stopped early.
if (binFile.curPosition() < MAX_FILE_SIZE) {
Serial.println(F("Truncating file"));
Serial.flush();
if (!binFile.truncate()) {
error("Can't truncate file");
}
}
Serial.print(F("Max write latency usec: "));
Serial.println(maxLatencyUsec);
Serial.print(F("Record time sec: "));
Serial.println(0.001*(t1 - t0), 3);
Serial.print(F("Sample count: "));
Serial.println(count/PIN_COUNT);
Serial.print(F("Overruns: "));
Serial.println(overruns);
Serial.print(F("FIFO_DIM: "));
Serial.println(FIFO_DIM);
Serial.print(F("maxFifoUse: "));
Serial.println(maxFifoUse + 1); // include ISR use.
Serial.println(F("Done"));
}
//------------------------------------------------------------------------------
void openBinFile() {
char name[NAME_DIM];
serialClearInput();
Serial.println(F("Enter file name"));
if (!serialReadLine(name, sizeof(name))) {
return;
}
if (!sd.exists(name)) {
Serial.println(name);
Serial.println(F("File does not exist"));
return;
}
binFile.close();
if (!binFile.open(name, O_RDWR)) {
Serial.println(name);
Serial.println(F("open failed"));
return;
}
Serial.println(F("File opened"));
}
//------------------------------------------------------------------------------
// Print data file to Serial
void printData() {
block_t buf;
if (!binFile.isOpen()) {
Serial.println(F("No current binary file"));
return;
}
binFile.rewind();
if (binFile.read(&buf , sizeof(buf)) != sizeof(buf)) {
error("Read metadata failed");
}
Serial.println(F("Type any character to stop"));
delay(1000);
while (!Serial.available() &&
binFile.read(&buf , sizeof(buf)) == sizeof(buf)) {
if (buf.count == 0) {
break;
}
if (buf.overrun) {
Serial.print(F("OVERRUN,"));
Serial.println(buf.overrun);
}
for (size_t i = 0; i < buf.count; i++) {
Serial.print(buf.data[i], DEC);
if ((i+1)%PIN_COUNT) {
Serial.print(',');
} else {
Serial.println();
}
}
}
Serial.println(F("Done"));
}
//------------------------------------------------------------------------------
void serialClearInput() {
do {
delay(10);
} while (Serial.read() >= 0);
}
//------------------------------------------------------------------------------
bool serialReadLine(char* str, size_t size) {
size_t n = 0;
while(!Serial.available()) {
}
while (true) {
int c = Serial.read();
if (c < ' ') break;
str[n++] = c;
if (n >= size) {
Serial.println(F("input too long"));
return false;
}
uint32_t m = millis();
while (!Serial.available() && (millis() - m) < 100){}
if (!Serial.available()) break;
}
str[n] = 0;
return true;
}
//------------------------------------------------------------------------------
void setup(void) {
if (ERROR_LED_PIN >= 0) {
pinMode(ERROR_LED_PIN, OUTPUT);
}
Serial.begin(9600);
while(!Serial) {}
Serial.println(F("Type any character to begin."));
while(!Serial.available()) {}

FillStack();

// Read the first sample pin to init the ADC.
analogRead(PIN_LIST[0]);

#if !ENABLE_DEDICATED_SPI
Serial.println(F(
"\nFor best performance edit SdFatConfig.h\n"
"and set ENABLE_DEDICATED_SPI nonzero"));
#endif // !ENABLE_DEDICATED_SPI
// Initialize SD.
if (!sd.begin(SD_CONFIG)) {
error("sd.begin failed");
}
#if USE_RTC
if (!rtc.begin()) {
error("rtc.begin failed");
}
if (!rtc.isrunning()) {
// Set RTC to sketch compile date & time.
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
error("RTC is NOT running!");
} else {
Serial.println(F("RTC is running"));
}
// Set callback
FsDateTime::setCallback(dateTime);
#endif // USE_RTC
}
//------------------------------------------------------------------------------
void loop(void) {
printUnusedStack();
// 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("l - list files"));
Serial.println(F("p - print data to Serial"));
Serial.println(F("r - record ADC data"));

while(!Serial.available()) {
SysCall::yield();
}
char c = tolower(Serial.read());
Serial.println();
if (ERROR_LED_PIN >= 0) {
digitalWrite(ERROR_LED_PIN, LOW);
}
// Read any Serial data.
do {
delay(10);
} while (Serial.available() && Serial.read() >= 0);

if (c == 'b') {
openBinFile();
} else if (c == 'c') {
if (createCsvFile()) {
binaryToCsv();
}
} else if (c == 'l') {
Serial.println(F("ls:"));
sd.ls(&Serial, LS_DATE | LS_SIZE);
} else if (c == 'p') {
printData();
} else if (c == 'r') {
createBinFile();
logData();
} else {
Serial.println(F("Invalid entry"));
}
}
#else // __AVR__
#error This program is only for AVR.
#endif // __AVR__

+ 78
- 0
examples/BackwardCompatibility/BackwardCompatibility.ino Bestand weergeven

@@ -0,0 +1,78 @@
// A simple read/write example for SD.h.
// Mostly from the SD.h ReadWrite example.
//
// Your SD must be formatted FAT16/FAT32.
//
// Set USE_SD_H nonzero to use SD.h.
// Set USE_SD_H zero to use SdFat.h.
//
#define USE_SD_H 0
//
#if USE_SD_H
#include <SD.h>
#else // USE_SD_H
#include "SdFat.h"
SdFat SD;
#endif // USE_SD_H

// Modify SD_CS_PIN for your board.
// For Teensy 3.6 and SdFat.h use BUILTIN_SDCARD.
#define SD_CS_PIN SS

File myFile;

void setup() {
Serial.begin(9600);
while (!Serial) {}

#if USE_SD_H
Serial.println(F("Using SD.h. Set USE_SD_H zero to use SdFat.h."));
#else // USE_SD_H
Serial.println(F("Using SdFat.h. Set USE_SD_H nonzero to use SD.h."));
#endif // USE_SD_H
Serial.println(F("\nType any character to begin."));
while (!Serial.available()) {
yield();
}
Serial.print("Initializing SD card...");
if (!SD.begin(SD_CS_PIN)) {
Serial.println("initialization failed!");
return;
}
Serial.println("initialization done.");

// open the file.
myFile = SD.open("test.txt", FILE_WRITE);

// if the file opened okay, write to it:
if (myFile) {
Serial.print("Writing to test.txt...");
myFile.println("testing 1, 2, 3.");
// close the file:
myFile.close();
Serial.println("done.");
} else {
// if the file didn't open, print an error:
Serial.println("error opening test.txt");
}

// re-open the file for reading:
myFile = SD.open("test.txt");
if (myFile) {
Serial.println("test.txt:");

// read from the file until there's nothing else in it:
while (myFile.available()) {
Serial.write(myFile.read());
}
// close the file:
myFile.close();
} else {
// if the file didn't open, print an error:
Serial.println("error opening test.txt");
}
}
void loop() {
// nothing happens after setup
}

+ 232
- 0
examples/BufferedPrint/BufferedPrint.ino Bestand weergeven

@@ -0,0 +1,232 @@
// Test and benchmark of the fast bufferedPrint class.
//
// Mainly for AVR but may improve print performance with other CPUs.
#include "SdFat.h"
#include "BufferedPrint.h"

// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 0
/*
Change the value of SD_CS_PIN if you are using SPI and
your hardware does not use the default value, SS.
Common values are:
Arduino Ethernet shield: pin 4
Sparkfun SD shield: pin 8
Adafruit SD shields and modules: pin 10
*/

// SDCARD_SS_PIN is defined for the built-in SD on some boards.
#ifndef SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SS;
#else // SDCARD_SS_PIN
// Assume built-in SD is used.
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#endif // SDCARD_SS_PIN

// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI)
#else // HAS_SDIO_CLASS
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI)
#endif // HAS_SDIO_CLASS

#if SD_FAT_TYPE == 0
SdFat sd;
typedef File file_t;
#elif SD_FAT_TYPE == 1
SdFat32 sd;
typedef File32 file_t;
#elif SD_FAT_TYPE == 2
SdExFat sd;
typedef ExFile file_t;
#elif SD_FAT_TYPE == 3
SdFs sd;
typedef FsFile file_t;
#else // SD_FAT_TYPE
#error Invalid SD_FAT_TYPE
#endif // SD_FAT_TYPE

// number of lines to print
const uint16_t N_PRINT = 20000;
//------------------------------------------------------------------------------
void benchmark() {
file_t file;
BufferedPrint<file_t, 64> bp;
// do write test
Serial.println();
for (int test = 0; test < 6; test++) {
char fileName[13] = "bench0.txt";
fileName[5] = '0' + test;
// open or create file - truncate existing file.
if (!file.open(fileName, O_RDWR | O_CREAT | O_TRUNC)) {
sd.errorHalt(&Serial, F("open failed"));
}
if (test & 1) {
bp.begin(&file);
}
uint32_t t = millis();
switch(test) {
case 0:
Serial.println(F("Test of println(uint16_t)"));
for (uint16_t i = 0; i < N_PRINT; i++) {
file.println(i);
}
break;

case 1:
Serial.println(F("Test of printField(uint16_t, char)"));
for (uint16_t i = 0; i < N_PRINT; i++) {
bp.printField(i, '\n');
}
break;

case 2:
Serial.println(F("Test of println(uint32_t)"));
for (uint16_t i = 0; i < N_PRINT; i++) {
file.println(12345678UL + i);
}
break;

case 3:
Serial.println(F("Test of printField(uint32_t, char)"));
for (uint16_t i = 0; i < N_PRINT; i++) {
bp.printField(12345678UL + i, '\n');
}
break;

case 4:
Serial.println(F("Test of println(double)"));
for (uint16_t i = 0; i < N_PRINT; i++) {
file.println((double)0.01*i);
}
break;

case 5:
Serial.println(F("Test of printField(double, char)"));
for (uint16_t i = 0; i < N_PRINT; i++) {
bp.printField((double)0.01*i, '\n');
}
break;

}
if (test & 1) {
bp.sync();
}
if (file.getWriteError()) {
sd.errorHalt(&Serial, F("write failed"));
}
double s = file.fileSize();
file.close();
t = millis() - t;
Serial.print(F("Time "));
Serial.print(0.001*t, 3);
Serial.println(F(" sec"));
Serial.print(F("File size "));
Serial.print(0.001*s);
Serial.println(F(" KB"));
Serial.print(F("Write "));
Serial.print(s/t);
Serial.println(F(" KB/sec"));
Serial.println();
}
}
//------------------------------------------------------------------------------
void testMemberFunctions() {
BufferedPrint<Print, 32> bp(&Serial);
char c = 'c'; // char
//#define BASIC_TYPES
#ifdef BASIC_TYPES
signed char sc = -1; // signed 8-bit
unsigned char uc = 1; // unsiged 8-bit
signed short ss = -2; // signed 16-bit
unsigned short us = 2; // unsigned 16-bit
signed long sl = -4; // signed 32-bit
unsigned long ul = 4; // unsigned 32-bit
#else // BASIC_TYPES
int8_t sc = -1; // signed 8-bit
uint8_t uc = 1; // unsiged 8-bit
int16_t ss = -2; // signed 16-bit
uint16_t us = 2; // unsigned 16-bit
int32_t sl = -4; // signed 32-bit
uint32_t ul = 4; // unsigned 32-bit
#endif // BASIC_TYPES
float f = -1.234;
double d = -5.678;
bp.println();
bp.println("Test print()");
bp.print(c);
bp.println();
bp.print("string");
bp.println();
bp.print(F("flash"));
bp.println();
bp.print(sc);
bp.println();
bp.print(uc);
bp.println();
bp.print(ss);
bp.println();
bp.print(us);
bp.println();
bp.print(sl);
bp.println();
bp.print(ul);
bp.println();
bp.print(f);
bp.println();
bp.print(d);
bp.println();
bp.println();

bp.println("Test println()");
bp.println(c);
bp.println("string");
bp.println(F("flash"));
bp.println(sc);
bp.println(uc);
bp.println(ss);
bp.println(us);
bp.println(sl);
bp.println(ul);
bp.println(f);
bp.println(d);
bp.println();

bp.println("Test printField()");
bp.printField(c, ',');
bp.printField("string", ',');
bp.printField(F("flash"), ',');
bp.printField(sc, ',');
bp.printField(uc, ',');
bp.printField(ss, ',');
bp.printField(us, ',');
bp.printField(sl, ',');
bp.printField(ul, ',');
bp.printField(f, ',');
bp.printField(d, '\n');

bp.sync();
}
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
while (!Serial) {}
Serial.println("Type any character to begin.");
while(!Serial.available()) {}
if (!sd.begin(SD_CONFIG)) {
sd.initErrorHalt(&Serial);
}
Serial.println();
Serial.println(F("Test member funcions:"));
testMemberFunctions();
Serial.println();
Serial.println(F("Benchmark performance for uint16_t, uint32_t, and double:"));
benchmark();
Serial.println("Done");
}
//------------------------------------------------------------------------------
void loop() {
}

+ 62
- 30
examples/DirectoryFunctions/DirectoryFunctions.ino Bestand weergeven

@@ -1,59 +1,92 @@
/*
* Example use of chdir(), ls(), mkdir(), and rmdir().
*/
#include <SPI.h>
#include "SdFat.h"
#include "sdios.h"
// SD card chip select pin.
const uint8_t chipSelect = SS;

// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 0
/*
Change the value of SD_CS_PIN if you are using SPI and
your hardware does not use the default value, SS.
Common values are:
Arduino Ethernet shield: pin 4
Sparkfun SD shield: pin 8
Adafruit SD shields and modules: pin 10
*/

// SDCARD_SS_PIN is defined for the built-in SD on some boards.
#ifndef SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SS;
#else // SDCARD_SS_PIN
// Assume built-in SD is used.
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#endif // SDCARD_SS_PIN

// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI)
#else // HAS_SDIO_CLASS
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI)
#endif // HAS_SDIO_CLASS
//------------------------------------------------------------------------------

// File system object.
#if SD_FAT_TYPE == 0
SdFat sd;

// Use for file creation in folders.
SdFile file;
File file;
File root;
#elif SD_FAT_TYPE == 1
SdFat32 sd;
File32 file;
File32 root;
#elif SD_FAT_TYPE == 2
SdExFat sd;
ExFile file;
ExFile root;
#elif SD_FAT_TYPE == 3
SdFs sd;
FsFile file;
FsFile root;
#endif // SD_FAT_TYPE

// Create a Serial output stream.
ArduinoOutStream cout(Serial);

// Buffer for Serial input.
char cinBuf[40];

// Create a serial input stream.
ArduinoInStream cin(Serial, cinBuf, sizeof(cinBuf));
//==============================================================================
// Error messages stored in flash.
#define error(msg) sd.errorHalt(F(msg))
//------------------------------------------------------------------------------
// Store error strings in flash to save RAM.
#define error(s) sd.errorHalt(&Serial, F(s))
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
// Wait for USB Serial

// Wait for USB Serial
while (!Serial) {
SysCall::yield();
}
delay(1000);

cout << F("Type any character to start\n");
// Wait for input line and discard.
cin.readline();
cout << endl;
// 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();
while (!Serial.available()) {
SysCall::yield();
}

// Initialize the SD card.
if (!sd.begin(SD_CONFIG)) {
sd.initErrorHalt(&Serial);
}
if (sd.exists("Folder1")
if (sd.exists("Folder1")
|| sd.exists("Folder1/file1.txt")
|| sd.exists("Folder1/File2.txt")) {
error("Please remove existing Folder1, file1.txt, and File2.txt");
}

int rootFileCount = 0;
sd.vwd()->rewind();
while (file.openNext(sd.vwd(), O_RDONLY)) {
if (!root.open("/")) {
error("open root");
}
while (file.openNext(&root, O_RDONLY)) {
if (!file.isHidden()) {
rootFileCount++;
}
@@ -113,7 +146,6 @@ void setup() {
if (!sd.rmdir("Folder1")) {
error("rmdir for Folder1 failed\n");
}

cout << F("\nFolder1 removed.\n");
cout << F("\nList of files on the SD.\n");
sd.ls(LS_R);

+ 79
- 0
examples/ExFatFormatter/ExFatFormatter.ino Bestand weergeven

@@ -0,0 +1,79 @@
// Force exFAT formatting for all SD cards larger than 512MB.
#include "SdFat.h"

/*
Change the value of SD_CS_PIN if you are using SPI and
your hardware does not use the default value, SS.
Common values are:
Arduino Ethernet shield: pin 4
Sparkfun SD shield: pin 8
Adafruit SD shields and modules: pin 10
*/

// SDCARD_SS_PIN is defined for the built-in SD on some boards.
#ifndef SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SS;
#else // SDCARD_SS_PIN
// Assume built-in SD is used.
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#endif // SDCARD_SS_PIN

// Select fastest interface.
#if HAS_SDIO_CLASS
// SD config for Teensy 3.6 SDIO.
#define SD_CONFIG SdioConfig(FIFO_SDIO)
//#define SD_CONFIG SdioConfig(DMA_SDIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI)
#else // HAS_SDIO_CLASS
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI)
#endif // HAS_SDIO_CLASS

SdExFat sd;
//------------------------------------------------------------------------------
void errorHalt() {
sd.printSdError(&Serial);
SysCall::halt();
}
#define error(s) (Serial.println(F(s)),errorHalt())
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
while (!Serial) {}
Serial.println(F("Type any character to begin"));
while (!Serial.available()) {
yield();
}
do {
delay(10);
} while(Serial.read() >= 0);
Serial.println();
Serial.println(F(
"Your SD will be formated exFAT.\r\n"
"All data on the SD will be lost.\r\n"
"Type 'Y' to continue.\r\n"));
while (!Serial.available()) {
yield();
}
if (Serial.read() != 'Y') {
Serial.println(F("Exiting, 'Y' not typed."));
return;
}
if (!sd.cardBegin(SD_CONFIG)) {
error("cardBegin failed");
}
if(!sd.format(&Serial)) {
error("format failed");
}
if (!sd.volumeBegin()) {
error("volumeBegin failed");
}
Serial.print(F("Bytes per cluster: "));
Serial.println(sd.bytesPerCluster());
Serial.println(F("Done"));
}
void loop() {
}

+ 9
- 0
examples/ExFatLogger/ExFatLogger.h Bestand weergeven

@@ -0,0 +1,9 @@
// Avoid IDE problems by defining struct in septate .h file.
// Pad record so size is a power of two for best write performance.
#ifndef ExFatLogger_h
#define ExFatLogger_h
const size_t ADC_COUNT = 4;
struct data_t {
uint16_t adc[ADC_COUNT];
};
#endif // ExFatLogger_h

+ 579
- 0
examples/ExFatLogger/ExFatLogger.ino Bestand weergeven

@@ -0,0 +1,579 @@
// Example to demonstrate write latency for preallocated exFAT files.
// I suggest you write a PC program to convert very large bin files.
//
// If an exFAT SD is required, the ExFatFormatter example will format
// smaller cards with an exFAT file system.
//
// The maximum data rate will depend on the quality of your SD,
// the size of the FIFO, and using dedicated SPI.
#include "SdFat.h"
#include "FreeStack.h"
#include "ExFatLogger.h"
//------------------------------------------------------------------------------
// This example was designed for exFAT but will support FAT16/FAT32.
// Note: Uno will not support SD_FAT_TYPE = 3.
// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 2
//------------------------------------------------------------------------------
// Interval between data records in microseconds.
// Try 250 with Teensy 3.6, Due, or STM32.
// Try 2000 with AVR boards.
// Try 4000 with SAMD Zero boards.
const uint32_t LOG_INTERVAL_USEC = 2000;

// Set USE_RTC nonzero for file timestamps.
// RAM use will be marginal on Uno with RTClib.
#define USE_RTC 0
#if USE_RTC
#include "RTClib.h"
#endif // USE_RTC

// LED to light if overruns occur.
#define ERROR_LED_PIN -1

/*
Change the value of SD_CS_PIN if you are using SPI and
your hardware does not use the default value, SS.
Common values are:
Arduino Ethernet shield: pin 4
Sparkfun SD shield: pin 8
Adafruit SD shields and modules: pin 10
*/

// SDCARD_SS_PIN is defined for the built-in SD on some boards.
#ifndef SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SS;
#else // SDCARD_SS_PIN
// Assume built-in SD is used.
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#endif // SDCARD_SS_PIN

// FIFO SIZE - 512 byte sectors. Modify for your board.
#ifdef __AVR_ATmega328P__
// Use 512 bytes for 328 boards.
#define FIFO_SIZE_SECTORS 1
#elif defined(__AVR__)
// Use 2 KiB for other AVR boards.
#define FIFO_SIZE_SECTORS 4
#else // __AVR_ATmega328P__
// Use 8 KiB for non-AVR boards.
#define FIFO_SIZE_SECTORS 16
#endif // __AVR_ATmega328P__

// Preallocate 1GiB file.
const uint32_t PREALLOCATE_SIZE_MiB = 1024UL;

// Select the fastest interface. Assumes no other SPI devices.
#if ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI)
#else // ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI)
#endif // ENABLE_DEDICATED_SPI

// Save SRAM if 328.
#ifdef __AVR_ATmega328P__
#include "MinimumSerial.h"
MinimumSerial MinSerial;
#define Serial MinSerial
#endif // __AVR_ATmega328P__
//==============================================================================
// Replace logRecord(), printRecord(), and ExFatLogger.h for your sensors.
void logRecord(data_t* data, uint16_t overrun) {
if (overrun) {
// Add one since this record has no adc data. Could add overrun field.
overrun++;
data->adc[0] = 0X8000 | overrun;
} else {
for (size_t i = 0; i < ADC_COUNT; i++) {
data->adc[i] = analogRead(i);
}
}
}
//------------------------------------------------------------------------------
void printRecord(Print* pr, data_t* data) {
static uint32_t nr = 0;
if (!data) {
pr->print(F("LOG_INTERVAL_USEC,"));
pr->println(LOG_INTERVAL_USEC);
pr->print(F("rec#"));
for (size_t i = 0; i < ADC_COUNT; i++) {
pr->print(F(",adc"));
pr->print(i);
}
pr->println();
nr = 0;
return;
}
if (data->adc[0] & 0X8000) {
uint16_t n = data->adc[0] & 0X7FFF;
nr += n;
pr->print(F("-1,"));
pr->print(n);
pr->println(F(",overuns"));
} else {
pr->print(nr++);
for (size_t i = 0; i < ADC_COUNT; i++) {
pr->write(',');
pr->print(data->adc[i]);
}
pr->println();
}
}
//==============================================================================
const uint64_t PREALLOCATE_SIZE = (uint64_t)PREALLOCATE_SIZE_MiB << 20;
// Max length of file name including zero byte.
#define FILE_NAME_DIM 40
// Max number of records to buffer while SD is busy.
const size_t FIFO_DIM = 512*FIFO_SIZE_SECTORS/sizeof(data_t);

#if SD_FAT_TYPE == 0
typedef SdFat sd_t;
typedef File file_t;
#elif SD_FAT_TYPE == 1
typedef SdFat32 sd_t;
typedef File32 file_t;
#elif SD_FAT_TYPE == 2
typedef SdExFat sd_t;
typedef ExFile file_t;
#elif SD_FAT_TYPE == 3
typedef SdFs sd_t;
typedef FsFile file_t;
#else // SD_FAT_TYPE
#error Invalid SD_FAT_TYPE
#endif // SD_FAT_TYPE

sd_t sd;

file_t binFile;
file_t csvFile;
// You may modify the filename. Digits before the dot are file versions.
char binName[] = "ExFatLogger00.bin";
//------------------------------------------------------------------------------
#if USE_RTC
RTC_DS1307 rtc;

// Call back for file timestamps. Only called for file create and sync().
void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) {
DateTime now = rtc.now();

// Return date using FS_DATE macro to format fields.
*date = FS_DATE(now.year(), now.month(), now.day());

// Return time using FS_TIME macro to format fields.
*time = FS_TIME(now.hour(), now.minute(), now.second());

// Return low time bits in units of 10 ms.
*ms10 = now.second() & 1 ? 100 : 0;
}
#endif // USE_RTC
//------------------------------------------------------------------------------
#define error(s) sd.errorHalt(&Serial, F(s))
#define dbgAssert(e) ((e) ? (void)0 : error("assert " #e))
//-----------------------------------------------------------------------------
// Convert binary file to csv file.
void binaryToCsv() {
uint8_t lastPct = 0;
uint32_t t0 = millis();
data_t binData[FIFO_DIM];

if (!binFile.seekSet(512)) {
error("binFile.seek faile");
}
uint32_t tPct = millis();
printRecord(&csvFile, nullptr);
while (!Serial.available() && binFile.available()) {
int nb = binFile.read(binData, sizeof(binData));
if (nb <= 0 ) {
error("read binFile failed");
}
size_t nr = nb/sizeof(data_t);
for (size_t i = 0; i < nr; i++) {
printRecord(&csvFile, &binData[i]);
}

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('%');
csvFile.sync();
}
}
if (Serial.available()) {
break;
}
}
csvFile.close();
Serial.print(F("Done: "));
Serial.print(0.001*(millis() - t0));
Serial.println(F(" Seconds"));
}
//-------------------------------------------------------------------------------
void createBinFile() {
binFile.close();
while (sd.exists(binName)) {
char* p = strchr(binName, '.');
if (!p) {
error("no dot in filename");
}
while (true) {
p--;
if (p < binName || *p < '0' || *p > '9') {
error("Can't create file name");
}
if (p[0] != '9') {
p[0]++;
break;
}
p[0] = '0';
}
}
if (!binFile.open(binName, O_RDWR | O_CREAT)) {
error("open binName failed");
}
Serial.println(binName);
if (!binFile.preAllocate(PREALLOCATE_SIZE)) {
error("preAllocate failed");
}

Serial.print(F("preAllocated: "));
Serial.print(PREALLOCATE_SIZE_MiB);
Serial.println(F(" MiB"));
}
//-------------------------------------------------------------------------------
bool createCsvFile() {
char csvName[FILE_NAME_DIM];
if (!binFile.isOpen()) {
Serial.println(F("No current binary file"));
return false;
}

// Create a new csvFile.
binFile.getName(csvName, sizeof(csvName));
char* dot = strchr(csvName, '.');
if (!dot) {
error("no dot in filename");
}
strcpy(dot + 1, "csv");
if (!csvFile.open(csvName, O_WRONLY | O_CREAT | O_TRUNC)) {
error("open csvFile failed");
}
serialClearInput();
Serial.print(F("Writing: "));
Serial.print(csvName);
Serial.println(F(" - type any character to stop"));
return true;
}
//-------------------------------------------------------------------------------
void logData() {
int32_t delta; // Jitter in log time.
int32_t maxDelta = 0;
uint32_t maxLogMicros = 0;
uint32_t maxWriteMicros = 0;
size_t maxFifoUse = 0;
size_t fifoCount = 0;
size_t fifoHead = 0;
size_t fifoTail = 0;
uint16_t overrun = 0;
uint16_t maxOverrun = 0;
uint32_t totalOverrun = 0;
uint32_t fifoBuf[128*FIFO_SIZE_SECTORS];
data_t* fifoData = (data_t*)fifoBuf;

// Write dummy sector to start multi-block write.
dbgAssert(sizeof(fifoBuf) >= 512);
memset(fifoBuf, 0, sizeof(fifoBuf));
if (binFile.write(fifoBuf, 512) != 512) {
error("write first sector failed");
}
serialClearInput();
Serial.println(F("Type any character to stop"));

// Wait until SD is not busy.
while (sd.card()->isBusy()) {}

// Start time for log file.
uint32_t m = millis();

// Time to log next record.
uint32_t logTime = micros();
while (true) {
// Time for next data record.
logTime += LOG_INTERVAL_USEC;

// Wait until time to log data.
delta = micros() - logTime;
if (delta > 0) {
Serial.print(F("delta: "));
Serial.println(delta);
error("Rate too fast");
}
while (delta < 0) {
delta = micros() - logTime;
}

if (fifoCount < FIFO_DIM) {
uint32_t m = micros();
logRecord(fifoData + fifoHead, overrun);
m = micros() - m;
if (m > maxLogMicros) {
maxLogMicros = m;
}
fifoHead = fifoHead < (FIFO_DIM - 1) ? fifoHead + 1 : 0;
fifoCount++;
if (overrun) {
if (overrun > maxOverrun) {
maxOverrun = overrun;
}
overrun = 0;
}
} else {
totalOverrun++;
overrun++;
if (overrun > 0XFFF) {
error("too many overruns");
}
if (ERROR_LED_PIN >= 0) {
digitalWrite(ERROR_LED_PIN, HIGH);
}
}
// Save max jitter.
if (delta > maxDelta) {
maxDelta = delta;
}
// Write data if SD is not busy.
if (!sd.card()->isBusy()) {
size_t nw = fifoHead > fifoTail ? fifoCount : FIFO_DIM - fifoTail;
// Limit write time by not writing more than 512 bytes.
const size_t MAX_WRITE = 512/sizeof(data_t);
if (nw > MAX_WRITE) nw = MAX_WRITE;
size_t nb = nw*sizeof(data_t);
uint32_t usec = micros();
if (nb != binFile.write(fifoData + fifoTail, nb)) {
error("write binFile failed");
}
usec = micros() - usec;
if (usec > maxWriteMicros) {
maxWriteMicros = usec;
}
fifoTail = (fifoTail + nw) < FIFO_DIM ? fifoTail + nw : 0;
if (fifoCount > maxFifoUse) {
maxFifoUse = fifoCount;
}
fifoCount -= nw;
if (Serial.available()) {
break;
}
}
}
Serial.print(F("\nLog time: "));
Serial.print(0.001*(millis() - m));
Serial.println(F(" Seconds"));
binFile.truncate();
binFile.sync();
Serial.print(("File size: "));
// Warning cast used for print since fileSize is uint64_t.
Serial.print((uint32_t)binFile.fileSize());
Serial.println(F(" bytes"));
Serial.print(F("totalOverrun: "));
Serial.println(totalOverrun);
Serial.print(F("FIFO_DIM: "));
Serial.println(FIFO_DIM);
Serial.print(F("maxFifoUse: "));
Serial.println(maxFifoUse);
Serial.print(F("maxLogMicros: "));
Serial.println(maxLogMicros);
Serial.print(F("maxWriteMicros: "));
Serial.println(maxWriteMicros);
Serial.print(F("Log interval: "));
Serial.print(LOG_INTERVAL_USEC);
Serial.print(F(" micros\nmaxDelta: "));
Serial.print(maxDelta);
Serial.println(F(" micros"));
}
//------------------------------------------------------------------------------
void openBinFile() {
char name[FILE_NAME_DIM];
serialClearInput();
Serial.println(F("Enter file name"));
if (!serialReadLine(name, sizeof(name))) {
return;
}
if (!sd.exists(name)) {
Serial.println(name);
Serial.println(F("File does not exist"));
return;
}
binFile.close();
if (!binFile.open(name, O_RDONLY)) {
Serial.println(name);
Serial.println(F("open failed"));
return;
}
Serial.println(F("File opened"));
}
//-----------------------------------------------------------------------------
void printData() {
if (!binFile.isOpen()) {
Serial.println(F("No current binary file"));
return;
}
// Skip first dummy sector.
if (!binFile.seekSet(512)) {
error("seek failed");
}
serialClearInput();
Serial.println(F("type any character to stop\n"));
delay(1000);
printRecord(&Serial, nullptr);
while (binFile.available() && !Serial.available()) {
data_t record;
if (binFile.read(&record, sizeof(data_t)) != sizeof(data_t)) {
error("read binFile failed");
}
printRecord(&Serial, &record);
}
}
//------------------------------------------------------------------------------
void printUnusedStack() {
#if HAS_UNUSED_STACK
Serial.print(F("\nUnused stack: "));
Serial.println(UnusedStack());
#endif // HAS_UNUSED_STACK
}
//------------------------------------------------------------------------------
void serialClearInput() {
do {
delay(10);
} while (Serial.read() >= 0);
}
//------------------------------------------------------------------------------
bool serialReadLine(char* str, size_t size) {
size_t n = 0;
while(!Serial.available()) {
yield();
}
while (true) {
int c = Serial.read();
if (c < ' ') break;
str[n++] = c;
if (n >= size) {
Serial.println(F("input too long"));
return false;
}
uint32_t m = millis();
while (!Serial.available() && (millis() - m) < 100){}
if (!Serial.available()) break;
}
str[n] = 0;
return true;
}
//------------------------------------------------------------------------------
void testSensor() {
const uint32_t interval = 200000;
int32_t diff;
data_t data;
serialClearInput();
Serial.println(F("\nTesting - type any character to stop\n"));
delay(1000);
printRecord(&Serial, nullptr);
uint32_t m = micros();
while (!Serial.available()) {
m += interval;
do {
diff = m - micros();
} while (diff > 0);
logRecord(&data, 0);
printRecord(&Serial, &data);
}
}
//------------------------------------------------------------------------------
void setup() {
if (ERROR_LED_PIN >= 0) {
pinMode(ERROR_LED_PIN, OUTPUT);
digitalWrite(ERROR_LED_PIN, HIGH);
}
Serial.begin(9600);

// Wait for USB Serial
while (!Serial) {
SysCall::yield();
}
delay(1000);
Serial.println(F("Type any character to begin"));
while (!Serial.available()) {
yield();
}
FillStack();
#if !ENABLE_DEDICATED_SPI
Serial.println(F(
"\nFor best performance edit SdFatConfig.h\n"
"and set ENABLE_DEDICATED_SPI nonzero"));
#endif // !ENABLE_DEDICATED_SPI

Serial.print(FIFO_DIM);
Serial.println(F(" FIFO entries will be used."));

// Initialize SD.
if (!sd.begin(SD_CONFIG)) {
sd.initErrorHalt(&Serial);
}
#if USE_RTC
if (!rtc.begin()) {
error("rtc.begin failed");
}
if (!rtc.isrunning()) {
// Set RTC to sketch compile date & time.
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
error("RTC is NOT running!");
}
// Set callback
FsDateTime::setCallback(dateTime);
#endif // USE_RTC
}
//------------------------------------------------------------------------------
void loop() {
printUnusedStack();
// Read any Serial data.
serialClearInput();

if (ERROR_LED_PIN >= 0) {
digitalWrite(ERROR_LED_PIN, LOW);
}
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("l - list files"));
Serial.println(F("p - print data to Serial"));
Serial.println(F("r - record data"));
Serial.println(F("t - test without logging"));
while(!Serial.available()) {
SysCall::yield();
}
char c = tolower(Serial.read());
Serial.println();

if (c == 'b') {
openBinFile();
} else if (c == 'c') {
if (createCsvFile()) {
binaryToCsv();
}
} else if (c == 'l') {
Serial.println(F("ls:"));
sd.ls(&Serial, LS_DATE | LS_SIZE);
} else if (c == 'p') {
printData();
} else if (c == 'r') {
createBinFile();
logData();
} else if (c == 't') {
testSensor();
} else {
Serial.println(F("Invalid entry"));
}
}

+ 47
- 0
examples/ExFatUnicodeTest/ExFatUnicodeTest.ino Bestand weergeven

@@ -0,0 +1,47 @@
// Simple test of Unicode file name.
// Note: Unicode is only supported by the SdExFat class.
// No exFAT functions will be defined for char* paths.
// The SdFs class cannot be used.
#include "SdFat.h"
#if USE_UNICODE_NAMES

// SDCARD_SS_PIN is defined for the built-in SD on some boards.
#ifndef SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SS;
#else // SDCARD_SS_PIN
// Assume built-in SD is used.
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#endif // SDCARD_SS_PIN

// Use SPI, SD_CS_PIN, SHARED_SPI, FULL_SPEED.
#define SD_CONFIG SdSpiConfig(SD_CS_PIN)

SdExFat sd;

ExFile file;

void setup() {
Serial.begin(9600);
while (!Serial) {
yield();
}
Serial.println("Type any character to begin");
while (!Serial.available()) {
yield();
}
if (!sd.begin(SD_CONFIG)) {
sd.initErrorHalt(&Serial);
}
if (!file.open(u"Euros \u20AC test.txt", FILE_WRITE)) {
Serial.println("file.open failed");
return;
}
file.println("This is not Unicode");
file.close();
Serial.println("Done!");
}
void loop() {
}
#else // USE_UNICODE_NAMES
#error USE_UNICODE_NAMES must be nonzero in SdFat/src/ExFatLib/ExFatCongfig.h
#endif // USE_UNICODE_NAMES

+ 66
- 18
examples/OpenNext/OpenNext.ino Bestand weergeven

@@ -1,16 +1,59 @@
/*
* Print size, modify date/time, and name for all files in root.
*/
#include <SPI.h>
#include "SdFat.h"

// SD default chip select pin.
const uint8_t chipSelect = SS;
// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 0
/*
Change the value of SD_CS_PIN if you are using SPI and
your hardware does not use the default value, SS.
Common values are:
Arduino Ethernet shield: pin 4
Sparkfun SD shield: pin 8
Adafruit SD shields and modules: pin 10
*/

// file system object
SdFat sd;
// SDCARD_SS_PIN is defined for the built-in SD on some boards.
#ifndef SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SS;
#else // SDCARD_SS_PIN
// Assume built-in SD is used.
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#endif // SDCARD_SS_PIN

SdFile file;
// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI)
#else // HAS_SDIO_CLASS
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI)
#endif // HAS_SDIO_CLASS

#if SD_FAT_TYPE == 0
SdFat sd;
File dir;
File file;
#elif SD_FAT_TYPE == 1
SdFat32 sd;
File32 dir;
File32 file;
#elif SD_FAT_TYPE == 2
SdExFat sd;
ExFile dir;
ExFile file;
#elif SD_FAT_TYPE == 3
SdFs sd;
FsFile dir;
FsFile file;
#else // SD_FAT_TYPE
#error invalid SD_FAT_TYPE
#endif // SD_FAT_TYPE
//------------------------------------------------------------------------------
// Store error strings in flash to save RAM.
#define error(s) sd.errorHalt(&Serial, F(s))
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
@@ -25,17 +68,18 @@ void setup() {
SysCall::yield();
}

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

// Open next file in root. The volume working directory, vwd, is root.
// Warning, openNext starts at the current position of sd.vwd() so a
// rewind may be neccessary in your application.
sd.vwd()->rewind();
while (file.openNext(sd.vwd(), O_RDONLY)) {
// Open root directory
if (!dir.open("/")){
error("dir.open failed");
}
// Open next file in root.
// Warning, openNext starts at the current position of dir so a
// rewind may be necessary in your application.
while (file.openNext(&dir, O_RDONLY)) {
file.printFileSize(&Serial);
Serial.write(' ');
file.printModifyDateTime(&Serial);
@@ -48,7 +92,11 @@ void setup() {
Serial.println();
file.close();
}
Serial.println("Done!");
if (dir.getError()) {
Serial.println("openNext failed");
} else {
Serial.println("Done!");
}
}
//------------------------------------------------------------------------------
void loop() {}
void loop() {}

+ 24
- 13
examples/QuickStart/QuickStart.ino Bestand weergeven

@@ -3,20 +3,36 @@
#include <SPI.h>
#include "SdFat.h"
#include "sdios.h"

// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 3
//
// Set DISABLE_CHIP_SELECT to disable a second SPI device.
// For example, with the Ethernet shield, set DISABLE_CHIP_SELECT
// to 10 to disable the Ethernet controller.
const int8_t DISABLE_CHIP_SELECT = -1;
//
// Test with reduced SPI speed for breadboards. SD_SCK_MHZ(4) will select
// 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.
#if SD_FAT_TYPE == 0
SdFat sd;

File file;
#elif SD_FAT_TYPE == 1
SdFat32 sd;
File32 file;
#elif SD_FAT_TYPE == 2
SdExFat sd;
ExFile file;
#elif SD_FAT_TYPE == 3
SdFs sd;
FsFile file;
#else // SD_FAT_TYPE
#error Invalid SD_FAT_TYPE
#endif // SD_FAT_TYPE
// Serial streams
ArduinoOutStream cout(Serial);

@@ -40,8 +56,8 @@ void reformatMsg() {

void setup() {
Serial.begin(9600);
// Wait for USB Serial
// Wait for USB Serial
while (!Serial) {
SysCall::yield();
}
@@ -120,18 +136,13 @@ void loop() {
reformatMsg();
return;
}
if (!sd.vwd()->isOpen()) {
cout << F("Can't open root directory.\n");
reformatMsg();
return;
}
cout << F("Can't determine error type\n");
return;
}
cout << F("\nCard successfully initialized.\n");
cout << endl;

uint32_t size = sd.card()->cardSize();
uint32_t size = sd.card()->sectorCount();
if (size == 0) {
cout << F("Can't determine the card size.\n");
cardOrSpeed();
@@ -142,13 +153,13 @@ void loop() {
cout << F(" MB (MB = 1,000,000 bytes)\n");
cout << endl;
cout << F("Volume is FAT") << int(sd.vol()->fatType());
cout << F(", Cluster size (bytes): ") << 512L * sd.vol()->blocksPerCluster();
cout << F(", Cluster size (bytes): ") << sd.vol()->bytesPerCluster();
cout << endl << endl;

cout << F("Files found (date time size name):\n");
sd.ls(LS_R | LS_DATE | LS_SIZE);

if ((sizeMB > 1100 && sd.vol()->blocksPerCluster() < 64)
if ((sizeMB > 1100 && sd.vol()->sectorsPerCluster() < 64)
|| (sizeMB < 2200 && sd.vol()->fatType() == 32)) {
cout << F("\nThis card should be reformatted for best performance.\n");
cout << F("Use a cluster size of 32 KB for cards larger than 1 GB.\n");

+ 153
- 0
examples/ReadCsvFile/ReadCsvFile.ino Bestand weergeven

@@ -0,0 +1,153 @@
#include "SdFat.h"

// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 0
/*
Change the value of SD_CS_PIN if you are using SPI and
your hardware does not use the default value, SS.
Common values are:
Arduino Ethernet shield: pin 4
Sparkfun SD shield: pin 8
Adafruit SD shields and modules: pin 10
*/

// SDCARD_SS_PIN is defined for the built-in SD on some boards.
#ifndef SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SS;
#else // SDCARD_SS_PIN
// Assume built-in SD is used.
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#endif // SDCARD_SS_PIN

// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI)
#else // HAS_SDIO_CLASS
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI)
#endif // HAS_SDIO_CLASS

#if SD_FAT_TYPE == 0
SdFat sd;
File file;
#elif SD_FAT_TYPE == 1
SdFat32 sd;
File32 file;
#elif SD_FAT_TYPE == 2
SdExFat sd;
ExFile file;
#elif SD_FAT_TYPE == 3
SdFs sd;
FsFile file;
#else // SD_FAT_TYPE
#error Invalid SD_FAT_TYPE
#endif // SD_FAT_TYPE

char line[40];

//------------------------------------------------------------------------------
// Store error strings in flash to save RAM.
#define error(s) sd.errorHalt(&Serial, F(s))
//------------------------------------------------------------------------------
// Check for extra characters in field or find minus sign.
char* skipSpace(char* str) {
while (isspace(*str)) str++;
return str;
}
//------------------------------------------------------------------------------
bool parseLine(char* str) {
char* ptr;

// Set strtok start of line.
str = strtok(str, ",");
if (!str) return false;
// Print text field.
Serial.println(str);
// Subsequent calls to strtok expects a null pointer.
str = strtok(nullptr, ",");
if (!str) return false;
// Convert string to long integer.
int32_t i32 = strtol(str, &ptr, 0);
if (str == ptr || *skipSpace(ptr)) return false;
Serial.println(i32);
str = strtok(nullptr, ",");
if (!str) return false;
// strtoul accepts a leading minus with unexpected results.
if (*skipSpace(str) == '-') return false;
// Convert string to unsigned long integer.
uint32_t u32 = strtoul(str, &ptr, 0);
if (str == ptr || *skipSpace(ptr)) return false;
Serial.println(u32);

str = strtok(nullptr, ",");
if (!str) return false;
// Convert string to double.
double d = strtod(str, &ptr);
if (str == ptr || *skipSpace(ptr)) return false;
Serial.println(d);
// Check for extra fields.
return strtok(nullptr, ",") == nullptr;
}
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
// Wait for USB Serial
while (!Serial) {
yield();
}
Serial.println("Type any character to start");
while (!Serial.available()) {
yield();
}
// Initialize the SD.
if (!sd.begin(SD_CONFIG)) {
sd.initErrorHalt(&Serial);
return;
}
// Remove any existing file.
if (sd.exists("ReadCsvDemo.csv")) {
sd.remove("ReadCsvDemo.csv");
}
// Create the file.
if (!file.open("ReadCsvDemo.csv", FILE_WRITE)) {
error("open failed");
}
// Write test data.
file.print(F(
"abc,123,456,7.89\r\n"
"def,-321,654,-9.87\r\n"
"ghi,333,0xff,5.55"));
// Rewind file for read.
file.rewind();
while (file.available()) {
int n = file.fgets(line, sizeof(line));
if (n <= 0) {
error("fgets failed");
}
if (line[n-1] != '\n' && n == (sizeof(line) - 1)) {
error("line too long");
}
if (!parseLine(line)) {
error("parseLine failed");
}
Serial.println();
}
file.close();
Serial.println(F("Done"));
}

void loop() {
}

+ 141
- 0
examples/RtcTimestampTest/RtcTimestampTest.ino Bestand weergeven

@@ -0,0 +1,141 @@
// Test of time-stamp callback.
// Set the callback with this statement.
// FsDateTime::setCallback(dateTime);
#include "SdFat.h"
// https://github.com/adafruit/RTClib
#include "RTClib.h"

// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 0
/*
Change the value of SD_CS_PIN if you are using SPI and
your hardware does not use the default value, SS.
Common values are:
Arduino Ethernet shield: pin 4
Sparkfun SD shield: pin 8
Adafruit SD shields and modules: pin 10
*/

// SDCARD_SS_PIN is defined for the built-in SD on some boards.
#ifndef SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SS;
#else // SDCARD_SS_PIN
// Assume built-in SD is used.
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#endif // SDCARD_SS_PIN

// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI)
#else // HAS_SDIO_CLASS
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI)
#endif // HAS_SDIO_CLASS

#if SD_FAT_TYPE == 0
SdFat sd;
File file;
#elif SD_FAT_TYPE == 1
SdFat32 sd;
File32 file;
#elif SD_FAT_TYPE == 2
SdExFat sd;
ExFile file;
#elif SD_FAT_TYPE == 3
SdFs sd;
FsFile file;
#else // SD_FAT_TYPE
#error Invalid SD_FAT_TYPE
#endif // SD_FAT_TYPE

RTC_DS1307 rtc;
//------------------------------------------------------------------------------
// Call back for file timestamps. Only called for file create and sync().
void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) {
DateTime now = rtc.now();

// Return date using FS_DATE macro to format fields.
*date = FS_DATE(now.year(), now.month(), now.day());

// Return time using FS_TIME macro to format fields.
*time = FS_TIME(now.hour(), now.minute(), now.second());
// Return low time bits in units of 10 ms, 0 <= ms10 <= 199.
*ms10 = now.second() & 1 ? 100 : 0;
}
//------------------------------------------------------------------------------
void printField(Print* pr, char sep, uint8_t v) {
if (sep) {
pr->write(sep);
}
if (v < 10) {
pr->write('0');
}
pr->print(v);
}
//------------------------------------------------------------------------------
void printNow(Print* pr) {
DateTime now = rtc.now();
pr->print(now.year());
printField(pr, '-',now.month());
printField(pr, '-',now.day());
printField(pr, ' ',now.hour());
printField(pr, ':',now.minute());
printField(pr, ':',now.second());
}
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
while (!Serial) {
yield();
}
Serial.println(F("Type any character to begin"));
while (!Serial.available()) {
yield();
}
if (!rtc.begin()) {
Serial.println(F("rtc.begin failed"));
return;
}
if (!rtc.isrunning()) {
Serial.println("RTC is NOT running!");
return;
// following line sets the RTC to the date & time this sketch was compiled
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
}
Serial.print(F("DateTime::now "));
printNow(&Serial);
Serial.println();

// Set callback
FsDateTime::setCallback(dateTime);
if (!sd.begin(SD_CONFIG)) {
sd.initErrorHalt(&Serial);
}
// Remove old version to set create time.
if (sd.exists("RtcTest.txt")) {
sd.remove("RtcTest.txt");
}
if (!file.open("RtcTest.txt", FILE_WRITE)) {
Serial.println(F("file.open failed"));
return;
}
// Print current date time to file.
file.print(F("Test file at: "));
printNow(&file);
file.println();
file.close();
// List files in SD root.
sd.ls(LS_DATE | LS_SIZE);
Serial.println(F("Done"));
}
//------------------------------------------------------------------------------
void loop() {
}

+ 58
- 64
examples/STM32Test/STM32Test.ino Bestand weergeven

@@ -6,19 +6,17 @@
#include "SdFat.h"
#include "FreeStack.h"

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

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

// Use second SPI port
SPIClass SPI_2(2);
SdFat sd2(&SPI_2);
// SdFatEX sd2(&SPI_2);

const uint8_t SD2_CS = PB12; // chip select for sd2
// Chip select PA4, shared SPI, 18 MHz, port 1.
#define SD1_CONFIG SdSpiConfig(PA4, SHARED_SPI, SD_SCK_MHZ(18), &SPI)
SdFs sd1;
FsFile file1;

// Use mySPI2 since SPI2 is used in SPI.h as a different type.
static SPIClass mySPI2(2);
// Chip select PB21, dedicated SPI, 18 MHz, port 2.
#define SD2_CONFIG SdSpiConfig(PB12, DEDICATED_SPI, SD_SCK_MHZ(18), &mySPI2)
SdFs sd2;
FsFile file2;

const uint8_t BUF_DIM = 100;
uint8_t buf[BUF_DIM];
@@ -28,14 +26,22 @@ 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))
#define error(msg) {Serial.println(msg); errorHalt();}
void errorHalt() {
if (sd1.sdErrorCode()) {
sd1.errorHalt();
}
sd2.errorHalt();
}
//------------------------------------------------------------------------------
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++) {
@@ -44,86 +50,72 @@ void setup() {

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

// initialize the first card
if (!sd1.begin(SD1_CS, SD_SCK_MHZ(18))) {
sd1.initError("sd1:");
if (!sd1.begin(SD1_CONFIG)) {
error("sd1.begin");
}
// create Dir1 on sd1 if it does not exist
if (!sd1.exists("/Dir1")) {
if (!sd1.mkdir("/Dir1")) {
sd1.errorExit("sd1.mkdir");
error("sd1.mkdir");
}
}
// Make Dir1 the working directory on sd1.
if (!sd1.chdir("Dir1")) {
error("dsd1.chdir");
}
// initialize the second card
if (!sd2.begin(SD2_CS, SD_SCK_MHZ(18))) {
sd2.initError("sd2:");
if (!sd2.begin(SD2_CONFIG)) {
error("sd2.begin");
}
// create Dir2 on sd2 if it does not exist
if (!sd2.exists("/Dir2")) {
if (!sd2.mkdir("/Dir2")) {
sd2.errorExit("sd2.mkdir");
error("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");
}
// Make Dir2 the working directory on sd2.
if (!sd2.chdir("Dir2")) {
error("sd2.chdir");
}
// remove test.bin from /Dir1 directory of sd1
if (sd1.exists("test.bin")) {
if (!sd1.remove("test.bin")) {
sd2.errorExit("remove test.bin");
error("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");
error("remove rename.bin");
}
}
// list current directory on both cards
// list directories.
Serial.println(F("------sd1 Dir1-------"));
sd1.ls();
sd1.ls("/", LS_R | LS_SIZE);
Serial.println(F("------sd2 Dir2-------"));
sd2.ls();
sd2.ls("/", LS_R | LS_SIZE);
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");
if (!file1.open(&sd1, "test.bin", O_RDWR | O_CREAT | O_TRUNC)) {
error("file1.open");
}
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");
error("file1.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_WRONLY | O_CREAT | O_TRUNC)) {
sd2.errorExit("file2");
if (!file2.open(&sd2, "copy.bin", O_WRONLY | O_CREAT | O_TRUNC)) {
error("file2.open");
}
Serial.println(F("Copying test.bin to copy.bin"));

@@ -134,13 +126,13 @@ void setup() {
while (1) {
int n = file1.read(buf, sizeof(buf));
if (n < 0) {
sd1.errorExit("read1");
error("file1.read");
}
if (n == 0) {
break;
}
if ((int)file2.write(buf, n) != n) {
sd2.errorExit("write2");
error("file2.write");
}
}
t = millis() - t;
@@ -151,23 +143,25 @@ void setup() {
Serial.println(F(" millis"));
// close test.bin
file1.close();
// sync copy.bin so ls works.
file2.close();
// list current directory on both cards
// list directories.
Serial.println(F("------sd1 -------"));
sd1.ls("/", LS_R | LS_DATE | LS_SIZE);
sd1.ls("/", LS_R | LS_SIZE);
Serial.println(F("------sd2 -------"));
sd2.ls("/", LS_R | LS_DATE | LS_SIZE);
sd2.ls("/", LS_R | LS_SIZE);
Serial.println(F("---------------------"));
Serial.println(F("Renaming copy.bin"));
// rename the copy
// Rename copy.bin. The renamed file will be in Dir2.
if (!sd2.rename("copy.bin", "rename.bin")) {
sd2.errorExit("sd2.rename");
error("rename copy.bin");
}
// list current directory on both cards
file2.close();
// list directories.
Serial.println(F("------sd1 -------"));
sd1.ls("/", LS_R | LS_DATE | LS_SIZE);
sd1.ls("/", LS_R | LS_SIZE);
Serial.println(F("------sd2 -------"));
sd2.ls("/", LS_R | LS_DATE | LS_SIZE);
sd2.ls("/", LS_R | LS_SIZE);
Serial.println(F("---------------------"));
Serial.println(F("Done"));
}

+ 19
- 0
examples/SdErrorCodes/SdErrorCodes.ino Bestand weergeven

@@ -0,0 +1,19 @@
// Print a list of error codes, symbols, and comments.
#include "SdFat.h"
void setup() {
Serial.begin(9600);
while (!Serial) {}
delay(1000);
Serial.println();
Serial.println(F("Code,Symbol - failed operation"));
for (uint8_t code = 0; code <= SD_CARD_ERROR_UNKNOWN; code++) {
Serial.print(code < 16 ? "0X0" : "0X");
Serial.print(code, HEX);
Serial.print(",");
printSdErrorSymbol(&Serial, code);
Serial.print(" - ");
printSdErrorText(&Serial, code);
Serial.println();
}
}
void loop() {}

+ 126
- 438
examples/SdFormatter/SdFormatter.ino Bestand weergeven

@@ -1,411 +1,76 @@
/*
* This program will format an SD or SDHC card.
* This program will format SD/SDHC/SDXC cards.
* Warning all data will be deleted!
*
* For SD/SDHC cards larger than 64 MB this
* program attempts to match the format
* This program attempts to match the format
* generated by SDFormatter available here:
*
* http://www.sdcard.org/consumers/formatter/
*
* For smaller cards this program uses FAT16
* and SDFormatter uses FAT12.
* For very small cards this program uses FAT16
* and the above SDFormatter uses FAT12.
*/

// 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:
// Arduino Ethernet shield: pin 4
// Sparkfun SD shield: pin 8
// Adafruit SD shields and modules: pin 10
const uint8_t chipSelect = SS;

// 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"
#include "sdios.h"
#if DEBUG_PRINT
#include "FreeStack.h"
#endif // DEBUG_PRINT

/*
Set DISABLE_CS_PIN to disable a second SPI device.
For example, with the Ethernet shield, set DISABLE_CS_PIN
to 10 to disable the Ethernet controller.
*/
const int8_t DISABLE_CS_PIN = -1;
/*
Change the value of SD_CS_PIN if you are using SPI
and your hardware does not use the default value, SS.
Common values are:
Arduino Ethernet shield: pin 4
Sparkfun SD shield: pin 8
Adafruit SD shields and modules: pin 10
*/

// SDCARD_SS_PIN is defined for the built-in SD on some boards.
#ifndef SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SS;
#else // SDCARD_SS_PIN
// Assume built-in SD is used.
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#endif // SDCARD_SS_PIN

// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI)
#else // HAS_SDIO_CLASS
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI)
#endif // HAS_SDIO_CLASS
//==============================================================================
// 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;
uint32_t cardCapacityMB;

// cache for SD block
cache_t cache;

// MBR information
uint8_t partType;
uint32_t relSector;
uint32_t partSize;

// Fake disk geometry
uint8_t numberOfHeads;
uint8_t sectorsPerTrack;

// FAT parameters
uint16_t reservedSectors;
uint8_t sectorsPerCluster;
uint32_t fatStart;
uint32_t fatSize;
uint32_t dataStart;

// constants for file system structure
uint16_t const BU16 = 128;
uint16_t const BU32 = 8192;

// strings needed in file system structures
char noName[] = "NO NAME ";
char fat16str[] = "FAT16 ";
char fat32str[] = "FAT32 ";
//------------------------------------------------------------------------------
#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;
}
SysCall::halt();
}
//------------------------------------------------------------------------------
#if DEBUG_PRINT
void debugPrint() {
cout << F("FreeStack: ") << FreeStack() << endl;
cout << F("partStart: ") << relSector << endl;
cout << F("partSize: ") << partSize << endl;
cout << F("reserved: ") << reservedSectors << endl;
cout << F("fatStart: ") << fatStart << endl;
cout << F("fatSize: ") << fatSize << endl;
cout << F("dataStart: ") << dataStart << endl;
cout << F("clusterCount: ");
cout << ((relSector + partSize - dataStart)/sectorsPerCluster) << endl;
cout << endl;
cout << F("Heads: ") << int(numberOfHeads) << endl;
cout << F("Sectors: ") << int(sectorsPerTrack) << endl;
cout << F("Cylinders: ");
cout << cardSizeBlocks/(numberOfHeads*sectorsPerTrack) << endl;
}
#endif // DEBUG_PRINT
//------------------------------------------------------------------------------
// write cached block to the card
uint8_t writeCache(uint32_t lbn) {
return card.writeBlock(lbn, cache.data);
}
//------------------------------------------------------------------------------
// initialize appropriate sizes for SD capacity
void initSizes() {
if (cardCapacityMB <= 6) {
sdError("Card is too small.");
} else if (cardCapacityMB <= 16) {
sectorsPerCluster = 2;
} else if (cardCapacityMB <= 32) {
sectorsPerCluster = 4;
} else if (cardCapacityMB <= 64) {
sectorsPerCluster = 8;
} else if (cardCapacityMB <= 128) {
sectorsPerCluster = 16;
} else if (cardCapacityMB <= 1024) {
sectorsPerCluster = 32;
} else if (cardCapacityMB <= 32768) {
sectorsPerCluster = 64;
} else {
// SDXC cards
sectorsPerCluster = 128;
}

cout << F("Blocks/Cluster: ") << int(sectorsPerCluster) << endl;
// set fake disk geometry
sectorsPerTrack = cardCapacityMB <= 256 ? 32 : 63;

if (cardCapacityMB <= 16) {
numberOfHeads = 2;
} else if (cardCapacityMB <= 32) {
numberOfHeads = 4;
} else if (cardCapacityMB <= 128) {
numberOfHeads = 8;
} else if (cardCapacityMB <= 504) {
numberOfHeads = 16;
} else if (cardCapacityMB <= 1008) {
numberOfHeads = 32;
} else if (cardCapacityMB <= 2016) {
numberOfHeads = 64;
} else if (cardCapacityMB <= 4032) {
numberOfHeads = 128;
} else {
numberOfHeads = 255;
}
}
//------------------------------------------------------------------------------
// zero cache and optionally set the sector signature
void clearCache(uint8_t addSig) {
memset(&cache, 0, sizeof(cache));
if (addSig) {
cache.mbr.mbrSig0 = BOOTSIG0;
cache.mbr.mbrSig1 = BOOTSIG1;
}
}
uint32_t cardSectorCount = 0;
uint8_t sectorBuffer[512];
//------------------------------------------------------------------------------
// 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");
}
for (uint32_t i = 0; i < count; i++) {
if ((i & 0XFF) == 0) {
cout << '.';
}
if (!card.writeData(cache.data)) {
sdError("Clear FAT/DIR writeData failed");
}
}
if (!card.writeStop()) {
sdError("Clear FAT/DIR writeStop failed");
}
#endif // USE_SDIO
cout << endl;
}
//------------------------------------------------------------------------------
// return cylinder number for a logical block number
uint16_t lbnToCylinder(uint32_t lbn) {
return lbn / (numberOfHeads * sectorsPerTrack);
}
//------------------------------------------------------------------------------
// return head number for a logical block number
uint8_t lbnToHead(uint32_t lbn) {
return (lbn % (numberOfHeads * sectorsPerTrack)) / sectorsPerTrack;
}
//------------------------------------------------------------------------------
// return sector number for a logical block number
uint8_t lbnToSector(uint32_t lbn) {
return (lbn % sectorsPerTrack) + 1;
}
//------------------------------------------------------------------------------
// format and write the Master Boot Record
void writeMbr() {
clearCache(true);
part_t* p = cache.mbr.part;
p->boot = 0;
uint16_t c = lbnToCylinder(relSector);
if (c > 1023) {
sdError("MBR CHS");
}
p->beginCylinderHigh = c >> 8;
p->beginCylinderLow = c & 0XFF;
p->beginHead = lbnToHead(relSector);
p->beginSector = lbnToSector(relSector);
p->type = partType;
uint32_t endLbn = relSector + partSize - 1;
c = lbnToCylinder(endLbn);
if (c <= 1023) {
p->endCylinderHigh = c >> 8;
p->endCylinderLow = c & 0XFF;
p->endHead = lbnToHead(endLbn);
p->endSector = lbnToSector(endLbn);
} else {
// Too big flag, c = 1023, h = 254, s = 63
p->endCylinderHigh = 3;
p->endCylinderLow = 255;
p->endHead = 254;
p->endSector = 63;
}
p->firstSector = relSector;
p->totalSectors = partSize;
if (!writeCache(0)) {
sdError("write MBR");
}
}
// SdCardFactory constructs and initializes the appropriate card.
SdCardFactory cardFactory;
// Pointer to generic SD card.
SdCard* m_card = nullptr;
//------------------------------------------------------------------------------
// generate serial number from card size and micros since boot
uint32_t volSerialNumber() {
return (cardSizeBlocks << 8) + micros();
}
//------------------------------------------------------------------------------
// format the SD as FAT16
void makeFat16() {
uint32_t nc;
for (dataStart = 2 * BU16;; dataStart += BU16) {
nc = (cardSizeBlocks - dataStart)/sectorsPerCluster;
fatSize = (nc + 2 + 255)/256;
uint32_t r = BU16 + 1 + 2 * fatSize + 32;
if (dataStart < r) {
continue;
}
relSector = dataStart - r + BU16;
break;
}
// check valid cluster count for FAT16 volume
if (nc < 4085 || nc >= 65525) {
sdError("Bad cluster count");
}
reservedSectors = 1;
fatStart = relSector + reservedSectors;
partSize = nc * sectorsPerCluster + 2 * fatSize + reservedSectors + 32;
if (partSize < 32680) {
partType = 0X01;
} else if (partSize < 65536) {
partType = 0X04;
} else {
partType = 0X06;
}
// write MBR
writeMbr();
clearCache(true);
fat_boot_t* pb = &cache.fbs;
pb->jump[0] = 0XEB;
pb->jump[1] = 0X00;
pb->jump[2] = 0X90;
for (uint8_t i = 0; i < sizeof(pb->oemId); i++) {
pb->oemId[i] = ' ';
}
pb->bytesPerSector = 512;
pb->sectorsPerCluster = sectorsPerCluster;
pb->reservedSectorCount = reservedSectors;
pb->fatCount = 2;
pb->rootDirEntryCount = 512;
pb->mediaType = 0XF8;
pb->sectorsPerFat16 = fatSize;
pb->sectorsPerTrack = sectorsPerTrack;
pb->headCount = numberOfHeads;
pb->hidddenSectors = relSector;
pb->totalSectors32 = partSize;
pb->driveNumber = 0X80;
pb->bootSignature = EXTENDED_BOOT_SIG;
pb->volumeSerialNumber = volSerialNumber();
memcpy(pb->volumeLabel, noName, sizeof(pb->volumeLabel));
memcpy(pb->fileSystemType, fat16str, sizeof(pb->fileSystemType));
// write partition boot sector
if (!writeCache(relSector)) {
sdError("FAT16 write PBS failed");
}
// clear FAT and root directory
clearFatDir(fatStart, dataStart - fatStart);
clearCache(false);
cache.fat16[0] = 0XFFF8;
cache.fat16[1] = 0XFFFF;
// write first block of FAT and backup for reserved clusters
if (!writeCache(fatStart)
|| !writeCache(fatStart + fatSize)) {
sdError("FAT16 reserve failed");
}
}
#define sdError(msg) {cout << F("error: ") << F(msg) << endl; sdErrorHalt();}
//------------------------------------------------------------------------------
// format the SD as FAT32
void makeFat32() {
uint32_t nc;
relSector = BU32;
for (dataStart = 2 * BU32;; dataStart += BU32) {
nc = (cardSizeBlocks - dataStart)/sectorsPerCluster;
fatSize = (nc + 2 + 127)/128;
uint32_t r = relSector + 9 + 2 * fatSize;
if (dataStart >= r) {
break;
void sdErrorHalt() {
if (!m_card) {
cout << F("Invalid SD_CONFIG") << endl;
} else if (m_card->errorCode()) {
if (m_card->errorCode() == SD_CARD_ERROR_CMD0) {
cout << F("No card, wrong chip select pin, or wiring error?") << endl;
}
cout << F("SD errorCode: ") << hex << showbase;
printSdErrorSymbol(&Serial, m_card->errorCode());
cout << F(" = ") << int(m_card->errorCode()) << endl;
cout << F("SD errorData = ") << int(m_card->errorData()) << endl;
}
// error if too few clusters in FAT32 volume
if (nc < 65525) {
sdError("Bad cluster count");
}
reservedSectors = dataStart - relSector - 2 * fatSize;
fatStart = relSector + reservedSectors;
partSize = nc * sectorsPerCluster + dataStart - relSector;
// type depends on address of end sector
// max CHS has lbn = 16450560 = 1024*255*63
if ((relSector + partSize) <= 16450560) {
// FAT32
partType = 0X0B;
} else {
// FAT32 with INT 13
partType = 0X0C;
}
writeMbr();
clearCache(true);

fat32_boot_t* pb = &cache.fbs32;
pb->jump[0] = 0XEB;
pb->jump[1] = 0X00;
pb->jump[2] = 0X90;
for (uint8_t i = 0; i < sizeof(pb->oemId); i++) {
pb->oemId[i] = ' ';
}
pb->bytesPerSector = 512;
pb->sectorsPerCluster = sectorsPerCluster;
pb->reservedSectorCount = reservedSectors;
pb->fatCount = 2;
pb->mediaType = 0XF8;
pb->sectorsPerTrack = sectorsPerTrack;
pb->headCount = numberOfHeads;
pb->hidddenSectors = relSector;
pb->totalSectors32 = partSize;
pb->sectorsPerFat32 = fatSize;
pb->fat32RootCluster = 2;
pb->fat32FSInfo = 1;
pb->fat32BackBootBlock = 6;
pb->driveNumber = 0X80;
pb->bootSignature = EXTENDED_BOOT_SIG;
pb->volumeSerialNumber = volSerialNumber();
memcpy(pb->volumeLabel, noName, sizeof(pb->volumeLabel));
memcpy(pb->fileSystemType, fat32str, sizeof(pb->fileSystemType));
// write partition boot sector and backup
if (!writeCache(relSector)
|| !writeCache(relSector + 6)) {
sdError("FAT32 write PBS failed");
}
clearCache(true);
// write extra boot area and backup
if (!writeCache(relSector + 2)
|| !writeCache(relSector + 8)) {
sdError("FAT32 PBS ext failed");
}
fat32_fsinfo_t* pf = &cache.fsinfo;
pf->leadSignature = FSINFO_LEAD_SIG;
pf->structSignature = FSINFO_STRUCT_SIG;
pf->freeCount = 0XFFFFFFFF;
pf->nextFree = 0XFFFFFFFF;
// write FSINFO sector and backup
if (!writeCache(relSector + 1)
|| !writeCache(relSector + 7)) {
sdError("FAT32 FSINFO failed");
}
clearFatDir(fatStart, 2 * fatSize + sectorsPerCluster);
clearCache(false);
cache.fat32[0] = 0x0FFFFFF8;
cache.fat32[1] = 0x0FFFFFFF;
cache.fat32[2] = 0x0FFFFFFF;
// write first block of FAT and backup for reserved clusters
if (!writeCache(fatStart)
|| !writeCache(fatStart + fatSize)) {
sdError("FAT32 reserve failed");
}
SysCall::halt();
}
//------------------------------------------------------------------------------
// flash erase all data
@@ -418,54 +83,73 @@ void eraseCard() {

do {
lastBlock = firstBlock + ERASE_SIZE - 1;
if (lastBlock >= cardSizeBlocks) {
lastBlock = cardSizeBlocks - 1;
if (lastBlock >= cardSectorCount) {
lastBlock = cardSectorCount - 1;
}
if (!card.erase(firstBlock, lastBlock)) {
if (!m_card->erase(firstBlock, lastBlock)) {
sdError("erase failed");
}
cout << '.';
if ((n++)%32 == 31) {
if ((n++)%64 == 63) {
cout << endl;
}
firstBlock += ERASE_SIZE;
} while (firstBlock < cardSizeBlocks);
} while (firstBlock < cardSectorCount);
cout << endl;

if (!card.readBlock(0, cache.data)) {
if (!m_card->readSector(0, sectorBuffer)) {
sdError("readBlock");
}
cout << hex << showbase << setfill('0') << internal;
cout << F("All data set to ") << setw(4) << int(cache.data[0]) << endl;
cout << F("All data set to ") << setw(4) << int(sectorBuffer[0]) << endl;
cout << dec << noshowbase << setfill(' ') << right;
cout << F("Erase done\n");
}
//------------------------------------------------------------------------------
void formatCard() {
cout << endl;
cout << F("Formatting\n");
initSizes();
if (card.type() != SD_CARD_TYPE_SDHC) {
cout << F("FAT16\n");
makeFat16();
ExFatFormatter exFatFormatter;
FatFormatter fatFormatter;

// Format exFAT if larger than 32GB.
bool rtn = cardSectorCount > 67108864 ?
exFatFormatter.format(m_card, sectorBuffer, &Serial) :
fatFormatter.format(m_card, sectorBuffer, &Serial);

if (!rtn) {
sdErrorHalt();
}
cout << F("Run the SdInfo example for format details.") << endl;
}
//------------------------------------------------------------------------------
void printConfig(SdSpiConfig config) {
if (DISABLE_CS_PIN < 0) {
cout << F(
"\nAssuming the SD is the only SPI device.\n"
"Edit DISABLE_CS_PIN to disable an SPI device.\n");
} else {
cout << F("FAT32\n");
makeFat32();
cout << F("\nDisabling SPI device on pin ");
cout << int(DISABLE_CS_PIN) << endl;
pinMode(DISABLE_CS_PIN, OUTPUT);
digitalWrite(DISABLE_CS_PIN, HIGH);
}
#if DEBUG_PRINT
debugPrint();
#endif // DEBUG_PRINT
cout << F("Format done\n");
cout << F("\nAssuming the SD chip select pin is: ") << int(config.csPin);
cout << F("\nEdit SD_CS_PIN to change the SD chip select pin.\n");
}
//------------------------------------------------------------------------------
void printConfig(SdioConfig config) {
(void)config;
cout << F("Assuming an SDIO interface.\n");
}
//------------------------------------------------------------------------------
void setup() {
char c;
Serial.begin(9600);
// Wait for USB Serial
// Wait for USB Serial
while (!Serial) {
SysCall::yield();
}
cout << F("Type any character to start\n");
printConfig(SD_CONFIG);
cout << F("\nType any character to start\n");
while (!Serial.available()) {
SysCall::yield();
}
@@ -475,21 +159,21 @@ void setup() {
} while (Serial.available() && Serial.read() >= 0);
cout << F(
"\n"
"This program can erase and/or format SD/SDHC cards.\n"
"This program can erase and/or format SD/SDHC/SDXC cards.\n"
"\n"
"Erase uses the card's fast flash erase command.\n"
"Flash erase sets all data to 0X00 for most cards\n"
"and 0XFF for a few vendor's cards.\n"
"\n"
"Cards larger than 2 GB will be formatted FAT32 and\n"
"smaller cards will be formatted FAT16.\n"
"Cards up to 2 GiB (GiB = 2^30 bytes) will be formated FAT16.\n"
"Cards larger than 2 GiB and up to 32 GiB will be formatted\n"
"FAT32. Cards larger than 32 GiB will be formatted exFAT.\n"
"\n"
"Warning, all data on the card will be erased.\n"
"Enter 'Y' to continue: ");
while (!Serial.available()) {
SysCall::yield();
}

c = Serial.read();
cout << c << endl;
if (c != 'Y') {
@@ -501,6 +185,32 @@ void setup() {
delay(10);
} while (Serial.available() && Serial.read() >= 0);

// Select and initialize proper card driver.
m_card = cardFactory.newCard(SD_CONFIG);
if (!m_card || m_card->errorCode()) {
sdError("card init failed.");
return;
}

cardSectorCount = m_card->sectorCount();
if (!cardSectorCount) {
sdError("Get sector count failed.");
return;
}

cout << F("\nCard size: ") << cardSectorCount*5.12e-7;
cout << F(" GB (GB = 1E9 bytes)\n");
cout << F("Card size: ") << cardSectorCount/2097152.0;
cout << F(" GiB (GiB = 2^30 bytes)\n");

cout << F("Card will be formated ");
if (cardSectorCount > 67108864) {
cout << F("exFAT\n");
} else if (cardSectorCount > 4194304) {
cout << F("FAT32\n");
} else {
cout << F("FAT16\n");
}
cout << F(
"\n"
"Options are:\n"
@@ -519,28 +229,6 @@ void setup() {
cout << F("Quiting, invalid option entered.") << endl;
return;
}
#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");
}
cardCapacityMB = (cardSizeBlocks + 2047)/2048;

cout << F("Card Size: ") << setprecision(0) << 1.048576*cardCapacityMB;
cout << F(" MB, (MB = 1,000,000 bytes)") << endl;

if (c == 'E' || c == 'F') {
eraseCard();
}
@@ -548,5 +236,5 @@ void setup() {
formatCard();
}
}
//------------------------------------------------------------------------------
void loop() {}
void loop() {
}

+ 179
- 169
examples/SdInfo/SdInfo.ino Bestand weergeven

@@ -1,93 +1,81 @@
/*
* This program attempts to initialize an SD card and analyze its structure.
*/
#include <SPI.h>
#include "SdFat.h"
#include "sdios.h"

// Set USE_SDIO to zero for SPI card access.
#define USE_SDIO 0
/*
* SD chip select pin. Common values are:
*
* Arduino Ethernet shield, pin 4.
* SparkFun SD shield, pin 8.
* Adafruit SD shields and modules, pin 10.
* Default SD chip select is the SPI SS pin.
*/
const uint8_t SD_CHIP_SELECT = SS;
Set DISABLE_CS_PIN to disable a second SPI device.
For example, with the Ethernet shield, set DISABLE_CS_PIN
to 10 to disable the Ethernet controller.
*/
const int8_t DISABLE_CS_PIN = -1;
/*
* Set DISABLE_CHIP_SELECT to disable a second SPI device.
* For example, with the Ethernet shield, set DISABLE_CHIP_SELECT
* 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
Change the value of SD_CS_PIN if you are using SPI
and your hardware does not use the default value, SS.
Common values are:
Arduino Ethernet shield: pin 4
Sparkfun SD shield: pin 8
Adafruit SD shields and modules: pin 10
*/
// SDCARD_SS_PIN is defined for the built-in SD on some boards.
#ifndef SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SS;
#else // SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#endif // SDCARD_SS_PIN

// serial output steam
ArduinoOutStream cout(Serial);
// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI)
#else // HAS_SDIO_CLASS
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI)
#endif // HAS_SDIO_CLASS

// global for card size
uint32_t cardSize;

// global for card erase size
uint32_t eraseSize;
//------------------------------------------------------------------------------
// store error strings in flash
#define sdErrorMsg(msg) sd.errorPrint(F(msg));
SdFs sd;
cid_t m_cid;
csd_t m_csd;
uint32_t m_eraseSize;
uint32_t m_ocr;
static ArduinoOutStream cout(Serial);
//------------------------------------------------------------------------------
uint8_t cidDmp() {
cid_t cid;
if (!sd.card()->readCID(&cid)) {
sdErrorMsg("readCID failed");
return false;
}
bool cidDmp() {
cout << F("\nManufacturer ID: ");
cout << hex << int(cid.mid) << dec << endl;
cout << F("OEM ID: ") << cid.oid[0] << cid.oid[1] << endl;
cout << uppercase << showbase << hex << int(m_cid.mid) << dec << endl;
cout << F("OEM ID: ") << m_cid.oid[0] << m_cid.oid[1] << endl;
cout << F("Product: ");
for (uint8_t i = 0; i < 5; i++) {
cout << cid.pnm[i];
cout << m_cid.pnm[i];
}
cout << F("\nVersion: ");
cout << int(cid.prv_n) << '.' << int(cid.prv_m) << endl;
cout << F("Serial number: ") << hex << cid.psn << dec << endl;
cout << int(m_cid.prv_n) << '.' << int(m_cid.prv_m) << endl;
cout << F("Serial number: ") << hex << m_cid.psn << dec << endl;
cout << F("Manufacturing date: ");
cout << int(cid.mdt_month) << '/';
cout << (2000 + cid.mdt_year_low + 10 * cid.mdt_year_high) << endl;
cout << int(m_cid.mdt_month) << '/';
cout << (2000 + m_cid.mdt_year_low + 10 * m_cid.mdt_year_high) << endl;
cout << endl;
return true;
}
//------------------------------------------------------------------------------
uint8_t csdDmp() {
csd_t csd;
uint8_t eraseSingleBlock;
if (!sd.card()->readCSD(&csd)) {
sdErrorMsg("readCSD failed");
return false;
}
if (csd.v1.csd_ver == 0) {
eraseSingleBlock = csd.v1.erase_blk_en;
eraseSize = (csd.v1.sector_size_high << 1) | csd.v1.sector_size_low;
} else if (csd.v2.csd_ver == 1) {
eraseSingleBlock = csd.v2.erase_blk_en;
eraseSize = (csd.v2.sector_size_high << 1) | csd.v2.sector_size_low;
bool csdDmp() {
bool eraseSingleBlock;
if (m_csd.v1.csd_ver == 0) {
eraseSingleBlock = m_csd.v1.erase_blk_en;
m_eraseSize = (m_csd.v1.sector_size_high << 1) | m_csd.v1.sector_size_low;
} else if (m_csd.v2.csd_ver == 1) {
eraseSingleBlock = m_csd.v2.erase_blk_en;
m_eraseSize = (m_csd.v2.sector_size_high << 1) | m_csd.v2.sector_size_low;
} else {
cout << F("csd version error\n");
cout << F("m_csd version error\n");
return false;
}
eraseSize++;
cout << F("cardSize: ") << 0.000512*cardSize;
m_eraseSize++;
cout << F("cardSize: ") << 0.000512 * sdCardCapacity(&m_csd);
cout << F(" MB (MB = 1,000,000 bytes)\n");

cout << F("flashEraseSize: ") << int(eraseSize) << F(" blocks\n");
cout << F("flashEraseSize: ") << int(m_eraseSize) << F(" blocks\n");
cout << F("eraseSingleBlock: ");
if (eraseSingleBlock) {
cout << F("true\n");
@@ -97,77 +85,123 @@ uint8_t csdDmp() {
return true;
}
//------------------------------------------------------------------------------
// print partition table
uint8_t partDmp() {
mbr_t mbr;
if (!sd.card()->readBlock(0, (uint8_t*)&mbr)) {
sdErrorMsg("read MBR failed");
void errorPrint() {
if (sd.sdErrorCode()) {
cout << F("SD errorCode: ") << hex << showbase;
printSdErrorSymbol(&Serial, sd.sdErrorCode());
cout << F(" = ") << int(sd.sdErrorCode()) << endl;
cout << F("SD errorData = ") << int(sd.sdErrorData()) << endl;
}
}
//------------------------------------------------------------------------------
bool mbrDmp() {
MbrSector_t mbr;
bool valid = true;
if (!sd.card()->readSector(0, (uint8_t*)&mbr)) {
cout << F("\nread MBR failed.\n");
errorPrint();
return false;
}
cout << F("\nSD Partition Table\n");
cout << F("part,boot,bgnCHS[3],type,endCHS[3],start,length\n");
for (uint8_t ip = 1; ip < 5; ip++) {
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;
MbrPart_t *pt = &mbr.part[ip - 1];
if ((pt->boot != 0 && pt->boot != 0X80) ||
getLe32(pt->relativeSectors) > sdCardCapacity(&m_csd)) {
valid = false;
}
cout << int(ip) << ',' << uppercase << showbase << hex;
cout << int(pt->boot) << ',';
for (int i = 0; i < 3; i++ ) {
cout << int(pt->beginCHS[i]) << ',';
}
cout << int(pt->type) << ',';
for (int i = 0; i < 3; i++ ) {
cout << int(pt->endCHS[i]) << ',';
}
cout << dec << getLe32(pt->relativeSectors) << ',';
cout << getLe32(pt->totalSectors) << endl;
}
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 = &mbr.part[ip - 1];
cout << int(ip) << ',' << hex << int(pt->boot) << ',' << int(pt->type);
cout << dec << ',' << pt->firstSector <<',' << pt->totalSectors << endl;
if (!valid) {
cout << F("\nMBR not valid, assuming Super Floppy format.\n");
}
return true;
}
//------------------------------------------------------------------------------
void volDmp() {
cout << F("\nVolume is FAT") << int(sd.vol()->fatType()) << endl;
cout << F("blocksPerCluster: ") << int(sd.vol()->blocksPerCluster()) << endl;
cout << F("clusterCount: ") << sd.vol()->clusterCount() << endl;
cout << F("freeClusters: ");
uint32_t volFree = sd.vol()->freeClusterCount();
cout << volFree << endl;
float fs = 0.000512*volFree*sd.vol()->blocksPerCluster();
cout << F("freeSpace: ") << fs << F(" MB (MB = 1,000,000 bytes)\n");
cout << F("fatStartBlock: ") << sd.vol()->fatStartBlock() << endl;
cout << F("fatCount: ") << int(sd.vol()->fatCount()) << endl;
cout << F("blocksPerFat: ") << sd.vol()->blocksPerFat() << endl;
cout << F("rootDirStart: ") << sd.vol()->rootDirStart() << endl;
cout << F("dataStartBlock: ") << sd.vol()->dataStartBlock() << endl;
if (sd.vol()->dataStartBlock() % eraseSize) {
cout << F("Data area is not aligned on flash erase boundaries!\n");
void dmpVol() {
cout << F("\nScanning FAT, please wait.\n");
uint32_t freeClusterCount = sd.freeClusterCount();
if (sd.fatType() <= 32) {
cout << F("\nVolume is FAT") << int(sd.fatType()) << endl;
} else {
cout << F("\nVolume is exFAT\n");
}
cout << F("sectorsPerCluster: ") << sd.sectorsPerCluster() << endl;
cout << F("clusterCount: ") << sd.clusterCount() << endl;
cout << F("freeClusterCount: ") << freeClusterCount << endl;
cout << F("fatStartSector: ") << sd.fatStartSector() << endl;
cout << F("dataStartSector: ") << sd.dataStartSector() << endl;
if (sd.dataStartSector() % m_eraseSize) {
cout << F("Data area is not aligned on flash erase boundary!\n");
cout << F("Download and use formatter from www.sdcard.org!\n");
}
}
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
// Wait for USB Serial
while (!Serial) {
SysCall::yield();
}
void printCardType() {

// use uppercase in hex and use 0X base prefix
cout << uppercase << showbase << endl;
cout << F("\nCard type: ");

// F stores strings in flash to save RAM
cout << F("SdFat version: ") << SD_FAT_VERSION << endl;
#if !USE_SDIO
if (DISABLE_CHIP_SELECT < 0) {
switch (sd.card()->type()) {
case SD_CARD_TYPE_SD1:
cout << F("SD1\n");
break;

case SD_CARD_TYPE_SD2:
cout << F("SD2\n");
break;

case SD_CARD_TYPE_SDHC:
if (sdCardCapacity(&m_csd) < 70000000) {
cout << F("SDHC\n");
} else {
cout << F("SDXC\n");
}
break;

default:
cout << F("Unknown\n");
}
}
//------------------------------------------------------------------------------
void printConfig(SdSpiConfig config) {
if (DISABLE_CS_PIN < 0) {
cout << F(
"\nAssuming the SD is the only SPI device.\n"
"Edit DISABLE_CHIP_SELECT to disable another device.\n");
"Edit DISABLE_CS_PIN to disable an SPI device.\n");
} else {
cout << F("\nDisabling SPI device on pin ");
cout << int(DISABLE_CHIP_SELECT) << endl;
pinMode(DISABLE_CHIP_SELECT, OUTPUT);
digitalWrite(DISABLE_CHIP_SELECT, HIGH);
cout << int(DISABLE_CS_PIN) << endl;
pinMode(DISABLE_CS_PIN, OUTPUT);
digitalWrite(DISABLE_CS_PIN, HIGH);
}
cout << F("\nAssuming the SD chip select pin is: ") << int(config.csPin);
cout << F("\nEdit SD_CS_PIN to change the SD chip select pin.\n");
}
//------------------------------------------------------------------------------
void printConfig(SdioConfig config) {
(void)config;
cout << F("Assuming an SDIO interface.\n");
}
//-----------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
// Wait for USB Serial
while (!Serial) {
SysCall::yield();
}
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
cout << F("SdFat version: ") << SD_FAT_VERSION << endl;
printConfig(SD_CONFIG);
}
//------------------------------------------------------------------------------
void loop() {
@@ -181,68 +215,44 @@ void loop() {
while (!Serial.available()) {
SysCall::yield();
}

uint32_t t = millis();
#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");
if (!sd.cardBegin(SD_CONFIG)) {
cout << F(
"\nSD initialization failed.\n"
"Do not reformat the card!\n"
"Is the card correctly inserted?\n"
"Is there a wiring/soldering problem?\n");
if (isSpi(SD_CONFIG)) {
cout << F(
"Is SD_CS_PIN set to the correct value?\n"
"Does another SPI device need to be disabled?\n"
);
}
errorPrint();
return;
}
#endif // USE_SDIO
t = millis() - t;
cout << F("init time: ") << t << " ms" << endl;

cardSize = sd.card()->cardSize();
if (cardSize == 0) {
sdErrorMsg("cardSize failed");
if (!sd.card()->readCID(&m_cid) ||
!sd.card()->readCSD(&m_csd) ||
!sd.card()->readOCR(&m_ocr)) {
cout << F("readInfo failed\n");
errorPrint();
return;
}
cout << F("\ninit time: ") << t << " ms" << endl;
cout << F("\nCard type: ");
switch (sd.card()->type()) {
case SD_CARD_TYPE_SD1:
cout << F("SD1\n");
break;

case SD_CARD_TYPE_SD2:
cout << F("SD2\n");
break;

case SD_CARD_TYPE_SDHC:
if (cardSize < 70000000) {
cout << F("SDHC\n");
} else {
cout << F("SDXC\n");
}
break;

default:
cout << F("Unknown\n");
}
if (!cidDmp()) {
printCardType();
cidDmp();
csdDmp();
cout << F("\nOCR: ") << uppercase << showbase;
cout << hex << m_ocr << dec << endl;
if (!mbrDmp()) {
return;
}
if (!csdDmp()) {
if (!sd.volumeBegin()) {
cout << F("\nvolumeBegin failed. Is the card formatted?\n");
errorPrint();
return;
}
uint32_t ocr;
if (!sd.card()->readOCR(&ocr)) {
sdErrorMsg("\nreadOCR failed");
return;
}
cout << F("OCR: ") << hex << ocr << dec << endl;
if (!partDmp()) {
return;
}
if (!sd.fsBegin()) {
sdErrorMsg("\nFile System initialization failed.\n");
return;
}
volDmp();
}
dmpVol();
}

+ 33
- 14
examples/SoftwareSpi/SoftwareSpi.ino Bestand weergeven

@@ -1,25 +1,44 @@
// An example of the SdFatSoftSpi template class.
// This example is for an Adafruit Data Logging Shield on a Mega.
// An example of the SoftSpiDriver template class.
// This example is for an old Adafruit Data Logging Shield on a Mega.
// Software SPI is required on Mega since this shield connects to pins 10-13.
// This example will also run on an Uno and other boards using software SPI.
//
#include <SPI.h>
#include "SdFat.h"
#if ENABLE_SOFTWARE_SPI_CLASS // Must be set in SdFat/SdFatConfig.h
#if SPI_DRIVER_SELECT == 2 // Must be set in SdFat/SdFatConfig.h

// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 0
//
// Chip select may be constant or RAM variable.
const uint8_t SD_CS_PIN = 10;
//
// Pin numbers in templates must be constants.
const uint8_t SOFT_MISO_PIN = 12;
const uint8_t SOFT_MOSI_PIN = 11;
const uint8_t SOFT_SCK_PIN = 13;
//
// Chip select may be constant or RAM variable.
const uint8_t SD_CHIP_SELECT_PIN = 10;

// SdFat software SPI template
SdFatSoftSpi<SOFT_MISO_PIN, SOFT_MOSI_PIN, SOFT_SCK_PIN> sd;
SoftSpiDriver<SOFT_MISO_PIN, SOFT_MOSI_PIN, SOFT_SCK_PIN> softSpi;
// Speed argument is ignored for software SPI.
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SD_SCK_MHZ(0), &softSpi)

// Test file.
SdFile file;
#if SD_FAT_TYPE == 0
SdFat sd;
File file;
#elif SD_FAT_TYPE == 1
SdFat32 sd;
File32 file;
#elif SD_FAT_TYPE == 2
SdExFat sd;
ExFile file;
#elif SD_FAT_TYPE == 3
SdFs sd;
FsFile file;
#else // SD_FAT_TYPE
#error Invalid SD_FAT_TYPE
#endif // SD_FAT_TYPE

void setup() {
Serial.begin(9600);
@@ -32,11 +51,11 @@ void setup() {
SysCall::yield();
}

if (!sd.begin(SD_CHIP_SELECT_PIN)) {
if (!sd.begin(SD_CONFIG)) {
sd.initErrorHalt();
}

if (!file.open("SoftSPI.txt", O_RDWR O _CREAT)) {
if (!file.open("SoftSPI.txt", O_RDWR | O_CREAT)) {
sd.errorHalt(F("open failed"));
}
file.println(F("This line was printed using software SPI."));
@@ -53,6 +72,6 @@ void setup() {
}
//------------------------------------------------------------------------------
void loop() {}
#else // ENABLE_SOFTWARE_SPI_CLASS
#error ENABLE_SOFTWARE_SPI_CLASS must be set non-zero in SdFat/SdFatConfig.h
#endif //ENABLE_SOFTWARE_SPI_CLASS
#else // SPI_DRIVER_SELECT
#error SPI_DRIVER_SELECT must be two in SdFat/SdFatConfig.h
#endif //SPI_DRIVER_SELECT

+ 136
- 0
examples/TeensyRtcTimestamp/TeensyRtcTimestamp.ino Bestand weergeven

@@ -0,0 +1,136 @@
// Test of time-stamp callback with Teensy3.
// The upload time will be used to set the RTC.
// You must arrange for syncing the RTC.
#include "SdFat.h"
#include <TimeLib.h>

// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 3
/*
Change the value of SD_CS_PIN if you are using SPI and
your hardware does not use the default value, SS.
Common values are:
Arduino Ethernet shield: pin 4
Sparkfun SD shield: pin 8
Adafruit SD shields and modules: pin 10
*/

// SDCARD_SS_PIN is defined for the built-in SD on some boards.
#ifndef SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SS;
#else // SDCARD_SS_PIN
// Assume built-in SD is used.
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#endif // SDCARD_SS_PIN

// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI)
#else // HAS_SDIO_CLASS
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI)
#endif // HAS_SDIO_CLASS

#if SD_FAT_TYPE == 0
SdFat sd;
File file;
#elif SD_FAT_TYPE == 1
SdFat32 sd;
File32 file;
#elif SD_FAT_TYPE == 2
SdExFat sd;
ExFile file;
#elif SD_FAT_TYPE == 3
SdFs sd;
FsFile file;
#else // SD_FAT_TYPE
#error Invalid SD_FAT_TYPE
#endif // SD_FAT_TYPE

//------------------------------------------------------------------------------
// Call back for file timestamps. Only called for file create and sync().
void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) {
// Return date using FS_DATE macro to format fields.
*date = FS_DATE(year(), month(), day());

// Return time using FS_TIME macro to format fields.
*time = FS_TIME(hour(), minute(), second());
// Return low time bits in units of 10 ms.
*ms10 = second() & 1 ? 100 : 0;
}
//------------------------------------------------------------------------------
time_t getTeensy3Time()
{
return Teensy3Clock.get();
}
//------------------------------------------------------------------------------
void printField(Print* pr, char sep, uint8_t v) {
if (sep) {
pr->write(sep);
}
if (v < 10) {
pr->write('0');
}
pr->print(v);
}
//------------------------------------------------------------------------------
void printNow(Print* pr) {
pr->print(year());
printField(pr, '-', month());
printField(pr, '-', day());
printField(pr, ' ', hour());
printField(pr, ':', minute());
printField(pr, ':', second());
}
//------------------------------------------------------------------------------
void setup() {
// set the Time library to use Teensy 3.0's RTC to keep time
setSyncProvider(getTeensy3Time);
Serial.begin(9600);
while (!Serial) {
yield();
}
Serial.println(F("Type any character to begin"));
while (!Serial.available()) {
yield();
}
if (timeStatus()!= timeSet) {
Serial.println("Unable to sync with the RTC");
return;
}
Serial.print(F("DateTime::now "));
printNow(&Serial);
Serial.println();

// Set callback
FsDateTime::setCallback(dateTime);
if (!sd.begin(SD_CONFIG)) {
sd.initErrorHalt(&Serial);
}
// Remove old version to set create time.
if (sd.exists("RtcTest.txt")) {
sd.remove("RtcTest.txt");
}
if (!file.open("RtcTest.txt", FILE_WRITE)) {
Serial.println(F("file.open failed"));
return;
}
// Print current date time to file.
file.print(F("Test file at: "));
printNow(&file);
file.println();
file.close();
// List files in SD root.
sd.ls(LS_DATE | LS_SIZE);
Serial.println(F("Done"));
}
//------------------------------------------------------------------------------
void loop() {
}

+ 78
- 47
examples/TeensySdioDemo/TeensySdioDemo.ino Bestand weergeven

@@ -1,23 +1,33 @@
// 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.

// Demonstrates yield() efficiency for SDIO modes.
// Uses built-in SD for SPI modes.
#include "SdFat.h"

// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 3

// 32 KiB buffer.
const size_t BUF_DIM = 32768;

// 8 MiB file.
const uint32_t FILE_SIZE = 256UL*BUF_DIM;

SdFatSdio sd;

SdFatSdioEX sdEx;

#if SD_FAT_TYPE == 0
SdFat sd;
File file;
#elif SD_FAT_TYPE == 1
SdFat32 sd;
File32 file;
#elif SD_FAT_TYPE == 2
SdExFat sd;
ExFile file;
#elif SD_FAT_TYPE == 3
SdFs sd;
FsFile file;
#else // SD_FAT_TYPE
#error Invalid SD_FAT_TYPE
#endif // SD_FAT_TYPE

uint8_t buf[BUF_DIM];

@@ -32,24 +42,25 @@ uint32_t yieldMicros = 0;
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);
Serial.print("Error: ");
Serial.println(msg);
if (sd.sdErrorCode()) {
if (sd.sdErrorCode() == SD_CARD_ERROR_ACMD41) {
Serial.println("Try power cycling the SD card.");
}
printSdErrorSymbol(&Serial, sd.sdErrorCode());
Serial.print(", ErrorData: 0X");
Serial.println(sd.sdErrorData(), HEX);
}
while (true) {}
}
bool ready = false;
//-----------------------------------------------------------------------------
bool sdBusy() {
return ready ? sd.card()->isBusy() : false;
}
//------------------------------------------------------------------------------
uint32_t kHzSdClk() {
return useEx ? sdEx.card()->kHzSdClk() : sd.card()->kHzSdClk();
}
//------------------------------------------------------------------------------
// Replace "weak" system yield() function.
void yield() {
@@ -81,8 +92,11 @@ void runTest() {
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;
uint32_t nRdWr = FILE_SIZE/nb;
if (!file.truncate(0)) {
errorHalt("truncate failed");
}

Serial.print(nb);
Serial.print(',');
uint32_t t = micros();
@@ -123,8 +137,8 @@ void runTest() {
Serial.println(yieldCalls);
Serial.print("yieldMaxUsec ");
Serial.println(yieldMaxUsec);
Serial.print("kHzSdClk ");
Serial.println(kHzSdClk());
// Serial.print("kHzSdClk ");
// Serial.println(kHzSdClk());
Serial.println("Done");
}
//-----------------------------------------------------------------------------
@@ -132,38 +146,55 @@ 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() {
static bool warn = true;
if (warn) {
warn = false;
Serial.println(
"SD cards must be power cycled to leave\n"
"SPI mode so do SDIO tests first.\n"
"\nCycle power on the card if an error occurs.");
}
do {
delay(10);
} while (Serial.available() && Serial.read());

Serial.println("Type '1' for SdFatSdioEX or '2' for SdFatSdio");
Serial.println(
"\nType '1' for FIFO SDIO"
"\n '2' for DMA SDIO"
"\n '3' for Dedicated SPI"
"\n '4' for Shared SPI");
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");
if (!sd.begin(SdioConfig(FIFO_SDIO))) {
errorHalt("begin failed");
}
// make sdEx the current volume.
sdEx.chvol();
} else {
useEx = false;
if (!sd.begin()) {
sd.initErrorHalt("SdFatSdio begin() failed");
Serial.println("\nFIFO SDIO mode.");
} else if (c == '2') {
if (!sd.begin(SdioConfig(DMA_SDIO))) {
errorHalt("begin failed");
}
Serial.println("\nDMA SDIO mode - slow for small transfers.");
} else if (c == '3') {
if (!sd.begin(SdSpiConfig(SDCARD_SS_PIN, DEDICATED_SPI, SD_SCK_MHZ(50)))) {
errorHalt("begin failed");
}
Serial.println("\nDedicated SPI mode.");
} else if (c == '4') {
if (!sd.begin(SdSpiConfig(SDCARD_SS_PIN, SHARED_SPI, SD_SCK_MHZ(50)))) {
errorHalt("begin failed");
}
// make sd the current volume.
sd.chvol();
Serial.println("\nShared SPI mode - slow for small transfers.");
} else {
Serial.println("Invalid input");
return;
}
ready = true;
runTest();
ready = false;
}

+ 108
- 67
examples/bench/bench.ino Bestand weergeven

@@ -1,16 +1,44 @@
/*
* This program is a simple binary write/read benchmark.
*/
#include <SPI.h>
#include "SdFat.h"
#include "sdios.h"
#include "FreeStack.h"

// Set USE_SDIO to zero for SPI card access.
#define USE_SDIO 0
// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 0
/*
Change the value of SD_CS_PIN if you are using SPI and
your hardware does not use the default value, SS.
Common values are:
Arduino Ethernet shield: pin 4
Sparkfun SD shield: pin 8
Adafruit SD shields and modules: pin 10
*/
// SDCARD_SS_PIN is defined for the built-in SD on some boards.
#ifndef SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SS;
#else // SDCARD_SS_PIN
// Assume built-in SD is used.
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#endif // SDCARD_SS_PIN

// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI)
#else // HAS_SDIO_CLASS
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI)
#endif // HAS_SDIO_CLASS

// Set PRE_ALLOCATE true to pre-allocate file clusters.
const bool PRE_ALLOCATE = true;

// SD chip select pin
const uint8_t chipSelect = SS;
// Set SKIP_FIRST_LATENCY true if the first read/write to the SD can
// be avoid by writing a file header or reading the first record.
const bool SKIP_FIRST_LATENCY = true;

// Size of read/write.
const size_t BUF_SIZE = 512;
@@ -29,38 +57,36 @@ const uint8_t READ_COUNT = 2;
// File size in bytes.
const uint32_t FILE_SIZE = 1000000UL*FILE_SIZE_MB;

uint8_t buf[BUF_SIZE];
// Insure 4-byte alignment.
uint32_t buf32[(BUF_SIZE + 3)/4];
uint8_t* buf = (uint8_t*)buf32;

// file system
#if USE_SDIO
// Traditional DMA version.
// SdFatSdio sd;
// Faster version.
SdFatSdioEX sd;
#else // USE_SDIO
#if SD_FAT_TYPE == 0
SdFat 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;

// test file
SdFile file;
File file;
#elif SD_FAT_TYPE == 1
SdFat32 sd;
File32 file;
#elif SD_FAT_TYPE == 2
SdExFat sd;
ExFile file;
#elif SD_FAT_TYPE == 3
SdFs sd;
FsFile file;
#else // SD_FAT_TYPE
#error Invalid SD_FAT_TYPE
#endif // SD_FAT_TYPE

// Serial output stream
ArduinoOutStream cout(Serial);
//------------------------------------------------------------------------------
// Store error strings in flash to save RAM.
#define error(s) sd.errorHalt(F(s))
#define error(s) sd.errorHalt(&Serial, F(s))
//------------------------------------------------------------------------------
void cidDmp() {
cid_t cid;
if (!sd.card()->readCID(&cid)) {

error("readCID failed");
}
cout << F("\nManufacturer ID: ");
@@ -81,13 +107,18 @@ void cidDmp() {
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
// Wait for USB Serial
// Wait for USB Serial
while (!Serial) {
SysCall::yield();
}
delay(1000);
cout << F("\nUse a freshly formatted SD for best performance.\n");
if (!ENABLE_DEDICATED_SPI) {
cout << F(
"\nSet ENABLE_DEDICATED_SPI nonzero in\n"
"SdFatConfig.h for best SPI performance.\n");
}

// use uppercase in hex and use 0X base prefix
cout << uppercase << showbase << endl;
@@ -99,33 +130,31 @@ void loop() {
uint32_t maxLatency;
uint32_t minLatency;
uint32_t totalLatency;
bool skipLatency;

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

// F( stores strings in flash to save RAM
// F() stores strings in flash to save RAM
cout << F("Type any character to start\n");
while (!Serial.available()) {
SysCall::yield();
}
cout << F("chipSelect: ") << int(chipSelect) << endl;
cout << F("FreeStack: ") << FreeStack() << endl;

#if USE_SDIO
if (!sd.begin()) {
sd.initErrorHalt();
if (!sd.begin(SD_CONFIG)) {
sd.initErrorHalt(&Serial);
}
#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();
if (sd.fatType() == FAT_TYPE_EXFAT) {
cout << F("Type is exFAT") << endl;
} else {
cout << F("Type is FAT") << int(sd.fatType()) << endl;
}
#endif // USE_SDIO
cout << F("Type is FAT") << int(sd.vol()->fatType()) << endl;
cout << F("Card size: ") << sd.card()->cardSize()*512E-9;

cout << F("Card size: ") << sd.card()->sectorCount()*512E-9;
cout << F(" GB (GB = 1E9 bytes)") << endl;

cidDmp();
@@ -136,42 +165,51 @@ void loop() {
}

// fill buf with known data
for (size_t i = 0; i < (BUF_SIZE-2); i++) {
for (uint16_t i = 0; i < (BUF_SIZE-2); i++) {
buf[i] = 'A' + (i % 26);
}
buf[BUF_SIZE-2] = '\r';
buf[BUF_SIZE-1] = '\n';

cout << F("File size ") << FILE_SIZE_MB << F(" MB\n");
cout << F("Buffer size ") << BUF_SIZE << F(" bytes\n");
cout << F("FILE_SIZE_MB = ") << FILE_SIZE_MB << endl;
cout << F("BUF_SIZE = ") << BUF_SIZE << F(" bytes\n");
cout << F("Starting write test, please wait.") << endl << endl;

// do write test
uint32_t n = FILE_SIZE/sizeof(buf);
uint32_t n = FILE_SIZE/BUF_SIZE;
cout <<F("write speed and latency") << endl;
cout << F("speed,max,min,avg") << endl;
cout << F("KB/Sec,usec,usec,usec") << endl;
for (uint8_t nTest = 0; nTest < WRITE_COUNT; nTest++) {
file.truncate(0);
if (PRE_ALLOCATE) {
if (!file.preAllocate(FILE_SIZE)) {
error("preAllocate failed");
}
}
maxLatency = 0;
minLatency = 9999999;
totalLatency = 0;
skipLatency = SKIP_FIRST_LATENCY;
t = millis();
for (uint32_t i = 0; i < n; i++) {
uint32_t m = micros();
if (file.write(buf, sizeof(buf)) != sizeof(buf)) {
sd.errorPrint("write failed");
file.close();
return;
if (file.write(buf, BUF_SIZE) != BUF_SIZE) {
error("write failed");
}
m = micros() - m;
if (maxLatency < m) {
maxLatency = m;
}
if (minLatency > m) {
minLatency = m;
}
totalLatency += m;
if (skipLatency) {
// Wait until first write to SD, not just a copy to the cache.
skipLatency = file.curPosition() < 512;
} else {
if (maxLatency < m) {
maxLatency = m;
}
if (minLatency > m) {
minLatency = m;
}
}
}
file.sync();
t = millis() - t;
@@ -190,26 +228,29 @@ void loop() {
maxLatency = 0;
minLatency = 9999999;
totalLatency = 0;
skipLatency = SKIP_FIRST_LATENCY;
t = millis();
for (uint32_t i = 0; i < n; i++) {
buf[BUF_SIZE-1] = 0;
uint32_t m = micros();
int32_t nr = file.read(buf, sizeof(buf));
if (nr != sizeof(buf)) {
sd.errorPrint("read failed");
file.close();
return;
int32_t nr = file.read(buf, BUF_SIZE);
if (nr != BUF_SIZE) {
error("read failed");
}
m = micros() - m;
if (maxLatency < m) {
maxLatency = m;
}
if (minLatency > m) {
minLatency = m;
}
totalLatency += m;
if (buf[BUF_SIZE-1] != '\n') {
error("data check");
error("data check error");
}
if (skipLatency) {
skipLatency = false;
} else {
if (maxLatency < m) {
maxLatency = m;
}
if (minLatency > m) {
minLatency = m;
}
}
}
s = file.fileSize();

+ 87
- 0
examples/debug/CardBusyTest/CardBusyTest.ino Bestand weergeven

@@ -0,0 +1,87 @@
#include "SdFat.h"

#ifdef __AVR__
const uint32_t FILE_SIZE_MiB = 10UL;
#else // __AVR__
const uint32_t FILE_SIZE_MiB = 100UL;
#endif

bool waitBusy = true;

#define SD_CONFIG SdSpiConfig(SS, DEDICATED_SPI)
// Config for Teensy 3.5/3.6 buit-in SD.
//#define SD_CONFIG SdSpiConfig(SDCARD_SS_PIN, DEDICATED_SPI)
//#define SD_CONFIG SdioConfig(FIFO_SDIO)

//------------------------------------------------------------------------------
const uint64_t FILE_SIZE = (uint64_t)FILE_SIZE_MiB << 20;

SdExFat sd;
ExFile file;

uint8_t buf[512];

#define error(s) sd.errorHalt(&Serial, F(s))
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);

// Wait for USB Serial
while (!Serial) {
SysCall::yield();
}
delay(1000);

Serial.println(F("Type any character to start\n"));
while (!Serial.available()) {
SysCall::yield();
}
// Initialize the SD card.
if (!sd.begin(SD_CONFIG)) {
sd.initErrorHalt();
}
if (!file.open("SdBusyTest.bin", O_RDWR | O_CREAT |O_TRUNC)) {
error("file open failed");
}
if (!file.preAllocate(FILE_SIZE)) {
error("preallocate failed");
}
Serial.print(F("Starting write of "));
Serial.print(FILE_SIZE_MiB);
Serial.println(F(" MiB."));
uint32_t maxMicros = 0;
uint32_t minMicros = 99999999;
uint32_t ms = millis();

// Write a dummy sector to start a multi-sector write.
if(file.write(buf, sizeof(buf)) != sizeof(buf)) {
error("write failed for first sector");
}

while (file.position() < FILE_SIZE) {
if (waitBusy) {
while (sd.card()->isBusy()) {}
}
uint32_t m = micros();
if (file.write(buf, sizeof(buf)) != sizeof(buf)) {
error("write failed");
}
m = micros() - m;
if (m < minMicros) {
minMicros = m;
}
if (m > maxMicros) {
maxMicros = m;
}
}
ms = millis() - ms;
Serial.print(F("minMicros: "));
Serial.println(minMicros);
Serial.print(F("maxMicros: "));
Serial.println(maxMicros);
Serial.print(1e-3*ms);
Serial.println(F(" Seconds"));
Serial.print(1.0*FILE_SIZE/ms);
Serial.println(F(" KB/sec"));
}
void loop() {}

+ 47
- 0
examples/debug/ExFatDbgDmp/ExFatDbgDmp.ino Bestand weergeven

@@ -0,0 +1,47 @@
#include "SdFat.h"
#define DUMP_RAW 0
#define DUMP_UPCASE 0
const uint8_t CS_PIN = SS;
//#define SD_CONFIG SdioConfig(FIFO_SDIO)
#define SD_CONFIG SdSpiConfig(CS_PIN)

SdExFat sd;
#define error(s) sd.errorHalt(&Serial, F(s))
void setup() {
Serial.begin(9600);
while (!Serial) {yield();}
Serial.println(F("Type any character to begin"));
while (!Serial.available()) {yield();}
if (!sd.begin(SD_CONFIG)){
error("begin failed");
}
#if DUMP_RAW
sd.dmpSector(&Serial, 0);
for (uint8_t i = 0; i < 24; i++) {
sd.dmpSector(&Serial, 0X8000 + i);
Serial.println();
}
return;
#endif // DUMP_RAW
ExFatFile root;
if (!root.openRoot(&sd)) {
error("openRoot failed");
}
sd.printDir(&Serial, &root);
// startSector = 0, sectorCount = 1.
sd.dmpFat(&Serial, 0, 1);
sd.dmpBitmap(&Serial);
sd.printVolInfo(&Serial);

sd.checkUpcase(&Serial);
#if DUMP_UPCASE
sd.printUpcase(&Serial);
#endif // DUMP_UPCASE
// sd.dmpCluster(&Serial, 8, 0, 4);
Serial.println("Done");
}

void loop() {
// put your main code here, to run repeatedly:

}

extras/SdFatTestSuite/examples/TestMkdir/TestMkdir.ino → examples/debug/TestMkdir/TestMkdir.ino Bestand weergeven

@@ -10,23 +10,22 @@
* Note: Some cards may 'stutter' others just get slow due
* to the number of flash erases this program causes.
*/
#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>

const uint8_t SD_CHIP_SELECT = SS;

SdFat sd;
typedef File file_t;

// store error strings in flash to save RAM
#define error(s) sd.errorHalt(F(s))
#define error(s) sd.errorHalt(&Serial, F(s))

/*
* create enough files to force a cluster to be allocated to dir.
*/
void dirAllocTest(FatFile* dir) {
void dirAllocTest(file_t* dir) {
char buf[32], name[32];
SdFile file;
file_t file;
uint16_t n;
uint32_t size = dir->dirSize();
@@ -37,7 +36,7 @@ void dirAllocTest(FatFile* dir) {
// open start time
uint32_t t0 = millis();
if (!file.open(dir, name, O_WRITE | O_CREAT | O_EXCL)) {
if (!file.open(dir, name, O_WRONLY | O_CREAT | O_EXCL)) {
error("open for write failed");
}
@@ -70,7 +69,7 @@ void dirAllocTest(FatFile* dir) {
// open start time
uint32_t t0 = millis();
if (!file.open(dir, name, O_READ)) {
if (!file.open(dir, name, O_RDONLY)) {
error("open for read failed");
}
@@ -102,6 +101,7 @@ void dirAllocTest(FatFile* dir) {
}

void setup() {
file_t root;
Serial.begin(9600);
while (!Serial) {} // wait for Leonardo
Serial.println(F("Type any character to start"));
@@ -110,23 +110,25 @@ void setup() {
// initialize the SD card at SPI_FULL_SPEED for best performance.
// try SPI_HALF_SPEED if bus errors occur.
if (!sd.begin(SD_CHIP_SELECT, SPI_FULL_SPEED)) sd.initErrorHalt();
if (!sd.begin(SD_CHIP_SELECT, SPI_FULL_SPEED)) {
sd.initErrorHalt(&Serial);
}
root.openRoot(&sd);
uint32_t m = millis();
// write files to root if FAT32
if (sd.vol()->fatType() == 32) {
// write files to root if not FAT16
if (sd.fatType() != 16) {
Serial.println(F("Writing files to root"));
dirAllocTest(sd.vwd());
dirAllocTest(&root);
}
// create sub1 and write files
SdFile sub1;
if (!sub1.mkdir(sd.vwd(), "SUB1")) error("makdeDir SUB1 failed");
file_t sub1;
if (!sub1.mkdir(&root, "SUB1")) error("makdeDir SUB1 failed");
Serial.println(F("Writing files to SUB1"));
dirAllocTest(&sub1);

// create sub2 and write files
SdFile sub2;
file_t sub2;
if (!sub2.mkdir(&sub1, "SUB2")) error("mkdir SUB2 failed");
Serial.println(F("Writing files to SUB2"));
dirAllocTest(&sub2);

extras/SdFatTestSuite/examples/TestRmdir/TestRmdir.ino → examples/debug/TestRmdir/TestRmdir.ino Bestand weergeven

@@ -6,23 +6,22 @@
* of flash erase operations caused by many random
* writes to file structures.
*/
#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>

const uint8_t SD_CHIP_SELECT = SS;

SdFat sd;
typedef File file_t;

// store error strings in flash to save RAM
#define error(s) sd.errorHalt(F(s))
#define error(s) sd.errorHalt(&Serial, F(s))

/*
* remove all files in dir.
*/
void deleteFiles(FatFile* dir) {
char name[32];
SdFile file;
file_t file;
// open and delete files
for (uint16_t n = 0; ; n++){
@@ -32,7 +31,7 @@ void deleteFiles(FatFile* dir) {
uint32_t t0 = millis();
// assume done if open fails
if (!file.open(dir, name, O_WRITE)) return;
if (!file.open(dir, name, O_WRONLY)) return;
// open end time and remove start time
uint32_t t1 = millis();
@@ -55,6 +54,7 @@ void deleteFiles(FatFile* dir) {
}

void setup() {
file_t root;
Serial.begin(9600);
while (!Serial) {} // wait for Leonardo
Serial.println(F("Type any character to start"));
@@ -63,24 +63,25 @@ void setup() {
// initialize the SD card at SPI_FULL_SPEED for best performance.
// try SPI_HALF_SPEED if bus errors occur.
if (!sd.begin(SD_CHIP_SELECT, SPI_FULL_SPEED)) sd.initErrorHalt();

// delete files in root if FAT32
if (sd.vol()->fatType() == 32) {
if (!sd.begin(SD_CHIP_SELECT, SPI_FULL_SPEED)) {
sd.initErrorHalt(&Serial);
}
root.openRoot(&sd);
// delete files in root if not FAT16.
if (sd.fatType() != 16) {
Serial.println(F("Remove files in root"));
deleteFiles(sd.vwd());
deleteFiles(&root);
}
// open SUB1 and delete files
SdFile sub1;
if (!sub1.open("SUB1", O_READ)) error("open SUB1 failed");
file_t sub1;
if (!sub1.open("SUB1", O_RDONLY)) error("open SUB1 failed");
Serial.println(F("Remove files in SUB1"));
deleteFiles(&sub1);

// open SUB2 and delete files
SdFile sub2;
if (!sub2.open(&sub1, "SUB2", O_READ)) error("open SUB2 failed");
file_t sub2;
if (!sub2.open(&sub1, "SUB2", O_RDONLY)) error("open SUB2 failed");
Serial.println(F("Remove files in SUB2"));
deleteFiles(&sub2);

@@ -95,4 +96,4 @@ void setup() {
Serial.println(F("Done"));
}

void loop() { }
void loop() { }

examples/#attic/AnalogLogger/AnalogLogger.ino → examples/examplesV1/#attic/AnalogLogger/AnalogLogger.ino Bestand weergeven


examples/#attic/BaseExtCaseTest/BaseExtCaseTest.ino → examples/examplesV1/#attic/BaseExtCaseTest/BaseExtCaseTest.ino Bestand weergeven


examples/#attic/HelloWorld/HelloWorld.ino → examples/examplesV1/#attic/HelloWorld/HelloWorld.ino Bestand weergeven


examples/#attic/MiniSerial/MiniSerial.ino → examples/examplesV1/#attic/MiniSerial/MiniSerial.ino Bestand weergeven


examples/#attic/PrintBenchmarkSD/PrintBenchmarkSD.ino → examples/examplesV1/#attic/PrintBenchmarkSD/PrintBenchmarkSD.ino Bestand weergeven


examples/#attic/SD_Size/SD_Size.ino → examples/examplesV1/#attic/SD_Size/SD_Size.ino Bestand weergeven


examples/#attic/SdFatSize/SdFatSize.ino → examples/examplesV1/#attic/SdFatSize/SdFatSize.ino Bestand weergeven


examples/#attic/StreamParseInt/StreamParseInt.ino → examples/examplesV1/#attic/StreamParseInt/StreamParseInt.ino Bestand weergeven


examples/#attic/append/append.ino → examples/examplesV1/#attic/append/append.ino Bestand weergeven


examples/#attic/average/average.ino → examples/examplesV1/#attic/average/average.ino Bestand weergeven


examples/#attic/benchSD/benchSD.ino → examples/examplesV1/#attic/benchSD/benchSD.ino Bestand weergeven


examples/#attic/bufstream/bufstream.ino → examples/examplesV1/#attic/bufstream/bufstream.ino Bestand weergeven


examples/#attic/cin_cout/cin_cout.ino → examples/examplesV1/#attic/cin_cout/cin_cout.ino Bestand weergeven


examples/#attic/eventlog/eventlog.ino → examples/examplesV1/#attic/eventlog/eventlog.ino Bestand weergeven


examples/#attic/fgetsRewrite/fgetsRewrite.ino → examples/examplesV1/#attic/fgetsRewrite/fgetsRewrite.ino Bestand weergeven


examples/#attic/readlog/readlog.ino → examples/examplesV1/#attic/readlog/readlog.ino Bestand weergeven


examples/#attic/readme.txt → examples/examplesV1/#attic/readme.txt Bestand weergeven


examples/AnalogBinLogger/AnalogBinLogger.h → examples/examplesV1/AnalogBinLogger/AnalogBinLogger.h Bestand weergeven


examples/AnalogBinLogger/AnalogBinLogger.ino → examples/examplesV1/AnalogBinLogger/AnalogBinLogger.ino Bestand weergeven

@@ -747,7 +747,7 @@ void logData() {
error("Can't truncate file");
}
}
if (!binFile.rename(sd.vwd(), binName)) {
if (!binFile.rename(binName)) {
error("Can't rename file");
}
Serial.print(F("File renamed: "));

+ 129
- 0
examples/examplesV1/DirectoryFunctions/DirectoryFunctions.ino Bestand weergeven

@@ -0,0 +1,129 @@
/*
* Example use of chdir(), ls(), mkdir(), and rmdir().
*/
#include <SPI.h>
#include "SdFat.h"
#include "sdios.h"
// SD card chip select pin.
const uint8_t chipSelect = SS;
//------------------------------------------------------------------------------

// File system object.
SdFat sd;

// Directory file.
SdFile root;

// Use for file creation in folders.
SdFile file;

// Create a Serial output stream.
ArduinoOutStream cout(Serial);

// Buffer for Serial input.
char cinBuf[40];

// Create a serial input stream.
ArduinoInStream cin(Serial, cinBuf, sizeof(cinBuf));
//==============================================================================
// Error messages stored in flash.
#define error(msg) sd.errorHalt(F(msg))
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);

// Wait for USB Serial
while (!Serial) {
SysCall::yield();
}
delay(1000);

cout << F("Type any character to start\n");
// Wait for input line and discard.
cin.readline();
cout << endl;

// 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")
|| sd.exists("Folder1/file1.txt")
|| sd.exists("Folder1/File2.txt")) {
error("Please remove existing Folder1, file1.txt, and File2.txt");
}

int rootFileCount = 0;
if (!root.open("/")) {
error("open root failed");
}
while (file.openNext(&root, O_RDONLY)) {
if (!file.isHidden()) {
rootFileCount++;
}
file.close();
if (rootFileCount > 10) {
error("Too many files in root. Please use an empty SD.");
}
}
if (rootFileCount) {
cout << F("\nPlease use an empty SD for best results.\n\n");
delay(1000);
}
// Create a new folder.
if (!sd.mkdir("Folder1")) {
error("Create Folder1 failed");
}
cout << F("Created Folder1\n");

// Create a file in Folder1 using a path.
if (!file.open("Folder1/file1.txt", O_WRONLY | O_CREAT)) {
error("create Folder1/file1.txt failed");
}
file.close();
cout << F("Created Folder1/file1.txt\n");

// Change volume working directory to Folder1.
if (!sd.chdir("Folder1")) {
error("chdir failed for Folder1.\n");
}
cout << F("chdir to Folder1\n");

// Create File2.txt in current directory.
if (!file.open("File2.txt", O_WRONLY | O_CREAT)) {
error("create File2.txt failed");
}
file.close();
cout << F("Created File2.txt in current directory\n");

cout << F("\nList of files on the SD.\n");
sd.ls("/", LS_R);

// Remove files from current directory.
if (!sd.remove("file1.txt") || !sd.remove("File2.txt")) {
error("remove failed");
}
cout << F("\nfile1.txt and File2.txt removed.\n");

// Change current directory to root.
if (!sd.chdir()) {
error("chdir to root failed.\n");
}

cout << F("\nList of files on the SD.\n");
sd.ls(LS_R);

// Remove Folder1.
if (!sd.rmdir("Folder1")) {
error("rmdir for Folder1 failed\n");
}

cout << F("\nFolder1 removed.\n");
cout << F("\nList of files on the SD.\n");
sd.ls(LS_R);
cout << F("Done!\n");
}
//------------------------------------------------------------------------------
// Nothing happens in loop.
void loop() {}

examples/LongFileName/LongFileName.ino → examples/examplesV1/LongFileName/LongFileName.ino Bestand weergeven


examples/LongFileName/testFiles/A long name can be 255 characters.txt → examples/examplesV1/LongFileName/testFiles/A long name can be 255 characters.txt Bestand weergeven


examples/LongFileName/testFiles/LFN,NAME.TXT → examples/examplesV1/LongFileName/testFiles/LFN,NAME.TXT Bestand weergeven


examples/LongFileName/testFiles/MIXCASE.txt → examples/examplesV1/LongFileName/testFiles/MIXCASE.txt Bestand weergeven


examples/LongFileName/testFiles/Not_8_3.txt → examples/examplesV1/LongFileName/testFiles/Not_8_3.txt Bestand weergeven


examples/LongFileName/testFiles/OK%83.TXT → examples/examplesV1/LongFileName/testFiles/OK%83.TXT Bestand weergeven


examples/LongFileName/testFiles/STD_8_3.TXT → examples/examplesV1/LongFileName/testFiles/STD_8_3.TXT Bestand weergeven


examples/LongFileName/testFiles/With Blank.txt → examples/examplesV1/LongFileName/testFiles/With Blank.txt Bestand weergeven


examples/LongFileName/testFiles/With.Two dots.txt → examples/examplesV1/LongFileName/testFiles/With.Two dots.txt Bestand weergeven


examples/LongFileName/testFiles/lower.txt → examples/examplesV1/LongFileName/testFiles/lower.txt Bestand weergeven


examples/LongFileName/testFiles/mixed.TXT → examples/examplesV1/LongFileName/testFiles/mixed.TXT Bestand weergeven


examples/LowLatencyLogger/LowLatencyLogger.ino → examples/examplesV1/LowLatencyLogger/LowLatencyLogger.ino Bestand weergeven

@@ -192,7 +192,7 @@ void binaryToCsv() {
Serial.println();
Serial.print(F("FreeStack: "));
Serial.println(FreeStack());
// Create a new csvFile.
strcpy(csvName, binName);
strcpy(&csvName[BASE_NAME_SIZE + 3], "csv");
@@ -245,7 +245,7 @@ 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));
@@ -349,19 +349,19 @@ 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;
uint8_t fullTail = 0;

// Use SdFat's internal buffer.
emptyStack[0] = (block_t*)sd.vol()->cacheClear();
@@ -374,7 +374,7 @@ void recordBinFile() {
}
emptyTop = BUFFER_BLOCK_COUNT;
minTop = BUFFER_BLOCK_COUNT;
// Start a multiple block write.
if (!sd.card()->writeStart(binFile.firstBlock())) {
error("writeStart failed");
@@ -383,7 +383,7 @@ void recordBinFile() {
Serial.println(FreeStack());
Serial.println(F("Logging - type any character to stop"));
bool closeFile = false;
uint32_t bn = 0;
uint32_t bn = 0;
uint32_t maxLatency = 0;
uint32_t overrun = 0;
uint32_t overrunTotal = 0;
@@ -393,7 +393,7 @@ void recordBinFile() {
logTime += LOG_INTERVAL_USEC;
if (Serial.available()) {
closeFile = true;
}
}
if (closeFile) {
if (curBlock != 0) {
// Put buffer in full queue.
@@ -412,7 +412,7 @@ void recordBinFile() {
overrun = 0;
}
if ((int32_t)(logTime - micros()) < 0) {
error("Rate too fast");
error("Rate too fast");
}
int32_t delta;
do {
@@ -423,24 +423,24 @@ void recordBinFile() {
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
#endif // ABORT_ON_OVERRUN
} else {
#if USE_SHARED_SPI
sd.card()->spiStop();
#endif // USE_SHARED_SPI
#endif // USE_SHARED_SPI
acquireData(&curBlock->data[curBlock->count++]);
#if USE_SHARED_SPI
sd.card()->spiStart();
#endif // USE_SHARED_SPI
#endif // USE_SHARED_SPI
if (curBlock->count == DATA_DIM) {
fullQueue[fullHead] = curBlock;
fullHead = fullHead < QUEUE_LAST ? fullHead + 1 : 0;
curBlock = 0;
}
}
}
}
if (fullHead == fullTail) {
@@ -506,7 +506,7 @@ void recoverTmpFile() {
if (binFile.read(&count, 2) != 2) error("read");
if (count == 0 || count > DATA_DIM) {
endBlock = midBlock - 1;
} else {
} else {
bgnBlock = midBlock;
}
}
@@ -529,7 +529,7 @@ void renameBinFile() {
binName[BASE_NAME_SIZE]++;
}
}
if (!binFile.rename(sd.vwd(), binName)) {
if (!binFile.rename(binName)) {
error("Can't rename file");
}
Serial.print(F("File renamed: "));
@@ -563,8 +563,8 @@ void setup(void) {
pinMode(ERROR_LED_PIN, OUTPUT);
}
Serial.begin(9600);
// Wait for USB Serial
// Wait for USB Serial
while (!Serial) {
SysCall::yield();
}
@@ -578,10 +578,10 @@ void setup(void) {
// 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))) {
@@ -609,11 +609,11 @@ 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("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("l - list files"));
Serial.println(F("r - record data"));
Serial.println(F("t - test without logging"));
while(!Serial.available()) {
@@ -623,7 +623,7 @@ void loop(void) {
Serial.println(F("LowLatencyLogger can not run with watchdog timer"));
SysCall::halt();
#endif
char c = tolower(Serial.read());

// Discard extra Serial data.
@@ -643,12 +643,12 @@ void loop(void) {
} else if (c == 'e') {
checkOverrun();
} else if (c == 'l') {
Serial.println(F("\nls:"));
sd.ls(&Serial, LS_SIZE);
Serial.println(F("\nls:"));
sd.ls(&Serial, LS_SIZE);
} else if (c == 'r') {
logData();
} else if (c == 't') {
testSensor();
testSensor();
} else {
Serial.println(F("Invalid entry"));
}

examples/LowLatencyLogger/UserFunctions.cpp → examples/examplesV1/LowLatencyLogger/UserFunctions.cpp Bestand weergeven


examples/LowLatencyLogger/UserTypes.h → examples/examplesV1/LowLatencyLogger/UserTypes.h Bestand weergeven


examples/LowLatencyLoggerADXL345/LowLatencyLogger.ino → examples/examplesV1/LowLatencyLoggerADXL345/LowLatencyLogger.ino Bestand weergeven

@@ -192,7 +192,7 @@ void binaryToCsv() {
Serial.println();
Serial.print(F("FreeStack: "));
Serial.println(FreeStack());
// Create a new csvFile.
strcpy(csvName, binName);
strcpy(&csvName[BASE_NAME_SIZE + 3], "csv");
@@ -245,7 +245,7 @@ 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));
@@ -349,19 +349,19 @@ 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;
uint8_t fullTail = 0;

// Use SdFat's internal buffer.
emptyStack[0] = (block_t*)sd.vol()->cacheClear();
@@ -374,7 +374,7 @@ void recordBinFile() {
}
emptyTop = BUFFER_BLOCK_COUNT;
minTop = BUFFER_BLOCK_COUNT;
// Start a multiple block write.
if (!sd.card()->writeStart(binFile.firstBlock())) {
error("writeStart failed");
@@ -383,7 +383,7 @@ void recordBinFile() {
Serial.println(FreeStack());
Serial.println(F("Logging - type any character to stop"));
bool closeFile = false;
uint32_t bn = 0;
uint32_t bn = 0;
uint32_t maxLatency = 0;
uint32_t overrun = 0;
uint32_t overrunTotal = 0;
@@ -393,7 +393,7 @@ void recordBinFile() {
logTime += LOG_INTERVAL_USEC;
if (Serial.available()) {
closeFile = true;
}
}
if (closeFile) {
if (curBlock != 0) {
// Put buffer in full queue.
@@ -412,7 +412,7 @@ void recordBinFile() {
overrun = 0;
}
if ((int32_t)(logTime - micros()) < 0) {
error("Rate too fast");
error("Rate too fast");
}
int32_t delta;
do {
@@ -423,24 +423,24 @@ void recordBinFile() {
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
#endif // ABORT_ON_OVERRUN
} else {
#if USE_SHARED_SPI
sd.card()->spiStop();
#endif // USE_SHARED_SPI
#endif // USE_SHARED_SPI
acquireData(&curBlock->data[curBlock->count++]);
#if USE_SHARED_SPI
sd.card()->spiStart();
#endif // USE_SHARED_SPI
#endif // USE_SHARED_SPI
if (curBlock->count == DATA_DIM) {
fullQueue[fullHead] = curBlock;
fullHead = fullHead < QUEUE_LAST ? fullHead + 1 : 0;
curBlock = 0;
}
}
}
}
if (fullHead == fullTail) {
@@ -506,7 +506,7 @@ void recoverTmpFile() {
if (binFile.read(&count, 2) != 2) error("read");
if (count == 0 || count > DATA_DIM) {
endBlock = midBlock - 1;
} else {
} else {
bgnBlock = midBlock;
}
}
@@ -529,7 +529,7 @@ void renameBinFile() {
binName[BASE_NAME_SIZE]++;
}
}
if (!binFile.rename(sd.vwd(), binName)) {
if (!binFile.rename(binName)) {
error("Can't rename file");
}
Serial.print(F("File renamed: "));
@@ -563,8 +563,8 @@ void setup(void) {
pinMode(ERROR_LED_PIN, OUTPUT);
}
Serial.begin(9600);
// Wait for USB Serial
// Wait for USB Serial
while (!Serial) {
SysCall::yield();
}
@@ -578,10 +578,10 @@ void setup(void) {
// 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))) {
@@ -609,11 +609,11 @@ 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("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("l - list files"));
Serial.println(F("r - record data"));
Serial.println(F("t - test without logging"));
while(!Serial.available()) {
@@ -623,7 +623,7 @@ void loop(void) {
Serial.println(F("LowLatencyLogger can not run with watchdog timer"));
SysCall::halt();
#endif
char c = tolower(Serial.read());

// Discard extra Serial data.
@@ -643,12 +643,12 @@ void loop(void) {
} else if (c == 'e') {
checkOverrun();
} else if (c == 'l') {
Serial.println(F("\nls:"));
sd.ls(&Serial, LS_SIZE);
Serial.println(F("\nls:"));
sd.ls(&Serial, LS_SIZE);
} else if (c == 'r') {
logData();
} else if (c == 't') {
testSensor();
testSensor();
} else {
Serial.println(F("Invalid entry"));
}

examples/LowLatencyLoggerADXL345/LowLatencyLoggerADXL345.ino → examples/examplesV1/LowLatencyLoggerADXL345/LowLatencyLoggerADXL345.ino Bestand weergeven


examples/LowLatencyLoggerADXL345/UserFunctions.cpp → examples/examplesV1/LowLatencyLoggerADXL345/UserFunctions.cpp Bestand weergeven


examples/LowLatencyLoggerADXL345/UserTypes.h → examples/examplesV1/LowLatencyLoggerADXL345/UserTypes.h Bestand weergeven


examples/LowLatencyLoggerADXL345/readme.txt → examples/examplesV1/LowLatencyLoggerADXL345/readme.txt Bestand weergeven


examples/LowLatencyLoggerMPU6050/LowLatencyLogger.ino → examples/examplesV1/LowLatencyLoggerMPU6050/LowLatencyLogger.ino Bestand weergeven

@@ -192,7 +192,7 @@ void binaryToCsv() {
Serial.println();
Serial.print(F("FreeStack: "));
Serial.println(FreeStack());
// Create a new csvFile.
strcpy(csvName, binName);
strcpy(&csvName[BASE_NAME_SIZE + 3], "csv");
@@ -245,7 +245,7 @@ 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));
@@ -349,19 +349,19 @@ 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;
uint8_t fullTail = 0;

// Use SdFat's internal buffer.
emptyStack[0] = (block_t*)sd.vol()->cacheClear();
@@ -374,7 +374,7 @@ void recordBinFile() {
}
emptyTop = BUFFER_BLOCK_COUNT;
minTop = BUFFER_BLOCK_COUNT;
// Start a multiple block write.
if (!sd.card()->writeStart(binFile.firstBlock())) {
error("writeStart failed");
@@ -383,7 +383,7 @@ void recordBinFile() {
Serial.println(FreeStack());
Serial.println(F("Logging - type any character to stop"));
bool closeFile = false;
uint32_t bn = 0;
uint32_t bn = 0;
uint32_t maxLatency = 0;
uint32_t overrun = 0;
uint32_t overrunTotal = 0;
@@ -393,7 +393,7 @@ void recordBinFile() {
logTime += LOG_INTERVAL_USEC;
if (Serial.available()) {
closeFile = true;
}
}
if (closeFile) {
if (curBlock != 0) {
// Put buffer in full queue.
@@ -412,7 +412,7 @@ void recordBinFile() {
overrun = 0;
}
if ((int32_t)(logTime - micros()) < 0) {
error("Rate too fast");
error("Rate too fast");
}
int32_t delta;
do {
@@ -423,24 +423,24 @@ void recordBinFile() {
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
#endif // ABORT_ON_OVERRUN
} else {
#if USE_SHARED_SPI
sd.card()->spiStop();
#endif // USE_SHARED_SPI
#endif // USE_SHARED_SPI
acquireData(&curBlock->data[curBlock->count++]);
#if USE_SHARED_SPI
sd.card()->spiStart();
#endif // USE_SHARED_SPI
#endif // USE_SHARED_SPI
if (curBlock->count == DATA_DIM) {
fullQueue[fullHead] = curBlock;
fullHead = fullHead < QUEUE_LAST ? fullHead + 1 : 0;
curBlock = 0;
}
}
}
}
if (fullHead == fullTail) {
@@ -506,7 +506,7 @@ void recoverTmpFile() {
if (binFile.read(&count, 2) != 2) error("read");
if (count == 0 || count > DATA_DIM) {
endBlock = midBlock - 1;
} else {
} else {
bgnBlock = midBlock;
}
}
@@ -529,7 +529,7 @@ void renameBinFile() {
binName[BASE_NAME_SIZE]++;
}
}
if (!binFile.rename(sd.vwd(), binName)) {
if (!binFile.rename(binName)) {
error("Can't rename file");
}
Serial.print(F("File renamed: "));
@@ -563,8 +563,8 @@ void setup(void) {
pinMode(ERROR_LED_PIN, OUTPUT);
}
Serial.begin(9600);
// Wait for USB Serial
// Wait for USB Serial
while (!Serial) {
SysCall::yield();
}
@@ -578,10 +578,10 @@ void setup(void) {
// 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))) {
@@ -609,11 +609,11 @@ 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("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("l - list files"));
Serial.println(F("r - record data"));
Serial.println(F("t - test without logging"));
while(!Serial.available()) {
@@ -623,7 +623,7 @@ void loop(void) {
Serial.println(F("LowLatencyLogger can not run with watchdog timer"));
SysCall::halt();
#endif
char c = tolower(Serial.read());

// Discard extra Serial data.
@@ -643,12 +643,12 @@ void loop(void) {
} else if (c == 'e') {
checkOverrun();
} else if (c == 'l') {
Serial.println(F("\nls:"));
sd.ls(&Serial, LS_SIZE);
Serial.println(F("\nls:"));
sd.ls(&Serial, LS_SIZE);
} else if (c == 'r') {
logData();
} else if (c == 't') {
testSensor();
testSensor();
} else {
Serial.println(F("Invalid entry"));
}

examples/LowLatencyLoggerMPU6050/LowLatencyLoggerMPU6050.ino → examples/examplesV1/LowLatencyLoggerMPU6050/LowLatencyLoggerMPU6050.ino Bestand weergeven


examples/LowLatencyLoggerMPU6050/UserFunctions.cpp → examples/examplesV1/LowLatencyLoggerMPU6050/UserFunctions.cpp Bestand weergeven


examples/LowLatencyLoggerMPU6050/UserTypes.h → examples/examplesV1/LowLatencyLoggerMPU6050/UserTypes.h Bestand weergeven


+ 60
- 0
examples/examplesV1/OpenNext/OpenNext.ino Bestand weergeven

@@ -0,0 +1,60 @@
/*
* Print size, modify date/time, and name for all files in root.
*/
#include <SPI.h>
#include "SdFat.h"

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

// file system object
SdFat sd;

SdFile root;
SdFile file;
//------------------------------------------------------------------------------
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 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 (!root.open("/")) {
sd.errorHalt("open root failed");
}
// Open next file in root.
// Warning, openNext starts at the current directory position
// so a rewind of the directory may be required.
while (file.openNext(&root, O_RDONLY)) {
file.printFileSize(&Serial);
Serial.write(' ');
file.printModifyDateTime(&Serial);
Serial.write(' ');
file.printName(&Serial);
if (file.isDir()) {
// Indicate a directory.
Serial.write('/');
}
Serial.println();
file.close();
}
if (root.getError()) {
Serial.println("openNext failed");
} else {
Serial.println("Done!");
}
}
//------------------------------------------------------------------------------
void loop() {}

examples/PrintBenchmark/PrintBenchmark.ino → examples/examplesV1/PrintBenchmark/PrintBenchmark.ino Bestand weergeven


+ 161
- 0
examples/examplesV1/QuickStart/QuickStart.ino Bestand weergeven

@@ -0,0 +1,161 @@
// Quick hardware test for SPI card access.
//
#include <SPI.h>
#include "SdFat.h"
#include "sdios.h"
//
// Set DISABLE_CHIP_SELECT to disable a second SPI device.
// For example, with the Ethernet shield, set DISABLE_CHIP_SELECT
// to 10 to disable the Ethernet controller.
const int8_t DISABLE_CHIP_SELECT = -1;
//
// 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;

// Serial streams
ArduinoOutStream cout(Serial);

// input buffer for line
char cinBuf[40];
ArduinoInStream cin(Serial, cinBuf, sizeof(cinBuf));

// SD card chip select
int chipSelect;

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

void reformatMsg() {
cout << F("Try reformatting the card. For best results use\n");
cout << F("the SdFormatter program in SdFat/examples or download\n");
cout << F("and use SDFormatter from www.sdcard.org/downloads.\n");
}

void setup() {
Serial.begin(9600);

// Wait for USB Serial
while (!Serial) {
SysCall::yield();
}
cout << F("\nSPI pins:\n");
cout << F("MISO: ") << int(MISO) << endl;
cout << F("MOSI: ") << int(MOSI) << endl;
cout << F("SCK: ") << int(SCK) << endl;
cout << F("SS: ") << int(SS) << endl;

if (DISABLE_CHIP_SELECT < 0) {
cout << F(
"\nBe sure to edit DISABLE_CHIP_SELECT if you have\n"
"a second SPI device. For example, with the Ethernet\n"
"shield, DISABLE_CHIP_SELECT should be set to 10\n"
"to disable the Ethernet controller.\n");
}
cout << F(
"\nSD chip select is the key hardware option.\n"
"Common values are:\n"
"Arduino Ethernet shield, pin 4\n"
"Sparkfun SD shield, pin 8\n"
"Adafruit SD shields and modules, pin 10\n");
}

bool firstTry = true;
void loop() {
// Read any existing Serial data.
do {
delay(10);
} while (Serial.available() && Serial.read() >= 0);

if (!firstTry) {
cout << F("\nRestarting\n");
}
firstTry = false;

cout << F("\nEnter the chip select pin number: ");
while (!Serial.available()) {
SysCall::yield();
}
cin.readline();
if (cin >> chipSelect) {
cout << chipSelect << endl;
} else {
cout << F("\nInvalid pin number\n");
return;
}
if (DISABLE_CHIP_SELECT < 0) {
cout << F(
"\nAssuming the SD is the only SPI device.\n"
"Edit DISABLE_CHIP_SELECT to disable another device.\n");
} else {
cout << F("\nDisabling SPI device on pin ");
cout << int(DISABLE_CHIP_SELECT) << endl;
pinMode(DISABLE_CHIP_SELECT, OUTPUT);
digitalWrite(DISABLE_CHIP_SELECT, HIGH);
}
if (!sd.begin(chipSelect, SPI_SPEED)) {
if (sd.card()->errorCode()) {
cout << F(
"\nSD initialization failed.\n"
"Do not reformat the card!\n"
"Is the card correctly inserted?\n"
"Is chipSelect set to the correct value?\n"
"Does another SPI device need to be disabled?\n"
"Is there a wiring/soldering problem?\n");
cout << F("\nerrorCode: ") << hex << showbase;
cout << int(sd.card()->errorCode());
cout << F(", errorData: ") << int(sd.card()->errorData());
cout << dec << noshowbase << endl;
return;
}
if (sd.vol()->fatType() == 0) {
cout << F("Can't find a valid FAT16/FAT32 partition.\n");
reformatMsg();
return;
}
cout << F("begin failed, can't determine error type\n");
return;
}
cout << F("\nCard successfully initialized.\n");
cout << endl;

uint32_t size = sd.card()->cardSize();
if (size == 0) {
cout << F("Can't determine the card size.\n");
cardOrSpeed();
return;
}
uint32_t sizeMB = 0.000512 * size + 0.5;
cout << F("Card size: ") << sizeMB;
cout << F(" MB (MB = 1,000,000 bytes)\n");
cout << endl;
cout << F("Volume is FAT") << int(sd.vol()->fatType());
cout << F(", Cluster size (bytes): ") << 512L * sd.vol()->blocksPerCluster();
cout << endl << endl;

cout << F("Files found (date time size name):\n");
sd.ls(LS_R | LS_DATE | LS_SIZE);

if ((sizeMB > 1100 && sd.vol()->blocksPerCluster() < 64)
|| (sizeMB < 2200 && sd.vol()->fatType() == 32)) {
cout << F("\nThis card should be reformatted for best performance.\n");
cout << F("Use a cluster size of 32 KB for cards larger than 1 GB.\n");
cout << F("Only cards larger than 2 GB should be formatted FAT32.\n");
reformatMsg();
return;
}
// Read any extra Serial data.
do {
delay(10);
} while (Serial.available() && Serial.read() >= 0);
cout << F("\nSuccess! Type any character to restart.\n");
while (!Serial.available()) {
SysCall::yield();
}
}

examples/RawWrite/RawWrite.ino → examples/examplesV1/RawWrite/RawWrite.ino Bestand weergeven


examples/ReadCsv/ReadCsv.ino → examples/examplesV1/ReadCsv/ReadCsv.ino Bestand weergeven


examples/ReadCsvArray/ReadCsvArray.ino → examples/examplesV1/ReadCsvArray/ReadCsvArray.ino Bestand weergeven


examples/ReadCsvStream/ReadCsvStream.ino → examples/examplesV1/ReadCsvStream/ReadCsvStream.ino Bestand weergeven


examples/ReadWrite/ReadWrite.ino → examples/examplesV1/ReadWrite/ReadWrite.ino Bestand weergeven


+ 175
- 0
examples/examplesV1/STM32Test/STM32Test.ino Bestand weergeven

@@ -0,0 +1,175 @@
/*
* 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"
#error See new Version 2 STM32 example
// set ENABLE_EXTENDED_TRANSFER_CLASS non-zero to use faster EX classes

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

// Use second SPI port
SPIClass SPI_2(2);
SdFat sd2(&SPI_2);
// SdFatEX sd2(&SPI_2);

const uint8_t SD2_CS = PB12; // chip select for sd2

const uint8_t 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) {
}

// 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()) {
}
Serial.print(F("FreeStack: "));
Serial.println(FreeStack());

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

+ 552
- 0
examples/examplesV1/SdFormatter/SdFormatter.ino Bestand weergeven

@@ -0,0 +1,552 @@
/*
* This program will format an SD or SDHC card.
* Warning all data will be deleted!
*
* For SD/SDHC cards larger than 64 MB this
* program attempts to match the format
* generated by SDFormatter available here:
*
* http://www.sdcard.org/consumers/formatter/
*
* For smaller cards this program uses FAT16
* and SDFormatter uses FAT12.
*/
#error use new Version 2 SdFormatter
// 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:
// Arduino Ethernet shield: pin 4
// Sparkfun SD shield: pin 8
// Adafruit SD shields and modules: pin 10
const uint8_t chipSelect = SS;

// 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"
#include "sdios.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;
uint32_t cardCapacityMB;

// cache for SD block
cache_t cache;

// MBR information
uint8_t partType;
uint32_t relSector;
uint32_t partSize;

// Fake disk geometry
uint8_t numberOfHeads;
uint8_t sectorsPerTrack;

// FAT parameters
uint16_t reservedSectors;
uint8_t sectorsPerCluster;
uint32_t fatStart;
uint32_t fatSize;
uint32_t dataStart;

// constants for file system structure
uint16_t const BU16 = 128;
uint16_t const BU32 = 8192;

// strings needed in file system structures
char noName[] = "NO NAME ";
char fat16str[] = "FAT16 ";
char fat32str[] = "FAT32 ";
//------------------------------------------------------------------------------
#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;
}
SysCall::halt();
}
//------------------------------------------------------------------------------
#if DEBUG_PRINT
void debugPrint() {
cout << F("FreeStack: ") << FreeStack() << endl;
cout << F("partStart: ") << relSector << endl;
cout << F("partSize: ") << partSize << endl;
cout << F("reserved: ") << reservedSectors << endl;
cout << F("fatStart: ") << fatStart << endl;
cout << F("fatSize: ") << fatSize << endl;
cout << F("dataStart: ") << dataStart << endl;
cout << F("clusterCount: ");
cout << ((relSector + partSize - dataStart)/sectorsPerCluster) << endl;
cout << endl;
cout << F("Heads: ") << int(numberOfHeads) << endl;
cout << F("Sectors: ") << int(sectorsPerTrack) << endl;
cout << F("Cylinders: ");
cout << cardSizeBlocks/(numberOfHeads*sectorsPerTrack) << endl;
}
#endif // DEBUG_PRINT
//------------------------------------------------------------------------------
// write cached block to the card
uint8_t writeCache(uint32_t lbn) {
return card.writeBlock(lbn, cache.data);
}
//------------------------------------------------------------------------------
// initialize appropriate sizes for SD capacity
void initSizes() {
if (cardCapacityMB <= 6) {
sdError("Card is too small.");
} else if (cardCapacityMB <= 16) {
sectorsPerCluster = 2;
} else if (cardCapacityMB <= 32) {
sectorsPerCluster = 4;
} else if (cardCapacityMB <= 64) {
sectorsPerCluster = 8;
} else if (cardCapacityMB <= 128) {
sectorsPerCluster = 16;
} else if (cardCapacityMB <= 1024) {
sectorsPerCluster = 32;
} else if (cardCapacityMB <= 32768) {
sectorsPerCluster = 64;
} else {
// SDXC cards
sectorsPerCluster = 128;
}

cout << F("Blocks/Cluster: ") << int(sectorsPerCluster) << endl;
// set fake disk geometry
sectorsPerTrack = cardCapacityMB <= 256 ? 32 : 63;

if (cardCapacityMB <= 16) {
numberOfHeads = 2;
} else if (cardCapacityMB <= 32) {
numberOfHeads = 4;
} else if (cardCapacityMB <= 128) {
numberOfHeads = 8;
} else if (cardCapacityMB <= 504) {
numberOfHeads = 16;
} else if (cardCapacityMB <= 1008) {
numberOfHeads = 32;
} else if (cardCapacityMB <= 2016) {
numberOfHeads = 64;
} else if (cardCapacityMB <= 4032) {
numberOfHeads = 128;
} else {
numberOfHeads = 255;
}
}
//------------------------------------------------------------------------------
// zero cache and optionally set the sector signature
void clearCache(uint8_t addSig) {
memset(&cache, 0, sizeof(cache));
if (addSig) {
cache.mbr.mbrSig0 = BOOTSIG0;
cache.mbr.mbrSig1 = BOOTSIG1;
}
}
//------------------------------------------------------------------------------
// 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");
}
for (uint32_t i = 0; i < count; i++) {
if ((i & 0XFF) == 0) {
cout << '.';
}
if (!card.writeData(cache.data)) {
sdError("Clear FAT/DIR writeData failed");
}
}
if (!card.writeStop()) {
sdError("Clear FAT/DIR writeStop failed");
}
#endif // USE_SDIO
cout << endl;
}
//------------------------------------------------------------------------------
// return cylinder number for a logical block number
uint16_t lbnToCylinder(uint32_t lbn) {
return lbn / (numberOfHeads * sectorsPerTrack);
}
//------------------------------------------------------------------------------
// return head number for a logical block number
uint8_t lbnToHead(uint32_t lbn) {
return (lbn % (numberOfHeads * sectorsPerTrack)) / sectorsPerTrack;
}
//------------------------------------------------------------------------------
// return sector number for a logical block number
uint8_t lbnToSector(uint32_t lbn) {
return (lbn % sectorsPerTrack) + 1;
}
//------------------------------------------------------------------------------
// format and write the Master Boot Record
void writeMbr() {
clearCache(true);
part_t* p = cache.mbr.part;
p->boot = 0;
uint16_t c = lbnToCylinder(relSector);
if (c > 1023) {
sdError("MBR CHS");
}
p->beginCylinderHigh = c >> 8;
p->beginCylinderLow = c & 0XFF;
p->beginHead = lbnToHead(relSector);
p->beginSector = lbnToSector(relSector);
p->type = partType;
uint32_t endLbn = relSector + partSize - 1;
c = lbnToCylinder(endLbn);
if (c <= 1023) {
p->endCylinderHigh = c >> 8;
p->endCylinderLow = c & 0XFF;
p->endHead = lbnToHead(endLbn);
p->endSector = lbnToSector(endLbn);
} else {
// Too big flag, c = 1023, h = 254, s = 63
p->endCylinderHigh = 3;
p->endCylinderLow = 255;
p->endHead = 254;
p->endSector = 63;
}
p->firstSector = relSector;
p->totalSectors = partSize;
if (!writeCache(0)) {
sdError("write MBR");
}
}
//------------------------------------------------------------------------------
// generate serial number from card size and micros since boot
uint32_t volSerialNumber() {
return (cardSizeBlocks << 8) + micros();
}
//------------------------------------------------------------------------------
// format the SD as FAT16
void makeFat16() {
uint32_t nc;
for (dataStart = 2 * BU16;; dataStart += BU16) {
nc = (cardSizeBlocks - dataStart)/sectorsPerCluster;
fatSize = (nc + 2 + 255)/256;
uint32_t r = BU16 + 1 + 2 * fatSize + 32;
if (dataStart < r) {
continue;
}
relSector = dataStart - r + BU16;
break;
}
// check valid cluster count for FAT16 volume
if (nc < 4085 || nc >= 65525) {
sdError("Bad cluster count");
}
reservedSectors = 1;
fatStart = relSector + reservedSectors;
partSize = nc * sectorsPerCluster + 2 * fatSize + reservedSectors + 32;
if (partSize < 32680) {
partType = 0X01;
} else if (partSize < 65536) {
partType = 0X04;
} else {
partType = 0X06;
}
// write MBR
writeMbr();
clearCache(true);
fat_boot_t* pb = &cache.fbs;
pb->jump[0] = 0XEB;
pb->jump[1] = 0X00;
pb->jump[2] = 0X90;
for (uint8_t i = 0; i < sizeof(pb->oemId); i++) {
pb->oemId[i] = ' ';
}
pb->bytesPerSector = 512;
pb->sectorsPerCluster = sectorsPerCluster;
pb->reservedSectorCount = reservedSectors;
pb->fatCount = 2;
pb->rootDirEntryCount = 512;
pb->mediaType = 0XF8;
pb->sectorsPerFat16 = fatSize;
pb->sectorsPerTrack = sectorsPerTrack;
pb->headCount = numberOfHeads;
pb->hidddenSectors = relSector;
pb->totalSectors32 = partSize;
pb->driveNumber = 0X80;
pb->bootSignature = EXTENDED_BOOT_SIG;
pb->volumeSerialNumber = volSerialNumber();
memcpy(pb->volumeLabel, noName, sizeof(pb->volumeLabel));
memcpy(pb->fileSystemType, fat16str, sizeof(pb->fileSystemType));
// write partition boot sector
if (!writeCache(relSector)) {
sdError("FAT16 write PBS failed");
}
// clear FAT and root directory
clearFatDir(fatStart, dataStart - fatStart);
clearCache(false);
cache.fat16[0] = 0XFFF8;
cache.fat16[1] = 0XFFFF;
// write first block of FAT and backup for reserved clusters
if (!writeCache(fatStart)
|| !writeCache(fatStart + fatSize)) {
sdError("FAT16 reserve failed");
}
}
//------------------------------------------------------------------------------
// format the SD as FAT32
void makeFat32() {
uint32_t nc;
relSector = BU32;
for (dataStart = 2 * BU32;; dataStart += BU32) {
nc = (cardSizeBlocks - dataStart)/sectorsPerCluster;
fatSize = (nc + 2 + 127)/128;
uint32_t r = relSector + 9 + 2 * fatSize;
if (dataStart >= r) {
break;
}
}
// error if too few clusters in FAT32 volume
if (nc < 65525) {
sdError("Bad cluster count");
}
reservedSectors = dataStart - relSector - 2 * fatSize;
fatStart = relSector + reservedSectors;
partSize = nc * sectorsPerCluster + dataStart - relSector;
// type depends on address of end sector
// max CHS has lbn = 16450560 = 1024*255*63
if ((relSector + partSize) <= 16450560) {
// FAT32
partType = 0X0B;
} else {
// FAT32 with INT 13
partType = 0X0C;
}
writeMbr();
clearCache(true);

fat32_boot_t* pb = &cache.fbs32;
pb->jump[0] = 0XEB;
pb->jump[1] = 0X00;
pb->jump[2] = 0X90;
for (uint8_t i = 0; i < sizeof(pb->oemId); i++) {
pb->oemId[i] = ' ';
}
pb->bytesPerSector = 512;
pb->sectorsPerCluster = sectorsPerCluster;
pb->reservedSectorCount = reservedSectors;
pb->fatCount = 2;
pb->mediaType = 0XF8;
pb->sectorsPerTrack = sectorsPerTrack;
pb->headCount = numberOfHeads;
pb->hidddenSectors = relSector;
pb->totalSectors32 = partSize;
pb->sectorsPerFat32 = fatSize;
pb->fat32RootCluster = 2;
pb->fat32FSInfo = 1;
pb->fat32BackBootBlock = 6;
pb->driveNumber = 0X80;
pb->bootSignature = EXTENDED_BOOT_SIG;
pb->volumeSerialNumber = volSerialNumber();
memcpy(pb->volumeLabel, noName, sizeof(pb->volumeLabel));
memcpy(pb->fileSystemType, fat32str, sizeof(pb->fileSystemType));
// write partition boot sector and backup
if (!writeCache(relSector)
|| !writeCache(relSector + 6)) {
sdError("FAT32 write PBS failed");
}
clearCache(true);
// write extra boot area and backup
if (!writeCache(relSector + 2)
|| !writeCache(relSector + 8)) {
sdError("FAT32 PBS ext failed");
}
fat32_fsinfo_t* pf = &cache.fsinfo;
pf->leadSignature = FSINFO_LEAD_SIG;
pf->structSignature = FSINFO_STRUCT_SIG;
pf->freeCount = 0XFFFFFFFF;
pf->nextFree = 0XFFFFFFFF;
// write FSINFO sector and backup
if (!writeCache(relSector + 1)
|| !writeCache(relSector + 7)) {
sdError("FAT32 FSINFO failed");
}
clearFatDir(fatStart, 2 * fatSize + sectorsPerCluster);
clearCache(false);
cache.fat32[0] = 0x0FFFFFF8;
cache.fat32[1] = 0x0FFFFFFF;
cache.fat32[2] = 0x0FFFFFFF;
// write first block of FAT and backup for reserved clusters
if (!writeCache(fatStart)
|| !writeCache(fatStart + fatSize)) {
sdError("FAT32 reserve failed");
}
}
//------------------------------------------------------------------------------
// flash erase all data
uint32_t const ERASE_SIZE = 262144L;
void eraseCard() {
cout << endl << F("Erasing\n");
uint32_t firstBlock = 0;
uint32_t lastBlock;
uint16_t n = 0;

do {
lastBlock = firstBlock + ERASE_SIZE - 1;
if (lastBlock >= cardSizeBlocks) {
lastBlock = cardSizeBlocks - 1;
}
if (!card.erase(firstBlock, lastBlock)) {
sdError("erase failed");
}
cout << '.';
if ((n++)%32 == 31) {
cout << endl;
}
firstBlock += ERASE_SIZE;
} while (firstBlock < cardSizeBlocks);
cout << endl;

if (!card.readBlock(0, cache.data)) {
sdError("readBlock");
}
cout << hex << showbase << setfill('0') << internal;
cout << F("All data set to ") << setw(4) << int(cache.data[0]) << endl;
cout << dec << noshowbase << setfill(' ') << right;
cout << F("Erase done\n");
}
//------------------------------------------------------------------------------
void formatCard() {
cout << endl;
cout << F("Formatting\n");
initSizes();
if (card.type() != SD_CARD_TYPE_SDHC) {
cout << F("FAT16\n");
makeFat16();
} else {
cout << F("FAT32\n");
makeFat32();
}
#if DEBUG_PRINT
debugPrint();
#endif // DEBUG_PRINT
cout << F("Format done\n");
}
//------------------------------------------------------------------------------
void setup() {
char c;
Serial.begin(9600);
// Wait for USB Serial
while (!Serial) {
SysCall::yield();
}
cout << F("Type any character to start\n");
while (!Serial.available()) {
SysCall::yield();
}
// Discard any extra characters.
do {
delay(10);
} while (Serial.available() && Serial.read() >= 0);
cout << F(
"\n"
"This program can erase and/or format SD/SDHC cards.\n"
"\n"
"Erase uses the card's fast flash erase command.\n"
"Flash erase sets all data to 0X00 for most cards\n"
"and 0XFF for a few vendor's cards.\n"
"\n"
"Cards larger than 2 GB will be formatted FAT32 and\n"
"smaller cards will be formatted FAT16.\n"
"\n"
"Warning, all data on the card will be erased.\n"
"Enter 'Y' to continue: ");
while (!Serial.available()) {
SysCall::yield();
}

c = Serial.read();
cout << c << endl;
if (c != 'Y') {
cout << F("Quiting, you did not enter 'Y'.\n");
return;
}
// Read any existing Serial data.
do {
delay(10);
} while (Serial.available() && Serial.read() >= 0);

cout << F(
"\n"
"Options are:\n"
"E - erase the card and skip formatting.\n"
"F - erase and then format the card. (recommended)\n"
"Q - quick format the card without erase.\n"
"\n"
"Enter option: ");

while (!Serial.available()) {
SysCall::yield();
}
c = Serial.read();
cout << c << endl;
if (!strchr("EFQ", c)) {
cout << F("Quiting, invalid option entered.") << endl;
return;
}
#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");
}
cardCapacityMB = (cardSizeBlocks + 2047)/2048;

cout << F("Card Size: ") << setprecision(0) << 1.048576*cardCapacityMB;
cout << F(" MB, (MB = 1,000,000 bytes)") << endl;

if (c == 'E' || c == 'F') {
eraseCard();
}
if (c == 'F' || c == 'Q') {
formatCard();
}
}
//------------------------------------------------------------------------------
void loop() {}

+ 248
- 0
examples/examplesV1/SdInfo/SdInfo.ino Bestand weergeven

@@ -0,0 +1,248 @@
/*
* This program attempts to initialize an SD card and analyze its structure.
*/
#include <SPI.h>
#include "SdFat.h"
#include "sdios.h"
#error Use new Version 2 SdInfo
// Set USE_SDIO to zero for SPI card access.
#define USE_SDIO 0
/*
* SD chip select pin. Common values are:
*
* Arduino Ethernet shield, pin 4.
* SparkFun SD shield, pin 8.
* Adafruit SD shields and modules, pin 10.
* Default SD chip select is the SPI SS pin.
*/
const uint8_t SD_CHIP_SELECT = SS;
/*
* Set DISABLE_CHIP_SELECT to disable a second SPI device.
* For example, with the Ethernet shield, set DISABLE_CHIP_SELECT
* 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);

// global for card size
uint32_t cardSize;

// global for card erase size
uint32_t eraseSize;
//------------------------------------------------------------------------------
// store error strings in flash
#define sdErrorMsg(msg) sd.errorPrint(F(msg));
//------------------------------------------------------------------------------
uint8_t cidDmp() {
cid_t cid;
if (!sd.card()->readCID(&cid)) {
sdErrorMsg("readCID failed");
return false;
}
cout << F("\nManufacturer ID: ");
cout << hex << int(cid.mid) << dec << endl;
cout << F("OEM ID: ") << cid.oid[0] << cid.oid[1] << endl;
cout << F("Product: ");
for (uint8_t i = 0; i < 5; i++) {
cout << cid.pnm[i];
}
cout << F("\nVersion: ");
cout << int(cid.prv_n) << '.' << int(cid.prv_m) << endl;
cout << F("Serial number: ") << hex << cid.psn << dec << endl;
cout << F("Manufacturing date: ");
cout << int(cid.mdt_month) << '/';
cout << (2000 + cid.mdt_year_low + 10 * cid.mdt_year_high) << endl;
cout << endl;
return true;
}
//------------------------------------------------------------------------------
uint8_t csdDmp() {
csd_t csd;
uint8_t eraseSingleBlock;
if (!sd.card()->readCSD(&csd)) {
sdErrorMsg("readCSD failed");
return false;
}
if (csd.v1.csd_ver == 0) {
eraseSingleBlock = csd.v1.erase_blk_en;
eraseSize = (csd.v1.sector_size_high << 1) | csd.v1.sector_size_low;
} else if (csd.v2.csd_ver == 1) {
eraseSingleBlock = csd.v2.erase_blk_en;
eraseSize = (csd.v2.sector_size_high << 1) | csd.v2.sector_size_low;
} else {
cout << F("csd version error\n");
return false;
}
eraseSize++;
cout << F("cardSize: ") << 0.000512*cardSize;
cout << F(" MB (MB = 1,000,000 bytes)\n");

cout << F("flashEraseSize: ") << int(eraseSize) << F(" blocks\n");
cout << F("eraseSingleBlock: ");
if (eraseSingleBlock) {
cout << F("true\n");
} else {
cout << F("false\n");
}
return true;
}
//------------------------------------------------------------------------------
// print partition table
uint8_t partDmp() {
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 = &mbr.part[ip - 1];
if ((pt->boot & 0X7F) != 0 || pt->firstSector > cardSize) {
cout << F("\nNo MBR. Assuming Super Floppy format.\n");
return true;
}
}
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 = &mbr.part[ip - 1];
cout << int(ip) << ',' << hex << int(pt->boot) << ',' << int(pt->type);
cout << dec << ',' << pt->firstSector <<',' << pt->totalSectors << endl;
}
return true;
}
//------------------------------------------------------------------------------
void volDmp() {
cout << F("\nVolume is FAT") << int(sd.vol()->fatType()) << endl;
cout << F("blocksPerCluster: ") << int(sd.vol()->blocksPerCluster()) << endl;
cout << F("clusterCount: ") << sd.vol()->clusterCount() << endl;
cout << F("freeClusters: ");
uint32_t volFree = sd.vol()->freeClusterCount();
cout << volFree << endl;
float fs = 0.000512*volFree*sd.vol()->blocksPerCluster();
cout << F("freeSpace: ") << fs << F(" MB (MB = 1,000,000 bytes)\n");
cout << F("fatStartBlock: ") << sd.vol()->fatStartBlock() << endl;
cout << F("fatCount: ") << int(sd.vol()->fatCount()) << endl;
cout << F("blocksPerFat: ") << sd.vol()->blocksPerFat() << endl;
cout << F("rootDirStart: ") << sd.vol()->rootDirStart() << endl;
cout << F("dataStartBlock: ") << sd.vol()->dataStartBlock() << endl;
if (sd.vol()->dataStartBlock() % eraseSize) {
cout << F("Data area is not aligned on flash erase boundaries!\n");
cout << F("Download and use formatter from www.sdcard.org!\n");
}
}
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
// Wait for USB Serial
while (!Serial) {
SysCall::yield();
}

// use uppercase in hex and use 0X base prefix
cout << uppercase << showbase << endl;

// 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"
"Edit DISABLE_CHIP_SELECT to disable another device.\n");
} else {
cout << F("\nDisabling SPI device on pin ");
cout << int(DISABLE_CHIP_SELECT) << endl;
pinMode(DISABLE_CHIP_SELECT, OUTPUT);
digitalWrite(DISABLE_CHIP_SELECT, HIGH);
}
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() {
// Read any existing Serial data.
do {
delay(10);
} while (Serial.available() && Serial.read() >= 0);

// F stores strings in flash to save RAM
cout << F("\ntype any character to start\n");
while (!Serial.available()) {
SysCall::yield();
}

uint32_t t = millis();
#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();
if (cardSize == 0) {
sdErrorMsg("cardSize failed");
return;
}
cout << F("\ninit time: ") << t << " ms" << endl;
cout << F("\nCard type: ");
switch (sd.card()->type()) {
case SD_CARD_TYPE_SD1:
cout << F("SD1\n");
break;

case SD_CARD_TYPE_SD2:
cout << F("SD2\n");
break;

case SD_CARD_TYPE_SDHC:
if (cardSize < 70000000) {
cout << F("SDHC\n");
} else {
cout << F("SDXC\n");
}
break;

default:
cout << F("Unknown\n");
}
if (!cidDmp()) {
return;
}
if (!csdDmp()) {
return;
}
uint32_t ocr;
if (!sd.card()->readOCR(&ocr)) {
sdErrorMsg("\nreadOCR failed");
return;
}
cout << F("OCR: ") << hex << ocr << dec << endl;
if (!partDmp()) {
return;
}
if (!sd.fsBegin()) {
sdErrorMsg("\nFile System initialization failed.\n");
return;
}
volDmp();
}

+ 59
- 0
examples/examplesV1/SoftwareSpi/SoftwareSpi.ino Bestand weergeven

@@ -0,0 +1,59 @@
// An example of the SdFatSoftSpi template class.
// This example is for an Adafruit Data Logging Shield on a Mega.
// Software SPI is required on Mega since this shield connects to pins 10-13.
// This example will also run on an Uno and other boards using software SPI.
//
#include <SPI.h>
#include "SdFat.h"
#error See Version 2 software SPI example
#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;
const uint8_t SOFT_MOSI_PIN = 11;
const uint8_t SOFT_SCK_PIN = 13;
//
// Chip select may be constant or RAM variable.
const uint8_t SD_CHIP_SELECT_PIN = 10;

// SdFat software SPI template
SdFatSoftSpi<SOFT_MISO_PIN, SOFT_MOSI_PIN, SOFT_SCK_PIN> sd;

// Test file.
SdFile file;

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();
}

if (!sd.begin(SD_CHIP_SELECT_PIN)) {
sd.initErrorHalt();
}

if (!file.open("SoftSPI.txt", O_RDWR | O_CREAT)) {
sd.errorHalt(F("open failed"));
}
file.println(F("This line was printed using software SPI."));

file.rewind();
while (file.available()) {
Serial.write(file.read());
}

file.close();

Serial.println(F("Done."));
}
//------------------------------------------------------------------------------
void loop() {}
#else // ENABLE_SOFTWARE_SPI_CLASS
#error ENABLE_SOFTWARE_SPI_CLASS must be set non-zero in SdFat/SdFatConfig.h
#endif //ENABLE_SOFTWARE_SPI_CLASS

examples/StdioBench/StdioBench.ino → examples/examplesV1/StdioBench/StdioBench.ino Bestand weergeven

@@ -1,6 +1,7 @@
// Benchmark comparing SdFile and StdioStream.
#include <SPI.h>
#include "SdFat.h"
#include "sdios.h"

// Define PRINT_FIELD nonzero to use printField.
#define PRINT_FIELD 0
@@ -24,9 +25,9 @@ const char* label[] =
};
//------------------------------------------------------------------------------
void setup() {
uint32_t printSize;
uint32_t printSize = 0;
uint32_t stdioSize = 0;
uint32_t printTime;
uint32_t printTime = 0;
uint32_t stdioTime = 0;

Serial.begin(9600);

+ 169
- 0
examples/examplesV1/TeensySdioDemo/TeensySdioDemo.ino Bestand weergeven

@@ -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"
#error See Version 2 SDIO example
// 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();
}

examples/Timestamp/Timestamp.ino → examples/examplesV1/Timestamp/Timestamp.ino Bestand weergeven

@@ -5,7 +5,6 @@
#include <SPI.h>
#include "SdFat.h"
#include "sdios.h"

SdFat sd;

SdFile file;
@@ -52,25 +51,12 @@ void dateTime(uint16_t* date, uint16_t* time) {
* Function to print all timestamps.
*/
void printTimestamps(SdFile& f) {
dir_t d;
if (!f.dirEntry(&d)) {
error("f.dirEntry failed");
}

cout << F("Creation: ");
f.printFatDate(d.creationDate);
cout << ' ';
f.printFatTime(d.creationTime);
cout << endl;

cout << F("Modify: ");
f.printFatDate(d.lastWriteDate);
cout <<' ';
f.printFatTime(d.lastWriteTime);
cout << endl;

cout << F("Access: ");
f.printFatDate(d.lastAccessDate);
f.printCreateDateTime(&Serial);
cout << endl << F("Modify: ");
f.printModifyDateTime(&Serial);
cout << endl << F("Access: ");
f.printAccessDateTime(&Serial);
cout << endl;
}
//------------------------------------------------------------------------------

examples/TwoCards/TwoCards.ino → examples/examplesV1/TwoCards/TwoCards.ino Bestand weergeven


examples/VolumeFreeSpace/VolumeFreeSpace.ino → examples/examplesV1/VolumeFreeSpace/VolumeFreeSpace.ino Bestand weergeven

@@ -36,7 +36,7 @@ void printFreeSpace() {
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
// Wait for USB Serial
// Wait for USB Serial
while (!Serial) {
SysCall::yield();
}
@@ -55,22 +55,22 @@ void setup() {
if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
sd.initErrorHalt();
}
// Insure no TEST_FILE.
// Insure no TEST_FILE.
sd.remove(TEST_FILE);
cout << F("\nFirst call to freeClusterCount scans the FAT.\n\n");
printFreeSpace();
cout << F("Create and write to ") << TEST_FILE << endl;
if (!file.open(TEST_FILE, O_WRONLY | O_CREAT)) {
sd.errorHalt(F("Create failed"));
}
file.print(F("Cause a cluster to be allocated"));
file.close();
cout << F("\nSecond freeClusterCount call is faster if\n");
cout << F("MAINTAIN_FREE_CLUSTER_COUNT is nonzero.\n\n");
printFreeSpace();

cout << F("Remove ") << TEST_FILE << endl << endl;

+ 222
- 0
examples/examplesV1/bench/bench.ino Bestand weergeven

@@ -0,0 +1,222 @@
/*
* This program is a simple binary write/read benchmark.
*/
#include <SPI.h>
#include "SdFat.h"
#include "sdios.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;

// Size of read/write.
const size_t BUF_SIZE = 512;

// File size in MB where MB = 1,000,000 bytes.
const uint32_t FILE_SIZE_MB = 5;

// Write pass count.
const uint8_t WRITE_COUNT = 2;

// Read pass count.
const uint8_t READ_COUNT = 2;
//==============================================================================
// End of configuration constants.
//------------------------------------------------------------------------------
// File size in bytes.
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;
#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;

// test file
SdFile file;

// Serial output stream
ArduinoOutStream cout(Serial);
//------------------------------------------------------------------------------
// Store error strings in flash to save RAM.
#define error(s) sd.errorHalt(F(s))
//------------------------------------------------------------------------------
void cidDmp() {
cid_t cid;
if (!sd.card()->readCID(&cid)) {
error("readCID failed");
}
cout << F("\nManufacturer ID: ");
cout << hex << int(cid.mid) << dec << endl;
cout << F("OEM ID: ") << cid.oid[0] << cid.oid[1] << endl;
cout << F("Product: ");
for (uint8_t i = 0; i < 5; i++) {
cout << cid.pnm[i];
}
cout << F("\nVersion: ");
cout << int(cid.prv_n) << '.' << int(cid.prv_m) << endl;
cout << F("Serial number: ") << hex << cid.psn << dec << endl;
cout << F("Manufacturing date: ");
cout << int(cid.mdt_month) << '/';
cout << (2000 + cid.mdt_year_low + 10 * cid.mdt_year_high) << endl;
cout << endl;
}
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);

// Wait for USB Serial
while (!Serial) {
SysCall::yield();
}
delay(1000);
cout << F("\nUse a freshly formatted SD for best performance.\n");

// use uppercase in hex and use 0X base prefix
cout << uppercase << showbase << endl;
}
//------------------------------------------------------------------------------
void loop() {
float s;
uint32_t t;
uint32_t maxLatency;
uint32_t minLatency;
uint32_t totalLatency;

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

// F( stores strings in flash to save RAM
cout << F("Type any character to start\n");
while (!Serial.available()) {
SysCall::yield();
}
cout << F("chipSelect: ") << int(chipSelect) << endl;
cout << F("FreeStack: ") << FreeStack() << endl;

#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;

cidDmp();

// open or create file - truncate existing file.
if (!file.open("bench.dat", O_RDWR | O_CREAT | O_TRUNC)) {
error("open failed");
}

// fill buf with known data
for (size_t i = 0; i < (BUF_SIZE-2); i++) {
buf[i] = 'A' + (i % 26);
}
buf[BUF_SIZE-2] = '\r';
buf[BUF_SIZE-1] = '\n';

cout << F("File size ") << FILE_SIZE_MB << F(" MB\n");
cout << F("Buffer size ") << BUF_SIZE << F(" bytes\n");
cout << F("Starting write test, please wait.") << endl << endl;

// do write test
uint32_t n = FILE_SIZE/sizeof(buf);
cout <<F("write speed and latency") << endl;
cout << F("speed,max,min,avg") << endl;
cout << F("KB/Sec,usec,usec,usec") << endl;
for (uint8_t nTest = 0; nTest < WRITE_COUNT; nTest++) {
file.truncate(0);
maxLatency = 0;
minLatency = 9999999;
totalLatency = 0;
t = millis();
for (uint32_t i = 0; i < n; i++) {
uint32_t m = micros();
if (file.write(buf, sizeof(buf)) != sizeof(buf)) {
sd.errorPrint("write failed");
file.close();
return;
}
m = micros() - m;
if (maxLatency < m) {
maxLatency = m;
}
if (minLatency > m) {
minLatency = m;
}
totalLatency += m;
}
file.sync();
t = millis() - t;
s = file.fileSize();
cout << s/t <<',' << maxLatency << ',' << minLatency;
cout << ',' << totalLatency/n << endl;
}
cout << endl << F("Starting read test, please wait.") << endl;
cout << endl <<F("read speed and latency") << endl;
cout << F("speed,max,min,avg") << endl;
cout << F("KB/Sec,usec,usec,usec") << endl;

// do read test
for (uint8_t nTest = 0; nTest < READ_COUNT; nTest++) {
file.rewind();
maxLatency = 0;
minLatency = 9999999;
totalLatency = 0;
t = millis();
for (uint32_t i = 0; i < n; i++) {
buf[BUF_SIZE-1] = 0;
uint32_t m = micros();
int32_t nr = file.read(buf, sizeof(buf));
if (nr != sizeof(buf)) {
sd.errorPrint("read failed");
file.close();
return;
}
m = micros() - m;
if (maxLatency < m) {
maxLatency = m;
}
if (minLatency > m) {
minLatency = m;
}
totalLatency += m;
if (buf[BUF_SIZE-1] != '\n') {
error("data check");
}
}
s = file.fileSize();
t = millis() - t;
cout << s/t <<',' << maxLatency << ',' << minLatency;
cout << ',' << totalLatency/n << endl;
}
cout << endl << F("Done") << endl;
file.close();
}

examples/dataLogger/dataLogger.ino → examples/examplesV1/dataLogger/dataLogger.ino Bestand weergeven


examples/fgets/fgets.ino → examples/examplesV1/fgets/fgets.ino Bestand weergeven


examples/formatting/formatting.ino → examples/examplesV1/formatting/formatting.ino Bestand weergeven


examples/getline/getline.ino → examples/examplesV1/getline/getline.ino Bestand weergeven


+ 106
- 0
examples/examplesV1/rename/rename.ino Bestand weergeven

@@ -0,0 +1,106 @@
/*
* This program demonstrates use of SdFile::rename()
* and SdFat::rename().
*/
#include <SPI.h>
#include "SdFat.h"
#include "sdios.h"

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

// file system
SdFat sd;

// Serial print stream
ArduinoOutStream cout(Serial);
//------------------------------------------------------------------------------
// store error strings in flash to save RAM
#define error(s) sd.errorHalt(F(s))
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);

// Wait for USB Serial
while (!Serial) {
SysCall::yield();
}
cout << F("Insert an empty SD. Type any character to start.") << endl;
while (!Serial.available()) {
SysCall::yield();
}

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

// Remove file/dirs from previous run.
if (sd.exists("dir2/DIR3/NAME3.txt")) {
cout << F("Removing /dir2/DIR3/NAME3.txt") << endl;
if (!sd.remove("dir2/DIR3/NAME3.txt") ||
!sd.rmdir("dir2/DIR3/") ||
!sd.rmdir("dir2/")) {
error("remove/rmdir failed");
}
}
// create a file and write one line to the file
SdFile file("Name1.txt", O_WRONLY | O_CREAT);
if (!file.isOpen()) {
error("Name1.txt");
}
file.println("A test line for Name1.txt");

// rename the file name2.txt and add a line.
if (!file.rename("name2.txt")) {
error("name2.txt");
}
file.println("A test line for name2.txt");

// list files
cout << F("------") << endl;
sd.ls(LS_R);

// make a new directory - "Dir1"
if (!sd.mkdir("Dir1")) {
error("Dir1");
}

// move file into Dir1, rename it NAME3.txt and add a line
if (!file.rename("Dir1/NAME3.txt")) {
error("NAME3.txt");
}
file.println("A line for Dir1/NAME3.txt");

// list files
cout << F("------") << endl;
sd.ls(LS_R);

// make directory "dir2"
if (!sd.mkdir("dir2")) {
error("dir2");
}

// close file before rename(oldPath, newPath)
file.close();

// move Dir1 into dir2 and rename it DIR3
if (!sd.rename("Dir1", "dir2/DIR3")) {
error("dir2/DIR3");
}

// open file for append in new location and add a line
if (!file.open("dir2/DIR3/NAME3.txt", O_WRONLY | O_APPEND)) {
error("dir2/DIR3/NAME3.txt");
}
file.println("A line for dir2/DIR3/NAME3.txt");
file.close();

// list files
cout << F("------") << endl;
sd.ls(LS_R);

cout << F("Done") << endl;
}
void loop() {}

+ 66
- 0
examples/examplesV1/v1v2.txt Bestand weergeven

@@ -0,0 +1,66 @@
diff -rb "C:\\Users\\bill\\Documents\\Arduino\\libraries\\SdFat\\examples/STM32Test/STM32Test.ino" "C:\\Users\\bill\\Documents\\ArduinoSdFat\\libraries\\SdFat\\examples\\examplesV1/STM32Test/STM32Test.ino"
8c8
<
---
> #error See new Version 2 STM32 example
diff -rb "C:\\Users\\bill\\Documents\\Arduino\\libraries\\SdFat\\examples/SdFormatter/SdFormatter.ino" "C:\\Users\\bill\\Documents\\ArduinoSdFat\\libraries\\SdFat\\examples\\examplesV1/SdFormatter/SdFormatter.ino"
14c14
<
---
> #error use new Version 2 SdFormatter
diff -rb "C:\\Users\\bill\\Documents\\Arduino\\libraries\\SdFat\\examples/SdInfo/SdInfo.ino" "C:\\Users\\bill\\Documents\\ArduinoSdFat\\libraries\\SdFat\\examples\\examplesV1/SdInfo/SdInfo.ino"
7c7
<
---
> #error Use new Version 2 SdInfo
diff -rb "C:\\Users\\bill\\Documents\\Arduino\\libraries\\SdFat\\examples/SoftwareSpi/SoftwareSpi.ino" "C:\\Users\\bill\\Documents\\ArduinoSdFat\\libraries\\SdFat\\examples\\examplesV1/SoftwareSpi/SoftwareSpi.ino"
7a8
> #error See Version 2 software SPI example
diff -rb "C:\\Users\\bill\\Documents\\Arduino\\libraries\\SdFat\\examples/StdioBench/StdioBench.ino" "C:\\Users\\bill\\Documents\\ArduinoSdFat\\libraries\\SdFat\\examples\\examplesV1/StdioBench/StdioBench.ino"
3a4
> #include "sdios.h"
27c28
< uint32_t printSize;
---
> uint32_t printSize = 0;
29c30
< uint32_t printTime;
---
> uint32_t printTime = 0;
diff -rb "C:\\Users\\bill\\Documents\\Arduino\\libraries\\SdFat\\examples/TeensySdioDemo/TeensySdioDemo.ino" "C:\\Users\\bill\\Documents\\ArduinoSdFat\\libraries\\SdFat\\examples\\examplesV1/TeensySdioDemo/TeensySdioDemo.ino"
9c9
<
---
> #error See Version 2 SDIO example
diff -rb "C:\\Users\\bill\\Documents\\Arduino\\libraries\\SdFat\\examples/Timestamp/Timestamp.ino" "C:\\Users\\bill\\Documents\\ArduinoSdFat\\libraries\\SdFat\\examples\\examplesV1/Timestamp/Timestamp.ino"
8d7
<
55,59d53
< dir_t d;
< if (!f.dirEntry(&d)) {
< error("f.dirEntry failed");
< }
<
61,73c55,59
< f.printFatDate(d.creationDate);
< cout << ' ';
< f.printFatTime(d.creationTime);
< cout << endl;
<
< cout << F("Modify: ");
< f.printFatDate(d.lastWriteDate);
< cout <<' ';
< f.printFatTime(d.lastWriteTime);
< cout << endl;
<
< cout << F("Access: ");
< f.printFatDate(d.lastAccessDate);
---
> f.printCreateDateTime(&Serial);
> cout << endl << F("Modify: ");
> f.printModifyDateTime(&Serial);
> cout << endl << F("Access: ");
> f.printAccessDateTime(&Serial);
diff -rb "C:\\Users\\bill\\Documents\\Arduino\\libraries\\SdFat\\examples/wipe/wipe.ino" "C:\\Users\\bill\\Documents\\ArduinoSdFat\\libraries\\SdFat\\examples\\examplesV1/wipe/wipe.ino"
1a2
> #error wipe is not supported in SdFat V2. Use bool format(print_t* pr = nullptr).

examples/wipe/wipe.ino → examples/examplesV1/wipe/wipe.ino Bestand weergeven

@@ -1,4 +1,5 @@
// Example to wipe all data from an already formatted SD.
#error wipe is not supported in SdFat V2. Use bool format(print_t* pr = nullptr).
#include <SPI.h>
#include "SdFat.h"
const int chipSelect = SS;
@@ -39,4 +40,4 @@ void setup() {
}

void loop() {
}
}

+ 54
- 17
examples/rename/rename.ino Bestand weergeven

@@ -1,27 +1,66 @@
/*
* This program demonstrates use of SdFile::rename()
* and SdFat::rename().
* This program demonstrates use of rename().
*/
#include <SPI.h>
#include "SdFat.h"
#include "sdios.h"

// SD chip select pin
const uint8_t chipSelect = SS;
// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 0

// file system
/*
Change the value of SD_CS_PIN if you are using SPI and
your hardware does not use the default value, SS.
Common values are:
Arduino Ethernet shield: pin 4
Sparkfun SD shield: pin 8
Adafruit SD shields and modules: pin 10
*/

// SDCARD_SS_PIN is defined for the built-in SD on some boards.
#ifndef SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SS;
#else // SDCARD_SS_PIN
// Assume built-in SD is used.
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#endif // SDCARD_SS_PIN


// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI)
#else // HAS_SDIO_CLASS
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI)
#endif // HAS_SDIO_CLASS

#if SD_FAT_TYPE == 0
SdFat sd;
File file;
#elif SD_FAT_TYPE == 1
SdFat32 sd;
File32 file;
#elif SD_FAT_TYPE == 2
SdExFat sd;
ExFile file;
#elif SD_FAT_TYPE == 3
SdFs sd;
FsFile file;
#else // SD_FAT_TYPE
#error Invalid SD_FAT_TYPE
#endif // SD_FAT_TYPE

// Serial print stream
ArduinoOutStream cout(Serial);
//------------------------------------------------------------------------------
// store error strings in flash to save RAM
#define error(s) sd.errorHalt(F(s))
#define error(s) sd.errorHalt(&Serial, F(s))
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
// Wait for USB Serial
// Wait for USB Serial
while (!Serial) {
SysCall::yield();
}
@@ -32,8 +71,8 @@ void setup() {

// 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.begin(SD_CONFIG)) {
sd.initErrorHalt(&Serial);
}

// Remove file/dirs from previous run.
@@ -46,15 +85,13 @@ void setup() {
}
}
// create a file and write one line to the file
SdFile file("Name1.txt", O_WRONLY | O_CREAT);
if (!file.isOpen()) {
if (!file.open("Name1.txt", O_WRONLY | O_CREAT)) {
error("Name1.txt");
}
file.println("A test line for Name1.txt");

// rename the file name2.txt and add a line.
// sd.vwd() is the volume working directory, root.
if (!file.rename(sd.vwd(), "name2.txt")) {
if (!file.rename("name2.txt")) {
error("name2.txt");
}
file.println("A test line for name2.txt");
@@ -69,7 +106,7 @@ void setup() {
}

// move file into Dir1, rename it NAME3.txt and add a line
if (!file.rename(sd.vwd(), "Dir1/NAME3.txt")) {
if (!file.rename("Dir1/NAME3.txt")) {
error("NAME3.txt");
}
file.println("A line for Dir1/NAME3.txt");
@@ -104,4 +141,4 @@ void setup() {

cout << F("Done") << endl;
}
void loop() {}
void loop() {}

BIN
extras/AnalogBinLoggerExtras/ADC_ENOB.PNG Bestand weergeven

Before After
Width: 640  |  Height: 444  |  Size: 87KB

BIN
extras/AnalogBinLoggerExtras/ADCdocs/ATmegaADCAccuracy.pdf Bestand weergeven


BIN
extras/AnalogBinLoggerExtras/ADCdocs/ExcelFFT.pdf Bestand weergeven


+ 0
- 98
extras/AnalogBinLoggerExtras/AdcErrorStudy.txt Bestand weergeven

@@ -1,98 +0,0 @@
Static Tests of the Arduino Internal ADC.

Several people have asked about the DC accuracy of the Arduino ADC when used in my data logging applications at slow sample rates.

Here are my results of some "hobby level" measurements of the Arduino ADC.

One question is how important is the ADC clock rate. I did measurents for an ADC clock rate of 125 kHz to 2MHz.

Another question is how much does Noise Reduction Mode help. I did a series of measurements using this mode.

Noise Reduction Mode only reduced the mean absolute error slightly.

I do calibration to remove Offset Error and Gain Error. Calibration is very important for good accuracy.

These tests depend on the Arduino voltage regulator providing a stable voltage during the tests. The Arduino ADC reference voltage is Vcc for these tests. This may not be realistic for practical applications

Integral Non-linearity (INL) is the main remaining source of error.

Here are my results for static (DC) tests of the internal ADC for three UNOs.

The Arduinos are powered by a high quality nine volt power supply.

These tests measure a DC level so do not include problems due to time jitter, S/H time, and other dynamic errors.
There are several studies of the dynamic behavior of the Arduino ADC that determine ENOB (Effective Number Of Bits).

I used a shield with a 12-bit MCP4921 DAC to generate voltage levels. This ADC has an output buffer so it provides a very low impedance source.

I measured the voltage of the DAC with a calibrated 18-bit MCP3422 ADC on the shield.

I used DAC levels from 20 to 4075 to avoid zero offset errors at low voltages and DAC buffer problems at high voltages.

Each series of measurements has 4056 data points.

This is a voltage range of about 0.023 to 4.972 volts.

I calibrated the Arduino ADC for each series of measurements with a linear fit of the form.

v = a + b*adcValue

Errors are the difference between the value measured with the 18-bit ADC and the calibrated value measured with the AVR ADC.

I also show the results for no calibration, the NoCal column, using the datasheet formula.

Vin = Vref*adcValue/1024


The rows in the tables tables are.

Min - minimum error in millivolts

Max - maximum error in millivolts

MAE - mean absolute error in millivolts


The columns in the tables are:

Ideal - results for a perfect 10-bit ADC for comparison.

NoCal - datasheet formula (5/1024)*adcValue with Noise Reduction Mode.

NR128 - Noise Reduction mode with Prescaler of 128 (ADC clock of 125 kHz).

PS128 - analogRead with Prescaler of 128 (ADC clock of 125 kHz).

PS64 - analogRead with Prescaler of 64 (ADC clock of 250 kHz).

PS32 - analogRead with Prescaler of 32 (ADC clock of 500 kHz).

PS16 - analogRead with Prescaler of 16 (ADC clock of 1 MHz).

PS8 - analogRead with Prescaler of 8 (ADC clock of 2 MHz).


Results for three UNO Arduinos

First Arduino - Error Millivolts
Ideal NoCal NR128 PS128 PS64 PS32 PS16 PS8
Min -2.44 -2.43 -3.72 -4.01 -3.88 -4.53 -6.57 -27.18
Max 2.44 11.69 3.74 4.24 4.15 5.17 8.69 23.21
MAE 1.22 5.02 1.33 1.38 1.37 1.44 1.96 4.11

Second Arduino - Error Millivolts

Ideal NoCal NR128 PS128 PS64 PS32 PS16 PS8
Min -2.44 -9.24 -4.87 -4.86 -5.05 -5.34 -6.52 -24.04
Max 2.44 11.62 3.95 4.64 4.69 5.71 8.41 21.29
MAE 1.22 5.33 1.41 1.43 1.44 1.53 2.02 4.05

Third Arduino - Error Millivolts

Ideal NoCal NR128 PS128 PS64 PS32 PS16 PS8
Min -2.44 -7.88 -4.12 -4.40 -4.32 -4.41 -6.97 -26.93
Max 2.44 12.53 3.80 4.04 4.18 5.27 8.84 24.59
MAE 1.22 4.85 1.29 1.33 1.34 1.42 1.91 4.10



+ 0
- 0
extras/AnalogBinLoggerExtras/DATA.png Bestand weergeven


Some files were not shown because too many files changed in this diff

Laden…
Annuleren
Opslaan