30前から

FPGAでいろいろ頑張ってみています

FPGAでSDカード内のWAVEファイルを再生する~その2

”SDカードをSPIモードにするまでのフローチャートを見てみる”

http://elm-chan.org/docs/mmc/gfx1/sdinit.png
引用元: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 ‐ 通信用語の基礎知識