#include <SFBSDRaw.h>
Public Types | |
enum | State { NOT_BEGUN = 0, UNINITTED, RESET_FAILED, CRC_ON_FAILED, TYPE_CHECK_FAILED, OP_COND_FAILED, READ_OCR_FAILED, CONFIG_FAILED, ACTIVE, INACTIVE_READ, INACTIVE_WRITE, ERROR_READ_SINGLE_BLOCK, ERROR_READ_REGISTER, ERROR_READ_TIMEOUT_DATA, ERROR_READ_CRC_DATA, ERROR_BAD_CSD_VERSION, ERROR_WRITE_TIMEOUT_DATA, ERROR_WRITE_SINGLE_BLOCK } |
State codes of an SDRaw host controller. More... | |
Public Member Functions | |
void | begin (u8 face) |
Begin using an SDRaw object to control an SD card connected to face. | |
void | begin (u8 face, u8 CSPin, u8 clkPin, u8 MOSIpin, u8 MISOpin) |
Begin using an SDRaw object to control an SD card. | |
bool | end () |
Deconfigure an SDRaw object. | |
u32 | getState () |
Get the current State of this SDRaw object. | |
u32 | getBlockCount () |
Return the total capacity of the SD card, measured in 512 byte blocks. | |
u64 | getByteCount () |
Return the total capacity of the SD card, measured in bytes. | |
u8 | getFace () |
Return the face this SDRaw object is controlling to power the SD Card. | |
bool | init () |
Attempt to initialize the SD card controlled by this SDRaw object. | |
bool | isActive () |
Return true iff this SDRaw object is prepared to perform a read or write operation. | |
bool | getInfo (SDRawDiskInfo &info) |
Read disk capacity and identification information from the disk. | |
bool | setBlockBuffer (u8 *buffer, u32 bufferLength) |
Provide (or remove) a block-sized (512 bytes) buffer for the SDRaw object to use for data buffering. | |
bool | read (u64 address, u8 *data, u32 length) |
Read length bytes into data, starting from disk address address. | |
bool | readBlock (u32 blockNumber, u8 *buffer, u32 blockOffset=0, u32 length=512) |
Read a block of data from the disk, storing some or all of it in buffer. | |
bool | write (u64 address, const u8 *data, u32 length) |
Write length bytes from data to disk, starting from disk address address. | |
bool | writeBlock (u32 blockNumber, const u8 *buffer) |
Write a full block of data to disk block blockNumber, . | |
bool | sync () |
Flush any pending buffered writes to disk. | |
bool | isSDHC () |
Return true if the disk is an 'Secure Digital High Capacity' card, false otherwise. | |
void | setSpiLog (bool val) |
Turn on or off low-level SPI protocol logging (for internal debugging). | |
u32 | readStatus () |
Read and return the internal status register of the card. |
Capable of reading and writing (at least some) SD and SDHC cards on any face at rates from 10KBytes/sec to 100Kbytes/sec or more, depending on factors such as the card type, size, and manufacturer, processor clock speed and load, programming technique, and the alignment of Jupiter with Mars. Getting 40-50KB/sec read and write is fairly easy; 120KB/sec read and write, or even more, can sometimes be achieved in benchmark code.
Note this code provides NO FILE SYSTEM! This is low-level direct disk access in terms of 512-byte blocks from the beginning of the disk to the end. And there is nothing stopping your sketch from creaming whatever file system might already be on the card, except your sketch not doing disk writes!
Using the simplest begin(u8) interface, this code is designed to drive an 'IXM SD Cell' board containing a MicroSD card, connected by at least one 7 pin header, on the LED side of the IXM, but the code can be configured (via begin(u8,u8,u8,u8,u8)) to drive an SD card (in SPI mode) via any four pins (data or Tx or Rx) and a single face power connection (so that the card can be power-cycled as part of its initialization sequence).
Warning: Misplugging an IXM SD Cell to an IXM while it contains an SD Card can INSTANTLY KILL the SD Card when the IXM is powered up! Always 'pop' the card before plugging or unplugging or handling the board! And be CAREFUL what you touch while you're pushing and popping cards!
Cards that have been tested successfully include:
Note that all speed numbers mentioned are only crude estimates, based on highly-variable statistically-insignificant timings on stripped-down benchmarking code! Expect less, perhaps much less, from actual production code! In particular, doing byte-at-a-time access, rather than dealing with full blocks, can easily halve those numbers, or worse.
Your Mileage Will Vary!
Note also that this library currently supports only single-block-at-a-time transfers; perhaps that is a factor in the PNY's write performance.
sdcard1.cpp, sdcard2.cpp, and sdcard3.cpp.
enum SDRaw::State |
State codes of an SDRaw host controller.
NOT_BEGUN | No begin() called (since last end(), at any rate). |
UNINITTED | begin() called but not yet init() |
RESET_FAILED | init() couldn't reset the card -- a common result when no card is present |
CRC_ON_FAILED | Attempt to enable CRC checking failed during init(). This is a bad sign. |
TYPE_CHECK_FAILED | Determining SD controller version failed during init(). Another bad sign. |
OP_COND_FAILED | Attempt to boot the SD card failed during init(). Yet another bad sign. |
READ_OCR_FAILED | Checking for an SDHC card failed during init(). Also a bad sign. |
CONFIG_FAILED | Attempt to set the block size failed during init(). Yes, another bad sign. |
ACTIVE | init() completed successfully, card ready for read/write. |
INACTIVE_READ | read(u64,u8*,u32) called when not ACTIVE. This means a sketch bug. |
INACTIVE_WRITE | write(u64,const u8*,u32) called when not ACTIVE. This means a sketch bug. |
ERROR_READ_SINGLE_BLOCK | Performing a block read failed. May suggest a bad connection or card. |
ERROR_READ_REGISTER | Reading a card register failed. May suggest a bad connection or card. |
ERROR_READ_TIMEOUT_DATA | Timeout reading a block or register. May suggest a bad connection or card. |
ERROR_READ_CRC_DATA | Checksum mismatch on read data block. May suggest a bad connection. |
ERROR_BAD_CSD_VERSION | Unrecognized version of CSD. A bad sign, or a SD card from the future. |
ERROR_WRITE_TIMEOUT_DATA | Timeout writing a block. May suggest a bad connection or card. |
ERROR_WRITE_SINGLE_BLOCK | Performing a block write failed. May suggest a bad connection or card. |
Begin using an SDRaw object to control an SD card.
The power to the SD card should be supplied by face, so that switching off and on the outbound power on that face will power-cycle the card. In addition, four pins must be provided for the SPI-mode interface to the card. These pins may be any of the data or serial pins on the IXM, not necessarily just those on face.
Note that the method only configures the SDRaw object; it still must be successfully initialized via init() before it can be used to perform I/O.
face | A face whose outbound power is connected to a (micro) SD card. | |
CSPin | A pin connected to the Chip Select input of an SD card (in SPI mode) | |
clkPin | A pin connected to the Clock input of an SD card (in SPI mode) | |
MOSIpin | A pin connected to the Master-Out-Slave-In input of an SD card (in SPI mode) | |
MISOpin | A pin connected to the Master-In-Slave-Out output of an SD card (in SPI mode) |
void SDRaw::begin | ( | u8 | face | ) |
Begin using an SDRaw object to control an SD card connected to face.
This is the simpler method, see begin(u8,u8,u8,u8,u8) for the more general mechanism. Note that the method only configures the SDRaw object; it still must be successfully initialized via init() before it can be used to perform I/O.
face | A face connected -- in an IXM SD Cell-compatible fashion -- to a (micro) SD card. |
bool SDRaw::end | ( | ) |
Deconfigure an SDRaw object.
Marks the SDRaw object internally as NOT_BEGUN, but note this method does not undo the effects of a begin() call. In particular, pin functions and pin modes changed by a begin() call remain changed. It is the caller's responsibility to reconfigure any affected hardware as desired after this call.
u32 SDRaw::getBlockCount | ( | ) | [inline] |
Return the total capacity of the SD card, measured in 512 byte blocks.
Returns 0 if the information cannot be accessed (because the SDRaw is not in state ACTIVE, or some other error).
u64 SDRaw::getByteCount | ( | ) | [inline] |
u8 SDRaw::getFace | ( | ) | [inline] |
bool SDRaw::getInfo | ( | SDRawDiskInfo & | info | ) |
Read disk capacity and identification information from the disk.
If successful, returns true
and populates the fields of info with the results. Otherwise returns false
(and getState() should provide more information).
info | An SDRawDiskInfo structure to populate. |
bool SDRaw::init | ( | ) |
Attempt to initialize the SD card controlled by this SDRaw object.
Returns true
if the initialization succeeds (and the card is then ready for I/O), and returns false
if some error occurred during initialization (and then the card is not ready for I/O, but getState() will provide more information about the error.
Note that this method can take a long time to complete -- up to a second or perhaps even more -- regardless of whether it ultimately succeeds or fails.
true
if initialization succeeded, false
if an error occurred. bool SDRaw::isSDHC | ( | ) | [inline] |
Return true
if the disk is an 'Secure Digital High Capacity' card, false
otherwise.
Return value is only valid if getState() returns ACTIVE.
Read length bytes into data, starting from disk address address.
Return true
if all went well, otherwise return false
and update getState() to reflect the problem.
length may be any value (that doesn't overrun RAM or disk), and neither address nor data have any alignment requirements.
However, the speed of this method depends on whether setBlockBuffer(u8*,u32) has previously been called to supply a (non-null) block buffer. If If it has not been called (or has been called most recently with a null argument), then this method performs an unbuffered block read operation, and so each call to this method will read at least 512 bytes from the disk, even if length is smaller than that. As a consequence, using this method without a buffer to read, say, one byte at a time, would be extremely inefficient.
On the other hand, if a block buffer has been provided, then a buffered read operation is performed, and so reads of sequentially increasing addresses will be reasonably efficient no matter what length is used.
For absolute maximum efficiency in this method, no block buffer should be provided, and address and length should both be multiples of 512.
address | Disk address (in bytes) to start reading data from, in the range of 0 to getByteCount()-length | |
data | RAM address to start writing data to. | |
length | Number of byts to transfer. |
true
if read succeeded, false
otherwiseRead a block of data from the disk, storing some or all of it in buffer.
A single full block is always read by this method, but the optional arguments blockOffset and length control how much of that block, if any, is stored in bufer. blockOffset, in the range of 0 to 512, determines how many of the disk block bytes should be skipped before beginning to store length bytes starting at buffer. With default values, the entire block is stored.
Return true
if all went well, otherwise return false
and update getState() to reflect the problem.
length and blockOffset may each have any value from 0 to 512, but note that this is an unbuffered block read operation, which will read a full 512 bytes from the disk even if length is smaller than that.
As a consequence, using this method to read, say, one byte at a time would be extremely inefficient.
blockNumber | Disk block (in units of 512 bytes per block) to read, in the range of 0 to getBlockCount()-1 | |
buffer | RAM address to start writing data to, with at least length bytes of space available | |
blockOffset | Number of read bytes to skip before beginning to store them, in the range of 0..512, default value 0. | |
length | Number of bytes to store into buffer, in the range of 0..512-blockOffset, default value 512. |
u32 SDRaw::readStatus | ( | ) |
Read and return the internal status register of the card.
Note the difference between this method, which always requests status information from the SD card itself, and getState(), which returns information not about the card, but about the SDRaw controller.
Calling this method is probably the fastest way to check if a previously successfully init()-ed card is still present and alive.
The return value is the card status bits as defined by the SD Card specification, and will be zero in the normal case.
Provide (or remove) a block-sized (512 bytes) buffer for the SDRaw object to use for data buffering.
It is not required to provide such a buffer, but if you don't then all your write operations must work in terms of 512 byte units at multiple-of-512 addresses, and all your read operations will involve reading at least 512 bytes from the disk, no matter what length your request.
Note that if, and as long as, a buffer is provided for an SDRaw to use, then the sketch should make no assumptions about the contents of that buffer at any given time. In particular, the sketch should not assume that the buffer contains the most-recently read or written disk block, because the SDRaw library is free to use the provided buffer for whatever internal purposes it wishes.
buffer | A pointer to a 512 byte block of RAM to use for buffering, or 0 to remove a previously provided buffer. | |
bufferLength | Must be 512 (unless buffer is 0, in which case bufferLength may also be 0). This argument is required for documentation and safety purposes; it is checked but not otherwise used, since the buffer size must be 512. |
bool SDRaw::sync | ( | ) |
Flush any pending buffered writes to disk.
Return true
if all went well (whether or not any actual writing was performed), else return false
and update getState() to reflect the problem.
Harmless to call if there are no writes pending, also harmless (but meaningless) to call unless a prior setBlockBuffer() with a non-block argument call has been made.
Write length bytes from data to disk, starting from disk address address.
Return true
if all went well, otherwise return false
and update getState() to reflect the problem.
The legal arguments to this command depend on whether setBlockBuffer(u8*,u32) has been called to supply a (non-null) block buffer. If it has not been called (or has been called most recently with a null argument), then both address and length must be a multiple of 512, or the sketch will die blinking E_API_ILLEGAL_STATE.
On the other hand, if a block buffer has been provided, then length may be any value (that doesn't overrun RAM or disk), and address has no alignment requirements. (data never has any alignment requirements.)
When a block buffer is available, this method will perform buffered writes, which means that (some or all of) the data you supply may not have actually been written to the disk by the time that this method returns. To be certain that all data has been written to disk, call sync(), after writing, to force any buffered data to be written.
address | Disk address (in bytes) to start writing data to, in the range of 0 to getByteCount()-length | |
data | RAM address to start reading data from. | |
length | Number of byts to transfer. |
true
if all went well, false
otherwise. Write a full block of data to disk block blockNumber, .
Return true
if all went well, otherwise return false
and update getState() to reflect the problem. That this is an unbuffered write not requiring a previous setBlockBuffer() to provide a buffer (and making no use of such a buffer if it was provided).
blockNumber | Disk block (in units of 512 bytes per block) to write, in the range of 0 to getBlockCount()-1 | |
buffer | RAM address to read data from, containing 512 bytes of data. |
true
if write succeeded, false
otherwise.