FPGAでSDカード内のWAVEファイルを再生する~その2
”SDカードをSPIモードにするまでのフローチャートを見てみる”
引用元:http://elm-chan.org/docs/mmc/gfx1/sdinit.png:image=http://elm-chan.org/docs/mmc/gfx1/sdinit.png
1)ダミークロック送信
電源を入れた後1ms以上待ち、74クロック以上のダミークロックを送る
2)CMD0の送信(MMC・リセット)
この時点ではSDモードの為、CRC必須
3)CMD8の送信(電源電圧の確認).
動作電圧をサポートしているか、ファイルシステムのバージョンチェック.
19~16bitで対応電圧を入れる"0001":2.7~3.6Vで、その他は未定義or予約.
15~8bitでチェックパターン"10101010"を推奨.
以上より、"0x48 000001AA 87"がCMD8.
レスポンスR7を確認.下12bitが"0x1AA"で帰ってきていればOK.
4)ACMD41の送信(SDカード初期化)
ACMDはアプリケーションスペシフィックコマンドの略.
CMD55を送信後にR1を受け取った後、CMD41を送信
CMD55:0x77 0000 0000 65
CMD44:0x69 4000 0000 77
下8bitはCCRで、CMD8後なので実際は不要.FFでもOK
CMD44の38bit目はSDHC(SD ハイキャパシティ)を有効にするビット
ACMD41で帰ってくるR3の38bit目がCCS(カードキャパシティステータス)のレスポンスビット.
CCSが1ならSDXC,SDHC,0なら2GByte以下のSDカードとわかる.
5)CMD9の送信
SDカードからの情報を読み書きする前に、セクタサイズ、SD容量などの必要情報(CSD)を調べ、
SPIモードへのイニシャル操作完了とする.
レスポンス(CSD情報)は、8byteで構成されている.
詳細は下記リンク.
”CSDについて”
ここでは必要と思われる項目のみ抜粋.
レジスタ名 | 役割 | SD(SC)bit位置 | SDHCbit位置 |
---|---|---|---|
READ_BL_LEN | セクタサイズ | 83~80 | 83~80 |
C_SIZE | 容量計算用の係数 | 73~62 | 69~48 |
C_SIZE_MULT | 容量計算用の係数 | 49~47 | 無し |
SD(SC)の容量計算方法
カード容量 = セクタ数(BLOCKNR) × セクタサイズ(BLOCK_LN)
セクタ数(BLOCKNR) = (C_SIZE+1)×MULT
MULT = 2^(C_SIZE_MULT+2)
セクタサイズ(BLOCK_LN) = 2^(READ_BL_LEN)
以上より
SD(SC)カード容量 = (C_SIZE+1)×2^(C_SIZE_MULT+2) × 2^(READ_BL_LEN)
SDXCの容量計算方法
カード容量 = セクタ数(BLOCKNR) × セクタサイズ(BLOCK_LN)
セクタ数(BLOCKNR) = (C_SIZE+1)
セクタサイズ(BLOCK_LN) = 2^(READ_BL_LEN)
SDHCカード容量 = (C_SIZE+1) × 2^(READ_BL_LEN)
CSD内のERASE SECTORサイズとは
削除する際のセクタサイズ.ちなみREAD_BL_LENの計算方法と異なる"0"で512byte
読み込み(READ_BL_LN)と異なる場合がある??
○参考文献
http://bluefish.orz.hm/sdoc/j203536_hb288032mm1.pdf:9ページ目にCSDレスポンスの一覧
”コマンド(CMD)とレスポンスの成り立ち”
コマンド一覧
初期化に使用するコマンドのみ抜粋
コマンドインデックス | 引数 | 応答 | 省略形 | 役割 |
---|---|---|---|---|
CMD0 | 00 00 00 00 | R1 | GO_IDLE_STATE | ソフトウェアリセット |
ACMD41 | 40 00 00 00 | R1※1 | APP_SEND_OP_COND | SDカード初期化 |
CMD8 | 00 00 01 AA | R7 | SEND_IF_COND | 電源電圧の確認 |
CMD9 | 00 00 00 00 | R1 | SEND_CSD | CSD読み出し |
CMD55 | 00 00 00 00 | R1 | APP_CMD | アプリケーションコマンド |
※1.SPIモードではR1,SDモードではR3
コマンド構成
ホスト(マイコンなど)から送信するデータ.6Byteから構成されている.
スタートbit(1bit) + トランスミッションbit(1bit) + CMD(6bit) + 引数(4Byte) + CRC(7bit) + ストップbit(1bit)
47 | 46 | 45~40 | 39~8 | 7~1 | 0 |
---|---|---|---|---|---|
0 | 1 | x(CMD) | x(引数) | x(CRC) | 1 |
47:スタートbit
46:トランスミッションbit(ホスト→カード:"1",カード→ホスト:"0")
45~40:CMD.CMD41であれば"101001"
39~8:引数
7~1:CRC-7
0:ストップbit
レスポンス構成
SDカードからの応答.対応するレスポンスによって、データ長も異なる.
○R1(1Byte)
エラーチェックのレスポンス.0x00でエラー無し
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|
0 | x | x | x | x | x | x | x |
7:0
6:Parameter error(引数エラー)
5:Address error(アドレスエラー)
4:Erase sequence error(イレース中にエラー)
3:Communication CRC error(CRCがエラー)
2:Illegal command(コマンドが正しくない)
1:Erase Reset(イレース前のエラー)
0:In idle state(カードがアイドル状態.初期化中など)
○R3(5Byte)
R1 + OCR(4Byte).SDモードの場合、ACMD41のレスポンスとなる.
もしくはCMD58によって取得可能.CRはSDカード電源電圧を示す.
文献によって、5Byte、6Byteと異なる.システムVerで異なる?(後で調べる)
○R7(5Byte)
R1 + 4Byte.R7
チェックパターンは、CMD8で設定したチェックパターンがそのまま返ってくる.
対応電圧もCMD8で送信する0x01が返ってくればOK.
39~32 | 31~28 | 27~12 | 11~8 | 7~0 |
---|---|---|---|---|
R1 | CMDバージョン | reserve | 対応電圧 | チェックパターン |
○参考文献
http://elm-chan.org/docs/mmc/mmc.html
SDカードの構造と内部レジスタ(その1) | ミームス(MEMEs)のサポートページ
SDカードの初期化について - C・C++ 解決済 | 教えて!goo
SDカードを使ってみよう
SDカード
”CRC-7の計算方法”
MMC/SDカードはCRC-7を使用.
送信側と受信側で同じ計算を行い、合っていればデータに問題がないと判定.
計算方法は、先頭の"1"のビットに揃えて、CRCの多項式のXORを取っていく.
SDカードで使用するCRC-7多項式:x^7 + x^3 + x^0 = 1000 1001
計算はパリティ分のビットも入れた47bit分で計算.(ストップビットは除く)
Cプログラムでの計算例は多数載っていますが、
実際に計算過程は載っていなくいまいちピンと来なかったので、一度手計算してみました.
下記CMD0の計算
CMD0:0x40 00 00 00 00, CRC[7:0],STOPbit(1) CRC-7多項式:x^7 + x^3 + x^0 = 1000 1001 0100 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 000 XOR) 0100 0100 1000 0000 0000 0000 0000 0000 0000 0000 0000 000 10 0100 00000 0000 0000 0000 0000 0000 0000 0000 000 XOR) 10 0010 01000 0000 0000 0000 0000 0000 0000 0000 000 1100 1000 0000 0000 0000 0000 0000 0000 0000 000 XOR) 1000 1001 0000 0000 0000 0000 0000 0000 0000 000 100 0001 0000 0000 0000 0000 0000 0000 0000 000 XOR) 100 0100 1000 0000 0000 0000 0000 0000 0000 000 101 1000 0000 0000 0000 0000 0000 0000 000 XOR) 100 0100 1000 0000 0000 0000 0000 0000 000 1 1100 1000 0000 0000 0000 0000 0000 000 XOR) 1 0001 0010 0000 0000 0000 0000 0000 000 1101 1010 0000 0000 0000 0000 0000 000 XOR) 1000 1001 0000 0000 0000 0000 0000 000 101 0011 0000 0000 0000 0000 0000 000 XOR) 100 0100 1000 0000 0000 0000 0000 000 1 0111 1000 0000 0000 0000 0000 000 XOR) 1 0001 0010 0000 0000 0000 0000 000 110 1010 0000 0000 0000 0000 000 XOR) 100 0100 1000 0000 0000 0000 000 10 1110 1000 0000 0000 0000 000 XOR) 10 0010 0100 0000 0000 0000 000 1100 1100 0000 0000 0000 000 XOR) 1000 1001 0000 0000 0000 000 100 0101 0000 0000 0000 000 XOR) 100 0100 1000 0000 0000 000 1 1000 0000 0000 000 XOR) 1 0001 0010 0000 000 1001 0010 0000 000 XOR) 1000 1001 0000 000 1 1011 0000 000 XOR) 1 0001 0010 000 1010 0010 000 XOR) 1000 1001 000 10 1011 000 XOR) 10 0010 010 CRC= 1001 010(1) CRC= 0x95
下記リンクを参考に,Cプログラムの復習がてら作りました.
***************************************************************************************** プログラム CMD用CRCデータ計算(Stopbit込み) ***************************************************************************************** #include<stdio.h> char crc7(char d[6]) { int crc, crc_prev; int i,j; crc = d[0]; for(i=1; i<6; i++) { for(j=7; j>=0; j--) { crc <<= 1; //左へ1bitシフト crc_prev = crc; //1bitシフトしたデータをコピー if (i<5) crc |= (d[i]>>j) & 1; //1bitシフトさせたデータへ次のデータを入れ込む(&1で) if (crc & 0x80) { crc ^= 0x89; } //先頭bitが1の場合、(1000 1001)をXOR演算 } } return crc_prev | 1; //Stopbitを入れ込む } int main(void) { char data[6]; char c; printf("CRCを計算する値を16進数で入力(CRCを除く1byte毎にEnter 5byte入力)\n"); //scanf("%x,%x,%x,%x,%x\n", &data[0],&data[1],&data[2],&data[3],&data[4]); scanf("%x\n", &data[0]); scanf("%x\n", &data[1]); scanf("%x\n", &data[2]); scanf("%x\n", &data[3]); scanf("%x\n", &data[4]); printf("入力データ=%02x %02x %02x %02x %02x\n", data[0] & 0x000000FF,data[1] & 0x000000FF,data[2] & 0x000000FF,data[3] & 0x000000FF,data[4] & 0x000000FF); c = crc7(data); printf("CRC = %02xです\n",c & 0x000000FF);// return 0; }
○参考文献
SDのCRC7計算ルーチン - nabeの雑記帳
wishid.hatenablog.com
CRC ‐ 通信用語の基礎知識