SDカードドライバの設計(2)

SDカードのファイルシステム

SDカードはファイルシステムにFATを採用しています。ですが実は、FATであることは必須ではありません。SDカードの低レベルインタフェース仕様のみを見れば、単なるセクタ単位の入出力なので、他のファイルシステムを入れることも可能です。
セクタサイズは512バイト(2GBのカードなどでたまに例外があります)なので、効率的な読み込みのためには最低512バイトのバッファが必要です。書き込みをする場合は、フラッシュメモリの特性である消去単位(数kB~数100kB)を考慮しないと性能や寿命の問題が出るのでさらに面倒ですが、ここではとりあえず読み込みだけを考えます。

ただ、現在販売されているSDカードはすべてFATフォーマット済みですし、パソコンを始めとしてデジタルカメラや携帯電話に至るまで、FATをサポートしているので、他のフォーマットを採用するのは相互運用性の面からは現実的ではありません。

ちなみに、デフォルトでMMC/SDカードは12ビットまたは16ビットFAT、SDHCカードは32ビットFATとなっています。通常はVFATとなっており、ロングファイルネームに対応しています。

さてそのFATですが、情報が少なく、実装はなかなか大変です。さらにZ80上での実装となるとほとんどWeb上には例がありません。AVRなんかだとMP3プレイヤーの実装例などがあるので比較的ソースを見つけることができるのですけどね。

そしてそのソースなのですが、バイト配列に対してオフセットを直接指定してアクセスしているものがほとんどで、非常に読みにくいです。そこで、今回は構造をきちんと定義した上で実装することからはじめました。ただこれも良し悪しで、gccなどの進化したCコンパイラならいいのですが、Z80で使えるsdccなどだと構造体の使い方によっては効率の悪いコードを吐き出します。実装ではこの辺も勘案してありますが、ここでは綺麗な世界(?)で説明します。

FATの構造(1): まずはセクタ0のMBRから

最初のセクタはいわゆるMBR (Master Boot Record)です。SDカー ドに限らず、フロッピーディスクやハードディスクなど、ほとんどすべてのブロックデバイスは、初期化後に初めてカードを読み込むときは必ずセクタ0を読み 込んで、基本情報を得ます。FATの場合、その構造は以下のようになっています。

struct MasterBootRecord {
BYTE checkRoutineOnX86[446];
struct {
BYTE bootDescriptor; /* 0x80: bootable device */
BYTE firstPartitionSector[3]; /* 1st sector number */
BYTE fileSystemDescriptor; /* FAT type */
BYTE lastPartitionSector[3];
DWORD firstSector; /* BPB sector number */
DWORD numberOfSectors;
} partitionTable[4]; /* up to four partitions per drive */
WORD sig; /* 0x55, 0xaa */
};

checkRoutineOnX86 は、主にx86 PCのBIOS向けと考えていいでしょう。PCはフロッピーであろうがハードディスクであろうが、ブート可能なデバイスを読み込んだときにここにあるコー ドを実行して、初期化を進めるようです。SDカードは普通ブートデバイスではないですし、x86に限った話でもないのでここの情報にはあまり意味はありま せん。

この中で実装に重要な情報は以下です。

partitionTable

パーティションごとの情報を格納する。ひとつのディスクには最大4つのパーティションが格納できるので、この構造体も4つある。

firstSector

パーティションの最初のセクタ、BIOS Parameters Blockの位置を表す。通常SDカードはパーティションは1つしかないので、partitionTable[0].firstSectorを見ればよい。

sig

シグネチャで、0x55, 0xaaの順番で格納されている。これはレコードの正当性を判断するのに使う。

fileSystemDescriptor

それから、fileSystemDescriptorというフィールドがあります。これはパーティションのFATの種類を以下のように表します(一部)。

0x01:FAT12
0x04または0x06:FAT16
0x0b:FAT32
0x0c:FAT32 (int32拡張)
0x0e:FAT16 (int32拡張)

FAT32 は無視するとしても、この0x0eが曲者です。実は、Windows XPなどで容量の小さなSDカードをフォーマットすると、実際にはFAT12でフォーマットされているにもかかわらず、 fileSystemDescriptorは0x0eになります。そのため、実際にはこのフィールドだけではFATの厳密な種類を判別できません。

あ とで説明しますが、FAT12とFAT16ではデータアクセス時のFATの読み方が違うため、厳密に判定できないと問題です。そのためこのフィールドは使 えません。市販されているSDカードをそのまま使う分には問題ないのですが、Windowsでフォーマットした途端に読めなくなってしまいます。

なんだか長くなったので、続きは次回...。

こちらもよく読まれています