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モードへの移行は、次のような手順で行う。

  1. 80クロックのダミークロックを送信する
  2. CS=Lにして、CMD0を発行する(カードはまだMMCモードなので、CRC必要)
  3. レスポンス=0x01を確認する
  4. CMD1を発行する
  5. レスポンス=0x00になるまで、手順4.を繰り返す

この移行手順の中では、カードはMMCモードにあるため、コマンド・トークンにCRCが必要である。

80クロックのダミークロック送信は、ダミーデータを送信することで実現する。ダミーデータは、コマンド・トークンのスタートビットと誤認識されないよう、0xffを送る。

レスポンスを確認する場合も、ダミーデータ(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レジスタの内容である。

Copyright © 2012-2024 ミームス(MEMEs)のサポートページ All rights reserved.
This site is using the Desk Mess Mirrored theme, v2.5, from BuyNowShop.com.