In a previous blog I discussed moving from a FAT16 based SD card to a FAT32 based SDHC card.
In that blog I went through the differences in Initialisation procedures between the different SD Specification.
In this blog I’ll detail the differences in Addressing schemes between the devices and the two File Systems.
FAT32 Addressing Changes
Due to how the addressing scheme in FAT16 is organised, a top limit exists at 2GB. In order to allow the FAT File System to expand in capacity, various changes have been made to the File System, including expanding and altering registers entries.
The Boot Sector Entry:
The Boot Sector Entry or BSE, holds critical information regarding the partition’s layout. The following table shows the layout of the FAT16 BSE;
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 |
The BSE has been modified and expanded to allow the File System to expand past the 2GB limit. The modified BSE for FAT32 is shown below. The value positions which have changed or been added are shown in red;
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 | Always 0 for FAT32 |
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 | Always 0 for FAT32 |
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 | Sectors Per FAT | 4 Bytes | Defines the total number of Sectors contained |
28h | Flags | 2 Bytes | Defines flags for Active FAT Copy and Mirroring |
2Ah | Version | 1 Byte | Version of FAT Drive |
2Ch | Cluster of Root Dir | 4 Bytes | Defines the Start Cluster of the Root Directory |
30h | FS Info Sector | 2 Bytes | Defines the first Sector of the File System Info. |
32h | Backup BSE Sector | 2 Bytes | Defines the First Sector of the Backup BSE |
34h | Reserved | 12 Bytes | Reserved Bytes |
40h | Drive Number | 1 Byte | Logical Drive Number of Partition |
41h | Reserved | 1 Byte | Reserved Byte |
42h | Boot Signature | 8 Bytes | Defines the Boot Signature of the File system |
43h | Volume Serial No | 4 Bytes | Defines the Serial number of the File system |
47h | Volume Label | 11 Bytes | Defines the Volume Label of the File system. |
52h | File System Type | 8 Bytes | Defines the type of File System on the SD card. |
As can be seen above, there have been quite a few changes to the BSE structure to cope with the conversion from FAT16 to FAT32.
Calculating the Root Directory Address (FAT16):
The formula use to calculate the Root Directory Address for FAT16 is;
RDE Address = FAT1 Start Address +
((No of FATs(From BSE) *
Sectors Per FAT(From BSE)) *
Bytes Per Sector(From BSE))
Calculating the Root Directory location (FAT32):
From the FAT32 BSE table above, we can see we have a new field at offset 2Ch; “Cluster of Root Directory”.
This field allows us to Jump from the first Data Cluster of File System directly to the Root Directory. We do of course need to calculate the first Data Cluster Address. The formula for this is;
First Data Cluster =
(Partition 1 Start Sector(From MBR) +
Reserved Sectors(From BSE) +
(No of FATs(From BSE) *
Sectors Per FAT(From BSE))) *
Bytes Per Sector(From BSE)
Once we have the address of the first Data Cluster, we are then able to calculate the address of the Root Directory. This is accomplished simply by applying the formula used for locating a File or Folder;
File / Folder Address =
Cluster 1 Start Address +
(((File/Folder Start Cluster–2) *
Secs/Cluster(From BSE)) * 512)
Thus we apply the formula above feeding in the Root Directory Start Cluster, to obtain the Root Directory Address.
SD Card Addressing Change
As SD cards have increased in size, it has become necessary for devices to use a different addressing scheme. FAT16 devices address on a Byte by Byte level. However, as devices have grown, this has become an unmanageable number.
This change of course affects the use of CMD17 – Block Read. Where the argument supplied is a 4 byte address to read data from. As mentioned above, for normal SD Cards this address is a byte unit address. However, the larger devices now use a Sector by Sector addressing scheme. Of course, this requires that the Host system take this into account when addressing the card, such that it must record which type of card is connected and make a decision of which addressing scheme to use based upon this. The card type is detected using the ACMD41 command sequence detailed in my previous blog.
The simplest way to handle this difference in code, is to simply check the card size before passing the address to CMD17. If the Host is connected to an SDHC device, then simply divide the Byte Address by 512 to reach the Sector Address.
Alternatively, rather than multiplying all Sector Address locations by the Bytes/Sector value, the Host may simply check the Card Type, if a Standard SD card is connected, then simply multiply the Sector Address by the Bytes/Sector value to reach the Byte Address.
This decision will no doubt depend upon whether you are writing code from scratch or upgrading already existing code.
Hi, nice info!.
ReplyDeleteI have a question, if i wanted to write in the byte 262144 of a card, with an SDSC card shall i use 0x40000 as the address and with an SDHC card shall i use 0x200? is that what you mean with the addressing change?
Thanks in advance!!!
Hi, I would also like to know the solution to Juan question.
ReplyDeletefor example, if I want to read data from byte address 0x000 40 8000 (as seen from hex editor/winhex), then I should use address 408000/200 = 0x00002040 when using CMD17/CMD18?
Thanks.