ある日、あぷあぷ(店名)で、4MBのマルチメディアカードが20枚セットで\2000というのを見つけました。
その、必要最小限の使い方をここにまとめます。
詳しくはデータシートなどを見てください。
以下マルチメディアカードをMMCと呼びます。
MMCを読んだり書いたりするためには、MMCと通信する必要があります。MMCとの通信方法には、MMCモードとSPIモードがあって、SPIモードのほうが簡単です。SPIモードではSPI通信と呼ばれている通信方法を使って通信します。クロック、データin、データoutの3本の信号線を使ったシリアル通信です。
先ずは配線です。MMCはSDカードと大きさやピンなどに互換性がありますから、秋月電子などで売ってる(2005/03) SDカード用のコネクタを使用できます。データシートに入れろと書いてあるので、素直に4と5の間に3と4の間に0.1uFのコンデンサを入れます。MMCのDOはホストのDIに、ホストのDOはMMCのDIに繋ぎます。ホストってのはMMCを操るマイコンなどのことです。
ピン番 | 略号 | 操作権 | なかみ |
1 | CS | ホスト | チップ選択信号 Lで選択 |
2 | DI(DataIn) | ホスト | データ信号 |
3 | GND | ホスト | 電源 0V |
4 | Vcc | ホスト | 電源 2.7〜3.6V (Typ3.0V) |
5 | CLK | ホスト | クロック信号 |
6 | GND | ホスト | 電源 0V |
7 | DO(DataOut) | MMC | データ信号 |
簡単なので、ぐだぐだ書くよりも実際に通信している所を覗いた方が解りやすいでしょう。
1、ホスト→カード 0xAB (1010 1011)
上でバイナリデータの送受信ができるのですが、意味のある構造を持たせてやらないと、「じDゃい1めうAしら」の様にMMCには理解してもらえません。「アドレス0x0019EAのデータを教えてくれ。」という様に理解してもらえるコマンドを送信すれば、「はい。そこのデータは0x674AF1AB… …FC17ですよ。」と答えてくれます。
例えば、CMD0というコマンドは以下のビット列になります。
START | コマンド 6bit | 引数 32bit | CRC 7bit | STOP | |||||||||||||||||||||||||||||||||||||||||||
0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 1 |
コマンドはスタートビット(START(01))から送り始め、ストップビット(STOP(1))で終わります。コマンド6bitにはCMDxxのxxが入ります。このxxは十進数表記で、例えばCMD17なら010001となります。引数32bitはリードコマンドCMD17ならアドレスが入ったりします。CRC 7bitはMMCモードからSPIモードに切り替えるCMD0の時だけ必要です、SPIモードになってからは無視されます(有効にもできます)。
コマンド | 引数 | レスポンス | はたらき |
CMD0 | なし(0で埋める) | R1 | カードをリセットする |
CMD1 | なし(0で埋める) | R1 | カードの初期化が完了したか否か聞く |
CMD16 | ブロック長[Byte] | R1 | CMD17、CMD24の転送ブロック長を設定する。リセット後のデフォルトは512Byte。上限2024Byteやライト時は無効で512Byte固定などカードによって制約あり。 |
CMD17 | アドレス[Byte] | R1 | シングルブロックリード。引数で指定したアドレスからCMD16で設定した分だけカードから読む。 |
CMD24 | アドレス[Byte] | R1 | シングルブロックライト。引数で指定したアドレスからCMD16で設定した分だけカードに書き込む。 |
コマンドを送ったら、MMCは返事をしてくれます。これをレスポンスと呼びます。 レスポンスにはR1とR2の2種類あります。 R2は使わないのでR1レスポンスを見てみましょう。 R1レスポンスは8bitで、以下の構造を持っていて、全て0だと正常ということになります。 R1レスポンスを受けるには、クロックを出しながらレスポンスの頭 0 が出るのを待った後、残り7bit分受信します、例えば。
常に0 | 引数が変 | アドレスが変 | 消去中エラー | CRCエラー | コマンドが変 | 意味不 | アイドル中 |
0 | * | * | * | * | * | * | * |
もう一つ必須なレスポンスがありました。データレスポンスです。?は気にしないでください。
0b???00101 | 問題なし |
0b???01011 | CRCエラー |
0b???01101 | よくわからないエラー |
シングルブロックリードの手順は、コマンドを送信する→レスポンスを受信する→データを受信する、です。 データを受信する時のMMCからの信号には、頭にスタートブロックと呼ばれるヘッダが8bit、尾にCRCが16bit、付加されます。データをサンドイッチにしてデータトークンを構成してます。シングルブロックリード時のスタートブロックは0xFEです。2進では11111110でアイドル時のバスは1なので0がスタートビットと思ってよさそうです。それから、CRCを無視するにしてもMMCは送信するのでデータ受信後に16クロック以上出すことを忘れずに。
シングルブロックライトの手順は、コマンドを送信する→レスポンスを受信する→データを送信する→データレスポンスを受ける→(書き込み終了を待つ)、です。
受信と同様に送信するデータにも、頭にスタートブロック8bit、尾にCRC 16bit、を加えてデータトークンを構成して送信する必要があります。
シングルブロックライトのスタートブロックも0xFEです。
尾のCRCはSPIモードでは無視してくれますがクロックだけ忘れずに。
データレスポンスはR1でよいのでしょうか?とは異なり、0b???00101なら成功です。
(書き込み終了を待つ)というのはMMCがデータを実際に書き込むために少々時間がかかるので、この間はコマンドを送信しないようにするということです。書き込み中はMMCのDOがLに保持されますから、これがHになるまで次のコマンドを送らないようにします。
MMC起動後はMMCモードなのでSPIモードに移行させます。 この手順を以下に示します。
8bitマイコンのAVR ATtiny26LはMMCと同じ2.7Vから動作しSPIをハードウェアでサポートしてます。 コレで読み書きしてみようと思います。
まずは読みです。市販のSDカードリーダでASCIIなテキストファイルを書き込んだMMCを、自作のリーダに挿して内容をCOMポート経由でPCの画面にダンプします。
プログラム 読み出した結果
つづいて書きです。その前に警告をば。
上の「●実験」で「読み出した結果」の 0040には「FAT12」という文字列が、 0042〜0047には第1FAT、0048〜004Dには第2FAT、004Eにはルートディレクトリエントリが、0x009Eにはファイルの断片が見えます。
MMCには書き込みブロック長が512Byteに固定されているものがあるので、FATをRAMが128Byteしかないマイコンで扱うのはちょっと難しいです。次回ということで。