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

        -------------------------------------------------------------------------



以上です。失礼いたしました。