MMCの実験 2009.06.20(土)〜 /
著作者名: 中野 良知 作成開始: 2009.06.14(日) 最新修正: 2011.08.15(月) △1 2クラスタ相当のファイル読出し。
目次 1. 概要 2. コマンド 2.1. コマンド・レスポンス 3. タイミングチャート 4. カードの初期化 4.1. SDCの初期化 4.2. MMCの初期化 5. 読出し手順 5.1. シングル・ブロック・リード 5.2. マルチ・ブロック・リード 6. 書込み手順 6.1. シングル・ブロック・ライト 6.2. マルチ・ブロック・ライト 7. メモリーマップ 8. FAT16システム 8.1. MBR(Master Boot Record) 8.2. BPB(BIOS Parameter Block) 8.3. FATタイプの決定 8.4. FAT Entry 8.5. FATクラスタをLBAに変換 8.6. ROOT DIR 8.7. DATA AREA 9. MMC端子配列 10. 回路図 10.1. USB通信・クロック発振・リセット 10.2. カードI/F 10.3. LCD表示器 11. 経過 12. 参考文献 1. 概要 Multi Media Card(MMC)からのデータ読出しと書込みの実験です。 MMCはSPIモードで操作します。 2. コマンド コマンドは6バイト構成 ビット列 MSB LSB MSB LSB MSB LSB MSB LSB MSB LSB MSB LSB 01xxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxx1 ←CMD → ←───────引数 ──────→ ←CRC→ 出力順→ 先頭の2ビットは固定値で、0はスタートビット。次の1はトランスミッションビット。 続く6ビットはコマンドインデックスで、0x40+コマンドインデックスで構成。 例:CMD0は0x40+0x00=0x40、CMD1は0x40+0x01=0x41。 CRCは7ビット。CMD0のみCRCを使用(固定値)。他のコマンドでは無効なCRC値を使用。 最終ビットはエンドビットで常に1。 実験で使用したコマンド CMD 値 引数(4byte) 応答 内容 ----+------+--------------+------+-------------------------------------- 0 0x40 0x00000000 R1 カードリセット。アイドルモードへ移行 1 0x41 0x00000000 R1 カード初期化 9 0x49 0x00000000 R1 CSD取得(Card Specific Data) 10 0x4A 0x00000000 R1 CID取得(Card IDdentification) 17 0x51 Data Address R1 シングル・ブロック・リード 18 0x52 Data Address R1 マルチ・ブロック・リード 23 0x57 0x0000XXXX R1 XXXXにマルチ・ブロック数を設定 24 0x58 Data Address R1 シングル・ブロック・ライト 25 0x59 Data Address R1 マルチ・ブロック・ライト 55 0x77 0x00000000 R1 SDCカード初期化用ACMD41=CMD55+CMD41 2.1. コマンド・レスポンス コマンドを発行すると、MMCからコマンドに対する応答があり、 実験で使用したコマンドでは、1バイトの応答 R1 が発生します。 R1の構成 b7 b6 b5 b4 b3 b2 b1 b0 ┌─┬─┬─┬─┬─┬─┬─┬─┐ │0 │ │ │ │ │ │ │ │ └─┴─┴─┴─┴─┴─┴─┴─┘ │ │ │ │ │ │ │ 内容 │ │ │ │ │ │ └ In Idle State │ │ │ │ │ └── Erase Reset │ │ │ │ └──── Illegal Command │ │ │ └────── Communication CRC Error │ │ └──────── Erase Sequence Error │ └────────── Adrress Error └──────────── Parameter Error コマンド発行後、DOから1バイトを受信し、b7=0ならば R1 応答です。 b7=1なら R1 を受信するまでカードをポーリングします。 R1を受信したら、R1の内容を判定します。 ビット=1で内容が示す状態にある事を表します。 3. タイミングチャート ──┐ ┌─┐ ┌─┐ ┌ ─ ─┐ ┌─┐ ┌─┐ ┌──── CLK └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ ↓ ↓ ↓ ─┐ ┌─────── ─ ──────────────── DI └───┘ ↓ ↓ ↓ ───────────── ─ ──┐ ┌───── DO └───────┘ ホストはMMCに対してCLKの立下り前にDIを出力。 ホストはMMCからのDOをCLKの立上り前にサンプリング。 データの授受をソフトで行った実験では、DI出力とDO入力ともに1μsecの遅延を設け た後にCLKを切換えました。 タイミングの詳細な規格値は、参考文献等を参照して下さい。 実験の後半では、ATmega8の内蔵周辺機能のSPIを下記の設定で使用しました。 SPI(Serial Peripheral Interface)の設定: 1) 割込禁止 2) 送信禁止 3) MSB first 4) マスタモード。(MMCの-CSはソフトで制御) 5) 出力(MMC-DI)=立下り 6) 入力(MMC-DO)=立上り 7) CPUクロック分周比=1/2。 MMC CLK=16MHz。1バイトのR/Wを1usecで実行。 1)-7)までの設定例: ldi acc, 0x1C ; out SPCR, acc ; sbi SPSR, SPI2X ; 1/2。1/16MHz*2=0.125usec 8) SPIの送受信の許可は、入出力の直前に実行。 例: acc(R17)に送信用データを設定し、rcall out_8bitを実行。 8ビット出力コーディング例 out_8bit: sbi SPCR, SPE ; 送信許可 out SPDR, acc ; 送信開始 out_8bit5: sbis SPSR, SPIF ; 送信完了ならばスキップ゚ rjmp out_8bit5 ; 送信完了まで待機 cbi SPCR, SPE ; 送信禁止 ret ; 8ビット入力コーディング例 in_8bit: sbi SPCR, SPE ; 送信許可 ser acc ; out SPDR, acc ; 送信開始 in_8bit5: sbis SPSR, SPIF ; 受信(転送)完了ならばスキップ rjmp in_8bit5 ; 受信(転送)完了まで待機 in acc, SPDR ; 受信データを取得 cbi SPCR, SPE ; 送信禁止 ret ; 呼び出し元へ復帰 4. カードの初期化 最初はSDCとして初期化を行いエラーならMMCとして初期化を行います。 (カードの初期化) │ No <SDC初期化でエラー?>──SDCの初期化完了 │Yes No <MMC初期化でエラー?>──MMCの初期化完了 │Yes カードの初期化に失敗 │ (終了) 4.1. SDCの初期化 1) 電源投入。 2) コマンド0発行カウンター設定 3) -CS=Hでダミークロックを80個送信。 4) -CS=L。 カード選択。 5) CMD0発行 CMD0=0x40 00 00 00 00 95 6) CMD0発行カウントオーバーなら初期化エラーで26)へ 7) R1応答受信(bit7=0待ち) 8) R1受信タイムオーバーなら初期化エラーで26)へ 9) 応答=0x01なら12)へ 10) 応答=0x1Fなら3)へループ 11) 応答=0x01または0x1F以外なら初期化エラーで26)へ 12) CMD55発行カウンター設定 13) ダミー8クロック出力 14) CMD55を発行 CMD55=(0x40+55) 00 00 00 00 01 15) CMD55発行カウントオーバーなら初期化エラーで26)へ 16) R1応答受信(bit7=0待ち) 17) R1受信タイムオーバーなら初期化エラーで26)へ 18) ダミー8クロック出力 19) ACMD41発行 ACMD41=(0x40+41) 00 00 00 00 01 20) R1応答受信(bit7=0待ち) 21) R1応答受信タイムオーバーなら初期化エラーで26)へ 22) R1=0x00なら初期化成功で25)へ 23) R1=0x05なら初期化エラーで26)へ 24) R1=0x00またはR1=0x05以外ならば13)へ 25) ダミー8クロック出力 26) -CS=H 27) 終了 4.2. MMCの初期化 電源投入後のMMCモードをSPIモードに変更する手順。 1) 電源投入でMMCモード。 2) -CS=Hでダミークロックを80個送信。DI(MOSI)=H。 MMCモードのRCAレジスターを初期化。 3) -CS=L。 カード選択。 4) CMD0発行。カードリセット。 CMD0=0x40 00 00 00 00 95 → データ送信順。MSB First。 5) R1受信(1バイト) 6) レスポンスチェック R1のbit7=1なら 5)へ戻って繰り返す。 R1のbit7=0で 7)へ。 7) ダミークロックを8個送信。DI(MOSI)=H。 8) CMD1発行。カード初期化。 CMD1=0x41 00 00 00 00 F9 9) R1受信(1バイト) 10) レスポンスチェック R1のbit7=1なら 9)へ戻って繰り返す。 R1のbit7=0で 11)へ 11) ダミークロックを8個送信。DI(MOSI)=H。 12) CMD1発行。 CMD1=0x41 00 00 00 00 F9 13) R1受信(1バイト) 14) レスポンスチェック R1のbit7=1なら 13)へ戻って繰り返す。 R1のbit7=0で 15)へ 15) SPIモード設定完了チェック。 R1=0x00以外なら 11)へ戻って繰り返す。 R1=0x00ならSPIモード設定完了。16)へ。 16) ダミークロックを8個送信。DI(MOSI)=H。 17) -CS=H。カード非選択。 5. 読出し手順 5.1. シングル・ブロック・リード MMCから1ブロック(セクタ)のデータを読出します。 読出し手順 1) -CS=L。カード選択。 2) LBAをバイトアドレスに変換 3) CMD17発行 CMD17=0x51 xx xx xx xx 01 xxはバイトアドレス。全部で4バイト。 4) R1受信(1バイト) R1のbit7=1なら 4)を繰り返す R1のbit7=0で 5)へ 5) DATA TOKEN受信(1バイト) 受信データ=0xFE以外なら 5)を繰り返す 受信データ=0xFEなら 6)へ 6) データ512バイト読出し 7) CRC 2バイト読出し 8) ダミークロック8ビット出力 9) -CS=H。カード非選択。 ─┐ ┌── -CS └──────────────────────┘ ──┬──┬─┬┬──┬────────┬─┬┬─── CLK └──┘ └┘ └────────┘ └┘ ──┬──┬───────────────────── DI └──┘ ───────┬┬──┬┬──────┬┬────── DO └┘ └┴──────┴┘ ├──┤ ├┤ ├┼──────┼┤ ├┤ 3) 4) 5) 6) 7) 8) 5.2. マルチ・ブロック・リード MMCから複数のブロック(セクタ)のデータを連続して読出します。 使用したMMCのCSD(Card Specific Data)を読出し CSD_STRUCTURE = 2 (2以上でマルチ・ブロック対応) SPEC_VERSION = 3 (3以上でマルチ・ブロック対応) WRITE_BL_LEN = 9 (9ブロックまで対応?) から、マルチ・ブロック・リードに対応している事を確認します。 データ読出しに先立ち、CMD23でブロック数=8を設定し、CMD18でデータを読出しま す。 読出し手順 1) -CS=L。カード選択。 2) CMD23発行 CMD23=0x57 00 00 00 08 01 3) R1受信 R1のbit7=1なら 3)を繰り返す R1のbit7=0で 4)へ 4) ダミークロック8ビット出力 5) LBAをバイトアドレスに変換 6) CMD18発行 CMD18=0x52 xx xx xx xx 01 xxはバイトアドレス。全部で4バイト。 7) R1受信 R1のbit7=1なら 7)を繰り返す R1のbit7=0で 8)へ 8) ブロックカウンタを設定 = 8 9) DATA TOKEN受信(1バイト) 受信データ=0xFE以外なら 9)を繰り返す 受信データ=0xFEなら 10)へ 10) 1ブロックデータ受信 11) CRC受信(2バイト) 12) 8ブロック受信完了チェック ブロックカウンタが 0 以外なら 9)へ戻る ブロックカウンタが 0 なら 13)へ 13) ダミークロック出力 14) -CS=H。カード非選択。 ─┐ ┌── -CS └───────────────────────── ───┘ ──┬──┬┬┬┬┬┬──┬┬┬┬────────┬─ ─┬┬─── CLK └──┘└┘└┘└──┘└┘└────────┘ └┘ ──┬──┬────┬──┬───────────── ────── DI └──┘ └──┘ ──────┬┬──────┬┬┬┬──────┬┬─ ────── DO └┘ └┘└┴──────┴┘ ├──┤├┤├┤├──┤├┤├┼──────┼┤ ├┤ 2) 3) 4) 6) 7) 9) 10) 11) 13) ├←──────→┤ ブロック数分を繰り返す 6. 書込み手順 6.1. シングル・ブロック・ライト 1ブロック(セクタ)のデータをMMCに書込みます。 書込み手順 1) -CS=L。カード選択。 2) LBAをバイトアドレスに変換 3) CMD24発行 CMD24=0x58 xx xx xx xx 01 xxはバイトアドレス。全部で4バイト。 4) R1受信 R1のbit7=1なら 4)を繰り返す R1のbit7=0で 5)へ 5) DATA TOKEN出力 1バイトの0xFEを出力 6) データ512バイト書込み 7) CRC出力(2バイト) 8) データレスポンス待ち R=1バイト受信 R=R & 0x1F R=0x05以外なら 8)を繰り返す R=0x05なら 9)へ 9) 書込み完了待ち(BUSY CHECK) B=1バイト受信 B=0x00なら 9)を繰り返す B=0x00以外なら 10)へ 10) ダミークロック8ビット出力 11) -CS=H。カード非選択。 ─┐ ┌── -CS └─────────────────────────┘ ──┬──┬─┬┬─┬┬────────┬┬┬┬┬┬──── CLK └──┘ └┘ └┴────────┴┴┴┘└┘ ──┬──┬────┬┬────────┬┬──────── DI └──┘ └┴────────┴┘ ───────┬┬────────────┬┬┬────── DO └┘ └┴┘ ├──┤ ├┤ ├┼────────┼┼┼┤├┤ 3) 4) 5) 6) 7)8)9) 10) 6.2. マルチ・ブロック・ライト 複数ブロック(セクタ)のデータを連続してMMCに書込みます。 使用したMMCのCSD(Card Specific Data)を読出し CSD_STRUCTURE = 2 (2以上でマルチ・ブロック対応) SPEC_VERSION = 3 (3以上でマルチ・ブロック対応) WRITE_BL_LEN = 9 (9ブロックまで対応?) から、マルチ・ブロック・ライトに対応している事を確認します。 データ書込みに先立ち、CMD23でブロック数=8を設定し、CMD25でデータを書込みま す。 注) DATA TOKEN出力の値は 0xFC で、他のリード/ライトの 0xFE と異なります。 書込み手順 1) -CS=L。カード選択。 2) CMD23発行 CMD23=0x57 00 00 00 08 01 3) R1受信 R1のbit7=1なら 3)を繰り返す R1のbit7=0で 4)へ 4) ダミークロック8ビット出力 5) LBAをバイトアドレスに変換 6) CMD25発行 CMD25=0x59 xx xx xx xx 01 xxはバイトアドレス。全部で4バイト。 7) R1受信 R1のbit7=1なら 7)を繰り返す R1のbit7=0で 8)へ 8) ブロックカウンタを設定 = 8 9) DATA TOKEN出力 1バイトの 0xFC を出力 10) 1ブロックデータ出力 11) CRC出力(2バイト) 12) データレスポンス待ち R = 1バイト受信 R &= 0x1F R = 0x05以外なら 12)を繰り返す R = 0x05なら 13)へ 13) 書込み完了待ち(BUSY CHECK) B = 1バイト受信 B = 0x00なら 13)を繰り返す B = 0x00以外なら 14)へ 14) 8ブロック出力完了チェック ブロックカウンタが 0 以外なら 9)へ戻る ブロックカウンタが 0 なら 15)へ 15) ダミークロック出力 16) -CS=H。カード非選択。 ─┐ ┌─ -CS └──────────────────────────── ───┘ ──┬──┬┬┬┬┬┬──┬┬┬┬┬───────┬┬┬┬─ ─┬┬── CLK └──┘└┘└┘└──┘└┘└┴───────┴┴┴┘ └┘ ──┬──┬────┬──┬──┬┬───────┬┬─── ───── DI └──┘ └──┘ └┴───────┴┘ ──────┬┬──────┬┬──────────┬┬┬─ ───── DO └┘ └┘ └┴┘ ├──┤├┤├┤├──┤├┤├┼───────┼┼┼┤ ├┤ 2) 3) 4) 6) 7) 9) 10) 11)12)13) 15) ├←─────────→┤ ブロック数分を繰り返す 7. メモリーマップ 使用しているMMCのメモリーマップです。 このMMCはFAT16システムで初期化されています。 ボリュームの先頭セクターはBPBで、ボリュームのメンバーはBPB、予約領域、FAT、 ROOT DIRとデータ領域です。 ┌───────┐LBA │MBR (1sector) │0 + PT_LBAOfs(0x20)─┐ ├───────┤ │ │ │ ┌─────────┘ │ │ │ ├───────┤ ↓ │BPB (1sector) │0x20 + BPB_RsvdSectCnt(0x1C) ─┐ ├ ─ ─ ─ ┤ │ │Reserved Area │ ┌──────────────┘ │(28sectors) │ │ ├───────┤ ↓ │FAT1 │0x3C + BPB_FATSz16(0xF2) ─┐ │(242sectors) │ ┌────────────┘ │(61952entries)│ │ ├───────┤ ↓ │FAT2 │0x12E + BPB_FATSz16(0xF2)─┐ │(242sectors) │ ┌────────────┘ │(61952entries)│ │ ├───────┤ ↓ │ROOT DIR │0x220 + (BPB_RootEntCnt(0x200) * DirEntryByte(0x20) │(32sectors) │ / BPB_BytsPerSec(0x200)─┐ │(512entries) │ ┌──────────────┘ ├───────┤ ↓ │DATA AREA │0x240 │(1980864 │ │ sectors) │ │(61902 │ │ clusters) │0x1E3BFF └───────┘ MBRには4個のパーティションブロックがあり、実験で使用したMMCは先頭の パーティションのみが有効です。 Reserved AreaはBPBを含めて28セクター。 DirEntryByteは1個のDIR ENTRYのバイト数で32バイト固定。 1sector=BPB_BytsPerSec=512バイト。 8. FAT16システム MBRのパーティション情報からBPBのLBAを取得します。 BPBからFATシステムの各種パラメータを取得します。 FATはクラスタのリンクテーブルです。 ROOT DIRにファイル名、ファイルサイズ、作成日時等のファイル情報を記録します。 DATA AREAにファイルのデータを記録します。 以下は各領域の概要です。 8.1. MBR(Master Boot Record) MMCのLBA=0にMBRが記録されています。 MBRの構成 OFFSET SIZE 内容 -------+------+---------------------------------------------------- 0 446 Boot Code。 未使用で全て0x00 446 16 Partition1。 実験で使用したMMCはここを使用 462 16 Partition2。 未使用で全て0x00 478 16 Partition3。 〃 494 16 Partition4。 〃 510 2 Sig。 0x55,0xAA。この値以外はFATとして認識しない Partition1の構成 OFFSET SIZE 項目名 内容 -------+------+----------------+------------------------------------ 8 4 PT_LbaOfs BPBセクターのLBA(FATボリュームの先頭) 12 4 PT_LbaSize LBAセクター数(FATボリューム内) 8.2. BPB(BIOS Parameter Block) FATボリュームの先頭セクターはBPBで、FATボリュームはBPB、予約領域、FAT、 ROOT DIR と DATA AREA で構成されます。 BPBのセクタアドレス(LBA)は、MBRの PT_LbaOfs に設定されています。 ┌───────┐LBA │MBR (1sector) │0 + PT_LbaOfs(0x20)─┐ ├───────┤ │ │ │ ┌─────────┘ │ │ │ ├───────┤ ↓ │BPB (1sector) │0x20 + BPB_RsvdSecCnt(0x1C)─┐ ├ ─ ─ ─ ┤ │ │Reserved Area │ ┌─────────────┘ │(28sectors) │ │ ├───────┤ ↓ │FAT1 │0x3C BPBの構成 OFFSET SIZE 項目名 内容 -------+------+----------------+------------------------------------ 0 3 BS_jmpBoot Boot用ジャンプコード 3 8 BS_OEMName "MSWIN4.1" 11 2 BPB_BytsPerSec バイト/セクタ 13 1 BPB_SecPerClus セクタ/クラスタ 14 2 BPB_RsvdSecCnt (*1) BPB基点でFAT1までのセクタ数 16 1 BPB_NumFATs FATの数。通常は2 17 2 BPB_RootEntCnt Root DIRのエントリ数 19 2 BPB_TotSec16 セクタ総数。0xFFFF個以下で有効 21 1 BPB_Media 標準=0xF8。FATのEntry0の下位に入る値 22 2 BPB_FATSz16 FATのセクタ数 24 2 BPB_SecPerTrk セクタ/トラック 26 2 BPB_NumHeads ヘッド数 28 4 BPB_HiddSec 隠蔽されたセクタ数 32 4 BPB_TotSec32 セクタ総数。0x10000個以上に適用 36 1 BS_DrvNum 交換媒体は0x00 37 1 BS_Reserved1 WinNTで使用。通常=0x00 38 1 BS_BootSig 拡張Boot標識 39 4 BS_VolID ボリュームID 43 11 BS_VolLab ボリュームラベル("NO NAME") 54 8 BS_FileSysType (*2) FATのタイプ。"FAT16"。 (*1) 予約領域にはBPBが含まれます。 (*2)「FATタイプの決定」の計算結果が優先します。 8.3. FATタイプの決定 BPBの各種情報からFAT12、FAT16、FAT32のタイプを決定します。 BPBの BS_FileSysType のFATタイプ文字列では決定出来ません。 FATタイプ決定の計算 1) ROOT DIR領域のセクタ数を求める。 (BPB_RootEntCnt * 32) + (BPB_BytsPerSec - 1) ÷) BPB_BytsPerSec ---------------------------------- = RootDirSectors 2) データ領域のセクタ数を求める BPB_TotSec16(or BPB_TotSec32) -) BPB_RsvdSecCnt -) (BPB_FATSz16 * BPB_NumFATs) -) RootDirSectors ---------------------------------- = DataSectors 3) クラスタ数を求める DataSectors ÷) BPB_SecPerClus --------------------- = ClustCnt FATタイプの決定 FAT12: ClustCnt < 4085 FAT16: 4085 <= ClustCnt < 65535 FAT32: ClustCnt > 65535 8.4. FAT Entry FAT(File Alocation Table)は、ファイルが使用するクラスタのリンクテーブルで す。 下記は実験で使用したMMCのFATのマップです │BPB │ ├────────┤LBA │FAT1 │0x3C + BPB_FATSz16(0xF2) ─┐ │(242 sectors) │ ┌────────────┘ │(61952 Entries) │ │ ├────────┤ ↓ │FAT2 │0x12E + BPB_FATSz16(0xF2)─┐ │(242 sectors) │ ┌────────────┘ │(61952 Entries) │ │ ├────────┤ ↓ │ROOT DIR │0x220 FAT16の1個のEntryは2バイトで、little endian形式です。 Entry Entry Entry Entry Entry Entry Entry [0] [1] [2] [3] [4] [5] [6] ┌───┬───┬───┬───┬───┬───┬───┬─ │ F8FF │ FFFF │ 0000 │ 0000 │ 0000 │ 0000 │ 0000 │ └───┴───┴───┴───┴───┴───┴───┴─ Entry[0]と[1]は予約済みで、それぞれ0xFFF8と0xFFFFです。 Entry[0]の下位桁の0xF8は、BPB_Mediaと同じ値です。 Entry[1]のbit15=0(0x7FFF)は、不正な中断を、 Entry[1]のbit14=0(0xBFFF)は、ハードエラー、を表します。 Entryの番号([]内)は、データ領域のクラスタ番号に相当します。 Entryの値が 0xFFF7の場合は不良クラスタです。 未使用のEntryには0x0000を設定。 使用したEntryには、次にリンクするEntry番号を設定し、リンク終端のEntryには 0xFFFFを設定します。 ファイルを削除すると、DIR Entryの DIR_FstClusLO からリンクするFAT Entry の全てに0x0000を設定します。 FATの設定例: 1つ目のファイルが、Entry[2][3][4]を使用し、 2つ目のファイルが、Entry[5]を使用した場合 Entry Entry Entry Entry Entry Entry Entry [0] [1] [2] [3] [4] [5] [6] ┌───┬───┬───┬───┬───┬───┬───┬─ │ F8FF │ FFFF │ 0300 │ 0400 │ FFFF │ FFFF │ 0000 │ └───┴───┴───┴───┴───┴───┴───┴─ 1つ目のファイルは、クラスター0x0002,0x0003,0x0004を使用。 2つ目のファイルは、クラスター0x0005を使用。 FATの領域は BPB_NumFATs 個あり、通常は2個で、FAT1とFAT2は同じ内容です。 各FAT領域には、BPB_FATSz16 個のセクタが在ります。 8.5. FATクラスタをLBAに変換 データ領域はクラスタ単位で分割され、先頭のクラスタ番号は2です。 クラスタのサイズは BPB_SecPerClus です。 │ROOT DIR │ ├───────┤LBA │DATA AREA │0x240 = 先頭クラスタ(No.2)の先頭のLBA │(1980864 │ │ sectors) │ │(61902 │ │ clusters) │0x1E3BFF └───────┘ C = cluster number FATSectors = BPB_FATSz16 RootDirSectors = BPB_RootEntCnt * 32 / BPB_BytsPerSec BPB_ResvdSecCnt // 予約領域のサイズ +) BPB_NumFATs * FATSectors // FAT領域のサイズ +) RootDirSectors // Root Dir領域のサイズ +) (C - 2) * BPB_SecPerClus; // データ領域先頭からの位置 */ +) PT_LbaOfs // BPBのLBA -------------------------------- = LBAセクターNo 実験に使用したMMCは BPB_FATSz16 = 242 BPB_RootEntCnt = 512 BPB_BytePerSec = 512 BPB_ResvdSecCnt = 28 BPB_NumFATs = 2 BPB_SecPerClus = 32 MBR_FirstSecNum = 32 RootDirSectors = 512 * 32 / 512 = 32 C=2の場合 28 // 予約領域のサイズ +) 2 * 242 // FAT領域のサイズ +) 32 // Root Dir領域のサイズ +) (2 - 2) * 32 // データ領域先頭からの位置 */ +) 32 // BPBのLBA ------------------ = 576(0x240) // LBAセクタNo 0x240は使用したMMCのDATA AREAの先頭セクタ(LBA)です。 8.6. ROOT DIR 1セクタにBPB_RootEntCnt個の DIR Entryがあり、1個のDIR Entryは32バイトです。 ROOT DIRのサイズは BPB_RootEntCnt * 32バイトです。 │FAT2 │ ├───────┤LBA │ROOT DIR │0x220 + (BPB_RootEntCnt(0x200) * DirEntryByte(0x20) │(32sectors) │ / BPB_BytsPerSec(0x200)─┐ │(512entries) │ ┌──────────────┘ ├───────┤ ↓ │DATA AREA │0x240 クラスタNo.2の先頭のLBA DIR Entryの構成 OFFSET SIZE 項目名 内容 -------+------+------------------+------------------------------------ 0 11 DIR_Name ファイル名(8バイト)。拡張子(3バイト) 11 1 DIR_Attr 0x20=アーカイブ 12 1 DIR_NTRes ファイル名、拡張子の小文字情報 13 1 DIR_CrtTimeTenth 10msec-199msec 14 2 DIR_CrtTime ファイル作成時刻 16 2 DIR_CrtDate ファイル作成月日 18 2 DIR_LstAccDate ファイルを開いた月日 20 2 DIR_FstClusHI 先頭クラスタNoの上位桁 22 2 DIR_WrtTime ファイル書込み時刻 24 2 DIR_WrtDate ファイル書込み年月日 26 2 DIR_FstClusLO 先頭クラスタNoの下位桁 28 4 DIR_FileSize ファイルサイズ(バイト) ファイル名は本体と拡張子ともに大文字。 左詰めで記述し残りはブランクを 設定します。 ファイル名本体と拡張子の区切りの"."は省略します。 例:"TEST.1"の場合 0 1 2 3 4 5 6 7 8 9 10 ┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐ │ T E S T 1 │ └─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘ │ ファイル名本体 │ 拡張子 │ 空のEntryは各項目に0x00を設定。 ファイルを削除する場合は、DIR_Nameの先頭バイトに0xE5を設定し、DIR_FstClusLO からリンクするFATのEntryの全てに0x0000を設定します。 (WindowsはMMCにファイルを作成する時に、DIR_Nameの先頭バイトが0xE5よりも0x00 のDIRエントリを優先して使用しています。 ファイルの作成と削除を繰り返すと、 DIR_Nameの先頭バイトが0xE5のDIRエントリが増えます。) FAT16では、DIR_FstClusLO がファイルの先頭クラスタで、FAT Entryにリンクしま す。 DIR_WrtDate、DIR_CrtDate、DIR_LstAccDateの書式 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 ┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐ │ │ └─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘ │ 年 - 1980 │ 月 │ 日 │ DIR_WrtTime、DIR_CrtTimeの書式 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 ┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐ │ │ └─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘ │ 時(24H) │ 分 │ 秒/2 │ 8.7. DATA AREA クラスタは連続したセクタの集まりで、データ領域はクラスタ単位で区分けされま す。 クラスタのサイズは BPB_SecPerClusセクタです。 先頭のクラスタの番号は2で、FAT Entry[2]とリンクします。 │ROOT DIR │ ├───────┤LBA │DATA AREA │0x240 = 先頭クラスタ(No.2)の先頭のLBA │(1980864 │ │ sectors) │ │(61902 │ │ clusters) │0x1E3BFF └───────┘ DATA AREA ┌───────┐─ │Cluster No.2 │ ↑ 1クラスタはBPB_SecPerClus(32)セクタ │ │ │ BPB_SecPerClus * BPB_BytsPerSecバイト(16,384byte) │ │ ↓ ├───────┤─ │Cluster No.3 │ │ │ │ │ ├───────┤ │ │ ├───────┤ │(Cluster No. │ │ 61904) │ │ │ └───────┘ ファイルサイズが1クラスタ以上で2クラスタ未満の場合、2個のクラスタを使用し てファイルのデータを記録します。 ファイルの消去は、DIR EntryとFAT Entryについて消去を行い、クラスタのデータ の消去は行いません。 メディアを完全に消去するためには、データ領域の全てのセクタを初期化する必要 があります。 9. MMC端子配列 MMC端子配列(SPIモード) ---------------------- |■ 8 | |■ 7 DO (MISO) | |■ 6 VSS (0V) | |■ 5 CLK (SCK) | |■ 4 VDD (3.3V) | |■ 3 VSS (0V) | |■ 2 DI (MOSI) | |■ 1 -CS | \ ■ 9 | ------------------- ソケット端子配列(ヒロセ HRS163-3416A) WRITE_PROTECT_SW ■ SW_C ■┏━━━━━━━┓ DISC_IN_SW ■┃ ┃ -- ■┃ ┃ DO ■┃ ┃ VSS ■┃ ┃ CLK ■┃ ┃ VDD ■┃ ┃ VSS ■┃ ┃ DI ■┃ ┃ CS ■┃ ┃ -- ■┗━━━━━━━┛(TOP VIEW) 10. 回路図 10.1. USB通信・クロック発振・リセット FT245RL ATmega644 ┌───┐ ┌─────┐ │ │ 1│ │9 │ RXF#├────┤PB0 RESET├─┤├──────●─ GND │ │ 2│ │ 0.1u │ │ RD#├────┤PB1 │ 50V │ │ │ 3│ │ │ PC │ TXE#├────┤PB2 │ │ ┌───┐ │ │ 4│ │ │ │ │ USB │ WR├────┤PB3 │ ┌─────┐ │ │ ├───┤ │ 14│ │13 │ │ │ │ │ │ DB0├──●─┤PD0 XTAL1├───●┤├┐ │ │ └───┘ │ │ ┌┘15│ │ │ ┴ │ │ │ │ DB1├──●─┤PD1 │ │ □ ●──┘ │ │ ├┘16│ │12 │ ┬ │ │ │ DB2├──●─┤PD2 XTAL2├───●┤├┘ │ │ │ ├┘17│ │ │ │ │ DB3├──●─┤PD3 │ └─────┘ │ │ ├┘18│ │ 20MHz │ DB4├────┤PD4 │ セラミック発振子 │ │ │ 19│ │ │ DB5├────┤PD5 │ │ │ │ 20│ │ │ DB6├────┤PD6 │ │ │ │ 21│ │ │ DB7├────┤PD7 │ │ │ │ │ │ └───┘ │ └─────┘ │ └─> DB0〜DB3はLCDモジュールとバスを共用 RXF# :送信用FIFOにデータ有り。 RD# :送信用FIFOからの読出しパルス。 TXE# :受信用FIFOに空きあり。 WR :受信用FIFOへの書込みパルス。 DB0-7:双方向データバス。 10.2. カードI/F ─●───●──●───────────── 5V │ │ │ MMC SOCKET R10K R10K │ ATmega644 ┌────┐ │ │ │ ┌─────┐ │ │1 │ │ │ 5│ │ │ -CS├──<] ─●──────────┤-SS(PB4) │ │ │2 │ │ 6│ │ │ DI├──<] ────────────┤MOSI(PB5) │ │ │3 │ │ 11,31│ │ │ Vss├─────●──────────┤GND │ │ │4 │ │ │ 10,30│ │ │ Vdd├─ 3.3V │ │ └───┤Vcc │ │ │5 │ │ 8│ │ │ CLK├──<] ─────●──────┤SCK(PB7) │ │ │6 │ │ │ │ Vss├─────● │ │ │ │7 │ 7│ │ │ DO├── [>────────────┤MISO(PB6) │ │ │8 │ │ │ │ ├ │ │ │ │ │9 │ │ │ │ ├ │ │ │ │ │ │ │ │ └────┘ │ └─────┘ │ ────●─────────────────── GND TC74VHC32F 1/4 ┌─┐ │ ├── ──<]─ = ──┤OR│ │ ├─┐ └─┘ │ ─●─ GND TA48033S ┌───┐ 5V ──●─┤IN OUT├─●────●─── 3.3V │ │ GND │ │ │ 33u ┴ └─┬─┘ ┴ 0.1u ┴ 100u 16V ┬ │ ┬ 50V ┬ 10V │ │ │ │ GND ──●───●───●────●─── GND 10.3. LCD表示器 20文字4行LCD ATmega644 SC2004CSWB ┌──────┐ ┌──────┐ │ │22 4│ │1 0V │ RS PC0├──────┤RS Vss├──────●── GMD │ │23 5│ │2 5V │ │ RW PC1├──────┤RW Vdd├──────│── 5V │ │24 6│ │3 ┌──┐ │ │ E PC2├──────┤E VLC├─┤5KΩ├ │ │ │14 11│ │ └↑─┘ │ │ DB4 PD0├───●──┤DB4 │ └───┘ │ │15 ┌┘ 12│ │ コントラスト調節用 │ DB5 PD1├───●──┤DB5 │ 半固定抵抗器 │ │16 ├┘ 13│ │ │ DB6 PD2├───●──┤DB6 │ │ │17 ├┘ 14│ │ │BUSY/DB7 PD3├───●──┤DB7 │ │ │ ├┘ │ │ └──────┘ │ └──────┘ │ ├─> FT245とバスを共用 └─> DB0とGND間を3.3KΩで接続(バス共用時の安定化) 11. 経過 △1 2011.09.03(土) WindowsはMMCにファイルを作成する時に、DIRエントリの先頭が0x00に設定されてい るエントリを優先して使用し、ファイルが削除され0xE5が書き込まれているエント リを後回しにします。 ファイルの削除と作成を繰り返していると、DIR領域の先頭 セクタを使いきり、後続するセクタのDIRエントリが使われます。 したがって、ファイル数が16個以下で運用している場合ても、ファイルの検索はDIR 領域の全セクタを対称にする必要があります。 2011.08.15(月) ファイル容量32,768バイト。2クラスタ(64セクタ)に相当の読出し動作確認。 ファイルの各行の数字列を数値(16進数)に変換した値と、各行読出し毎にインクリ メントした値との自動比較を実行。 使用ファイル : TEST10.TXT 実行結果 : 1行目から10948行目まで数値が一致しOK。 : 最終の10949行目は、'End'文字列のため数値の不一致でエラーを : 検出。但し、LCD表示で'End'を確認しOK。 2011.08.14(日) 数字列を数値(16進数)に変換するサブルーチンを作成。 str2num : 機能=数字列を数値(16進数)に変換 ; 引数=str_bufに数字列。文字列の終了コード$00 ; 戻値=レジスタcal_00-034バイトに数値化した値 power_series : 機能=累乗計算。acc^temp : 引数=acc=底、temp=指数。各1バイト : 戻値=cal_10-cal_13(4バイト) 2011.08.12(金) 1クラスタ目が再読出しされる件で、サブルーチンget_next_fat_entryを修正。 get_next_fat_entry : 機能=次のFAT Entry Noの取得 : 引数=なし : 戻値=cal_00-03=次のFAT Entry No : Zflg=1ならFAT_Entry_no=$FFFFでリンク無し *修正追加 → : 変数(FAT_Entry_no)に次のFAT Entry Noを代入 2011.08.11(木) 読出しテスト用ファイルを作成。 ファイル名 : TEST10.TXT ファイルサイズ: 32,768バイト。2クラスタ(64セクタ)に相当。 ファイル内容 : 1行目から10948行目までは行番号と同じ数字列。 : 10949行目は'End'文字列。 : 各行の数字列・文字列の後部には行頭移動(0x0D)と改行(0x0A)が : 続く。 テスト結果 2クラスタ目の読出しの時に、1クラスタ目が再読出しされる。 2011.08.10(水) ファイルの読出しとLCDへの表示を追加。 2011.08.04(木) ファイルリスト。表示データバッファーのページ0。 SW押しでカーソルを次の行の先頭に移動。 同SWを長く押すとカーソル行のファイルを選択。 選択したファイルの番号(=ファイルテーブルの組番号) 2011.08.02(火) ファイル選択ルーチン。 file_select: LCD表示中のファイルリストからファイルを選択。 戻り値=ファイル番号(0-15)=ファイルテーブルの組番号。 2011.08.01(月) ATmega644をATmega1284Pに変更しました。 スタックの開始アドレスを変更。($10FF→$40FF) ROMの書き込みはATmega644モードで代用。 | ATmega644PA | ATmega1284P --------+--------------+--------------- ROM | 64K | 128K EEPROM | 2K | 4K RAM | 4K | 16K 2011.07.29(金) ページ表示ルーチンを作成。 lcd_page_dsp: 指定したページの4行をLCDに表示。 引数= 表示データバッファーのページ番号(0-3)。 2011.07.28(木) 表示データバッファーを1ページから4ページに変更。 │← 20桁 →│ ┌──────┐── │page0 │ ↑ │ 80byte │ 4行 │ │ │ │ │ ↓ ├──────┤── │ │ │ │ ├──────┤ │page3 │ │ 80byte │ │ │ │ │ └──────┘ SRAM使用量=320バイト(page0からpage3の合計) 2011.07.26(火) ファイルテーブル操作ルーチン作成。 get_file_size: ファイルサイズを変数(FILE_SIZE)にコピー。 引数=ファイルテーブルの組番号(0-15) 2011.07.25(月) ファイルテーブル操作ルーチン作成。 get_file_name: ファイルネームを変数(FILE_NAME)にコピー。 引数=ファイルテーブルの組番号(0-15) 2011.07.22(金) LCD表示制御用ルーチンを作成 lcd_cursor_on: カーソルオン。引数=LCDの行番号(0-3) lcd_cursor_down: カーソルダウン。点滅カーソルを1行下に移動。 2011.07.20(水) ファイルテーブルの生成。 make_file_tableルーチンを実行すると、DIRデータから有効なファイルのデータを 下記のデータ構造体に格納します。 ファイルテーブル構造 ┌──────┬─────┬──────────┬─────────┐ 0│file name(8)│拡張子(3) │先頭クラスタ番号(4) │ファイルサイズ(4) │ ├──────┼─────┼──────────┼─────────┤ 〜 〜 ├──────┼─────┼──────────┼─────────┤ 15│ │ │ │ │ └──────┴─────┴──────────┴─────────┘ ↑ └ 0組目から15組目迄の16組に対応。 ()内はバイト数。 先頭クラスタ番号とファイルサイズはlittle endianで格納。 SRAM使用量=(8+3+4+4)*16=304バイト。 2011.07.17(日) カードの初期化、MBR、BPB、DIRを順次読出し。 DIRクラスタの先頭セクタを検索し、DIRリストを表示。 DIRの先頭セクタ中のファイル数を表示。最大16ファイル迄。 ATmega644のヒューズビットのCKSELを1110から0110に変更する事で 20MHzセラミック発振子での動作が安定になり、カード初期化からDIR読出しまでの 繰り返しを40,000回クリアしました。 2011.07.01(金) LCDモジュールを追加しました。 2010.09.01(水) SDCのマルチブロックライト後のMBRおよびBPB読出エラーを対策しました。 最終ブロックのデータ書込みのビジーが解除された後に、 1) STOP TRANS TOKEN(0xFD)を発行 2) 1バイトの入力(ダミー) 3) STOP TRANS TOKENのビジーの解除待ち を追加しました。 2010.08.30(月) SDC初期化コマンドACMD41の実行ルーチンをATmega644に追加。 SDCの初期化はOK。但し、MMCの初期化に同ルーチン使用するとMMCの初期化に失敗 します。 SDC初期化コマンドACMD41を実行しても、マルチブロック・ライト直後のMBRやBPBの 読出しエラーは改善されんませんでした。 シングルブロック・ライトならば、MBRやBPBはエラー無く読み出せます。 SDCもMMCとして初期化すれば使えています。ACMD41はSDCの拡張された機能を使う 時に必要になるのか詳細は不明です。 2010.08.27(金) SDC書込み検討。シングルブロックとマルチブロックライトで書込みOK。 但し、マルチブロックライト後のMBRおよびBPB読出しでエラー発生。 マルチブロックライト後にマルチブロックリードを実行すると、MBRおよびBPBの 読出しエラーは発生しない。 マルチブロックライトの後半にCMD12(書込み終了)、CMD23(ブロック数変更)を実行 しても改善されない。 2010.08.23(月) マルチブロック読出し後のCMD12、CMD23の追加が、MMC制御に影響がしない事を確 認。 2010.08.22(日) SDCマルチブロック読出し検討。CMD12でマルチブロックリード終了、CMD23で ブロック数=1に変更すると、マルチブロックリード後のシングルブブックリード でエラーなく読出しが完了。 2010.08.18(水) microSDC(2GB)のFATデーター解析。 ┌───────┐LBA │MBR (1sector) │0 + PT_LBAOfs(0x89)─┐ ├───────┤ │ │ │ ┌─────────┘ │ │ │ ├───────┤ ↓ │BPB (1sector) │0x89 + BPB_RsvdSectCnt(0x01) ─┐ │ │ ┌──────────────┘ ├───────┤ ↓ │FAT1 │0x8A + BPB_FATSz16(0xEB) ─┐ │(235sectors) │ ┌────────────┘ │(60160entries)│ │ ├───────┤ ↓ │FAT2 │0x175 + BPB_FATSz16(0xEB)─┐ │(235sectors) │ ┌────────────┘ │(60160entries)│ │ ├───────┤ ↓ │ROOT DIR │0x260 + (BPB_RootEntCnt(0x200) * DirEntryByte(0x20) │(32sectors) │ / BPB_BytsPerSec(0x200)─┐ │(512entries) │ ┌──────────────┘ ├───────┤ ↓ │DATA AREA │0x280 │(1980864 │ │ sectors) │ │(61902 │ │ clusters) │0x3A9F76 └───────┘ 2010.08.17(火) Win AppとATmega644はMMC用のプログラムに変更なしで、 microSDC+アダプターの初期化を実施、MBR、BPBが読めた。 1クラスター読み出し後、2回目以降の読出しでデータ化けが発生。 2010.08.12(木) microSDC 2GB アダプター付きを購入。 2009.09.20(日) FT245+ATmega644でMMCへのR/W時間を測定しました。 FT245+ATmega644 ブロック数 RD WR -----------+--------+----------- シングル 1 2.6ms 2.8ms シングル 8 18.2ms 26.4ms マルチ 8 14.6ms 13.6ms (参考) FT232+ATmega644 ブロック数 RD WR -----------+--------+----------- シングル 8 85.6ms 85.6ms マルチ 8 83.2ms 83.2ms 2009.09.15(火) FT232をFT245に変更しました。 ATmega644とのデータ通信を8ビットパラレルで行います。 FT245RL ATmega644 ┌───┐ ┌───┐ │ │ │ │ │ RXF#├───────┤PB0 │ PC │ RD#├───────┤PB1 │ ┌───┐ │ TXE#├───────┤PB2 │ │ │ USB │ WR├───────┤PB3 │ │ ├───┤ │ │ │ │ │ │ DB0├───────┤PD0 │ └───┘ │ DB1├───────┤PD1 │ │ DB2├───────┤PD2 │ │ DB3├───────┤PD3 │ │ DB4├───────┤PD4 │ │ DB5├───────┤PD5 │ │ DB6├───────┤PD6 │ │ DB7├───────┤PD7 │ │ │ │ │ └───┘ └───┘ RXF# :送信用FIFOにデータ有り。 RD# :送信用FIFOからの読出しパルス。 TXE# :受信用FIFOに空きあり。 WR :受信用FIFOへの書込みパルス。 DB0-7:双方向データバス。 2009.09.12(土) ATmega644のVccを3.3Vから5Vに変更しました。 -CS,DI,DO,CLK信号のレベル変換にTC74VHC32Fを使用。 MMCのVdd=3.3Vは、5VからTA48033S(3端子レギュレーター)で生成。 ─●───●──●───────────── 5V │ │ │ MMC SOCKET R10K R10K │ ATmega644 ┌────┐ │ │ │ ┌─────┐ │ │1 │ │ │ 5│ │ │ -CS├──<├─●──────────┤-SS(PB4) │ │ │2 │ │ 6│ │ │ DI├──<├────────────┤MOSI(PB5) │ │ │3 │ │ 11,31│ │ │ Vss├─────●──────────┤GND │ │ │4 │ │ │ 10,30│ │ │ Vdd├─ 3.3V │ │ └───┤Vcc │ │ │5 │ │ 8│ │ │ CLK├──<├─────●──────┤SCK(PB7) │ │ │6 │ │ │ │ Vss├─────● │ │ │ │7 │ 7│ │ │ DO├──┤>────────────┤MISO(PB6) │ │ │8 │ │ │ │ ├ │ │ │ │ │9 │ │ │ │ ├ │ │ │ │ │ │ │ │ └────┘ │ └─────┘ │ ────●─────────────────── GND TC74VHC32F 1/4 ┌─┐ │ ├── ──<├─ = ──┤OR│ │ ├─┐ └─┘ │ ─●─ GND 2009.09.08(火) ATmega8からATmega644Pに移行。 ──●───●──●───────────── 3.3V │ │ │ MMC SOCKET R10K R10K │ ATmega644 ┌────┐ │ │ │ ┌─────┐ │ │1 │ │ │ 5│ │ │ -CS├──●──────────┤-SS(PB4) │ │ │2 │ │ 6│ │ │ DI├─────────────┤MOSI(PB5) │ │ │3 │ │ 11,31│ │ │ Vss├────●────────┤GND │ │ │4 │ │ │ 10,30│ │ │ Vdd├─────────●───┤Vcc │ │ │5 │ │ 8│ │ │ CLK├──────●──────┤SCK(PB7) │ │ │6 │ │ │ │ Vss├────● │ │ │ │7 │ 7│ │ │ DO├─────────────┤MISO(PB6) │ │ │8 │ │ │ │ ├ │ │ │ │ │9 │ │ │ │ ├ │ │ │ │ │ │ │ │ └────┘ │ └─────┘ │ ────●────────────────── GND VCC=3.3V、クロック12MHz(セラミック発振子)で動作確認。 2009.09.02(水) マルチ・ブロック・ライト手順の項目を追加。 2009.08.30(日) シングル・ブロック・ライト手順の項目を追加。 2009.08.26(火) マルチ・ブロック・リード手順の項目を追加。 2009.08.24(月) シングル・ブロック・リード手順の項目を追加。 2009.08.19(水) MMC.asmにマルチ・ブロック・リードを追加しました。 CMD23とCMD18コマンドで、8ブロック(セクタ)を連続して読出します。 読込み時間比較 シングルとマルチともに8ブロック(セクタ)の読出しで測定。 送信 シングル マルチ ------+----------+----------- 有り 85.6msec 83.2msec 無し 14.8msec 10.5msec 送信「無し」は、ATmega8からFT232へのデータ送信をスキップする様にプログラム を変更して測定。 2009.08.16(日) MMC.asmにマルチ・ブロック・ライトを追加しました。 CMD23とCMD25コマンドで、8ブロック(セクタ)を連続して書込みます。 書込み時間比較 シングルとマルチともに8ブロック(セクタ)の書込みで測定。 データ受信 シングル マルチ -----------+----------+----------- 有り 85.6msec 83.2msec 無し 25.2msec 11.7msec データ受信「無し」は、FT232からのデータ受信を待たずにダミーデータを書き 込む様にプログラムを変更して測定。 FT232からATmega8へのデータ通信レートが向上すれば、マルチ・ブロック・ライト が効果的です。 2009.08.14(金) ステップパルス出力を高速化し、F6000.DATに対応しました。 1ステップの間隔は25usec。 変更点: リングバッファーの空きが512バイトになってから次のセクタを読出す方式を、 1バイト空く毎にMMCから1バイトを読出す方式に変更し、FAT読出し中のリングバッ ファーの残量を増やしました。 FAT読出し中のリングバッファー残量比較 変更 最大バッファー残量 -----+---------------------- 前 128バイト 後 640バイト File 出力時間(sec) (mm/min) 計算値 実測値 ----------+---------+--------- F100 122.88 117 F1000 12.29 11.8 F2000 6.14 5.88 F3000 4.10 4.00 F4000 3.07 2.98 F5000 2.46 2.36 F6000 2.05 2.08 F7000 1.76 11.7 F8000 1.54 52.4 2009.08.12(水) リングバッファーに読み込んだステップパルスデータを、タイマー1の割込ごとに PORTCに出力しました。 F100.DATからF2000.DATは正常、F3000.DATからF8000.DATはバーストします。 F1000.DATの出力をDIGIMOで観測。 -A相と-B相は、A相トリガーで観測した波形を切り貼り。 2009.08.10(月) ステッピングモータ用駆動データを作成し、MMCに保存しました。 条件 1) 送りネジリード=1mm 2) 1-2相駆動で400ステップ/回転 3) 1パルスのデータ構成 項目 バイト数 ---------------+----------- プリスケーラー 1 タイマカウント 2 パルスデータ 1 4) ファイルの容量は327,680バイト 81,920ステップの駆動データを収納 5) 送り速度 出力時間 (mm/min) (sec) ----------+------------- 100 122.88 1000 12.29 2000 6.14 3000 4.10 4000 3.07 5000 2.46 6000 2.05 7000 1.76 8000 1.54 (*)F1000で1Gバイトの場合、出力時間は約10.4時間。 DIR情報 2009.08.08(土) FAT読出しルーチンをMMC.asmに追加しました。 FATの1セクタを4ブロックに分割し、必要なEntry Noが含まれるブロックを SRAMのFAT領域に保存します。 MMCのFAT │ │ ─ ─ ─ │ │ ↓ │1/4 sector│→───┤ ─┬─ ├─────┤ │ ↑ │1/4 sector│→───┤ │ │ ─ ─ ─ │ │ SRAMのFAT │ │1/4 sector│→───┤ ├────┤ 1sector│ ─ ─ ─ │ ├──→│128byte │ │ │1/4 sector│→───┤ ├────┤ │ │ ─ ─ ─ │ │ ↓ │1/4 sector│→───┤ ─┼─ ├─────┤ │ ↑ │1/4 sector│→───┤ │ │ ─ ─ ─ │ │ 2009.08.04(火) ROOT DIR読出し関連のサブルーチンをMMC.asmに追加しました。 DIR_readサブルーチンは、1セクター分のDIRデータをリングバッファーに読出しま す。 get_file_infoサブルーチンは、ファイルNo(DIR Entry No)に対応したDIR Entryから FILE NAME、先頭クラスタNo、ファイルサイズを取り出しSRAMに保存します。 a b ┌─────────────────────────┐ │ リングバッファー(640byte) │ └─────────────────────────┘ │││ SRAM │││ ├──┤ └──→│ │FILE NAME(11バイト) ││ ├──┤ └─→│ │先頭クラスタ(2バイト) │ ├──┤ └→│ │FILE SIZE(4バイト) ├──┤ 2009.07.31(金) BPBの読出しルーチンをMMC.asmに移植しました。 読出したBPBからパラメータをSRAMに保存。 NAME SIZE OFFSET -----------------+-------------+---------------- BPB_BytsPerSec: .byte 2 ; 11,12 BPB_SecPerClus: .byte 1 ; 13 BPB_RsvdSecCnt: .byte 2 ; 14,15 BPB_RootEntCnt: .byte 2 ; 17,18 BPB_TotSec16: .byte 2 ; 19,20 BPB_FATSz16: .byte 2 ; 22,23 BPB_TotSec32: .byte 4 ; 32,33,34,35 次式でデータ領域の先頭LBAを計算し、SRAMに保存。 (BPB_RootEntCnt * DirEntryByte / BPB_BytsPerSec) +) (BPB_FATSz16 + BPB_FATSz16) +) PT_LBAOfs +) BPB_RsvdSectCnt -------------------------------------------------------- = DATA_AREA_TOP(4バイト) SRAMのDATA_AREA_TOP(4バイト)の値。 │ROOT DIR │ ├───────┤LBA │DATA AREA │0x240 = 先頭クラスタ(No.2)の先頭のLBA │(1980864 │ │ sectors) │ │(61902 │ │ clusters) │0x1E3BFF └───────┘ 2009.07.28(火) MBRの読出しルーチンをMMC.asmに移植しました。 1セクター(512バイト)の読出し時間=2.08msec。転送レート=246Kbyte/sec。 読出したデータはリングバッファーに順次格納。 リングバッファーの読出しポインタをPT_LbaOfsにオフセットし、BPBの先頭セクタ (LBA)を取り出しSRAMに保存しました。 SRAMに保存したPT_LbaOfsの値(4バイト)です。 ┌────┐ │MMC │ 読出したデータ │ ├───┐ │ │ │ └────┘ │ remain │ a │←───→↓Xレジスタで格納先をポイント b ┌─────────────────────────┐ │ リングバッファー(640byte) │ └─────────────────────────┘ │←→↑YレジスタをオフセットしてPT_LbaOfs値の取り出し元をポイント │ │ ├──┤ └──→│ │SRAMのPT_LbaOfsに保存 ├──┤ データを取り出した後は、Y=Xにしてremain=0にします。 a ↓Xレジスタ(格納ポインタ) b ┌─────────────────────────┐ │ リングバッファー(640byte) │ └─────────────────────────┘ ↑Yレジスタ(読出しポインタ) リングバッファーのaとbはソフトで仮想的につながります。 2009.07.26(日) 「FAT16システム」の項目を追加。 2009.07.24(金) MMCの入出力制御をソフト方式から、ATmega8のSPIに変更しました。 SPI(Serial Peripheral Interface)の設定: 1) 割込禁止 2) 送信禁止 3) MSB first 4) マスタ。MMCの-CSはソフトで制御。 5) 出力(MMC-DI)=立下り 6) 入力(MMC-DO)=立上り 7) CPUクロック分周比=1/2。 MMC CLK=16MHz。1バイトのR/Wを1usecで実行。 1)-7)までの設定例: ldi acc, 0x1C ; out SPCR, acc ; sbi SPSR, SPI2X ; 1/2。1/16MHz*2=0.125usec 8) SPIの送受信の許可は、入出力の直前に実行。 例: acc(R17)に送信用データを設定し、rcall out_8bitを実行。 out_8bit: sbi SPCR, SPE ; 送信許可 out SPDR, acc ; 送信開始 out_8bit5: sbis SPSR, SPIF ; 送信完了ならばスキップ゚ rjmp out_8bit5 ; 送信完了まで待機 cbi SPCR, SPE ; 送信禁止 ret ; 2009.07.22(水) MMCのリセットと初期化の手続きをMMC.asmに移植しました。 リセットと初期化の手順は「MMCをSPIモードに設定」の項目を参照して下さい。 2009.07.20(月) Nセクター読込みの手続きを、Windows App側(MMC.exe)からATmega8側(MMC.asm)に 移行しました。 MMC.exe側の手続きは、読出しコードとLBAおよびセクター数を発行します。 読込み手順(MMC.asm) 1) チップ選択オン 2) CMD17出力 (コマンド、アドレス、CRC。全6バイト) 3) R1チェックとDATA TOKENチェック 4) データを1バイト読出す毎にホスト(MMC.exe)へ送信。セクター分繰り返し 5) CRCの読出し(2バイト) 6) ダミーク8ロック出力 7) 2)へループ。指定セクター分繰り返し。 8) チップ選択オフ FAT一括読出のデータ転送レートは、141,312bytes/2.96sec=47,741bytes/sec。 2009.07.18(土) ATmega8用プログラムにNセクター書込みルーチンを追加しました。Nは256以下。 CMD24出力、DATA TOKEN出力、セクターデータ出力、ビジーチェックの一連の処理を 指定セクター分ATmega8内で実行します。 MMC Appからは、LBA(3バイト)、セクター数(1バイト)、書込データ(512バイト× セクター数)を送信します。 処理時間比較 書込みファイルサイズ=295,034バイトの場合。608セクタ(19クラスタ)に相当。 書込み手続き 時間 書込みレート --------------+---------+------------------- MMC Appで処理 60.00秒 5.188Kbyte/sec ATmega8で処理 7.18秒 41.205Kbyte/sec 改善点 1) ATmega8にNセクター書込みルーチンを追加。 2) RS-232CのCTS制御を採用。リングバッファーのオーバランを防止。 3) ATmega8のクロックを内蔵RC8MHzから、セラミック発振子16MHzに変更。 FT232RLとATmega8間の通信レート500Kボーでデータ化けを防止。 2009.07.16(木) MMCにファイルの書込みを行いました。 App内のFATでエントリの予約を行い、エントリのリンク順にクラスターNoを取得。 取得したクラスターNoを、MMCのLBAに変換してCMD24で書込みます。 DIR FAT情報 青色のエントリ19個が予約されました。 19クラスタ(608セクタ)の書込み時間60秒。書込みレート5.188Kbyte/sec。 chip on送信、CMD24送信、1セクターデータ送信、書込み終了待ちチェック、 chip off送信等を分割しているため、書込み時間が長くなります。 2009.07.11(土) MMCからFATシステムを一括して読み出したAppのメモリ上で、 ファイルの生成、削除を行いました。 5つのファイルを生成した後のDIR情報。 そのFAT情報 黄色はFATシステムの予約エントリ。 各ファイルに1クラスターが割り当てられています。 TEST4.TSTを削除した後のDIR情報。 そのFAT情報 緑色の枠はファイル削除で解放されたFATエントリ。 3クラスターの容量でTEST6.TSTを生成した時のDIR情報。 そのFAT情報 水色はTEST6.TSTに割り当てられたエントリで、 3クラスター分が割り当てられています。 2009.07.08(水) FATシステムの一括読出し時間を51秒から2.5秒に改善しました。 データ転送レートは141,312bytes/2.5sec=56,524bytes/sec。 変更点: 1) ATmega8への読出しコマンド送信を、1セクター毎から32セクター毎に変更。 2) FT232とATmega8間の通信レートを250Kbaudから1Mbaudに変更。 3) MMCクロックのH、L期間調整用の遅延1μsecを削除又はNOP命令1個に変更。 2009.07.05(日) MMCからMBR(512)、BPB(512)、FAT(512*242)、ROOT DIR(512*32)を一括して読出し Windows Appのメモリ領域に展開しました。276セクター、141,312バイト。 所用時間は51秒。転送レートは2,770bytes/sec。 USB経由で1セクター毎に読出しを繰り返すため時間が掛かります。 2009.07.03(金) セクター0x240(LBA)にデータを[WRITE]し、[READ]しました。 ├───────┤LBA │DATA AREA │0x240 ←WRITE/READセクター │(1980864 │ │ sectors) │ │(61902 │ │ clusters) │0x1E3BFF └───────┘ 2009.07.01(水) MMCへの書込み検討で、データを壊したときのリカバリー用に、 MBR.dat、BPB.dat、FAT.datを、PCにバックアップしました。 保存したBPB.datのダンプリスト。 アドレス0x50から0x1DFまでのデータ(0x00)は省略。 2009.06.26(金) ROOT DIR領域の割り出し。 ROOT DIRはFAT1の領域の後に続きます。 先頭セクター(LBA)は FAT1の先頭(0x12E) +) BPB_FATSz16(0xF2) ---------------------------- = 0x220 ROOT DIR領域の容量は BPB_RootEntCnt(512) *) DIRエントリサイズ(32bytes固定) /) BPB_BytsPerSec(512bytes) -------------------------------------- = 32セクター(0x20) ROOT DIRの最終セクターは ROOT DIR先頭セクター(0x220) +) ROOT DIR領域の容量(0x20) -) 1 -------------- = 0x23F 2009.06.24(水)のデータチェックでROOT DIRの0x220から0x23Fまでのセクターの データは全て0x00で、ファイルが登録されていないことを表しています。 2009.06.25(木) FATのLABを検証しました。 FATはBPBを先頭にしてBPB_RsvdSecCnt分オフセットしたセクターに設定されます。 FAT16システムではBPB_RsvdSecCnt=1が慣習的で、見なした解説も見受けられます。 使用したMMCはBPB_RsvdSecCnt=0x1Cで、この値を考慮すると、 メモリーマップ ├───────┤LBA │BPB (1sector) │0x20 + BPB_RsvdSectCnt(0x1C) ─┐ ├───────┤ │ │ │ ┌──────────────┘ │ │ │ ├───────┤ ↓ │FAT0 │0x3C + BPB_FATSz16(0xF2) ─┐ │(242sectors) │ ┌────────────┘ ├───────┤ ↓ │FAT1 │0x12E + BPB_FATSz16(0xF2) │(242sectors) │ ├───────┤ FAT0とFAT1の先頭のLBAは、昨日の検索結果と一致します。 2009.06.24(水) FATはどこに?。 BPBの次のセクター(0x21)を読出したところ、512バイトの全てが0x00で、FATらしき データがありません。 0x00以外が書き込まれているセクターを検索するプログラムを実行し、 下記のLBA(MMCの論理セクターアドレス)を抽出。 LBA 備考 --------------+------------------- 0x00 MBR 0x20 BPB 0x3C FAT0? 0x12E FAT1? 0x240〜0xA7B 出荷テストデータ? LBAの0x3Cと0x12Eを読み出すと FAT[0]=0xFFF8と、FAT[1]=0xFFFFが見つかりました。 FATのエントリーは2バイトのリトルエンディアン(little endian)方式です。 2009.06.23(火) BPBの読出しと解析。 BPBはセクター0x20。 BS_FilSysType="FAT16 "は参考値で、 FATの決定は以下の計算結果で判定する。 RootDirSectors = ((BPB_RootEntCnt * 32) + (BPB_BytsPerSec - 1)) / BPB_BytsPerSec; TotalSect = BPB_TotSec16; FATSectors = BPB_FATSz16; DataSectors = TotalSect - BPB_ResvdSecCnt - FATSectors * BPB_NumFATs - RootDirSectors; CountOfClusters = DataSectors / BPB_SecPerClus; で CountOfClustersが 4085 未満なら"FAT12"。 CountOfClustersが 4085以上で65525未満なら"FAT16"。 CountOfClustersが 65525以上なら"FAT32"。 したがってこのMMCは"FAT16"です。 2009.06.22(月) セクター0の読出しと解析。 セクター0にはFATのMBR(Master Boot Recode)が入っています。 オフセット0x000から0x1BDまでのデータは全て0x00です。 オフセット0x1BEからパーティションテーブルが4個定義されています。 各パーティションテーブルは16バイト構成です。 partitionTable[0]から、 非ブート用のパーティション (bootDescriptor=00)。 FAT16 (fileSystemDescriptor=06)。 BPB(BIOS Parameter Block)のセクター番号=0x20 (firstSectorNumber=00000020)。 などが分かります。 partitionTable[1][2][3]のデータは全て0です。 2009.06.19(金) コマンドCMD9のR1=0x05コマンドイリーガル発生原因を検討。 原因:コマンドCMD1でR1=0x01に続けてCMD9を発行した為。 対策:CMD1でR1=0x01の次に、R1=0x00になるまでCMD1を繰り返し発行する。 CMD9でMMCのCard Specific Data(CSD)を読出してCARD_SIZEを計算。 途中CS=OFFで0.5秒間の遅延は、MMC初期化後のCS=OFF→ONの動作を確認する為に挿 入。 CARD SIZEの計算式は CSDからc_size、c_size_mult、read_bl_lenを取得。 int mult = (int)(Math.Pow((double)2, (double)(c_size_mult + 2))); int blocknr = (c_size + 1) * mult; int block_len = (int)(Math.Pow((double)2, (double)read_bl_len)); int card_size = blocknr * block_len; BLOCKNRはセクター数。BLOCK LENはセクター容量。 カードの容量は1Gバイト以上あります。 (2の30乗をいわゆる1Gバイトとすると約5.5%少ないです。) 2009.06.18(木) MMCのリセット、初期化、Card Specific Data(CSD)の読出しを実行。 コマンドCND9のR1=0x05でコマンドイリーガルが発生。 2009.06.17(水) MMCリセット(SPIモード設定)プログラム作成。 Win App側でコマンドを初期化の手順に沿ってATmega8へ送信。 ATmega8側でコマンドに対応したシリアルデータを入出力。 MMCは未接続で、DIGIMOで観測した波形 ch1:MMCのCK(クロック)。 ch2:MMCのDI(入力データ)。 a :ダミーの80クロック。MMCモードのRCAレジスターを初期化。 b :初期化コマンド。CMD0=0x400000000095。 c :R1応答を受信。ビジーチェック用のMMCのDO(出力データ)はマニュアルで設定。 d :ダミーの8クロック。 2009.06.16(火) MMC Windows AppからATmega8のポート制御の実験。 GUIの釦クリックで、ATmega8のPB2に0.2秒間のHレベルを出力。 PC FT232RLモジュール ATmega8 ┌──────┐ ┌─────┐ RS-232 ┌──────┐ │MMCテスト用 │USB │ TxD├────┤RxD │ │Win App ├──┤ │ │ PB2├── │ │ │ RxD├────┤TxD │ └──────┘ └─────┘9600ボー└──────┘ or 1Mボー 内部RC発振クロック=8MHz 結果: Vcc=5VではOK。 Vcc=3.3VではNG。 3.3VでNGの原因: Vccが下がった事でATmega8の内部RC発振器の発振周波数が下がり、RS-232通信の ボーレートが一致しない為に、PCからのコマンドを誤って受信した。 対策: ATmega8のOSCCALレジスターの値を調整しクロック周波数を8MHzに設定。 OSCCALの値は、タイマー0の1msec毎の割込みで交番する信号をPB2に出力し、その周 期を測定しながら調整。 2009.06.15(月) ATmega8とFT232RLモジュールを結線。 MMCテスト用Windows AppをVC#で作成。 ATmega8用アセンブリプログラムMMC.asmを作成。 2009.06.14(日) 本資料作成開始。 MMCをリセット(SPIモードに設定)する手続きを検討。 2009.06.13(土) MMCソケットとATmega88を結線。 ──●───●──●───────────── 3.3V │ │ │ MMC SOCKET R10K R10K │ ATmega8 ┌────┐ │ │ │ ┌─────┐ │ │1 │ │ │ 16│ │ │ -CS├──●──────────┤-SS(PB2) │ │ │2 │ │ 17│ │ │ DI├─────────────┤MOSI(PB3) │ │ │3 │ │ 8,22│ │ │ Vss├────●────────┤GND │ │ │4 │ │ │ 7,20│ │ │ Vdd├─────────●───┤Vcc │ │ │5 │ │ 19│ │ │ CLK├──────●──────┤SCK(PB5) │ │ │6 │ │ │ │ Vss├────● │ │ │ │7 │ 18│ │ │ DO├─────────────┤MISO(PB4) │ │ │8 │ │ │ │ ├ │ │ │ │ │9 │ │ │ │ ├ │ │ │ │ │ │ │ │ └────┘ │ └─────┘ │ ────●────────────────── GND 2009.06.04(木) AVR WRITER2 基板製作。Vcc3.3V書き込みでATmega88とMMCとの直結が可能。 JP1の2,3間を短絡し3.3Vを選択。 3.3VはUSB電源5Vから3端子レギュレータ(ロードロップタイプ)で生成。 ターゲット回路(MMC、ATmega88)の電源(3.3V)はこの基板から供給します。 AVR WRITER2回路図 2008.08.22(金) MMCソケットアダプター基板切削。ソケットマウント。 2008.08.21(木) MMCソケットアダプター基板作図。 2008.08.20(水) MMCソケットEAGLEライブラリ作成。裏返しだった為やり直し。 2008.08.18(月) MMC1GBを購入。 12. 参考文献 「フラッシュ・メモリー・カードの徹底研究」 CQ出版社。 Hardware White Paper FATファイル・システム概要 OSの起動*パーティション FAT FS フォーマットの実装についての覚え書き
MMCの実験のTopへ
サイトのTopへ
法律条項 この資料により生じたいかなる障害や損害に対し、著者は全てを免責されるものとします。 この資料は、著作権法の下で保護され複製は禁止です。 この資料による製品化および製品の販売は禁止です。
inserted by FC2 system