MMC/SDCの使いかた

MMC/SDC使いかた


更新: 2020. 9. 14


mmc_sdc

現在広く普及しているメモリカードのひとつに、SDメモリカード(Secure Digital Memory Card)があります。SDメモリカード(以下SDCと表記)は、マルチメディアカード(Multi-Media Card、以下MMCと表記)上位互換のシステムとして開発されたもので、SDC対応機器はいくつかの考慮だけでMMCを同じソケットで使うことができます。これらのメモリカードには、機能はそのままで外形だけ小型化されたバリエーションがあります。MMC/SDCは内部にマイコンを持ち、フラッシュ メモリの制御(消去、書き込み、エラー制御、消耗均等化など)は内部で完結しています。データの読み書きは基本的にブロック(512バイト)単位となり、この点でハードディスクなどの汎用ストレージデバイスと変わるところはありません。ファイルシステムにはFATまたはexFATが採用されています。

現在、MMCはメモリカードとして流通することはなく、eMMCという規格で内蔵ストレージとしての利用がメインとなっています。

ここでは、MMC/SDCを組み込みシステムで利用する際に最低限知っておくべき点や、いろいろ気づいた点などをコンパクトにまとめておきます。これからMMC/SDCを使ってみようとしている方の参考になれば幸いです。

  1. 端子配列
  2. SPIモード
  3. SPIモード初期化手順
  4. データ転送
  5. 端子処理と活線挿抜
  6. バス接続の注意点
  7. SPIモードのSCLK周波数
  8. 書き込み速度の最適化
  9. MMC/SDCのライセンス
  10. 資料

端子配列

SDC/MMC contact surface
miniSD | microSD

右の写真にMMCとSDCの端子部を示します。MMCは7接点、SDCはそれに2接点を追加した9接点となっています。このうち、電源がそれぞれ3接点を占めているので、有効信号線数はそれぞれ4本と6本ということになります。信号名からも分かるように、データ伝送はクロック同期シリアルで行われます。

動作電源電圧は、動作可能範囲を示すレジスタを読み出して確認することになっていますが、全てのMMC/SDCは少なくとも2.7~3.6Vの範囲で動作するので、その範囲の電源電圧に決め打ちしてもOKです。電源電流は読み書き動作のピークで数十mA流れるので、余裕を見て100mA程度は確保しておいた方がよいでしょう。

SPIモード

SPIモードの最小構成

SPIモードはMMC/SDCを簡単に制御するために設定された代替の動作モードです。SPIモードの伝送制御はネイティブモードよりも単純なので、マイコン内蔵のSPIポートまたはGPIOポートで容易に制御できます。組み込みシステムではコストの点からMMC/SDC専用インターフェースを設けられないことも多いのですが、SPIモードでMMC/SDCを制御すれば廉価なシステムが実現できます。SDCのSPIモードは、Mode0準拠のタイミングで規定されています。MMCではラッチ・シフト共にクロックの立ち上がりで規定されていてSPIとは異なりますが、SPIモードではMode0のタイミングで動作するようです。したがって、SPIポートの設定はMode0(CPHA=0, CPOL=0)とするのが適当です(Mode3でも多くは動く)。DOピンのプルアップ抵抗は省略できません(さもないといくつかのカードは初期化に失敗する)。

コマンドとレスポンス

SPIモードでは各信号の入出力方向が固定され、バイト指向のシリアル伝送となります。コマンドフレームは6バイトの固定長で、次のようなフォーマットで伝送されます。カードにコマンドを送るとそれに対するレスポンス(形式はコマンド毎に異なる)が返って来るので、ポーリング(0xFFを送信して受信データを調べる)しながらレスポンス待ちます。コマンド応答時間(NCR)は、0~8バイト(SDC)または、1~8バイト(MMC)となっています。一つのトランザクション(コマンド送信開始からレスポンス、データ転送(あるならば))の間はCSをアサート(Low)に保持しておかなければなりません。


SPIコマンドセット

それぞれのコマンドはCMD<n>といった略号で表記されます。nはそのコマンドのインデックス番号を示し、0~63です。ここでは、通常の読み書きで使用されるコマンドを中心に載せておきます。全コマンドの詳細については、MMC/SDCそれぞれのスペックシートを参照してください。

コマンド
インデックス
引数応答データ
転送
省略形説明
CMD0無し(0)R1無しGO_IDLE_STATEソフトウェアリセット。
CMD1無し(0)R1無しSEND_OP_COND初期化開始。
ACMD41(*1)*2R1無しAPP_SEND_OP_CONDSDC専用。初期化開始。
CMD8*3R7なしSEND_IF_CONDSDC V2専用。動作電圧確認。
CMD9無し(0)R1ありSEND_CSDCSD読み出し。
CMD10無し(0)R1ありSEND_CIDCID読み出し。
CMD12無し(0)R1b無しSTOP_TRANSMISSIONリード動作停止。
CMD16ブロック長[31:0]R1無しSET_BLOCKLENR/Wブロック長変更。
CMD17アドレス[31:0]R1ありREAD_SINGLE_BLOCKシングルブロック読み出し。
CMD18アドレス[31:0]R1ありREAD_MULTIPLE_BLOCKマルチブロック読み出し。
CMD23ブロック数[15:0]R1無しSET_BLOCK_COUNTMMC専用。次のマルチブロック読み出し/書き込
みコマンドでの転送ブロック数を設定。
ACMD23(*1)ブロック数[22:0]R1無しSET_WR_BLOCK_ERASE_COUNTSDC専用。次のマルチブロック書き込みコマンド
でのプレ消去ブロック数を設定。
CMD24アドレス[31:0]R1ありWRITE_BLOCKシングルブロック書き込み。
CMD25アドレス[31:0]R1ありWRITE_MULTIPLE_BLOCKマルチブロック書き込み。
CMD55(*1)無し(0)R1無しAPP_CMDアプリケーション特化コマンド。
CMD58無し(0)R3無しREAD_OCROCR読み出し。
*1: ACMD<n>とは、CMD55,CMD<n>のコマンドシーケンスを意味する。
*2: 予約(0)[31], HCS[30], 予約(0)[29:0]
*3: 予約(0)[31:12], Supply Voltage(1)[11:8], Check Pattern(0xAA)[7:0]

SPIレスポンス

MMC and SDC

コマンドに対するカードのレスポンスには、コマンドにより決まっていて、R1、R2、R3、R7の4タイプがあります。ここではR1とR3だけ説明しておきます。ほとんどのコマンドでは1バイト長のR1が返ります。R1のビットフィールドは右の図に示すようになっていて、0x00で成功を示します。何らかのエラーがあった場合は対応するビットが立ちます。R2は2バイト(R1+8ビットのステータス)、R3/R7は5バイト(R1+32ビットの戻り値)の形式で返されます。

処理に時間のかかるコマンドでは、R1bレスポンスとなっています。R1bではR1レスポンスに続いてDO出力にビジーフラグ(連続したLowレベル)が出力されます。内部処理が終わって0xFFが受信されるまでホストはポーリングしながら待ちます。

SPIモード初期化手順

MMC/SDCは電源ONリセットにより、まずそれ本来のネイティブな動作モードになります。SPIモードに初期化するには次の手順を踏む必要があります。(フロー チャート)

電源ONまたはカード挿入後

電源ONにより、カードはそれ本来のネイティブな(SPIモードでない)動作モードに入ります。電源電圧が規定の範囲(2.7~3.6V)に達したあと少なくとも1ms待ち、DI,CSをHレベルにしてSCLKを74クロック以上入れるとコマンドを受け付ける準備ができます。

ソフトウェア リセット

SPIの伝送速度を100k~400kbpsに設定します。CS信号をアサート(Low)してCMD0でソフトウェアリセットをかけます。CMD0を受信したときカードはCS信号をサンプルし、Lowレベルの場合はSPIモードに入ります。CMD0を送るときはまだSPIモードではないので、コマンドパケットのCRCは有効な値でなければなりません。SPIモードに入るとカード側のCRCチェックがOFFになるので、コマンドパケット送信ルーチンではCMD0とCMD8にだけ有効なCRCバイトでハードコーディングしておいて良いでしょう。リセットが正常にかかるとカードはアイドル状態に入り、In Idle Stateビットの立ったR1レスポンス(0x01)が返ります。この状態ではまだ読み書き系コマンドは使えません。なお、SPIモードに入った後もCMD59でCRCチェックをONにすることもできます。

初期化の開始と完了待ち

次にCMD1を送るとカードは初期化を開始します。初期化の終了を確認するため、CMD1を繰り返し送信してレスポンスを調べます。初期化が終了すると、In Idle Stateビットがクリアされた(0x00)レスポンスが返ります。カードによっては初期化に数百msかかることがあるので、タイムアウトには余裕を持っておくべきです。初期化終了を確認したあとは通常のデータ読み書きが可能になります。

SDCではCMD1の代わりにACMD41での初期化が推奨されています。SDCとMMC両方に対応する場合は、先にSDCとして初期化コマンドを送ってみてrejectされたらMMCと判断してCMD1で初期化を行うのが理想的です。

最後にOCR、CSDを読み込んで各種パラメータを確認します。OCRはカードの電源電圧範囲を示しているので、そのシステムで使用可能かチェックしますが、2.7~3.6Vの範囲で使うなら特に確認する必要はありません。CSD内のTRAN_SPEEDフィールドはカードの最大動作周波数を示しているので、これに従いSPIの伝送速度を再設定します(MMCでは20MHz、SDCでは25MHz)。SPIモードの場合は、速度を制限する状態(OD駆動)が無いので、速度切り替えなしで最初から20/25MHzでも多くはOKです。2Gバイトのメモリカードでは、ブロック サイズの初期値が512以外の場合があるので、CMD16でブロックサイズを512バイトに再設定しておきます。

大容量SDカードとその対応方法

SDSCカードの容量は、8Mバイト~2Gバイトとなっています。これは、規定のファイルシステムであるFATの最大容量が2Gバイトであることによります。(FATは仕様上4Gバイトまでいけますが、当時現役のMS-DOSが2Gバイトまでしか対応しなかったからなのでしょう)

SDHCカードの容量は、2Gバイト超~32Gバイト以下となっています。これは、規定のファイルシステムであるFAT32の最大容量が32Gバイトであることによります。(FAT32は仕様上2Tバイトまでいけますが、Microsoftの公式サポートは32Gバイトまで)

SDXCカードの容量は、32Gバイト超~2Tバイト以下となっています。規定のファイルシステムであるexFATは2Tバイト超にも対応するのですが、アドレス方式(32ビットLBA)がSDHCから変更無いため、2Tバイト止まりとなります。

SDUCカードではアドレス方式を38ビットLBAに拡張することで2Tバイト超~128Tバイトとなっています。規定のファイルシステムはexFATです。ただし、SDUCカードではSPIモードがサポートされなくなりました。38ビットLBA方式は、SPIモードでは仕様上サポートされない(SD Ver.2の後に追加された)機能だからです。

さて、SDHC以降の大容量SDカードでは、初期化方法が少し異なります。CMD0でカードがアイドル状態に入ったら、初期化開始の前にCMD8を送ります(引数は0x1AAで、CRCは有効でなければなりません)。CMD8が拒否されたらSD Ver.1またはMMC Ver.3なので、引き続き前項の処理で初期化します。CMD8が受け付けられると、R7(R1+32ビットの戻り値)が返ります。戻り値の下位12ビットが0x1AAならそのカードはSD Ver.2以上で、2.7V~3.6Vで動作が可能なことを示しています。それ以外の値の場合、そのカードは仕様不明なので初期化失敗とします。続いて、ACMD41(引数のHCS[bit30]を立てる)を使って初期化を開始します。初期化が完了したらOCRを読み出します。OCR中のCCS[bit30]が1ならそのカードはSDHCまたはSDXCで、アドレス方式はLBA(ブロックサイズは512バイト固定)となり、次のセクションで説明するリード/ライト動作ではバイト単位ではなくブロック単位のアドレスを使用します。

データ転送

データパケットとレスポンス

data block

データ転送を伴うトランザクションでは、コマンドレスポンスに続いてデータブロックが授受されます。データブロックはトークン、データブロック、CRCから成るデータパケットとして伝送されます。データパケットは右の図に示すフォーマットとなっていて、トークンは3通りあります。このうち、マルチブロックライト終了を示すStop Tranトークンはデータ部とCRCを持たず単独で使われます。


シングルブロックリード


読み出し書き込みコマンドの引数はバイトまたはブロック単位の開始アドレスです。上位レイヤにより指定されたアドレスは、そのカードのアドレッシングモードに応じて適切にスケーリングする必要があります。読み出しコマンドが受け付けられた後、内部で読み出し動作が行われデータパケットが送られて来るので、ポーリングしながら待ちます。ホストはデータトークンを確認したら、続くデータブロックとCRCを取り込みます。ブロックサイズはデフォルトでは512バイトになっています(CMD16で変更することもできます)。読み出し中に何らかのエラーが発生したときは、データパケットの代わりに1バイトのエラートークンが返ります。

マルチブロックリード


指定アドレスを先頭にした複数のデータブロックが転送されます。MMCでは、転送ブロック数を指定せずにマルチブロックリードを開始(open-ended multiple block read)した場合、またSDCでは常時、必要なブロック数を転送した後、CMD12で読み出し動作を止めなければなりません。このとき、CMD12の直後に返る1バイトは無効なので、そのバイトを読み捨ててからCMD12のレスポンスを受信します。何らかのエラーが発生したときも同様にCMD12でリード動作を止めます。

シングルブロックライト


書き込みコマンドが受け付けられたら、データパケットを送信します。コマンドレスポンスとデータパケットの間は1バイト以上空けなければ(0xFFを送信)なりません。CRCがOFFの場合、データパケットのCRCはチェックされませんが、フィールドとして必要なので適当なダミーデータを送る必要があります。データパケットを送ると直後にデータレスポンスが返るので、正常に転送されたかどうか確認できます。データレスポンスの後はビジーフラグが出力されるので、ポーリングしながら書き込み動作終了を待ちます。

原則として、ひとつのトランザクションの間はCSをアサート(Low)に保たなければなりませんが、カードがビジー状態の間は、CSをデアサート(High)してSPIバスを解放することができます。次にCSをアサートしてポーリングを再開しときまだビジー状態ならカードは再びDOをLowに駆動します。そこで、先行ビジーチェック(コマンドおよびデータブロック送信の直前にビジーチェックを入れる)にするとデータ転送終了と同時にCPUを解放でき、CPU時間を有効に使えます。なお、内部で書き込み処理が開始されるのは、データレスポンスのあと1バイト分クロックが走ってからなので、先行ビジーチェックの場合は注意が必要です。追加クロックのときのCSの状態は問われないので、後で説明するバス解放処理をもって追加クロックとすることもできます。

マルチブロックライト


指定アドレスを先頭にした複数のデータブロックが転送されます。直前に転送ブロック数を指定せずにマルチブロックライトを開始(open-ended multiple block write)した場合、必要なブロック数を転送した後、転送終了を示すStop Tranトークンを送ってデータ転送を終了させます。Stop Tranトークンに対するビジーフラグは、1バイト置いて出力されます。なお、SDCでは pre-defined, open-endedにかかわらず、常にStop Tranトークンが必要です。

CSD,CIDの読み出し

これらの読み出しは、シングルブロックリードと同じで、読み出しコマンドを送るとそれぞれデータパケット(データ部16バイト)としてホストに送信されます。CSD,CIDおよびOCRの詳細については、MMC/SDCのスペックシートを参照してください。

端子処理と活線挿抜

dip

タイミングによってフローティング状態になる信号線は、プルアップやプルダウンで適切にレベル固定しておくべきです。DI、DOのアイドル状態はHighレベルなので、プルアップが適当です。MMC/SDCの規格によると、これらの端子は50k~100kΩでプルアップすべしとなっています。クロック信号については常にホストから駆動されるので処理は明記されていませんが、浮くタイミングがあるなら適宜レベル固定した方が良いでしょう。

電源ON状態でカードの抜き差し(活線挿抜)をするアプリケーションでは、電源回路にもある程度の考慮をしないと誤動作に悩まされることになります。たとえば、システム電源をソケットに直接接続してあると、カードを挿入した瞬間にカードに内蔵されているコンデンサへの突入電流でシステム電源がディップします。右の図のAがそれの様子で、600mVの電源ディップが発生しています。これはBODをトリガさせるには十分なレベルです。Bはその対策としてインダクタを入れて突入電流を抑制したものです。ディップは200mV程度となり、何とか許容範囲に入りました。また力業で大容量OSコンを入れば、ほぼ問題のないレベルになります。ただし、OSコンはLDOを発振させる場合があるので注意が必要です。

バス接続の注意点

SPIではCS信号により個々のデバイスが選択され、複数のデバイスをSPIにバス結線することができます。普通のSPIデバイスなら、CS信号によって非同期的にDO信号を駆動/解放しますが、MMC/SDCの場合はこのタイミングが少し異なり、SCLKに同期して駆動/解放が行われます。このため、MMC/SDCと他のSPIデバイスをバス接続したとき、DO出力が衝突する可能性があります。右の図にMMC/SDCのDO駆動/解放のタイミングチャートと波形を示します(DO信号は見やすいように1/2 Vddに吊ってあります)。このように、MMC/SDCに確実にDO信号を解放させるには、CSをHighにしたあと1バイト分クロックを送っておく必要があります。また、先行ビジーチェックとする場合も駆動開始の遅れに注意が必要です。

もう一つ重要な点は、MMC/SDCは初期状態でネイティブモード(CS信号を使わない)であることです。つまり、その状態で他のスレーブへの通信が行われると、MMC/SDCが意図せず応答して信号の衝突が発生する可能性があります。このため、他のスレーブへのアクセス開始に先立ち、MMC/SDCをSPIモードへ初期化しておかなければなりません。

右の図にバス接続を考慮したSPIトランザクションの制御シーケンスを示します。なお、バス接続に限らずダミーバイトの挿入はカードによる互換性問題を解消する傾向があります。

SPIモードのSCLK周波数

MMC/SDCは、20/25MHzまでの動作が可能です。ネイティブモードコントローラは、当然のことながら最高速度での動作を保証していますが、SPIモードではマイコンのAC特性の問題により、常に最高速度で動作できるとは限りません。実際、いくつかのマイコンでは、計算上の最高周波数が10MHzに満たないものもあります。右の図にSPIモードの動作タイミングを示します。tdはMMC/SDCのSCLK-DO遅延で、SDCでは最大14nsです。tsuはマイコンのMISO入力のセットアップ時間です。これによりSCLKの最高周波数は、
FSCLK(max) = 0.5 / (td + tsu)
ということになります。

書き込み速度の最適化

MMC/SDCのほとんどはメモリアレーにNAND型フラッシュメモリを使用しています。NAND型はビット単価が安く、大量のデータの書き込み/読み出しを高速に行えるのが特徴です。しかしその反面、データの一部の書き換えは苦手というデメリットがあります。元々フラッシュメモリというのは、データを書き込む前に古いデータを消去する必要があり、また消去の最小単位(消去ブロックという)は書き込みの単位よりもずっと大きくなります。NAND型の場合、書き込み/消去のブロックサイズは512B/16KBまたは2048B/128KBです。これは、1セクタ(512B)の書き換えであっても、カード内部ではそのセクタを含む消去ブロック全体(16KBまたは128KB)の読み出し/消去/再書き込みが行われていることを意味します。

ベンチマークをとってみる

ここで、RAMの限られた組み込みシステムを想定して、チープな8bit MCU(ATmega64/9.2MHz)を使っていくつかのカードにファイルを読み書きする実験をしてみました。RAMサイズの都合から2KB単位でのwrite(), read()としています。その結果、128MB SDCでは Write: 77kB/秒、Read: 328kB/秒で、512MB SDCでは Write: 28kB/秒、Read: 234kB/秒、128MB MMCでは Write: 182kB/秒、Read: 312kB/秒となりました。

このように、512MB SDCの書き込み速度は128MB SDCの1/3という悲惨な結果になってしまいました。記録メディアは高密度になるほど速くなるものですが、メモリカードに限っては逆の傾向となることもあるのです。MMCについてはSDCの数倍とまずまずの速度のようです。今回ダメダメだったSDCですが、高速タイプを謳っているのもあるので、いろいろ試してみると面白いと思います。→その後いくつか試したところ、PQIのSDCはMMCと同等の書き込み性能を示しましたが、パナと東芝の標準タイプはチマチマ書きが苦手なようです。

消去ブロック サイズの影響

さらに書き込み動作を詳しく調べるため、処理ルーチン内でデータ転送後のビジー時間(ポーリング回数)を出力しています。1行に複数の数値があるのは、マルチブロックライトが行われている部分で、行頭から各データブロックのビジー時間で、最後がStopTranトークン後のビジー時間となります。

これらを比較してみたところ、128MBと512MBでは内部処理が異なるようで、128MB SDCではマルチブロック転送が終わる都度、512MB SDCではある程度バッファを持っているらしく、4KB溜まった時点で書き込み処理が行われているようです。このため単純な比較はできませんが、消去ブロック書き換え時間は128MB SDCでは3800、512MB SDCでは30000と見られ、約8倍の時間がかかっていることになります。このことから、テストした 128MB SDCはスモールブロックの、512MB SDCはラージブロックまたは多値記録のメモリチップが使われていることが推測できます。もちろん、後者の方が部分書き換えの効率は悪いです。なお、512MB SDCでは先頭の512KB分だけが何故か高速になっています。これはclose()時のFAT/ディレクトリ領域の書き戻し時間から分かります。もしかしたら、FAT領域となるメモリ先頭部分は何か特別な扱いになっているのかも知れません。

書き込み性能の改善策

write transactions

さて、MMC/SDCの性能を最大限に引き出すためには、一度に書き込むセクタ数を可能な限り大きく(少なくとも消去ブロック単位)取ればいいということが分かりました。つまり、RAMをたくさん用意してfwrite()に大きなデータ ブロックを渡すということです。ドライバレベルでは、カードがマルチブロックライトを効率よく実行するため、書き込むセクタ数を予めカードに伝えておく必要があります(pre-defined multiple block writeという)。しかし、そのコマンドはMMCとSDCでは異なる(MMCではCMD23、SDCではACMD23)ので注意が必要です。まぁ、RAMが数KB程度のマイコンでは書き込み性能アップは諦めた方がいいでしょう。それよりも、高速なカードを選んで使う方が賢明といえます。

なお、カード出荷時はFATボリュームのデータ領域が消去ブロック境界にアライメントするように区画設定と論理フォーマットがされています。これをMMC/SDCの特性を考慮しないシステム(たとえばパソコン標準のフォーマッタ)で不用意に区画設定や再フォーマットすると、この関係が崩れて効率が低下する場合があります。試しに512MB SDCをパソコンでFAT32フォーマットしてみたら、PCでのファイルコピー速度が数分の一に低下してしまいました。MMC/SDCの再フォーマットは対応デバイス上(パソコンなら専用ツール)で行うべきです。

MMC/SDCのライセンス

SD規格(SDメモリ、SDIO)はSDAおよびSD-3C, LLCが開発・提供する商品です。したがって、これを利用するデバイス(SDカードやホスト機器)を製造販売する事業者(法人または個人)はSDA会員である必要があります。たとえばホスト機器の場合、SDカード対応を謳うもの(SDモード/SPIモードに関わらず)が該当し、これらの製造販売にあたってはSD-3C, LLCとHALA(Host and Ancillary Product License Agreement)を締結している必要もあります。組み込みモジュールなどの半製品の場合、それの販売者か最終製品の販売者の少なくともどちらかにライセンスが必要です。

逆に、SDカードに対応していたとしてもSDカード対応を謳わなければ(ナンセンスですが!)その必要はありませんし、単なる個人プロジェクトとして完結する場合もライセンスは不要です。なお、SDAの年会費は $2,500 (一般会員)で、HALAのライセンス料は年間 $3,000 です。必要な技術資料が入手できるとか製品にSDロゴの使用ができるなどのメリットを考えれば、まぁ安いといえます。でも、それすら払いたくないケチなメーカ(大手を含む)は「MMC対応」とか「MMCまたは互換カード対応」とか「TFカード(microSDの隠語)対応」などと言って誤魔化しているようですが(笑)。

MMCの場合、製造販売に関してライセンス等は必要ありませんが、技術資料が公開されておらずMMCA(現在はJEDECに移管)から購入しなければなりません。