Introduction: Running FAT16 on the Ti Launchpad


This video demonstates the code in action for reading a SD card

you will need the following:
Any MSP430 chip with USI and 4k or more flash
an SD Card
a capcitor (anything more than 10uf)
Code Composer Studio 5 (grace makes things easier)

Step 1: Start Up Filesystem

You need to download the code and include the files in the SD folder of the project:
MMC.c
MMC.h
ThinFAT.c
ThinFAT.h

#include "mmc.h"
#include "ThinFAT.h"


then you have to edit the MMC.h file at the beginning where you want your card select port to be:
//card select currently set to P2.7
#define SD_CSn_PxOUT    P2OUT
#define SD_CSn_PxDIR    P2DIR
#define SD_CSn_PIN      BIT7

Wireing:
P1.2 - TA0.1 - Left Channel Out
P1.3 - Input for Playing and Changing Music File
P1.4 - TA0.2 - Right Channel Out
P1.5 - SMCLK out - SD Card Pin 5
P1.6 - SDO - SD Card Pin 2 MOSI
P1.7 - SDA - SD Card Pin 7 MISO
P2.7 - CS - SD Card Pin 1 Card Select
VCC - SD Card Pin 3,6
Ground - SD Card Pin 4

Next you initilise the FAT file system and the SD card for reading:
ThinFAT_Init();

Step 2: Index Files on SD Card

First you need to write a callback for the Filesystem to capture data on each file as it is read:

struct sPlaylist {
unsigned int CurrentFile;
unsigned int FileCount;
unsigned int FileIndex;
} Playlist;

char IndexWavFile(unsigned char Filename[],unsigned char Extension[])
{
if(Extension[0]==87 && Extension[1]==65 && Extension[2]==86)
{
  Playlist.FileCount++;
}
return ThinFAT_Fail;
}
The code above recive the filename and extension of the file being opened.  it then checks the file extension if it is 'wav' you can check any file extension useing the following table as it's acsii encoded:
http://www.asciitable.com/

the callback returns a fail for all of the files as it's only meant to index files.  you can use this same callback for indexing folders too.

once you have made the callback for indexing these files you can then hand this callback to the filesystem to be run for each of the files or folders found in the current folder.  the end of file callback needs to be included even if it's not going to be used.

// Find a file
ThinFAT_FindFile((*IndexWavFile), (*EndWavFile));
// Find a folder
ThinFAT_FindFolder((*IndexFolders), (*EndWavFile));

Step 3: Open a File for Reading

now that you have indexed the files on your current folder, you need to open one of them which you need another callback for which can return ThinFAT_Success for.  you can do this with a simple index to check which one it is as the callback will be called in the same order for all of the files in a given folder.

char CheckWavFile(unsigned char Filename[],unsigned char Extension[])
{
if(Extension[0]==87 && Extension[1]==65 && Extension[2]==86)
{
  if(Playlist.FileIndex==Playlist.CurrentFile)
  {
   Playlist.FileIndex=0;
return ThinFAT_Success;
  }else
  {
   Playlist.FileIndex++;
return ThinFAT_Fail;
  }
}
return ThinFAT_Fail;
}

next what you need is an end of file callback for when you reach the end of the file you are playing.  you can also include a function to dectect if the file is active or not so you can use this same callback for closeing the file manualy yourself partway through reading.  you first test in this fuction with ThinFAT_ActiveFile() if the file is active and then run ThinFAT_CloseFile() if the file is active.
void EndWavFile()
{
WDTCTL = WDTPW + WDTHOLD;  // Pause Updating Samples
// Check if file is active and close it
if(ThinFAT_ActiveFile()==ThinFAT_Success)
{ThinFAT_CloseFile();}
Playlist.FileIndex=0;
}

once you have both callbacks ready you can call the command to search and open the file.
ThinFAT_FindFile((*CheckWavFile), (*EndWavFile));

Step 4: Read a File Stream

once a file is opened for streaming you only need to call the following command to read a byte from a file:
audioOut.CurrentSample =ThinFATReadByte();

you can also read Int and Long values from a file but you will need to know if they are big or little endian format.  in each of the commands a lower case B or a L prefix the type of value being read.

// Read a Little-endian Int
audioOut.CurrentSample =ThinFATReadlInt()

// Read a Big Endian Int
audioOut.CurrentSample =ThinFATReadbInt()

// Read a Little-endian Long
audioOut.CurrentSample =ThinFATReadlLong()

// Read a Big-endian Long
audioOut.CurrentSample =ThinFATReadbLong()

to check on the progress of reading the file you can call ThinFAT_FileProgress() which will return the current sector of the file being read from the SD card.  you can then compare this to the file size which is returned by ThinFAT_FileSize():
CurrentFileSector = ThinFAT_FileProgress();
CurrentFileSize = ThinFAT_FileSize();

When you are finished with the file you can call:
ThinFAT_CloseFile();
but you also need a callback ready for when the file is finished that can also tidy up the function your performing.

Step 5: Factors to Consider

There are some important things to consider about useing this filesystem:
it only reads FAT16 filesystems - no SDHC support
it wont read long filenames - keep file names less than 8 characters, extensions below 3 characters
it has no support for file fragments - defrag your SD card before reading
it uses 3K of flash - use a microcontroller with 3K or more flash space

This Project is Based on the Following:
http://www.secure-digital-card-source-code-driver.com/layout-of-a-mmc-or-sd-card-with-fat/the-master-boot-record
http://www.tavi.co.uk/phobos/fat.html
http://www.maverick-os.dk/FileSystemFormats/FAT16_FileSystem.html
http://www.diylife.com/2008/04/25/make-a-talking-msp430-microcontroller/
http://www.ti.com/mcu/docs/litabsmultiplefilelist.tsp?sectionId=96&tabId=1502&literatureNumber=slaa281b&docCategoryId=1&familyId=342

With the Watchdog timer on a 512 divider you have about the maximum sample rate that your processor should be able to handle without skipping some bytes.  you can reach:
2kHz Sample rate on 1MHz
16kHz Sample rate on 8MHz
24kHz Sample rate on 12MHz
32kHz Sample rate on 16MHz
however keep in mind that the power useage is detirmined by your DCO frequency, the faster you run your system the more power that you use.  and that soldering directly to the pins of a Micro-SD adaptor makes a fantastic Micro-SD Slot.