MMCの制御方法などについて『MMC対応カーネル Ver.1.25』のソースを読んで勉強させていただきました。
ソースを読んでいて、いくつか気付いたことがあったので、報告します。
● スーパーフロッピー形式への対応
『MMC対応カーネル Ver.1.25』は、MMC/SDカードがハードディスク形式でフォーマットされていることを前提としています。
通常、MMC/SDカードはハードディスク形式のフォーマットで出荷されているようなので、これで問題ないのですけれど、
稀に、何らかの拍子にスーパーフロッピー形式になってしまうことがあるようです。
また、MMC/SDカードの仕様上は、スーパーフロッピー形式で出荷することも有り得るみたいです。
スーパーフロッピー形式にはMBRが無いため、『MMC対応カーネル Ver.1.25』はmmcInit()の初期化に失敗してしまいます。
スーパーフロッピー形式になってしまったMMC/SDカードは、fdiskツールを使ってハードディスク形式に戻すことができます。
しかし、Windowsからはどちらの形式でも同じように扱えるため、スーパーフロッピー形式になってしまったことに気付かず、
そのまま使い続けてしまうことが多いと思います。
このようなケースがどれぐらいあるのかは不明なのですけれど、(僕は今回ありました...(^^;)
『MMC対応カーネル』側でスーパーフロッピー形式のMMC/SDカードにも対応しておくとより確実かな、と思いました。
ハードディスク形式とスーパーフロッピー形式を正確に判別するのはやや手間がかかるので、正確な判別は行わず、
まずはこれまで通りハードディスク形式で初期化してみて、失敗ならばスーパーフロッピー形式と仮定してリトライします。
-------------------------------------------------------------------------
mmc_api.c - unsigned char mmcInitCore(void) 関数
◎変更前
//MBRからブートセクタまでのオフセットを取得
ulOffsetSector = mmcGetBootSecterOffset();
//ちゃんと取得できたか?
if(ulOffsetSector == 0xFFFFFFFF)
return 0;
//ブートセクタからファイルシステムの情報を取得
if(mmcGetFileSystemInfo(ulOffsetSector) == 0)
return 0;
//固定長のワークエリアをヒープ領域から取得
if(mmcAllocFixedWorkArea() == 0)
return 0;
◎変更後
//MBRからブートセクタまでのオフセットを取得
ulOffsetSector = mmcGetBootSecterOffset();
//ブートセクタからファイルシステムの情報を取得
if((ulOffsetSector == 0xFFFFFFFF) ||
(mmcGetFileSystemInfo(ulOffsetSector) == 0))
{
//スーパーフロッピー形式と仮定してリトライ
ulOffsetSector = 0;
if(mmcGetFileSystemInfo(ulOffsetSector) == 0)
return 0;
}
//固定長のワークエリアをヒープ領域から取得
if(mmcAllocFixedWorkArea() == 0)
return 0;
-------------------------------------------------------------------------
手元の環境で試したところ、この方法で両フォーマット形式とも正しくmmcInit()の初期化に成功しました。
● CID受信について@
以下、動作上はまったく問題なく、ソース上だけの話です。細かくってスミマセン。
『MMC対応カーネル Ver.1.25』は、MMC/SDカードからCIDデータを受信するために、次のような処理を行っています。
-------------------------------------------------------------------------
mmc_api.c - unsigned char mmcGetCIDInfo(MMC_CID_INFO *pCIDInfo) 関数
unsigned char ucaRecvCID[sizeof(MMC_CID_INFO)]; //CID情報受信用バッファ
(中略)
//レスポンス後に送信されるCIDデータを受信
if(mmcRecvData(ucaRecvCID,sizeof(MMC_CID_INFO)) == 1)
-------------------------------------------------------------------------
MMC/SDカードから送られてくるCIDデータは16バイトですから、16バイトの受信を行うはずです。
が、sizeof(MMC_CID_INFO)は20バイトです…
-------------------------------------------------------------------------
mmc_api.h - MMC_CID_INFO 構造体宣言
//CID(Card IDentification number) カードIDレジスタ情報構造体
typedef struct tag_MMC_CID_INFO
{
unsigned char ucMID; // + 0,1: ManufactureID(8bit)
// + 1,1: (暗黙のパディング)
unsigned short usOID; // + 2,2: OEM/Application ID(16bit)
unsigned char ucPNM[6]; // + 4,6: Product name(48bit)
unsigned char ucPRV; // +10,1: Product revision(8bit)
// +11,1: (暗黙のパディング)
unsigned long ulPSN; // +12,4: Product serial number(32bit)
unsigned char ucMDT; // +16,1: Manufacturing date(8bit)
unsigned char ucCRC; // +17,1: 7-bit CRC checksum(7bit)
// +18,2: (暗黙のパディング)
} MMC_CID_INFO; // =20
-------------------------------------------------------------------------
CIDデータの受信手順においては、実際に送られてくるより多くのデータを受信することは問題にならないため、
このままでもまったく大丈夫なのですけれど、厳密にはこうかな、と思いました。
-------------------------------------------------------------------------
mmc_api.c - unsigned char mmcGetCIDInfo(MMC_CID_INFO *pCIDInfo) 関数
◎変更前
unsigned char ucaRecvCID[sizeof(MMC_CID_INFO)]; //CID情報受信用バッファ
(中略)
//レスポンス後に送信されるCIDデータを受信
if(mmcRecvData(ucaRecvCID,sizeof(MMC_CID_INFO)) == 1)
◎変更後
unsigned char ucaRecvCID[16]; //CID情報受信用バッファ
(中略)
//レスポンス後に送信されるCIDデータを受信
if(mmcRecvData(ucaRecvCID,16) == 1)
-------------------------------------------------------------------------
● CID受信についてA
SPIモードでのCSDレジスタおよびCIDレジスタの内容を読み込むことは、単純なリードブロックトランザクションです。
すなわち、スタートバイト(1バイト)・CIDデータ(16バイト)・16ビットCRC(2バイト)の、データトークンが返送されてきます。
(http://www.renesas.com/avs/resource/japan/jpn/pdf/flashcard/j203658_hb28e016mm2.pdf 56ページ CID/CSDレジスタリード 参照)
『MMC対応カーネル Ver.1.25』は、CSD受信ではちゃんと16ビットCRCの受信を行っているのですが、
-------------------------------------------------------------------------
mmc_api.c - unsigned char mmcGetCSDInfo(MMC_CSD_INFO *pCSDInfo) 関数
//受信に成功
ucRet = 1;
//CSDを読み出した後は16クロック以上のダミー
//クロックを送らないと、次の処理に移ること
//ができないみたいです。
//なにか来てるみたいだし(--; CRC?
//16クロック分のダミー送信
mmcByteSend(0xFF);
mmcByteSend(0xFF);
}
}
//カードをNonActiveに
CARD_DISABLE
-------------------------------------------------------------------------
CID受信では16ビットCRCの受信を行っていないようです。
-------------------------------------------------------------------------
mmc_api.c - unsigned char mmcGetCIDInfo(MMC_CID_INFO *pCIDInfo)
//受信に成功
ucRet = 1;
}
}
//カードをNonActiveに
CARD_DISABLE
-------------------------------------------------------------------------
MMC/SDカードから送られてくるデータを全部受信しないと、その後の動作が不安定になるはずです。
しかしながら、『MMC対応カーネル Ver.1.25』は問題なく動作しています。
なぜ大丈夫かというと、前述の「CID受信について@」で、CIDデータ16バイトのところ20バイト受信していたためです。
余分な4バイトのうち、最初の2バイトが16ビットCRCの受信になっていた、というわけです。
(意図してそういうふうにしてあったのだとしたら、ごめんなさい)
そんなわけで、こちらも厳密にはこうかな、と思いました。
-------------------------------------------------------------------------
mmc_api.c - unsigned char mmcGetCIDInfo(MMC_CID_INFO *pCIDInfo)
◎変更前
//受信に成功
ucRet = 1;
}
}
//カードをNonActiveに
CARD_DISABLE
◎変更後
//受信に成功
ucRet = 1;
//CIDデータの最後に付いて来る
//16bit分のCRCをダミークロックを
//送って無視する
//16クロック分のダミー送信
mmcByteSend(0xFF);
mmcByteSend(0xFF);
}
}
//カードをNonActiveに
CARD_DISABLE
-------------------------------------------------------------------------
以上です。失礼いたしました。