FAT16 and FAT32 Systems: How to Add Mass Storage to Your Embedded Applications
When working in the embedded world there are some chances that you will come across an application requiring greater memory storage space than is available in most microcontrollers and even external EEPROMs. That's why SD or MMC cards are great. They are cheap and easy to work with. For most applications all you need is an SPI port, and even if one is not available you can easily emulate one on most microcontrollers. With the SPI port you can communicate and store data to the SD cards, but it gets a bit trickier. Most applications will require you to store or retrieve data from a personal computer. So you need a way to connect your application to the computer and more importantly a method to organize the data in a way that will be recognized by the computer’s operating system. For this you need to have some sort of file management system. Chances are you will use the FAT 16 or FAT 32 system. The File Allocation Table (FAT) system is somewhat simple and supported by almost all operating systems. It is better to understand how it works before adding it to your embedded device.
SD or MMC cards tend to manage their memory in fixed sizes known as sectors or sometimes page sizes, they are usually of 512 or 256 bytes. In a FAT system some of these sectors are used for the File Allocation Table which acts like an index while the other sectors are used for data storage. All these sectors can be joined together to form what’s known as clusters. Cluster size can range from 1 to 64 sectors. Clusters are entities that are tracked within the File Allocation Table. Since the clusters can range from 1 to 64 sectors, a decision on cluster size must be taken. The advantage of having a larger cluster size is that fewer clusters are used to manage the memory space and therefore a smaller File Allocation Table is required. This makes things more efficient on the file system, however it wastes a lot of memory space when small files are stored to each cluster. So basically you want to choose your cluster size according to the data type and size that you will be working with. The smaller the data is the smaller the cluster size should be. This will ensure an efficient use of the memory space.
The present File Allocation Table is just a table containing information about each cluster. For instance in a FAT16 system each table index is a 16-bit integer showing if the cluster is empty or full, linked to another cluster, reserved or containing bad sectors. A full cluster is represented by 0xFFFF while an empty cluster is given 0x0000. When a file requires more than one cluster of memory space, a chain of clusters is formed and the File Allocation Table links these clusters by having the address of the next cluster stated in each index up until the last cluster which has a 0xFFFF to represent the end of the data or the last cluster in the file. Also 0x0001 represents a reserved cluster and 0xFFF7 represents a bad cluster. The table below describes these features.
The File Allocation Table is very important and two or more copies of it are stored before the data clusters. The main purpose of the File Allocation Table is to keep track of cluster status (empty, full) and location; however it does not contain any information about the currently stored files. For this purpose we have the root directory.
The root directory holds an important file information such as filename, extension, attributes (archive, directory, hidden, read-only, system and volume), creation date and time, the first cluster address of the data file/directory and finally the size of the file/directory. The root directory is stored after the last copy of the File Allocation Table and before the present data clusters. The root directory structure is shown in the next table.
The attributes have some bit masks in the directory entry. They are 01 for Read only, 02 for Hidden, 04 for System, 08 for Volume label, 10 for Subdirectory, and 20 for Archive. The Time and Date store the last time the file was modified. For the Time section bits 15 to 11 represent Hours, bits 10 to 5 represent Minutes, and bits 4 to 0 represent Seconds divided by two. For the Date section bits 15 to 9 represent Year starting from 1980 to 2107, bits 8 to 5 represent Month, and bits 4 to 0 represent the Day. The First Cluster section links the file with the File Allocation Table. This number points to the first cluster containing the file data. Lastly, the Size section contains the data file size (in bytes). You can use the information from the root directory to write a variety of different functions for your embedded system. For example time and date printing of a data sensor in a data logger.
Now that you know the basic structure of the FAT16 system, you can start to develop applications where users can easily communicate with your embedded device and a computer. Adding a mass storage device like an SD card will add flexibility to any device. It is very consuming to write the necessary code to implement the FAT16 system as well as the code to support communications with an SD card. The good news is that there are many free and paid software libraries that take care of the coding for you. All you need to do is modify the code to fit the specific pin-outs and architecture of your microcontroller.
For instance Microchip offers a “File I/O Functions Using Microchip's Memory Disk Drive File System Library” which is basically the FAT16 system for some of their PIC devices. You can download the source code and application report from here. Also, in some cases there are hardware modules available that implement the FAT system for you. Thanks to them you will save development time; however these chips are very expensive and mostly used in USB mass storage devices. Personally I find that they are a waste of money since it is relatively simple to implement the FAT system on your own microcontroller.