Browse Source

Add SD library (not optimised).

master
flabbergast 4 years ago
parent
commit
2c954a58e4

+ 150
- 0
xmega/libraries/SD/File.cpp View File

@@ -0,0 +1,150 @@
/*

SD - a slightly more friendly wrapper for sdfatlib

This library aims to expose a subset of SD card functionality
in the form of a higher level "wrapper" object.

License: GNU General Public License V3
(Because sdfatlib is licensed with this.)

(C) Copyright 2010 SparkFun Electronics

*/

#include <SD.h>

/* for debugging file open/close leaks
uint8_t nfilecount=0;
*/

File::File(SdFile f, const char *n) {
// oh man you are kidding me, new() doesnt exist? Ok we do it by hand!
_file = (SdFile *)malloc(sizeof(SdFile));
if (_file) {
memcpy(_file, &f, sizeof(SdFile));
strncpy(_name, n, 12);
_name[12] = 0;
/* for debugging file open/close leaks
nfilecount++;
Serial.print("Created \"");
Serial.print(n);
Serial.print("\": ");
Serial.println(nfilecount, DEC);
*/
}
}

File::File(void) {
_file = 0;
_name[0] = 0;
//Serial.print("Created empty file object");
}

File::~File(void) {
// Serial.print("Deleted file object");
}

// returns a pointer to the file name
char *File::name(void) {
return _name;
}

// a directory is a special type of file
boolean File::isDirectory(void) {
return (_file && _file->isDir());
}


size_t File::write(uint8_t val) {
return write(&val, 1);
}

size_t File::write(const uint8_t *buf, size_t size) {
size_t t;
if (!_file) {
setWriteError();
return 0;
}
_file->clearWriteError();
t = _file->write(buf, size);
if (_file->getWriteError()) {
setWriteError();
return 0;
}
return t;
}

int File::peek() {
if (! _file)
return 0;

int c = _file->read();
if (c != -1) _file->seekCur(-1);
return c;
}

int File::read() {
if (_file)
return _file->read();
return -1;
}

// buffered read for more efficient, high speed reading
int File::read(void *buf, uint16_t nbyte) {
if (_file)
return _file->read(buf, nbyte);
return 0;
}

int File::available() {
if (! _file) return 0;

uint32_t n = size() - position();

return n > 0X7FFF ? 0X7FFF : n;
}

void File::flush() {
if (_file)
_file->sync();
}

boolean File::seek(uint32_t pos) {
if (! _file) return false;

return _file->seekSet(pos);
}

uint32_t File::position() {
if (! _file) return -1;
return _file->curPosition();
}

uint32_t File::size() {
if (! _file) return 0;
return _file->fileSize();
}

void File::close() {
if (_file) {
_file->close();
free(_file);
_file = 0;

/* for debugging file open/close leaks
nfilecount--;
Serial.print("Deleted ");
Serial.println(nfilecount, DEC);
*/
}
}

File::operator bool() {
if (_file)
return _file->isOpen();
return false;
}


+ 15
- 0
xmega/libraries/SD/README.txt View File

@@ -0,0 +1,15 @@
** SD - a slightly more friendly wrapper for sdfatlib **

This library aims to expose a subset of SD card functionality in the
form of a higher level "wrapper" object.

License: GNU General Public License V3
(Because sdfatlib is licensed with this.)

(C) Copyright 2010 SparkFun Electronics

Now better than ever with optimization, multiple file support, directory handling, etc - ladyada!

Modifications for XMEGA (c) 2015 flabbergast - taken from Teensyduino 1.22.
Not optimised in any way on XMEGAs.


+ 616
- 0
xmega/libraries/SD/SD.cpp View File

@@ -0,0 +1,616 @@
/*

SD - a slightly more friendly wrapper for sdfatlib

This library aims to expose a subset of SD card functionality
in the form of a higher level "wrapper" object.

License: GNU General Public License V3
(Because sdfatlib is licensed with this.)

(C) Copyright 2010 SparkFun Electronics


This library provides four key benefits:

* Including `XSD.h` automatically creates a global
`SD` object which can be interacted with in a similar
manner to other standard global objects like `Serial` and `Ethernet`.

* Boilerplate initialisation code is contained in one method named
`begin` and no further objects need to be created in order to access
the SD card.

* Calls to `open` can supply a full path name including parent
directories which simplifies interacting with files in subdirectories.

* Utility methods are provided to determine whether a file exists
and to create a directory heirarchy.


Note however that not all functionality provided by the underlying
sdfatlib library is exposed.

*/

/*

Implementation Notes

In order to handle multi-directory path traversal, functionality that
requires this ability is implemented as callback functions.

Individual methods call the `walkPath` function which performs the actual
directory traversal (swapping between two different directory/file handles
along the way) and at each level calls the supplied callback function.

Some types of functionality will take an action at each level (e.g. exists
or make directory) which others will only take an action at the bottom
level (e.g. open).

*/

#include "SD.h"

// Used by `getNextPathComponent`
#define MAX_COMPONENT_LEN 12 // What is max length?
#define PATH_COMPONENT_BUFFER_LEN MAX_COMPONENT_LEN+1

bool getNextPathComponent(char *path, unsigned int *p_offset,
char *buffer) {
/*

Parse individual path components from a path.

e.g. after repeated calls '/foo/bar/baz' will be split
into 'foo', 'bar', 'baz'.

This is similar to `strtok()` but copies the component into the
supplied buffer rather than modifying the original string.


`buffer` needs to be PATH_COMPONENT_BUFFER_LEN in size.

`p_offset` needs to point to an integer of the offset at
which the previous path component finished.

Returns `true` if more components remain.

Returns `false` if this is the last component.
(This means path ended with 'foo' or 'foo/'.)

*/

// TODO: Have buffer local to this function, so we know it's the
// correct length?

int bufferOffset = 0;

int offset = *p_offset;

// Skip root or other separator
if (path[offset] == '/') {
offset++;
}

// Copy the next next path segment
while (bufferOffset < MAX_COMPONENT_LEN
&& (path[offset] != '/')
&& (path[offset] != '\0')) {
buffer[bufferOffset++] = path[offset++];
}

buffer[bufferOffset] = '\0';

// Skip trailing separator so we can determine if this
// is the last component in the path or not.
if (path[offset] == '/') {
offset++;
}

*p_offset = offset;

return (path[offset] != '\0');
}



boolean walkPath(char *filepath, SdFile& parentDir,
boolean (*callback)(SdFile& parentDir,
char *filePathComponent,
boolean isLastComponent,
void *object),
void *object = NULL) {
/*

When given a file path (and parent directory--normally root),
this function traverses the directories in the path and at each
level calls the supplied callback function while also providing
the supplied object for context if required.

e.g. given the path '/foo/bar/baz'
the callback would be called at the equivalent of
'/foo', '/foo/bar' and '/foo/bar/baz'.

The implementation swaps between two different directory/file
handles as it traverses the directories and does not use recursion
in an attempt to use memory efficiently.

If a callback wishes to stop the directory traversal it should
return false--in this case the function will stop the traversal,
tidy up and return false.

If a directory path doesn't exist at some point this function will
also return false and not subsequently call the callback.

If a directory path specified is complete, valid and the callback
did not indicate the traversal should be interrupted then this
function will return true.

*/


SdFile subfile1;
SdFile subfile2;

char buffer[PATH_COMPONENT_BUFFER_LEN];

unsigned int offset = 0;

SdFile *p_parent;
SdFile *p_child;

SdFile *p_tmp_sdfile;

p_child = &subfile1;

p_parent = &parentDir;

while (true) {

boolean moreComponents = getNextPathComponent(filepath, &offset, buffer);

boolean shouldContinue = callback((*p_parent), buffer, !moreComponents, object);

if (!shouldContinue) {
// TODO: Don't repeat this code?
// If it's one we've created then we
// don't need the parent handle anymore.
if (p_parent != &parentDir) {
(*p_parent).close();
}
return false;
}

if (!moreComponents) {
break;
}

boolean exists = (*p_child).open(*p_parent, buffer, O_RDONLY);

// If it's one we've created then we
// don't need the parent handle anymore.
if (p_parent != &parentDir) {
(*p_parent).close();
}

// Handle case when it doesn't exist and we can't continue...
if (exists) {
// We alternate between two file handles as we go down
// the path.
if (p_parent == &parentDir) {
p_parent = &subfile2;
}

p_tmp_sdfile = p_parent;
p_parent = p_child;
p_child = p_tmp_sdfile;
} else {
return false;
}
}

if (p_parent != &parentDir) {
(*p_parent).close(); // TODO: Return/ handle different?
}

return true;
}



/*

The callbacks used to implement various functionality follow.

Each callback is supplied with a parent directory handle,
character string with the name of the current file path component,
a flag indicating if this component is the last in the path and
a pointer to an arbitrary object used for context.

*/

boolean callback_pathExists(SdFile& parentDir, char *filePathComponent,
boolean isLastComponent, void *object) {
/*

Callback used to determine if a file/directory exists in parent
directory.

Returns true if file path exists.

*/
SdFile child;

boolean exists = child.open(parentDir, filePathComponent, O_RDONLY);

if (exists) {
child.close();
}

return exists;
}



boolean callback_makeDirPath(SdFile& parentDir, char *filePathComponent,
boolean isLastComponent, void *object) {
/*

Callback used to create a directory in the parent directory if
it does not already exist.

Returns true if a directory was created or it already existed.

*/
boolean result = false;
SdFile child;

result = callback_pathExists(parentDir, filePathComponent, isLastComponent, object);
if (!result) {
result = child.makeDir(parentDir, filePathComponent);
}

return result;
}


/*

boolean callback_openPath(SdFile& parentDir, char *filePathComponent,
boolean isLastComponent, void *object) {

Callback used to open a file specified by a filepath that may
specify one or more directories above it.

Expects the context object to be an instance of `SDClass` and
will use the `file` property of the instance to open the requested
file/directory with the associated file open mode property.

Always returns true if the directory traversal hasn't reached the
bottom of the directory heirarchy.

Returns false once the file has been opened--to prevent the traversal
from descending further. (This may be unnecessary.)

if (isLastComponent) {
SDClass *p_SD = static_cast<SDClass*>(object);
p_SD->file.open(parentDir, filePathComponent, p_SD->fileOpenMode);
if (p_SD->fileOpenMode == FILE_WRITE) {
p_SD->file.seekSet(p_SD->file.fileSize());
}
// TODO: Return file open result?
return false;
}
return true;
}
*/



boolean callback_remove(SdFile& parentDir, char *filePathComponent,
boolean isLastComponent, void *object) {
if (isLastComponent) {
return SdFile::remove(parentDir, filePathComponent);
}
return true;
}

boolean callback_rmdir(SdFile& parentDir, char *filePathComponent,
boolean isLastComponent, void *object) {
if (isLastComponent) {
SdFile f;
if (!f.open(parentDir, filePathComponent, O_READ)) return false;
return f.rmDir();
}
return true;
}



/* Implementation of class used to create `SDCard` object. */



boolean SDClass::begin(uint8_t csPin) {
/*

Performs the initialisation required by the sdfatlib library.

Return true if initialization succeeds, false otherwise.

*/
return card.init(SPI_HALF_SPEED, csPin) &&
volume.init(card) &&
root.openRoot(volume);
}



// this little helper is used to traverse paths
SdFile SDClass::getParentDir(const char *filepath, int *index) {
// get parent directory
SdFile d1 = root; // start with the mostparent, root!
SdFile d2;

// we'll use the pointers to swap between the two objects
SdFile *parent = &d1;
SdFile *subdir = &d2;

const char *origpath = filepath;

while (strchr(filepath, '/')) {

// get rid of leading /'s
if (filepath[0] == '/') {
filepath++;
continue;
}

if (! strchr(filepath, '/')) {
// it was in the root directory, so leave now
break;
}

// extract just the name of the next subdirectory
uint8_t idx = strchr(filepath, '/') - filepath;
if (idx > 12)
idx = 12; // dont let them specify long names
char subdirname[13];
strncpy(subdirname, filepath, idx);
subdirname[idx] = 0;

// close the subdir (we reuse them) if open
subdir->close();
if (! subdir->open(parent, subdirname, O_READ)) {
// failed to open one of the subdirectories
return SdFile();
}
// move forward to the next subdirectory
filepath += idx;

// we reuse the objects, close it.
parent->close();

// swap the pointers
SdFile *t = parent;
parent = subdir;
subdir = t;
}

*index = (int)(filepath - origpath);
// parent is now the parent diretory of the file!
return *parent;
}


File SDClass::open(const char *filepath, uint8_t mode) {
/*

Open the supplied file path for reading or writing.

The file content can be accessed via the `file` property of
the `SDClass` object--this property is currently
a standard `SdFile` object from `sdfatlib`.

Defaults to read only.

If `write` is true, default action (when `append` is true) is to
append data to the end of the file.

If `append` is false then the file will be truncated first.

If the file does not exist and it is opened for writing the file
will be created.

An attempt to open a file for reading that does not exist is an
error.

*/

int pathidx;

// do the interative search
SdFile parentdir = getParentDir(filepath, &pathidx);
// no more subdirs!

filepath += pathidx;

if (! filepath[0]) {
// it was the directory itself!
return File(parentdir, "/");
}

// Open the file itself
SdFile file;

// failed to open a subdir!
if (!parentdir.isOpen())
return File();

// there is a special case for the Root directory since its a static dir
if (parentdir.isRoot()) {
if ( ! file.open(SD.root, filepath, mode)) {
// failed to open the file :(
return File();
}
// dont close the root!
} else {
if ( ! file.open(parentdir, filepath, mode)) {
return File();
}
// close the parent
parentdir.close();
}

if (mode & (O_APPEND | O_WRITE))
file.seekSet(file.fileSize());
return File(file, filepath);
}


/*
File SDClass::open(char *filepath, uint8_t mode) {
//

Open the supplied file path for reading or writing.

The file content can be accessed via the `file` property of
the `SDClass` object--this property is currently
a standard `SdFile` object from `sdfatlib`.

Defaults to read only.

If `write` is true, default action (when `append` is true) is to
append data to the end of the file.

If `append` is false then the file will be truncated first.

If the file does not exist and it is opened for writing the file
will be created.

An attempt to open a file for reading that does not exist is an
error.

//

// TODO: Allow for read&write? (Possibly not, as it requires seek.)

fileOpenMode = mode;
walkPath(filepath, root, callback_openPath, this);

return File();

}
*/


//boolean SDClass::close() {
// /*
//
// Closes the file opened by the `open` method.
//
// */
// file.close();
//}


boolean SDClass::exists(char *filepath) {
/*

Returns true if the supplied file path exists.

*/
return walkPath(filepath, root, callback_pathExists);
}


//boolean SDClass::exists(char *filepath, SdFile& parentDir) {
// /*
//
// Returns true if the supplied file path rooted at `parentDir`
// exists.
//
// */
// return walkPath(filepath, parentDir, callback_pathExists);
//}


boolean SDClass::mkdir(char *filepath) {
/*

Makes a single directory or a heirarchy of directories.

A rough equivalent to `mkdir -p`.

*/
return walkPath(filepath, root, callback_makeDirPath);
}

boolean SDClass::rmdir(char *filepath) {
/*

Makes a single directory or a heirarchy of directories.

A rough equivalent to `mkdir -p`.

*/
return walkPath(filepath, root, callback_rmdir);
}

boolean SDClass::remove(char *filepath) {
return walkPath(filepath, root, callback_remove);
}


// allows you to recurse into a directory
File File::openNextFile(uint8_t mode) {
dir_t p;

//Serial.print("\t\treading dir...");
while (_file->readDir(&p) > 0) {

// done if past last used entry
if (p.name[0] == DIR_NAME_FREE) {
//Serial.println("end");
return File();
}

// skip deleted entry and entries for . and ..
if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') {
//Serial.println("dots");
continue;
}

// only list subdirectories and files
if (!DIR_IS_FILE_OR_SUBDIR(&p)) {
//Serial.println("notafile");
continue;
}

// print file name with possible blank fill
SdFile f;
char name[13];
_file->dirName(p, name);
//Serial.print("try to open file ");
//Serial.println(name);

if (f.open(_file, name, mode)) {
//Serial.println("OK!");
return File(f, name);
} else {
//Serial.println("ugh");
return File();
}
}

//Serial.println("nothing");
return File();
}

void File::rewindDirectory(void) {
if (isDirectory())
_file->rewind();
}

SDClass SD;

+ 103
- 0
xmega/libraries/SD/SD.h View File

@@ -0,0 +1,103 @@
/*

SD - a slightly more friendly wrapper for sdfatlib

This library aims to expose a subset of SD card functionality
in the form of a higher level "wrapper" object.

License: GNU General Public License V3
(Because sdfatlib is licensed with this.)

(C) Copyright 2010 SparkFun Electronics

*/

#ifndef __SD_H__
#define __SD_H__

#include <Arduino.h>

#include <utility/SdFat.h>
#include <utility/SdFatUtil.h>

#define FILE_READ O_READ
#define FILE_WRITE (O_READ | O_WRITE | O_CREAT)

class File : public Stream {
private:
char _name[13]; // our name
SdFile *_file; // underlying file pointer

public:
File(SdFile f, const char *name); // wraps an underlying SdFile
File(void); // 'empty' constructor
~File(void); // destructor
virtual size_t write(uint8_t);
virtual size_t write(const uint8_t *buf, size_t size);
virtual int read();
virtual int peek();
virtual int available();
virtual void flush();
int read(void *buf, uint16_t nbyte);
boolean seek(uint32_t pos);
uint32_t position();
uint32_t size();
void close();
operator bool();
char * name();

boolean isDirectory(void);
File openNextFile(uint8_t mode = O_RDONLY);
void rewindDirectory(void);

using Print::write;
};

class SDClass {

private:
// These are required for initialisation and use of sdfatlib
Sd2Card card;
SdVolume volume;
SdFile root;

// my quick&dirty iterator, should be replaced
SdFile getParentDir(const char *filepath, int *indx);
public:
// This needs to be called to set up the connection to the SD card
// before other methods are used.
boolean begin(uint8_t csPin = SD_CHIP_SELECT_PIN);

// Open the specified file/directory with the supplied mode (e.g. read or
// write, etc). Returns a File object for interacting with the file.
// Note that currently only one file can be open at a time.
File open(const char *filename, uint8_t mode = FILE_READ);

// Methods to determine if the requested file path exists.
boolean exists(char *filepath);

// Create the requested directory heirarchy--if intermediate directories
// do not exist they will be created.
boolean mkdir(char *filepath);

// Delete the file.
boolean remove(char *filepath);

boolean rmdir(char *filepath);

private:

// This is used to determine the mode used to open a file
// it's here because it's the easiest place to pass the
// information through the directory walking function. But
// it's probably not the best place for it.
// It shouldn't be set directly--it is set via the parameters to `open`.
int fileOpenMode;

friend class File;
friend boolean callback_openPath(SdFile&, char *, boolean, void *);
};

extern SDClass SD;

#endif

+ 124
- 0
xmega/libraries/SD/examples/CardInfo/CardInfo.ino View File

@@ -0,0 +1,124 @@
/*
SD card test
This example shows how use the utility libraries on which the'
SD library is based in order to get info about your SD card.
Very useful for testing a card when you're not sure whether its working or not.
The circuit:
* SD card attached to SPI bus as follows:
** MOSI - pin 11 on Arduino Uno/Duemilanove/Diecimila
** MISO - pin 12 on Arduino Uno/Duemilanove/Diecimila
** CLK - pin 13 on Arduino Uno/Duemilanove/Diecimila
** CS - depends on your SD card shield or module.
Pin 4 used here for consistency with other Arduino examples

created 28 Mar 2011
by Limor Fried
modified 9 Apr 2012
by Tom Igoe
*/
// include the SD library:
#include <SD.h>
#include <SPI.h>

// set up variables using the SD utility library functions:
Sd2Card card;
SdVolume volume;
SdFile root;

// change this to match your SD shield or module;
// Arduino Ethernet shield: pin 4
// Adafruit SD shields and modules: pin 10
// Sparkfun SD shield: pin 8
// Teensy 2.0: pin 0
// Teensy++ 2.0: pin 20
#if defined(XMEGA_XA4U)
const int chipSelect = 22;
#else
const int chipSelect = 4;
#endif

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


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


// we'll use the initialization code from the utility libraries
// since we're just testing if the card is working!
if (!card.init(SPI_HALF_SPEED, chipSelect)) {
Serial.println("initialization failed. Things to check:");
Serial.println("* is a card is inserted?");
Serial.println("* Is your wiring correct?");
Serial.println("* did you change the chipSelect pin to match your shield or module?");
return;
} else {
Serial.println("Wiring is correct and a card is present.");
}

// print the type of card
Serial.print("\nCard type: ");
switch(card.type()) {
case SD_CARD_TYPE_SD1:
Serial.println("SD1");
break;
case SD_CARD_TYPE_SD2:
Serial.println("SD2");
break;
case SD_CARD_TYPE_SDHC:
Serial.println("SDHC");
break;
default:
Serial.println("Unknown");
}

// Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
if (!volume.init(card)) {
Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card");
return;
}


// print the type and size of the first FAT-type volume
uint32_t volumesize;
Serial.print("\nVolume type is FAT");
Serial.println(volume.fatType(), DEC);
Serial.println();
volumesize = volume.blocksPerCluster(); // clusters are collections of blocks
volumesize *= volume.clusterCount(); // we'll have a lot of clusters
volumesize *= 512; // SD card blocks are always 512 bytes
Serial.print("Volume size (bytes): ");
Serial.println(volumesize);
Serial.print("Volume size (Kbytes): ");
volumesize /= 1024;
Serial.println(volumesize);
Serial.print("Volume size (Mbytes): ");
volumesize /= 1024;
Serial.println(volumesize);

Serial.println("\nFiles found on the card (name, date and size in bytes): ");
root.openRoot(volume);
// list all files in the card with date and size
root.ls(LS_R | LS_DATE | LS_SIZE);
}


void loop(void) {
}

+ 104
- 0
xmega/libraries/SD/examples/Datalogger/Datalogger.ino View File

@@ -0,0 +1,104 @@
/*
SD card datalogger
This example shows how to log data from three analog sensors
to an SD card using the SD library.
The circuit:
* analog sensors on analog ins 0, 1, and 2
* SD card attached to SPI bus as follows:
** MOSI - pin 11
** MISO - pin 12
** CLK - pin 13
** CS - pin 4
created 24 Nov 2010
modified 9 Apr 2012
by Tom Igoe
This example code is in the public domain.
*/

#include <SD.h>
#include <SPI.h>

// On the Ethernet Shield, CS is pin 4. Note that even if it's not
// used as the CS pin, the hardware CS pin (10 on most Arduino boards,
// 53 on the Mega) must be left as an output or the SD library
// functions will not work.

// change this to match your SD shield or module;
// Arduino Ethernet shield: pin 4
// Adafruit SD shields and modules: pin 10
// Sparkfun SD shield: pin 8
// Teensy 2.0: pin 0
// Teensy++ 2.0: pin 20
#if defined(XMEGA_XA4U)
const int chipSelect = 22;
#else
const int chipSelect = 4;
#endif

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


Serial.print("Initializing SD card...");
// make sure that the default chip select pin is set to
// output, even if you don't use it:
pinMode(10, OUTPUT);
// see if the card is present and can be initialized:
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
// don't do anything more:
return;
}
Serial.println("card initialized.");
}

void loop()
{
// make a string for assembling the data to log:
String dataString = "";

// read three sensors and append to the string:
for (int analogPin = 0; analogPin < 3; analogPin++) {
int sensor = analogRead(analogPin);
dataString += String(sensor);
if (analogPin < 2) {
dataString += ",";
}
}

// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
File dataFile = SD.open("datalog.txt", FILE_WRITE);

// if the file is available, write to it:
if (dataFile) {
dataFile.println(dataString);
dataFile.close();
// print to the serial port too:
Serial.println(dataString);
}
// if the file isn't open, pop up an error:
else {
Serial.println("error opening datalog.txt");
}
}










+ 85
- 0
xmega/libraries/SD/examples/DumpFile/DumpFile.ino View File

@@ -0,0 +1,85 @@
/*
SD card file dump
This example shows how to read a file from the SD card using the
SD library and send it over the serial port.
The circuit:
* SD card attached to SPI bus as follows:
** MOSI - pin 11
** MISO - pin 12
** CLK - pin 13
** CS - pin 4
created 22 December 2010
by Limor Fried
modified 9 Apr 2012
by Tom Igoe
This example code is in the public domain.
*/

#include <SD.h>
#include <SPI.h>

// On the Ethernet Shield, CS is pin 4. Note that even if it's not
// used as the CS pin, the hardware CS pin (10 on most Arduino boards,
// 53 on the Mega) must be left as an output or the SD library
// functions will not work.

// change this to match your SD shield or module;
// Arduino Ethernet shield: pin 4
// Adafruit SD shields and modules: pin 10
// Sparkfun SD shield: pin 8
// Teensy 2.0: pin 0
// Teensy++ 2.0: pin 20
#if defined(XMEGA_XA4U)
const int chipSelect = 22;
#else
const int chipSelect = 4;
#endif

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


Serial.print("Initializing SD card...");
// make sure that the default chip select pin is set to
// output, even if you don't use it:
pinMode(10, OUTPUT);
// see if the card is present and can be initialized:
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
// don't do anything more:
return;
}
Serial.println("card initialized.");
// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
File dataFile = SD.open("datalog.txt");

// if the file is available, write to it:
if (dataFile) {
while (dataFile.available()) {
Serial.write(dataFile.read());
}
dataFile.close();
}
// if the file isn't open, pop up an error:
else {
Serial.println("error opening datalog.txt");
}
}

void loop()
{
}


+ 97
- 0
xmega/libraries/SD/examples/Files/Files.ino View File

@@ -0,0 +1,97 @@
/*
SD card basic file example
This example shows how to create and destroy an SD card file
The circuit:
* SD card attached to SPI bus as follows:
** MOSI - pin 11
** MISO - pin 12
** CLK - pin 13
** CS - pin 4
created Nov 2010
by David A. Mellis
modified 9 Apr 2012
by Tom Igoe
This example code is in the public domain.
*/
#include <SD.h>
#include <SPI.h>

File myFile;

// change this to match your SD shield or module;
// Arduino Ethernet shield: pin 4
// Adafruit SD shields and modules: pin 10
// Sparkfun SD shield: pin 8
// Teensy 2.0: pin 0
// Teensy++ 2.0: pin 20
#if defined(XMEGA_XA4U)
const int chipSelect = 22;
#else
const int chipSelect = 4;
#endif

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


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

if (!SD.begin(chipSelect)) {
Serial.println("initialization failed!");
return;
}
Serial.println("initialization done.");

if (SD.exists("example.txt")) {
Serial.println("example.txt exists.");
}
else {
Serial.println("example.txt doesn't exist.");
}

// open a new file and immediately close it:
Serial.println("Creating example.txt...");
myFile = SD.open("example.txt", FILE_WRITE);
myFile.close();

// Check to see if the file exists:
if (SD.exists("example.txt")) {
Serial.println("example.txt exists.");
}
else {
Serial.println("example.txt doesn't exist.");
}

// delete the file:
Serial.println("Removing example.txt...");
SD.remove("example.txt");

if (SD.exists("example.txt")){
Serial.println("example.txt exists.");
}
else {
Serial.println("example.txt doesn't exist.");
}
}

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




+ 98
- 0
xmega/libraries/SD/examples/ReadWrite/ReadWrite.ino View File

@@ -0,0 +1,98 @@
/*
SD card read/write
This example shows how to read and write data to and from an SD card file
The circuit:
* SD card attached to SPI bus as follows:
** MOSI - pin 11
** MISO - pin 12
** CLK - pin 13
** CS - pin 4
created Nov 2010
by David A. Mellis
modified 9 Apr 2012
by Tom Igoe
This example code is in the public domain.
*/
#include <SD.h>
#include <SPI.h>

File myFile;

// change this to match your SD shield or module;
// Arduino Ethernet shield: pin 4
// Adafruit SD shields and modules: pin 10
// Sparkfun SD shield: pin 8
// Teensy 2.0: pin 0
// Teensy++ 2.0: pin 20
#if defined(XMEGA_XA4U)
const int chipSelect = 22;
#else
const int chipSelect = 4;
#endif

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


Serial.print("Initializing SD card...");
// On the Ethernet Shield, CS is pin 4. It's set as an output by default.
// Note that even if it's not used as the CS pin, the hardware SS pin
// (10 on most Arduino boards, 53 on the Mega) must be left as an output
// or the SD library functions will not work.
pinMode(10, OUTPUT);
if (!SD.begin(chipSelect)) {
Serial.println("initialization failed!");
return;
}
Serial.println("initialization done.");
// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
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
}



+ 97
- 0
xmega/libraries/SD/examples/listfiles/listfiles.ino View File

@@ -0,0 +1,97 @@
/*
SD card basic file example
This example shows how to create and destroy an SD card file
The circuit:
* SD card attached to SPI bus as follows:
** MOSI - pin 11
** MISO - pin 12
** CLK - pin 13
** CS - pin 4
created Nov 2010
by David A. Mellis
modified 9 Apr 2012
by Tom Igoe
This example code is in the public domain.
*/
#include <SD.h>
#include <SPI.h>

File root;

// change this to match your SD shield or module;
// Arduino Ethernet shield: pin 4
// Adafruit SD shields and modules: pin 10
// Sparkfun SD shield: pin 8
// Teensy 2.0: pin 0
// Teensy++ 2.0: pin 20
#if defined(XMEGA_XA4U)
const int chipSelect = 22;
#else
const int chipSelect = 4;
#endif

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


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

if (!SD.begin(chipSelect)) {
Serial.println("initialization failed!");
return;
}
Serial.println("initialization done.");

root = SD.open("/");
printDirectory(root, 0);
Serial.println("done!");
}

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

void printDirectory(File dir, int numTabs) {
while(true) {
File entry = dir.openNextFile();
if (! entry) {
// no more files
//Serial.println("**nomorefiles**");
break;
}
for (uint8_t i=0; i<numTabs; i++) {
Serial.print('\t');
}
Serial.print(entry.name());
if (entry.isDirectory()) {
Serial.println("/");
printDirectory(entry, numTabs+1);
} else {
// files have sizes, directories do not
Serial.print("\t\t");
Serial.println(entry.size(), DEC);
}
entry.close();
}
}




+ 30
- 0
xmega/libraries/SD/keywords.txt View File

@@ -0,0 +1,30 @@
#######################################
# Syntax Coloring Map SD
#######################################

#######################################
# Datatypes (KEYWORD1)
#######################################

SD KEYWORD1
File KEYWORD1

#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
exists KEYWORD2
mkdir KEYWORD2
remove KEYWORD2
rmdir KEYWORD2
open KEYWORD2
close KEYWORD2
seek KEYWORD2
position KEYWORD2
size KEYWORD2

#######################################
# Constants (LITERAL1)
#######################################
FILE_READ LITERAL1
FILE_WRITE LITERAL1

+ 418
- 0
xmega/libraries/SD/utility/FatStructs.h View File

@@ -0,0 +1,418 @@
/* Arduino SdFat Library
* Copyright (C) 2009 by William Greiman
*
* This file is part of the Arduino SdFat Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino SdFat Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef FatStructs_h
#define FatStructs_h
/**
* \file
* FAT file structures
*/
/*
* mostly from Microsoft document fatgen103.doc
* http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx
*/
//------------------------------------------------------------------------------
/** Value for byte 510 of boot block or MBR */
uint8_t const BOOTSIG0 = 0X55;
/** Value for byte 511 of boot block or MBR */
uint8_t const BOOTSIG1 = 0XAA;
//------------------------------------------------------------------------------
/**
* \struct partitionTable
* \brief MBR partition table entry
*
* A partition table entry for a MBR formatted storage device.
* The MBR partition table has four entries.
*/
struct partitionTable {
/**
* Boot Indicator . Indicates whether the volume is the active
* partition. Legal values include: 0X00. Do not use for booting.
* 0X80 Active partition.
*/
uint8_t boot;
/**
* Head part of Cylinder-head-sector address of the first block in
* the partition. Legal values are 0-255. Only used in old PC BIOS.
*/
uint8_t beginHead;
/**
* Sector part of Cylinder-head-sector address of the first block in
* the partition. Legal values are 1-63. Only used in old PC BIOS.
*/
unsigned beginSector : 6;
/** High bits cylinder for first block in partition. */
unsigned beginCylinderHigh : 2;
/**
* Combine beginCylinderLow with beginCylinderHigh. Legal values
* are 0-1023. Only used in old PC BIOS.
*/
uint8_t beginCylinderLow;
/**
* Partition type. See defines that begin with PART_TYPE_ for
* some Microsoft partition types.
*/
uint8_t type;
/**
* head part of cylinder-head-sector address of the last sector in the
* partition. Legal values are 0-255. Only used in old PC BIOS.
*/
uint8_t endHead;
/**
* Sector part of cylinder-head-sector address of the last sector in
* the partition. Legal values are 1-63. Only used in old PC BIOS.
*/
unsigned endSector : 6;
/** High bits of end cylinder */
unsigned endCylinderHigh : 2;
/**
* Combine endCylinderLow with endCylinderHigh. Legal values
* are 0-1023. Only used in old PC BIOS.
*/
uint8_t endCylinderLow;
/** Logical block address of the first block in the partition. */
uint32_t firstSector;
/** Length of the partition, in blocks. */
uint32_t totalSectors;
} __attribute__((packed));
/** Type name for partitionTable */
typedef struct partitionTable part_t;
//------------------------------------------------------------------------------
/**
* \struct masterBootRecord
*
* \brief Master Boot Record
*
* The first block of a storage device that is formatted with a MBR.
*/
struct masterBootRecord {
/** Code Area for master boot program. */
uint8_t codeArea[440];
/** Optional WindowsNT disk signature. May contain more boot code. */
uint32_t diskSignature;
/** Usually zero but may be more boot code. */
uint16_t usuallyZero;
/** Partition tables. */
part_t part[4];
/** First MBR signature byte. Must be 0X55 */
uint8_t mbrSig0;
/** Second MBR signature byte. Must be 0XAA */
uint8_t mbrSig1;
} __attribute__((packed));
/** Type name for masterBootRecord */
typedef struct masterBootRecord mbr_t;
//------------------------------------------------------------------------------
/**
* \struct biosParmBlock
*
* \brief BIOS parameter block
*
* The BIOS parameter block describes the physical layout of a FAT volume.
*/
struct biosParmBlock {
/**
* Count of bytes per sector. This value may take on only the
* following values: 512, 1024, 2048 or 4096
*/
uint16_t bytesPerSector;
/**
* Number of sectors per allocation unit. This value must be a
* power of 2 that is greater than 0. The legal values are
* 1, 2, 4, 8, 16, 32, 64, and 128.
*/
uint8_t sectorsPerCluster;
/**
* Number of sectors before the first FAT.
* This value must not be zero.
*/
uint16_t reservedSectorCount;
/** The count of FAT data structures on the volume. This field should
* always contain the value 2 for any FAT volume of any type.
*/
uint8_t fatCount;
/**
* For FAT12 and FAT16 volumes, this field contains the count of
* 32-byte directory entries in the root directory. For FAT32 volumes,
* this field must be set to 0. For FAT12 and FAT16 volumes, this
* value should always specify a count that when multiplied by 32
* results in a multiple of bytesPerSector. FAT16 volumes should
* use the value 512.
*/
uint16_t rootDirEntryCount;
/**
* This field is the old 16-bit total count of sectors on the volume.
* This count includes the count of all sectors in all four regions
* of the volume. This field can be 0; if it is 0, then totalSectors32
* must be non-zero. For FAT32 volumes, this field must be 0. For
* FAT12 and FAT16 volumes, this field contains the sector count, and
* totalSectors32 is 0 if the total sector count fits
* (is less than 0x10000).
*/
uint16_t totalSectors16;
/**
* This dates back to the old MS-DOS 1.x media determination and is
* no longer usually used for anything. 0xF8 is the standard value
* for fixed (non-removable) media. For removable media, 0xF0 is
* frequently used. Legal values are 0xF0 or 0xF8-0xFF.
*/
uint8_t mediaType;
/**
* Count of sectors occupied by one FAT on FAT12/FAT16 volumes.
* On FAT32 volumes this field must be 0, and sectorsPerFat32
* contains the FAT size count.
*/
uint16_t sectorsPerFat16;
/** Sectors per track for interrupt 0x13. Not used otherwise. */
uint16_t sectorsPerTrtack;
/** Number of heads for interrupt 0x13. Not used otherwise. */
uint16_t headCount;
/**
* Count of hidden sectors preceding the partition that contains this
* FAT volume. This field is generally only relevant for media
* visible on interrupt 0x13.
*/
uint32_t hidddenSectors;
/**
* This field is the new 32-bit total count of sectors on the volume.
* This count includes the count of all sectors in all four regions
* of the volume. This field can be 0; if it is 0, then
* totalSectors16 must be non-zero.
*/
uint32_t totalSectors32;
/**
* Count of sectors occupied by one FAT on FAT32 volumes.
*/
uint32_t sectorsPerFat32;
/**
* This field is only defined for FAT32 media and does not exist on
* FAT12 and FAT16 media.
* Bits 0-3 -- Zero-based number of active FAT.
* Only valid if mirroring is disabled.
* Bits 4-6 -- Reserved.
* Bit 7 -- 0 means the FAT is mirrored at runtime into all FATs.
* -- 1 means only one FAT is active; it is the one referenced in bits 0-3.
* Bits 8-15 -- Reserved.
*/
uint16_t fat32Flags;
/**
* FAT32 version. High byte is major revision number.
* Low byte is minor revision number. Only 0.0 define.
*/
uint16_t fat32Version;
/**
* Cluster number of the first cluster of the root directory for FAT32.
* This usually 2 but not required to be 2.
*/
uint32_t fat32RootCluster;
/**
* Sector number of FSINFO structure in the reserved area of the
* FAT32 volume. Usually 1.
*/
uint16_t fat32FSInfo;
/**
* If non-zero, indicates the sector number in the reserved area
* of the volume of a copy of the boot record. Usually 6.
* No value other than 6 is recommended.
*/
uint16_t fat32BackBootBlock;
/**
* Reserved for future expansion. Code that formats FAT32 volumes
* should always set all of the bytes of this field to 0.
*/
uint8_t fat32Reserved[12];
} __attribute__((packed));
/** Type name for biosParmBlock */
typedef struct biosParmBlock bpb_t;
//------------------------------------------------------------------------------
/**
* \struct fat32BootSector
*
* \brief Boot sector for a FAT16 or FAT32 volume.
*
*/
struct fat32BootSector {
/** X86 jmp to boot program */
uint8_t jmpToBootCode[3];
/** informational only - don't depend on it */
char oemName[8];
/** BIOS Parameter Block */
bpb_t bpb;
/** for int0x13 use value 0X80 for hard drive */
uint8_t driveNumber;
/** used by Windows NT - should be zero for FAT */
uint8_t reserved1;
/** 0X29 if next three fields are valid */
uint8_t bootSignature;
/** usually generated by combining date and time */
uint32_t volumeSerialNumber;
/** should match volume label in root dir */
char volumeLabel[11];
/** informational only - don't depend on it */
char fileSystemType[8];
/** X86 boot code */
uint8_t bootCode[420];
/** must be 0X55 */
uint8_t bootSectorSig0;
/** must be 0XAA */
uint8_t bootSectorSig1;
} __attribute__((packed));
//------------------------------------------------------------------------------
// End Of Chain values for FAT entries
/** FAT16 end of chain value used by Microsoft. */
uint16_t const FAT16EOC = 0XFFFF;
/** Minimum value for FAT16 EOC. Use to test for EOC. */
uint16_t const FAT16EOC_MIN = 0XFFF8;
/** FAT32 end of chain value used by Microsoft. */
uint32_t const FAT32EOC = 0X0FFFFFFF;
/** Minimum value for FAT32 EOC. Use to test for EOC. */
uint32_t const FAT32EOC_MIN = 0X0FFFFFF8;
/** Mask a for FAT32 entry. Entries are 28 bits. */
uint32_t const FAT32MASK = 0X0FFFFFFF;
/** Type name for fat32BootSector */
typedef struct fat32BootSector fbs_t;
//------------------------------------------------------------------------------
/**
* \struct directoryEntry
* \brief FAT short directory entry
*
* Short means short 8.3 name, not the entry size.
*
* Date Format. A FAT directory entry date stamp is a 16-bit field that is
* basically a date relative to the MS-DOS epoch of 01/01/1980. Here is the
* format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the
* 16-bit word):
*
* Bits 9-15: Count of years from 1980, valid value range 0-127
* inclusive (1980-2107).
*
* Bits 5-8: Month of year, 1 = January, valid value range 1-12 inclusive.
*
* Bits 0-4: Day of month, valid value range 1-31 inclusive.
*
* Time Format. A FAT directory entry time stamp is a 16-bit field that has
* a granularity of 2 seconds. Here is the format (bit 0 is the LSB of the
* 16-bit word, bit 15 is the MSB of the 16-bit word).
*
* Bits 11-15: Hours, valid value range 0-23 inclusive.
*
* Bits 5-10: Minutes, valid value range 0-59 inclusive.
*
* Bits 0-4: 2-second count, valid value range 0-29 inclusive (0 - 58 seconds).
*
* The valid time range is from Midnight 00:00:00 to 23:59:58.
*/
struct directoryEntry {
/**
* Short 8.3 name.
* The first eight bytes contain the file name with blank fill.
* The last three bytes contain the file extension with blank fill.
*/
uint8_t name[11];
/** Entry attributes.
*
* The upper two bits of the attribute byte are reserved and should
* always be set to 0 when a file is created and never modified or
* looked at after that. See defines that begin with DIR_ATT_.
*/
uint8_t attributes;
/**
* Reserved for use by Windows NT. Set value to 0 when a file is
* created and never modify or look at it after that.
*/
uint8_t reservedNT;
/**
* The granularity of the seconds part of creationTime is 2 seconds
* so this field is a count of tenths of a second and its valid
* value range is 0-199 inclusive. (WHG note - seems to be hundredths)
*/
uint8_t creationTimeTenths;
/** Time file was created. */
uint16_t creationTime;
/** Date file was created. */
uint16_t creationDate;
/**
* Last access date. Note that there is no last access time, only
* a date. This is the date of last read or write. In the case of
* a write, this should be set to the same date as lastWriteDate.
*/
uint16_t lastAccessDate;
/**
* High word of this entry's first cluster number (always 0 for a
* FAT12 or FAT16 volume).
*/
uint16_t firstClusterHigh;
/** Time of last write. File creation is considered a write. */
uint16_t lastWriteTime;
/** Date of last write. File creation is considered a write. */
uint16_t lastWriteDate;
/** Low word of this entry's first cluster number. */
uint16_t firstClusterLow;
/** 32-bit unsigned holding this file's size in bytes. */
uint32_t fileSize;
} __attribute__((packed));
//------------------------------------------------------------------------------
// Definitions for directory entries
//
/** Type name for directoryEntry */
typedef struct directoryEntry dir_t;
/** escape for name[0] = 0XE5 */
uint8_t const DIR_NAME_0XE5 = 0X05;
/** name[0] value for entry that is free after being "deleted" */
uint8_t const DIR_NAME_DELETED = 0XE5;
/** name[0] value for entry that is free and no allocated entries follow */
uint8_t const DIR_NAME_FREE = 0X00;
/** file is read-only */
uint8_t const DIR_ATT_READ_ONLY = 0X01;
/** File should hidden in directory listings */
uint8_t const DIR_ATT_HIDDEN = 0X02;
/** Entry is for a system file */
uint8_t const DIR_ATT_SYSTEM = 0X04;
/** Directory entry contains the volume label */
uint8_t const DIR_ATT_VOLUME_ID = 0X08;
/** Entry is for a directory */
uint8_t const DIR_ATT_DIRECTORY = 0X10;
/** Old DOS archive bit for backup support */
uint8_t const DIR_ATT_ARCHIVE = 0X20;
/** Test value for long name entry. Test is
(d->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME. */
uint8_t const DIR_ATT_LONG_NAME = 0X0F;
/** Test mask for long name entry */
uint8_t const DIR_ATT_LONG_NAME_MASK = 0X3F;
/** defined attribute bits */
uint8_t const DIR_ATT_DEFINED_BITS = 0X3F;
/** Directory entry is part of a long name */
static inline uint8_t DIR_IS_LONG_NAME(const dir_t* dir) {
return (dir->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME;
}
/** Mask for file/subdirectory tests */
uint8_t const DIR_ATT_FILE_TYPE_MASK = (DIR_ATT_VOLUME_ID | DIR_ATT_DIRECTORY);
/** Directory entry is for a file */
static inline uint8_t DIR_IS_FILE(const dir_t* dir) {
return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == 0;
}
/** Directory entry is for a subdirectory */
static inline uint8_t DIR_IS_SUBDIR(const dir_t* dir) {
return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == DIR_ATT_DIRECTORY;
}
/** Directory entry is for a file or subdirectory */
static inline uint8_t DIR_IS_FILE_OR_SUBDIR(const dir_t* dir) {
return (dir->attributes & DIR_ATT_VOLUME_ID) == 0;
}
#endif // FatStructs_h

+ 849
- 0
xmega/libraries/SD/utility/Sd2Card.cpp View File

@@ -0,0 +1,849 @@
/* Arduino Sd2Card Library
* Copyright (C) 2009 by William Greiman
*
* This file is part of the Arduino Sd2Card Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino Sd2Card Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <Arduino.h>
#include <SPI.h>
#include "Sd2Card.h"
#ifdef SPI_HAS_TRANSACTION
static SPISettings settings;
#endif
#if defined(__MK20DX128__) || defined(__MK20DX256__)
#define USE_TEENSY3_SPI
// Teensy 3.0 functions (copied from sdfatlib20130629)
#include <mk20dx128.h>
// Limit initial fifo to three entries to avoid fifo overrun
#define SPI_INITIAL_FIFO_DEPTH 3
// define some symbols that are not in mk20dx128.h
#ifndef SPI_SR_RXCTR
#define SPI_SR_RXCTR 0XF0
#endif // SPI_SR_RXCTR
#ifndef SPI_PUSHR_CONT
#define SPI_PUSHR_CONT 0X80000000
#endif // SPI_PUSHR_CONT
#ifndef SPI_PUSHR_CTAS
#define SPI_PUSHR_CTAS(n) (((n) & 7) << 28)
#endif // SPI_PUSHR_CTAS
static void spiBegin() {
SIM_SCGC6 |= SIM_SCGC6_SPI0;
}
static void spiInit(uint8_t spiRate) {
switch (spiRate) {
// the top 2 speeds are set to 24 MHz, for the SD library defaults
case 0: settings = SPISettings(24000000, MSBFIRST, SPI_MODE0); break;
case 1: settings = SPISettings(24000000, MSBFIRST, SPI_MODE0); break;
case 2: settings = SPISettings(8000000, MSBFIRST, SPI_MODE0); break;
case 3: settings = SPISettings(4000000, MSBFIRST, SPI_MODE0); break;
case 4: settings = SPISettings(3000000, MSBFIRST, SPI_MODE0); break;
case 5: settings = SPISettings(2000000, MSBFIRST, SPI_MODE0); break;
default: settings = SPISettings(400000, MSBFIRST, SPI_MODE0);
}
SPI.begin();
}
/** SPI receive a byte */
static uint8_t spiRec() {
SPI0_MCR |= SPI_MCR_CLR_RXF;
SPI0_SR = SPI_SR_TCF;
SPI0_PUSHR = 0xFF;
while (!(SPI0_SR & SPI_SR_TCF)) {}
return SPI0_POPR;
}
/** SPI receive multiple bytes */
static uint8_t spiRec(uint8_t* buf, size_t len) {
// clear any data in RX FIFO
SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_CLR_RXF | SPI_MCR_PCSIS(0x1F);
// use 16 bit frame to avoid TD delay between frames
// get one byte if len is odd
if (len & 1) {
*buf++ = spiRec();
len--;
}
// initial number of words to push into TX FIFO
int nf = len/2 < SPI_INITIAL_FIFO_DEPTH ? len/2 : SPI_INITIAL_FIFO_DEPTH;
for (int i = 0; i < nf; i++) {
SPI0_PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | 0XFFFF;
}
uint8_t* limit = buf + len - 2*nf;
while (buf < limit) {
while (!(SPI0_SR & SPI_SR_RXCTR)) {}
SPI0_PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | 0XFFFF;
uint16_t w = SPI0_POPR;
*buf++ = w >> 8;
*buf++ = w & 0XFF;
}
// limit for rest of RX data
limit += 2*nf;
while (buf < limit) {
while (!(SPI0_SR & SPI_SR_RXCTR)) {}
uint16_t w = SPI0_POPR;
*buf++ = w >> 8;
*buf++ = w & 0XFF;
}
return 0;
}
static void spiRecIgnore(size_t len) {
// clear any data in RX FIFO
SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_CLR_RXF | SPI_MCR_PCSIS(0x1F);
// use 16 bit frame to avoid TD delay between frames
// get one byte if len is odd
if (len & 1) {
spiRec();
len--;
}
// initial number of words to push into TX FIFO
int nf = len/2 < SPI_INITIAL_FIFO_DEPTH ? len/2 : SPI_INITIAL_FIFO_DEPTH;
for (int i = 0; i < nf; i++) {
SPI0_PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | 0XFFFF;
len -= 2;
}
//uint8_t* limit = buf + len - 2*nf;
//while (buf < limit) {
while (len > 0) {
while (!(SPI0_SR & SPI_SR_RXCTR)) {}
SPI0_PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | 0XFFFF;
SPI0_POPR;
len -= 2;
}
// limit for rest of RX data
while (nf > 0) {
while (!(SPI0_SR & SPI_SR_RXCTR)) {}
SPI0_POPR;
nf--;
}
}
/** SPI send a byte */
static void spiSend(uint8_t b) {
SPI0_MCR |= SPI_MCR_CLR_RXF;
SPI0_SR = SPI_SR_TCF;
SPI0_PUSHR = b;
while (!(SPI0_SR & SPI_SR_TCF)) {}
}
/** SPI send multiple bytes */
static void spiSend(const uint8_t* output, size_t len) {
// clear any data in RX FIFO
SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_CLR_RXF | SPI_MCR_PCSIS(0x1F);
// use 16 bit frame to avoid TD delay between frames
// send one byte if len is odd
if (len & 1) {
spiSend(*output++);
len--;
}
// initial number of words to push into TX FIFO
int nf = len/2 < SPI_INITIAL_FIFO_DEPTH ? len/2 : SPI_INITIAL_FIFO_DEPTH;
// limit for pushing data into TX fifo
const uint8_t* limit = output + len;
for (int i = 0; i < nf; i++) {
uint16_t w = (*output++) << 8;
w |= *output++;
SPI0_PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | w;
}
// write data to TX FIFO
while (output < limit) {
uint16_t w = *output++ << 8;
w |= *output++;
while (!(SPI0_SR & SPI_SR_RXCTR)) {}
SPI0_PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | w;
SPI0_POPR;
}
// wait for data to be sent
while (nf) {
while (!(SPI0_SR & SPI_SR_RXCTR)) {}
SPI0_POPR;
nf--;
}
}
//------------------------------------------------------------------------------
#elif defined(__AVR_XMEGA__)
// functions for hardware SPI
/** Send a byte to the card */
static void spiSend(uint8_t b) {
SPI.transfer(b);
}
/** Receive a byte from the card */
static uint8_t spiRec(void) {
return SPI.transfer(0xFF);
}
//------------------------------------------------------------------------------
#else
// functions for hardware SPI
/** Send a byte to the card */
static void spiSend(uint8_t b) {
SPDR = b;
while (!(SPSR & (1 << SPIF)));
}
/** Receive a byte from the card */
static uint8_t spiRec(void) {
spiSend(0XFF);
return SPDR;
}
#endif
//------------------------------------------------------------------------------
// send command and return error code. Return zero for OK
uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) {
// end read if in partialBlockRead mode
readEnd();
// select card
chipSelectLow();
// wait up to 300 ms if busy
waitNotBusy(300);
// send command