SDカードの構造と内部レジスタ(その1)
SDカードは、microSDカードなどの派生品も含め、デジタルカメラなどに広く使われている。
SDカードの前身としてMMC(Muiti Media Card)カードがある。大雑把に言えば、SDカードはMMCをベースに、著作権保護の機能を追加したものと考えられる。
SDカードの構造
SDカードの端子部分は、下図のようになっている。
各端子の機能と、MEMEsのSH7085への接続を次に示す。
端子名 | MMCモード | SPIモード | MEMEs SH7085端子 |
1 | CD/D3 | CS | PE9 |
2 | CMD | Din | TxD |
3 | Vss | Vss | |
4 | Vdd | Vdd | |
5 | CLK | CLK | SCK |
6 | Vss | Vss | |
7 | D0 | Dout | RxD |
8 | D1 | ― | |
9 | D2 | ― |
※その他に「Card Detect」がSH7085のPE11に接続されている。
SDカードには「MMCモード」と「SPIモード」とがあり、両者には次のような違いがある。
- 使用する信号線の違い(MMCモードでは、「クロック」「コマンド」「データ(D0)」の3本。SPIモードでは、「クロック」「Din」「Dout」の3本)
- MMCモードでは、「コマンド」「データ」の信号線は双方向信号である
- MMCモードではCRCを使うが、SPIモードでは使わなくてもよい
- 電源投入直後はMMCモードで立ち上がる
今回はSH7085内蔵のSCIを用いて、SPIモードでの接続を行う。電源投入時はMMCモードであるので、モード切替コマンドをMMCモードで送信し、以降はSPIモードで通信を行うという手順をとる。
SDカードとの通信
・通信フォーマット
SDカードのSPIモードにおいて、コマンドとレスポンスだけからなる、もっとも簡単な通信は下図のようになる。
まず、マスタがコマンドを送信し、スレーブはそれに対するコマンド・レスポンスを送る。
データがある場合は次のようになる。
まず、マスタからスレーブに対してデータを送る場合は、下図のようになる。
マスタがコマンドを送信し、スレーブがコマンド・レスポンスを返す。続いてマスタがデータ(必要なだけ)送信し、スレーブはデータ・レスポンスを返す。コマンド・レスポンスとデータ・レスポンスはフォーマットが違うので注意が必要である。
次に、スレーブからデータを読み出す場合は、下図のようになる。
マスタがコマンドを送信し、スレーブがコマンド・レスポンスを返す。続いてスレーブがデータを送信する。
・コマンド・トークンのフォーマット
上の図の「コマンド(6バイト)」を、「コマンド・トークン」と呼ぶ。
マスタが送信するコマンド・トークンのフォーマットを下図に示す。
コマンド・トークンは、コマンド部、引数部、CRC部の3つで構成されている。全6バイト(48ビット)である。
コマンド・トークンの先頭(MSB)は必ず0であり(スタートビット)、最終ビット(LSB)は必ず1になる(ストップビット)。
代表的なコマンドを次に示す。
コマンド | 送信時の値 | 引数 | 意味 | レスポンスタイプ |
CMD0 | 0x40 | なし | カードをリセットしてアイドル状態にする | R1 |
CMD1 | 0x41 | なし | カード初期化を実行 | R1 |
CMD9 | 0x49 | なし | カードのCSDを取得する | R1 |
CMD10 | 0x4a | なし | カードのCIDを取得する | R1 |
CMD13 | 0x4d | なし | Statusレジスタの値を返す | R2 |
CMD16 | 0x50 | 転送ブロック長 | 転送ブロック長を設定する | R1 |
CMD17 | 0x51 | メモリアドレス | 設定されたブロック長のデータを取得する | R1 |
CMD58 | 0x7a | なし | OCRレジスタを取得する | R3 |
引数部は、コマンドによっては不要となるが、その場合でも空データ(0x00)を送信し、コマンド・トークンの合計6バイトを守らなければならない。
CRC部は、コマンド部~引数部をCRC7で演算したものである。図のように1バイト(8ビット)の内、上位7ビットがCRC、最下位(LSB)は1固定であるので、計算したCRCを1bit左シフトするなどの考慮が必要である。
・CRC(巡回冗長検査)
SDカードのコマンド・トークンで使われるCRCはCRC7である。多項式は
CRCの計算方法はいくつかあるが、下のようなCRC生成回路をそのままCで実現することとする。
プログラム例を示す。
1: char calc_CRC7(char *data, int len) { 2: int i, j; 3: char crc, dt; 4: 5: crc = 0; 6: for (i = 0; i < len; i++) { 7: dt = *data++; 8: for (j = 0; j < 8; j++) { 9: crc <<=1; 10: if ((crc & 0x80) ^ (dt & 0x80)) 11: crc ^= 0x09; 12: dt <<= 1; 13: } 14: } 15: return (crc & 0x7f); 16: }
ここで得られたCRCを、コマンド・トークンのCRC部として使う場合は、1bit左シフトして、さらにLSB=1にしなければならない。
・コマンド・レスポンス
コマンドに対して、カードが返送するコマンド・レスポンスは「フォーマットR1」、「フォーマットR2」、「フォーマットR3」の3種類がある(コマンド・トークンの項の、コマンド一覧を参照)。
— フォーマットR1 —
フォーマットR1はもっとも基本的なレスポンスで、CMD0などで用いられる。また、「フォーマットR2」や「フォーマットR3」の先頭部分としても用いられる。
コマンド・レスポンスのMSBは常に0である。
bit6~bit1はエラー発生を示すフラグであり、必要に応じて使用する。
bit0の「In Idle State」は、SPIモード移行時に確認するビットである。
— フォーマットR2 —
フォーマットR2は、CMD13(Statusレジスタの取得)で使われるレスポンスである。
先頭の1バイトは、フォーマットR1と同じである。
続く1バイトに、追加のStatusレジスタの値が入る。
— フォーマットR3 —
フォーマットR3は、CMD58(OCRレジスタの取得)で使われるレスポンスである。
先頭の1バイトは、フォーマットR1と同じである。
続く4バイトにOCRレジスタの値が入る。OCRレジスタは動作条件レジスタと呼ばれ、カードの動作電圧情報を含んでいる。
※ : カードの内部レジスタの内、StatusレジスタとOCRレジスタは、コマンド・レスポンスの一部として返される。その他の内部レジスタやカード内のデータなどは、次に解説するデータ・トークンとして返される。
・データ・トークン
コマンド発行によりデータ転送が発生する場合は、データ・トークンが用いられる。フォーマットは次のようになっている。
データ・トークンは、データ・トークン・スタート・バイト部、データ部、CRC部の3つから構成される。
データ・トークン・スタート・バイトは、データ・トークンの最初に現れ、値は0xfeである。データ・トークン・スタート・バイトの前に0xff(ビジーを示す)が出現する場合があるが、不要であるので読み飛ばす。
データ部は転送するデータの本体である。データ長はコマンドによって違う。
CRC部は、データ部のCRCである(データ・トークン・スタート・バイトは計算に入れない)。
CRC部は、CMD9/CMD10に対するデータ・トークンの場合と、セクタ・データの場合とではフォーマットが異なる。
CMD9/CMD10に対するデータ・トークンでは、まずデータ部に対してのCRC7部(1バイト)があり、続いてデータ部とCRC7部に対するCRC16部(2バイト)がある。
セクタ・データ転送時は、データ部に対するCRC16部(2バイト)のみとなる。
・データ・レスポンス
カードへのデータ書き込みを行った場合などに、カードからデータ・レスポンスが送られる。フォーマットを次に示す。
SPIモードへの移行手順
SDカードは、電源投入直後はMMCモードで起動している。SH7085内蔵のSCIを用いて通信するためには、コマンドを発行してSPIモードへ移行しなければならない。
SPIモードへの移行は、次のような手順で行う。
- 80クロックのダミークロックを送信する
- CS=Lにして、CMD0を発行する(カードはまだMMCモードなので、CRC必要)
- レスポンス=0x01を確認する
- CMD1を発行する
- レスポンス=0x00になるまで、手順4.を繰り返す
この移行手順の中では、カードはMMCモードにあるため、コマンド・トークンにCRCが必要である。
レスポンスを確認する場合も、ダミーデータ(0xff)を送りながら受信を行う。コマンド送信後すぐにカードがレスポンスを返すとは限らないので、何回か繰り返す必要がある。コマンド・レスポンスの場合は、レスポンスのMSBは必ず0であることを利用して、レスポンスを見つけるようにする。
以上で、カードをSPIモードに移行することができる。SPIモードになれば、SH7085のSCIを用いてカードと通信することが可能である(MMCモードでは、信号線の定義が違っていて、コマンド線とデータ線になっていて、両方とも双方向通信である。SCIと接続してもTxD、RxDそれぞれが送受信できないといけなくなってしまう・・・SH7085では不可能である)
SDカード その他の信号
SDカードを使用するには、SPI通信の信号線以外にも、いくつか必要な信号がある。
・CS信号
Card Select信号の略で、SDカードとSPIモードで通信する際に使用する。「SPIの使い方」のテキストの、SS(Slave Select)信号と同一である。SPIバス上に複数のデバイスが接続されている場合、通信相手を選択する信号である。
MEMEsではSH7085のPE9に接続されている。なおPE9はLED5との兼用端子であるため、SDカード使用時にはLED5は使うことはできない。
アクティブ・ローの信号なので、SDカードと通信する場合はLレベルにする。
・CD信号
Card Detect信号の略で、カードソケットにSDカードが入っているかどうかを検出する信号である。これはSDカードの端子に存在する信号ではなく、SDカードソケットに存在する信号である。
カードが存在すれば0、カードがなければ1になる信号である。
MEMEsではSH7085のPE11に接続されている。なおPE11はLED6との兼用端子であるため、SDカード使用時にはLED6は使うことはできない。
SDカードのように、抜き差し可能なデバイスは、常に存在しているとは限らない。通信相手がない場合に通信を試みて、無限ループに入り込むようなプログラムは作ってはならない。必ず相手の存在を確認して、通信を行うこと。
演習問題
次のワークスペースをダウンロードして、展開する。
sd1.zip
・演習1:1バイト送受信関数の作成
プロジェクト[sd1_1]を使用する。関数SPI_tx_rx()は未完成である。「SPI通信」のテキストを参考に完成せよ。
正しく動作すると、HtermにSDカードへのコマンド・トークン(0x40・・・)と、SDカードからのコマンド・レスポンス(0x01)が表示され、終了する。これは、SPIモードへの移行手順の先頭部分である。
・演習2:SPIモード移行関数の作成
プロジェクト[sd1_2]を使用する。関数Enter_SPI_mode()は未完成である。テキストを参考に完成せよ。
エラーが発生した場合は、戻り値-1として関数を終了する。正常終了の場合の戻り値は1とする。
コマンドの送信には、関数SD_send_cmd()を使用する。この関数はコマンド・トークンを送信した後、コマンド・レスポンスを待ち、戻り値としてコマンド・レスポンスを返す。
正しく動作すると、HtermにSDカードのCID(カード識別レジスタ)の内容が表示される。CIDレジスタには次のような情報が含まれている。
詳しくは「SDカードの構造と内部レジスタ(その2)」で解説する。
名称 | バイト数 |
Manufacture ID | 1 |
OEM/Application ID | 2 |
Product Name | 6 |
Product Revision | 1 |
Pruduct Serial Number | 4 |
Manufacturing Date | 1 |
CRC | 1 |
・演習3:CSDレジスタを読み出す
プロジェクト[sd1_2]を使用する。SDカードのCSDレジスタを読み出し、Htermに表示する機能を追加せよ。
CSDレジスタは、CMD9を発行することにより得られる、128ビット(16バイト)の情報である。
CIDと同様に、コマンド発行後にコマンド・レスポンスを待つ。その後データ・トークンを受信し、データ・トークンスタートバイトを除いた16バイトがCSDレジスタの内容である。