SDCard

My experiments with SD Cards!

This code requires mbed Library version 14, or greater!

To ensure you are using the latest version, click on the "mbed" library in your project. An "update" button will appear if there is a newer version, allowing you to bring it up to date.

Introduction

SD Cards are widely used by loads of devices for storage; phones, mp3 players, pc's etc. That means they are a very cheap option for storing large amounts of non-volatile data (i.e. the data is not lost when the power is removed). They should be ideal for data logging and storing audio/images.

SD Card Basic Interface

SD and MMC cards support various protocols, but common to them all is one based on SPI. This is the one i'm experimenting with as, whilst not being the most high performance, it uses a generic SPI interface so will be more portable.

SD Cards are block devices. That means you read/write data in multiples of the block size (usually 512-bytes); the interface is basically "read from block address n", "write to block address m". Note that a filesystem (e.g. FAT) is an abstraction on top of this, and the disk itself knows nothing about the filesystem.

The hardware socket I'm using is a SparkFun MicroSD Breakout Board. Here is the wiring i'm using (you can obviously use either SPI port, and any DigitalOut):



SparkFun MicroSD Breakout Board
MicroSD Breakout    mbed
   CS  o-------------o 13   (DigitalOut cs)
   DI  o-------------o 5    (SPI mosi)
   VCC o-------------o VOUT
   SCK o-------------o 7    (SPI sclk)
   GND o-------------o GND  
   DO  o-------------o 6    (SPI miso)
   CD  o

I've just been testing on a 1GB Kingston and 1GB Transcend card, but will aim to test on different cards over time. I'd recommend sticking to 1GB cards or below however, as bigger ones will probably either a) use block sizes bigger than 512 bytes (needed to get around addressing limitations, and won't work) or b) use a High Capacity version of the standard (which I haven't implemented yet).

The cards were formatted using:

  • Windows Vista, Right-click, Format...
  • Capacity: 971MB
  • Filesystem: FAT (Default) [FAT, FAT32, NTFS, exFAT]
  • Allocation size: 16 kbytes

SD Card SPI Protocol

My first experiments were based on the NXP MMC Card Interface Appnote which were enough to get something working.

However, I decided to re-write it from scratch to make use of the mbed Interface Libraries (neatens and simplifies the code), make it more robust and complete (the appnote code had a few bugs and often didn't work, and only implemented some of the required functionality), and also so I knew the code was "clean" (i.e. i knew it was written as per the spec and it didn't contain anyone elses code).

So, what needs to be implemented? There is an mbed library that supports FAT filesystems (FATFileSystem), which abstracts a generic block device interface in to a filesystem we can use with the standard C functions fopen/fprintf and friends. We also already have libraries for SPI and DigitalOut Interfaces. Therefore, what we need to do is take the block device commands that come down to us from the filesystem, and translate them in to the SPI commands the SD card understands. The mechanism we use is to derive a new filesystem (SDFileSystem) from the generic filesystem (FATFileSystem), and implement the virtual block functions (disk_initialize(), disk_write(), disk_sectors(), ...)

The SPI protocol used by the SD Cards is documented in a publicly available cut down spec, and I found it pretty easy to write the code from:

From this we can see the basic requirements are to reset the card in to SPI mode, initialise the card, get the disk size and set the block size. Then construct and perform read and write transactions.

The resulting code from this is at SDCard/SDFileSystem; I've documented all the essential parts at the top of the .cpp source file if you want to read more.

Using the Code

Here is a walkthrough on how to get it working (example writes a file to a formated SD card)

  • Start a new project so you pull in the mbed library

Import as Library: (this is the generic filesystem library)

  http://mbed.co.uk/projects/libraries/svn/FATFileSystem/trunk

Import as Files: (this is the SD Card code)

  http://mbed.co.uk/projects/cookbook/svn/SDCard/SDFileSystem

Change your code to...

#include "mbed.h"
#include "SDFileSystem.h"
SDFileSystem sd(p5, p6, p7, p13, "sd");
int main() { printf("Hello World!\n");
FILE *fp = fopen("/sd/foo.txt", "w"); if(fp == NULL) { error("Could not open file for write\n"); } fprintf(fp, "Hello SD Card World!"); fclose(fp);
printf("Goodbye World!\n"); }

Insert a formatted disk, reset, and hopefully it'll write a file to the disk. Plug the disk back in to your PC to check it worked!

Knight Rider Upgrade…

Now we have a way to store big files...

http://www.youtube.com/watch?v=tmfkLJY-1hc

Sectors and Clusters

Here is some terminology:

  • Sectors/Blocks - The disk "hardware" block size you can read/write. Although I think there are exceptions, this is commonly 512-bytes. For mbed, i'm going to suggest it is always 512-bytes (you can always emulate by joining blocks or read-modify-write)
  • Clusters - The "software" collection of sectors, which is the minimum allocation unit for files in FAT

The FAT file system uses the following cluster sizes. These sizes the same under Microsoft Windows NT, Microsoft MS-DOS, Microsoft Windows 95 and any other operating system that supports FAT:

   Drive Size          FAT Type   Sectors       Cluster
   (logical volume)               Per Cluster   Size
   -----------------   --------   -----------   -------
   0 MB - 15 MB        12-bit     8             4K
   16 MB - 127 MB      16-bit     4             2K
   128 MB - 255 MB     16-bit     8             4K
   256 MB - 511 MB     16-bit     16            8K
   512 MB - 1023 MB    16-bit     32            16K
   1024 MB - 2048 MB   16-bit     64            32K
   2048 MB - 4096 MB   16-bit     128           64K
   *4096 MB - 8192 MB  16-bit     256           128K  NT V4.0 only
   *8192 MB - 16384 MB 16-bit     512           256K  NT V4.0 only

First Experiments

Here is the first working debug dump I got:

source:/SDCard/doc/HelloSDCardWorld.png