microSD Shield Quickstart Guide


microSD Shield

From digital cameras to smart phones and even some laptops, SD cards are found everywhere. On an Arduino a microSD card provides the ability to save lots of information to a file system (think dataloggers), as well as to retrieve megabytes of data. This page serves as a starting point for everything you need to get up and running with the microSD Shield for the Arduino.

http://www.sparkfun.com/images/products/09802-05b.jpg

How do I assemble it?

For a step by step guide to assemble the MicroSd shield see the Assembly Guide

What do I do with it?

While the Arduino does have some on-board memory it's really not very much, only 1 kilobyte. If you're building something like an MP3 player, picture viewer or data logger you're going to need a lot more memory than 1 kilobyte. A microSD card is really just memory that you can read and write to; even better is that with Arduino you can implement a file system, like FAT16 or FAT32, which lets you easily create, read and write to files. microSD cards are available with memory sizes of 256 MB all the way up to 32 GB and higher! You can pick any size card you'd like to suit you application without modifying the sketch. If you want to start digging around with some example sketches here's a good starting point:

How do I make it work?

Once you've got the shield assembled you can begin to change the example code to make the microSD shield do your bidding:


How do I create a file?

In order to write information to a microSD card we need to have access to a file. If a file doesn't exist yet it must be created. Before the file can be created, though, we must initialize the microSD card to use a FAT file system, initialize a volume on the file system, and then finally open the root directory in the volume. Once all of this is done we can create a file. Luckily for us, the SdFat library (written by William Greiman) does most of the work for us! First create the objects that are needed for the FAT library to work. This code must go at the start of the sketch before both the loop and the setup sections:

//Create the variables to be used by SdFat Library
char name[] = "Test.txt";//Create an array that contains the name 
                           of our file.
Sd2Card card;
SdVolume volume;
SdFile root;
SdFile file;

To initialize the FAT filesystem, the volume and open the root directory all we need to do is place this code in the setup section of the sketch:

pinMode(10, OUTPUT);       //Pin 10 must be set as an output for the SD
                             communication to work.   
card.init();               //Initialize the SD card and configure the 
                             I/O pins.
volume.init(card);         //Initialize a volume on the SD card.
root.openRoot(volume);     //Open the root directory in the volume.

Now we can create the file. We'll need access to the root object and the file name, which were both created at the beginning of the sketch. We'll also use the constants O_CREATE, O_APPEND and O_WRITE to tell the sketch we want to create a file in write mode, and that we want to append data to the end of the file. The constants are defined by the SdFat library; you can learn more about them by reading the documentation located in the library folder. This line of code will create a file in the root directory with the file name designated by the variable 'name':

file.open(root, name, O_CREAT | O_APPEND | O_WRITE);    //Open or
create the file 'name' in 'root' for writing to the end of the file


How do I open a file?

To read or write from a file, the file in question must first be opened. In order to open a file the file's name must be known. There are several different ways to open a file: a file can be created and opened (like in the example above), it can be opened in read mode, or it can be opened in write mode. We also specify the index of the file where we want to start reading or writing. For example, if we want to read from the beginning of a file we would open the file like this:

file.open(root, name, O_READ);    //Open the file in read mode.

However, if we want to write to the end of a file we would change the command to look like this:

file.open(root, name, O_WRITE | O_APPEND);  //Open the file in
        write mode and append the data to the end of the file.

It's also important to remember that after we're finished reading or writing data to the file it should be closed. If the file isn't closed after writing data to it the data might not end up being saved. It's also just good practice to close this file as it helps to maintain the integrity of the file system. To close the file just use this function:

file.close();  //Close the file


What if I don't know the file name of a file I want to open?

If you're building something like an MP3 Player or a Picture Viewer than the sketch probably won't know all of the file names on the microSD card (you may add or delete songs/pictures). In this case you'll need to be able to open files without knowing their name. Luckily for us the SdFat library has a method of opening files by their location in the FAT file system; all we have to do is find the location of the files. Let's look at some code that will open and print information from all of the files on an SD card (assuming that all of the files on the card are text files):

while(root.readDir(directory)>0){
    file.open(root, root.curPosition()/32-1, O_READ);
    in_char=file.read();              //Get the first byte in
                                        the file.
    //Keep reading characters from the file until we get an
     error or reach the end of the file. (This will output the 
     entire contents of the file).
    while(in_char >=0){            //If the value of the
                                     character is less than 0 we've
                                     reached the end of the file.
        Serial.print(in_char);    //Print the current character
        in_char=file.read();      //Get the next character
    }
    file.close();    //Close the file
    Serial.println();
}

Before this loop is started, 'root' is an empty file structure. The function:

while(root.readDir(directory)>0)

loads information about the first file in the directory into root. If the function returns a 0 then we've reached the end of the directory; therefor we execute this function repeatedly until we get a 0 returned. Each time we execute the function we retrieve some information about the file. The next line of the sketch is:

file.open(root, root.curPosition()/32-1, O_READ);

You should recognize parts of this function from when we learned how to open a file. However this time instead of telling the file.open() function the name of the file to open, we're indicating the index of the file that needs to be opened. Since we've loaded information about a file into the 'root' variable we can find the file's position using the curPosition() function. However, the documentation of the file.open() command tells us that if we're giving the function an index of a file we need to divide the position by 32. Then, since indices are always 0 based in computer language, we subtract 1 to find the actual index of the file.

Once we open the file and read all of the information from it we close the file and go back to the beginning of the 'while' loop. When the readDir() command is executed again information for the next file in the directory is loaded into 'root.' This is how we move on to the next file.


How do I write to a file?

The most useful aspect of a microSD card is using it write information to a file that can later be used on a computer to view information. Maybe you're building a data logger, or maybe it's an audio recorder; regardless of what it is you're recording you'll need to know how to write information you've retrieved from the real world and save it to a file. Once you've created and opened a file, saving data is very easy! Let's look at  a few lines of code that will simply copy the string "Millis: " followed by an integer into a string, and then save the string to a file.

file.open(root, name, O_CREAT | O_APPEND | O_WRITE);
    //Open or create the file 'name' in 'root' for
      writing to the end of the file.
sprintf(contents, "Millis: %d\n", millis());
    //Copy the letters 'Millis: ' followed by the 
      integer value of the millis() function into the 
      'contents' array.
file.print(contents);    //Write the 'contents' array
                           to the end of the file.
file.close();            //Close the file.

The first line in the sample we should be pretty familiar with; we've opened a file in write mode, and we're going to write to the end of the file. The 'sprintf()' function is a nifty function that allows us to copy a formatted string into a buffer. In this case the function copies the text 'Millis: ', then we substitute the '%d' for the number returned by the function millis(). Finally we add a new-line character at the end of the string. All of this is copied to the 'contents' buffer. The 'millis()' function is an Arduino function that simply returns the number of milliseconds that have elapsed since the sketch started running. So for example, if the sketch has been running for 200 milliseconds and this code was executed the text 'Millis: 200' would be copied to the 'contents' buffer. Now we've captured the data that needs to be saved to the file. All we have to do is print the buffer to the file (just like if you wanted to print information to the Serial terminal in Arduino). Don't forget to close the file after you finish writing information to it!

Challenge: Can you alter this code to save information read from an Analog input pin? Try using a thermistor to read temperature every second and save the information to a file every time you read the value.


How do I read from a file?

There are many reasons we might want to read information from a file on a microSD card; accessing songs or pictures, retrieving system setting or maybe analyzing a set of data that was saved earlier. Whatever the reason is the method for accessing the data from a file is the same, and it's easy too! In fact, if you know how to get information from a Serial connection than you should already be pretty familiar with the process.  In order to read data we'll need a buffer to store the information; then we'll just use the 'read()' function in the SdFat library to grab information from an opened file. In this example code a buffer has been created named 'file_contents.'

char file_contents[256];           //This is a data
            buffer that holds data read from a file

Now we just need to open a file and start reading data from it. There are two ways to read data from a file using the SdFat library; we can read one character at a time or we can read a specific amount of data from a file. We'll look at both methods. If we are reading one character at a time we need to keep the size of the buffer in mind; our buffer size is 256 characters. Here's an example of how to read data from a file one character at a time:

int index=0;  //Create a variable to keep track of
                our position in the data buffer.
file.open(root, name, O_READ);    //Open the file
                                    in read mode.
file_contents[index]=file.read();
                 //Get the first byte in the file.
//Keep reading characters from the file until we
 get an error or reach the end of the file. 
(This will output the entire contents of the file).
while(file_contents[index] >=0 && index < 256){
    //If the value of the character is less than 0 we've reached 
    the end of the file. If index is 256 than our buffer is full.
    index+=1;                 //Move to the next position in the
                                data buffer.
    file_contents[index]=file.read(); //Get the next character
}
file.close();    //Close the file
for(int i=0; i

In this example we read one character at a time from the file and save it to our data buffer. The loop keeps track of two conditions. If the character read from the file is 0 than we've reached the end of the file, so we exit the loop and close the file. On the other hand, if the 'index' value reaches 256 than we've completely filled the data buffer so we can't keep adding data to it. If this happens we also exit the loop and close the file. After closing the file the sketch prints the contents of the buffer to the screen.

This method of reading data from a file (one character at a time) can be a bit slow and cumbersome to code. If you know how much data you need to read from a file and you are confident that your data buffer has enough room to store the data then you may prefer this method of reading data from a file:

int index=0;
int data_size=10;    
//This variable sets the number of bytes to read from the file.
index=file.read(file_contents, data_size);    
//file_contents is the data buffer for storing data. data_size is a 
variable set to the amount of data to read.
file.close();    //Close the file
for(int i=0; i

Much simpler!  This example will read 'data_size' bytes (10) from the file and store the data into the 'file_contents' data buffer. The 'index' variable will contain the number of bytes read from the file in case it's different than the number we specified; this could happen if we reach the end of the file before reading the 'data_size' bytes.


Can I really use any size microSD card without modifying the code?

Well yes, any size that's currently available, and as long as you use a library that supports a FAT file system. The SdFat library (the one we've been using) supports both FAT16 and FAT32. FAT32 can support volume sizes up to 2 TiB in size; I'm pretty sure you can't even get microSD cards with that much storage...yet. So, as long as the microSD card being used is formatted in either FAT16 or FAT32 then the code will be the same regardless of the cards size.


I downloaded a FAT library for Arduino on my own from the Web but it's not working! Why not?

If you decided to go and download a FAT library from the Internet on your own, good for you! Arduino is all about learning and exploring on your own. You may have found, though, that the library is not working for you. It happens to the best of us! In physical computing we have the added complexity of hardware to keep in mind when we are trying to debug a project. If you've downloaded a library that you're confident in then the problem is likely arising from a hardware issue rather than a code issue. In the case of the microSD card, the problem probably lies within the SPI communication library.

SPI is a protocol designed for communicating between two devices. You can read more about it on wikiepedia; but for our purposes it's important to know that there are four signals used in SPI: MOSI, MISO, SCK and CS (or SS). These signals are defined in a FAT library and associated with a specific pin. On Arduino, the default pins are D10 (CS), D11, (MOSI), D12 (MISO) and D13 (SCK). The FAT library you are using has probably defined the signals according to these defaults. The microSD shield, however, uses pin D8 for the CS signal. If this is left unchanged, the library will not work. You'll need to read your libraries documentation to find out where the signals are defined and change the definition accordingly. For example, in the SdFat library the definition is located in the file named 'ArduinoPins.h' and to change the signal definition on line number 518 from

#define SS_PIN  10

to

#define SS_PIN  8

Did you try this and the library still isn't working? The FAT library is probably using an internal SPI library. The SPI library expects D10 to be configured as an output (even if it's not being used!). In the setup section of your sketch configure D10 to be an output and you should be ready to go.

pinMode(10, OUTPUT);

Schematic and PCB Layout

For technical information including the schematic and design files, please see the product page. You may also want to add/review the comments on this page or do a google search for example projects that use the MicroSD shield.

 

Have a suggestion for how we can improve this quickstart guide? Concepts not explained clearly? Need more example code? Please let us know. You can leave a comment below or email us spark@sparkfun.com. Also let us know if this is the most awesome Quickstart guide you have ever encountered and we will stop trying to improve it.

Comments 26 comments

  • Looks like the SDFat library may need to be updated for arduino 1.0. Here are the issues I get compiling the SdFatAnalogLogger

    In file included from SdFatAnalogLogger.cpp:13: C:\Documents and Settings\kyle brewer\My Documents\arduino-1.0\libraries\SdFat/SdFat.h:294: error: conflicting return type specified for ‘virtual void SdFile::write(uint8_t)’ C:\Documents and Settings\kyle brewer\My Documents\arduino-1.0\hardware\arduino\cores\arduino/Print.h:48: error: overriding ‘virtual size_t Print::write(uint8_t)’

    I have seen this issues with a couple different 3rd party libraries and they had to update recently for the new version.

    example

    http://code.google.com/p/sdfatlib/issues/detail?id=31#c6

    • Yo SparkFun, can you link to a SDFat library that fixes the above issue. I fixed this:

      replace

      include “WProgram.h”

      with

      include “Arduino.h”

      But I’m still getting the same error as Member #201847 when compiling. I perused the example he linked, but I cannot figure out where and how to apply the fixes in the Arduino SdFat Library by William Greiman. Thanks.


      Edit: Nevermind. Bill’s new library found here:

      http://code.google.com/p/sdfatlib/downloads/detail?name=sdfatlib20111205.zip&can=2&q=

      appears to working. Thanks.

  • How can I copy Images to the Memory card using this MicroSD Shield?

  • I am getting error code 0x01,0XFF “No card, wrong chip select pin, or SPI problem?” Sometimes I can get around it be resetting the board, but it’s very problematic. I can’t find a definition for error code 0xFF anywhere in the library files. Anyone else encounter this or know what it may be from?

  • I’m getting this error message over the “volume.init(card);”, it seems like there’s no matching function to this command. I know the shield is connected (because the light red is on), but I’m not really sure if it’s working or if the SDcard is not working.

  • Is there a shield like this for the Arduino leananerdo? And if not, how would you hook this up? (Or hook up any SD card to a Arduino leanardo / mini for that matter?)

  • For which class of SDHC cards this shield works?

    • class ultimately refers to the speed. For 99% of applications, the card will be faster than you need. You can use a class 2 and it should be fine. anything faster won’t benefit you. An arduino just can’t process data that quickly.

  • Does this microSD shield work with microSDHC cards? Also, it is possible to get a hardcopy or at least print your quickstart guide?

    • it does work with SDHC cards, formatting is the most important factor.

      we do not have a hardcopy if the guide, we try to minimize paper waste.

  • hello. may i know, what is the different between SD library & SDfat library? can i read & write data into microSD memory card by using SD library for this mircoSD Shield? or it is compulsory to use SDfat library for this shield? with all, regards.

  • how can i make the arduino read an MP3 file present on a microSD card…………… is it possible??…………….

  • Hi, I want to make a wifi-card reader device,use iPhone/iPad to read/write file to this device, so is it possible to do this? (use microSD Shield, wifly and Duemilanove). If yes, could you tell me the communication interface between microSD Shield, wifly and Duemilanove? for example:
    Duemilanove — SPI(or UART) — wifly
    wifly — SPI — microSD Shield

  • I received this product today and noted that the shied does not fit on the UNO as depicted in the image above. The shield rest on the the USB connector making it difficult to make a good header pin fit and possibly a poor connection. Is this a defective microSD Shield or Defective UNO (both are new).

  • I can’t get anything from the ‘SDFatInfo’ example. Serial monitor says ‘type any character to start’, but entering a character does nothing. I’ve tried another sd card, but no difference. What could it be? Using arduino 21 on an Uno with the sf micro sd shield.

  • Did you get it to write as a audio file? I am trying to record multiple line-in audio and tag the audio files with date, time and GPS coordinates as the name of the MP3 or wav file. Save file to microSD shield.

  • hm… in the examples where “we don’t know the name of the file” you have stuff showing how to send everything from the file to the uart… how do we get only the file name and extension? is it part of what is being sent to the serial port? thx

  • hi, I would like someone that knows about sdcard and already used it a lot to answer this stuff(I never used it, but I would like to, so I’m trying to figure out the easier way to start)… so my question is… I was looking at some stuff and I found this ic:<br />
    <br />
    http://www.thaieasyelec.net/index.php/Components/SMD-IC/CH376-File-Manage/Control-IC-for-USB-Flash-Drive-and-SD-card/p_173.html<br />
    <br />
    “file manage/control ic”<br />
    so, it would be easier to use sd cards with this kind of ic? I actually didn’t take a look at it or how to interface it, but what you guys think?<br />
    <br />
    you know, even if it’s easier with this ic, the fact that there is an already made library and shield for arduino makes me think if I should go with it =x<br />
    <br />
    ps: bad english =(

  • PWM pins are digital already. I don;t think you can change the definitions in the header and actually make it work. There is a software TWI interface which I’ve used with the Adafruit RTC/SD logger successfully, but I’ve not looked at this for this shield yet. I expect to be looking at this in the next week or so

  • I have a Mega board, and the only way I have been able to get the shield to function is to jumper pins on the mega 53(SS),51(MOSI),50(MISO),and 52 (SCK) to the shield pins 8(SS), 11(MOSI), 12 MISO, and 13 (SCK).
    I believe that there are another set of pin definitions in ArduinoPins.h near line 22 that may need to be changed for the mega, however making that change. I still could not get the shield to function.
    On the Mega pins 2 - 13 are label PWM how do I change them to digital so that I can get the sheild to function with out the jumpers?
    Thanks

    • I had the same problem with jumpers, for me worked this: in your library/utility in file Sd2PinMap.h the paragraph starting “// SPI port” the following paragraph rewrite to this: uint8_t const SS_PIN = 53; uint8_t const MOSI_PIN = 51; uint8_t const MISO_PIN = 50; uint8_t const SCK_PIN = 52;

      this should help ;-)

    • One other thing.. I think if you define MEDA_SOFT_SPI
      “#define MEGA_SOFT_SPI 1” in Sd2Card.h it should work.
      I verified that this does work indeed

    • One other thing.. I think if you define MEDA_SOFT_SPI
      “#define MEGA_SOFT_SPI 1” in Sd2Card.h it should work.

  • How would you write other files like MP3 or WAV?
    Is it possible?

    • The library also allows you to read and write binary data to/from a file, you just need to know how to form a proper .MP3 or .WAV file.