I have been working on a project where the client requires their device to have it's firmware updated from a Secure Digital (SD) Card.
The standard way to store and access data on SD cards is to use the MS FAT File System.
- The SD CARDs are SanDisk 512 MB and are preprogrammed with a Master Boot Record, Boot Record, FAT 1, FAT 2, Root Directory, and two files. The address and sector numbers for these entities are listed in Table 1. Table 1 SD Card Road Map Address Sector Cluster Description 0:0000 0 N.A. Master Boot Record which contains the Partition table) 1.
- I use the Master Boot Record while format! For USB thumb drive,it open up but no content inside the window! For the SD card, it detected & shown STOP icon & SD E.
- Name va vsize raw size flags.text: 0x2000: 0x1839b0: 0x183a00: R-X CODE.reloc: 0x186000: 0xc: 0x200: R- IDATA DISCARDABLE.rsrc: 0x188000: 0xd90c: 0xda00: R- IDATA.
The first, Quick, is simply a standard format that erases the Master Boot Record (MBR) on the SD card. Even though the data cannot be accessed using Explorer or Finder on Windows and Mac, it remains on the card itself. The Full (Overwrite) option will initialize the card and overwrite all the data with meaningless data.
There are several libraries available dotted around the Internet which allow developers to access SD using FAT. However, if you are on a tight program space budget, such as in the Boot-Loader of an embedded Microcontroller, then you may need to program the FAT File System access manually.
This process is reasonably difficult to accomplish in raw code as there are quite a few steps to perform before you gain access to the actual file you are after.
I'll outline here the basic features of FAT16, which for the purposes of this example, will be the simplest to begin with.
The FAT16 Layout
The layout of the MS FAT16 File System can be seen below;
The Master Boot Record (MBR):
The Master Boot Record is the first location that the Host File System parses in order to navigate the File Structure of the SD Card. It is always located at Sector zero and not only sets out the addressing parameters of the File System but also contains operating code run by the host at startup.
Address (Offset) | Item | Length | Notes |
0x0000 | Executable Code | 446 Bytes | Executed by the Host system at startup |
0x01BE (00h) | Partition 1: State (Partition 1 Entry Begin) | 1 Byte | Beginning of the Partition 1 Entry. 16 Bytes Total. The State determines if the Partition is Active (80h) or Inactive (00h) |
0x01BF (01h) | Partition 1: Start Head | 1 Byte | |
0x01C0 (02h) | Partition 1: Start Sector / Cylinder | 2 Bytes | Defines the Start Sector and Cylinder of Partition 1 |
0x01C2 (04h) | Partition 1: Partition Type | 1 Byte | Defines the Type of Partition; 01h = 12bit FAT 04h = 16bit FAT (<32Mb) 05h = Ex MSDOS 06h = 16bit FAT (>32Mb) 0Bh = 32bit FAT (<2Gb) |
0x01C3 (05h) | Partition 1: End Head | 1 Byte | |
0x01C4 (06h) | Partition 1: End Sector / Cylinder | 2 Bytes | Defines the End Sector and Cylinder of Partition 1 |
0x01C6 (08h) | Partition 1: Start Sector | 4 Bytes | Contains the Start Sector Address of Partition 1. Defined as the number of Sectors between the MBR and the first Sector of the Partition. |
0x01CA (0Ch) | Partition 1: Partition Length (Partition 1 Entry End) | 4 Bytes | End of the Partition 1 Entry. 16 Bytes Total. Defines the number of Sectors in the Partition |
0x01CE | Partition 2 Entry | 16 Bytes | Defined as above |
0x01DE | Partition 3 Entry | 16 Bytes | Defined as above |
0x01EE | Partition 4 Entry | 16 Bytes | Defined as above |
0x01FE | Executable Marker | 2 Bytes | Set as 0x55AA |
The Boot Sector Entry (BSE):
Offset | 1st sector of Partition |
Size | 512 Bytes |
Address Location Calculation | Partition Start Sector (From MBR) * Bytes / Sector |
The Boot Sector Entry contains all the pertinent information regarding the Partitions' structure. The basic layout is shown below;
Offset | Item | Length | Notes |
00h | Jump Code | 3 Bytes | Contains executable Machine code to allow the Host System to jump past the BSE |
03h | OEM ID | 8 Bytes | The system name which formatted the device |
0Bh | Bytes Per Sector | 2 Bytes | Normally 0x2000 (512 ) |
0Dh | Sectors Per Cluster | 1 Byte | |
0Eh | No of Reserved Sectors | 2 Bytes | |
10h | No of FATs | 1 Byte | The Number of FAT Entries |
11h | Max Root Directory Entries | 2 Bytes | For SD Cards this is usually 0x2000 (512) |
13h | Total Sectors in Partition | 2 Bytes | Only set if the device is < 32Mb. Will likely be unset 0x0000 |
15h | Media Type | 1 Byte | 0xF8 = Hard Drive |
16h | Sectors Per FAT | 2 Bytes | Used for reaching the Root Directory |
18h | Sectors Per Track | 2 Bytes | |
1Ah | No of Heads | 2 Bytes | |
1Ch | No of Hidden Sectors | 4 Bytes | Number of hidden sectors between the start of the disk and the BSE |
20h | No of Sectors in a Partition | 4 Bytes | Total number of Sectors in the Partition |
24h | Logical Drive No | 1 Byte | 0x80 for Hard Drives |
25h | Head No | 1 Byte | Usually 0x00 |
26h | Extended Boot Signature | 1 Byte | Always 0x29 denoting that Serial No, Label and Type fields are valid |
27h | Serial No | 4 Bytes | Serial No of the Device |
2Bh | Partition Name | 11 Bytes | |
36h | FAT Type | 8 Bytes | |
3Eh | Executable Boot Code | 448 Bytes | Allows the host to find the first file which boots the system |
0x01FE | Executable Signature | 2 Bytes | End of BSE |
FAT Entries (FAT):
Offset | FAT1 = 1st sector after Reserved Sectors |
Size | Sectors Per FAT (From BSE) |
Address Location Calculation | FAT1 = (Partition Start Sector(From MBR) + Reserved Sectors(From BSE)) * Bytes / Sector |
The FAT Entries lay out how the Partitions' identically sized clusters are laid out. There are normally two FAT Entries in order to help prevent FAT corruption problems.
The FAT is located in the first sector after the Reserved Sectors. All sectors between Partition Start Sector and the FAT, which includes the Boot Sector Entry, are contained within the Reserved Sectors Allocation.
So, to find the first FAT we navigate from the beginning of the Device, adding together the Partition Start Sector and the Number of bytes contained in the Reserved Sectors section.
Root Directory Entry (RDE):
Offset | After last FAT |
Size | No of Root Entries(From BSE) * 32 |
Address Location Calculation | RDE = FAT1 Start Address + ((No of FATS(From BSE) * Sectors Per FAT(From BSE)) * Bytes Per Sector) |
The Root Directory contains the Main Directory and File Structure for the entire Partition
The Root directory is almost identical to a standard File System Directory with only a few differences, namely; The first byte is the first character of the Partition Name. The Create Date and Time are set to 0x00. Ccleaner ios 11.
The Root directory appears after the last FAT, and so can be found by adding the Start Address of the first FAT to the number of Bytes occupied by all FAT's, which is invariably 2 for SD Cards. Thus the formula can be simplifed to;
RDE = FAT1 Start Address +
((2 * Sectors Per FAT) * 512)
Brave search engine. Each entry in the Root Directory consumes a total of 32 Bytes as shown below;
Offset | Item | Length | Notes |
00h | DOS Filename | 8 Bytes | For all other Directories the first byte has special values. |
08h | DOS File Extension | 3 Bytes | |
0Bh | File Attributes | 1 Byte | 8 bits to denote various attributes |
0Ch | NT Case Info | 1 Byte | Used for Windows NT Casing Info |
0Dh | Create Time (ms) | 1 Byte | 10ms Units |
0Eh | Create Time (Hrs/Mins/Secs) | 2 Bytes | |
10h | Create Date | 2 Bytes | |
12h | Last Access Date | 2 Bytes | |
14h | File / Folder Start Cluster (High) | 2 Bytes | Only used in FAT32 Systems |
16h | Last Modified Time | 2 Bytes | |
18h | Last Modified Date | 2 Bytes | |
1Ah | File / Folder Start Cluster (Low) | 2 Bytes | |
1Ch | File Size (Bytes) | 4 Bytes | Folders will have a File Size of 0x0000 |
Sub Directory / Files:
Offset | After Root Directory |
Size | N/a |
Address Location Calculation | Root Folder Address + (Max Root Directory Entries(From BSE) * 32) + ((( File / Folder Start Cluster(From RDE) – 2) * Sectors Per Cluster(From BSE) ) * Bytes Per Sector(From BSE) ) Normally For SD Cards using FAT16; Max Root Directory Entries = 512 Bytes Per Sector = 512 |
A Sub Directory takes on almost exactly the same format as the root Directory above.
All data stored after the Root Directory is located in the third Data Cluster, thus in order to find the location of all data we must subtract these two clusters from the Start Cluster given in the File / Folder Start Cluster Field.
The first data is found using the formula above, however for SD Cards using FAT16, the maximum Root Directory Entries and Bytes Per Sector are invariably 512. Thus the formula can be simplified to the following;
First Data = Root Folder Address + 16384 +
(((File/Folder St Cluster – 2) *
Sectors Per Cluster) * 512)
A Worked Example:
Card Type | Sandisk 2Gb SD |
MBR Length | 512 |
Partition 1 Start Sector | 129 |
Bytes Per Sector | 512 |
Sectors Per Cluster | 64 |
Reserved Sectors | 2 |
Number of FAT's | 2 |
Sectors Per FAT | 239 |
Hidden Sectors | 129 |
BSE Length | 512 |
Number of Root Entries | 512 |
The table above gives all the information taken from the MBR and BSE of the Card.
Calculating the BSE Address:
BSE = Partition Start Sector *
Bytes Per Sector
BSE = 129 * 512
BSE = 66048 = 0x10200
Calculating the FAT1 Address:
FAT1 = (Partition Start Sector +
Reserved Sectors) * Bytes Per Sector)
FAT1 = (129 + 2) * 512 Creative cloud will not update.
FAT1 = 131 * 512
FAT1 = 67072 = 0x10600
Calculating the Root Directory Address:
RDE = FAT1 Start Address +
((No of FATS * Sectors Per FAT) *
Bytes Per Sector)
RDE = 67072 +
((2 * 239) *
512)
RDE = 67072 + (478 * 512)
RDE = 67072 + 244736
Master Boot Record Sd Card
RDE = 311808 = 0x4C200
Windows Boot Sd Card
Calculating the First File Address:
For a file or folder which has a starting cluster value of 0x04, then the following will locate the start address;
File = Root Folder Address +
(Max Root Entries * 32) +
(((File/Folder St Cluster – 2) *
Sectors Per Cluster) *
Bytes Per sector)
File = 311808 +
(512 * 32) +
(((4 – 2) *
64) *
512)
File = 311808 +
16384 +
((2 * 64) * 512)
File = 311808 + 16384 + (128 * 512)
File = 311808 + 16384 + 65536
File = 393728 = 0x60200