マイコンからSDカードへの書き込みについて

こんにちは。softmです

以前,タイマーの使い方を教えていただいたものですが,そちらの問題は

解決いたしましたので,新たに質問をさせていただきます。

これまではシリアル通信でデータをパソコンに送信していました。

それを,パソコンではなくSDカードに保存したい(可能であればCSVファイルで)のですが,やり方が全く分かりません。

ちなみにマイクロSDカードスロットDIP化キット(秋月電子:K-05488)を使用して書き込みを行うつもりです。

どなたかわかる方ご教授願います。

使用しているマイコンはRX65N,開発環境はCS+です。

  • softmさん、こんにちは。NoMaYです。

    今の私の理解は以下のような感じです。(これで合っていると思うのですけど、、、  間違ってるかも、、、  こっちの方かな、、、)

    (1) RXスマートコンフィグレータで以下の画面コピーのFITモジュールを組み込む(新しいバージョンがリリース済みかもです)
    (2) ソースを生成させる
    (3) ソースと一緒に生成されたドキュメントを読む
    (4) ドキュメントの指示に従ってデモプログラムをダウンロードする
    (5) デモプログラムのドキュメントとデモプログラムのソースを読む

    以下、RXスマートコンフィグレータの画面コピーです。(すみません、英語表示になってますが、気にしないで下さい。)




    [関連リンク]

    MMC/SDCの使いかた
    elm-chan.org/docs/mmc/mmc.html

    [関連リンク追加]

    MMCドライバでのエラーについて
    japan.renesasrulz.com/cafe_rene/f/forum18/5192/mmc/29363#29363

    あと、従来はSDカードの仕様が公開されていなかったので上記のような苦肉の策を採ったのですが、
    昨今、SD Simplified SpecificationというのがSD Associationから公開されまして、方針を変えました。
    SD Simplified Specificationに従ったソフト・情報であればルネサスから公開可能という判断しております。
    まずは、SDHI(SD Host Controller)を載せているRX65N等の製品用にSDHI制御用のSDカードドライバを公開しました。


  • 鈴木さん、こんにちは。Sugachanceです。

    解説ありがとうございます。

    そうでした!2GB制限がありましたね。

  • こんにちは。NoMaYです。

    デモプログラムをダウンロードしてビルドしてみました。(デモプログラムはRX72Mのものしかありませんのでビルドまでです。) 以下、主な手順の画面コピーです。(あーー、ごめんなさい、別スレッドでEtherのことをしていて、e2 studioで画面コピーをとってしまいました。すみません。トホホ、、、)








     

  • こんにちは、NAKAといます。

    SDをSPIモードでアクセスするのは、2GBまでの制限があると思います。

    SDカードをただのメモリとして使用するなら、SD(~2GB)でもSDHC(~32GB)でも制限はないです。規格によってアドレスへのアクセスが違うだけです、SDは書き込みのアドレスを直接指定しますが、SDHCは書き込むブロックを指定します。NAKAの印象はSDカードの中にもマイコンが入っていて、そのマイコンに対してSPI通信でコマンドを投げてやることで、書き込みや読出しができるものです。全ての規格に対応しようとすると、コマンドを投げてそのSDカードがどの規格かを判断し、制御を変える必要があります。

    大分前なので、細かいことはほとんど忘れちゃったけど、webとかインターフェースやトラ技とかSDカードのコマンドを調べながらやった記憶があります。

    FATはデバイスのRAM容量の関係で入れられませんでした。R78/I1E

    GR-SAKURA(RX63N)等にSDカードからRS232Cでパソコンに送信して、CSVにしてました。

    こんな感じで初期化して(SDHC(~32GB)のみ対応)

    /*******************************************************************************
    // 関数名 : init_MicroSDHC(void)
    // 動作 : SDカードの初期化(SDHC) 
    // 引数 : 戻り値: 最後のCMD1のリターン値
    //    0x00:正常終了         
    //    0x01:初期化中のまま終了       
    //    0xFF:ビジーのまま終了
    // 作成 : NAKA  17.05.29
    // ****************************************************************************/
    unsigned char init_MicroSDHC(void)
    {
     unsigned short i;
     unsigned short j;
     unsigned char error_code,res,f_res;
     unsigned char f_NG;
     
     __DI();         //割り込み 禁止☆070801

     error_code = 0xFF;
     f_NG = 0;
     CSI00_CS = 1;       //終了
     //(2)80クロックのダミークロック
     for(i=0; i<10; i++)
     {
      WriteSPI0(0xFF);  //80クロック送信(値は0xFF)
     }
     //(3)CSをLにしてCMD0(CRC付き)を発行
     CSI00_CS = 0;       //開始
        WriteSPI0(0x40);   //CMD0:リセット命令 SPIモードへ移行
        WriteSPI0(0x00);    //引数1
        WriteSPI0(0x00);    //引数2
        WriteSPI0(0x00);    //引数3
        WriteSPI0(0x00);    //引数4
        WriteSPI0(0x95);    //CRC7
     //(4)データラインにレスポンス(x01)
     //while(ReadSPI0()!=0x01);  //0x01待ち *要タイムアウト設定
     while(ReadSPI0()!=0x01)   //0x01待ち *要タイムアウト設定
     {
      j++;
      if(j >=6500)    //タイムアウト
      {
       j = 0;
       f_NG = 1;
       break;
      }
     }

     if(f_NG == 0)
     {
     //(5)CMD1を発行。レスポンス(0x01) *SDHCタイプのカードの場合はCMD8を発行。レスポンスが0x01か0x00ならSDHCの可能性あり、以下の処理が異なるので注意
     //(6)レスポンスが0x00になるまでCMD1を発行。初期化完了。
     f_res = 1;
     do{
      CSI00_CS = 1;   //同期を取る(以下3行)
      WriteSPI0(0xFF);
      CSI00_CS = 0;
      WriteSPI0(0x48);  //CMD8:初期化&状況確認(レスポンス0x01は初期化中、0x00は終了)
      WriteSPI0(0x00);   //引数1
         WriteSPI0(0x00);   //引数2
         WriteSPI0(0x01);   //引数3
         WriteSPI0(0xAA);   //引数4
         WriteSPI0(0x87);   //CRC7(実際にはSPIモードなので無視される)
      for(i=0; i<1000; i++) //レスポンスチェック(通常は数回でコマンドレスポンスが返る)
      {
       res = ReadSPI0();
       if (res != 0xFF) break; //レスポンス評価、ビジー(0xFF)検出ならリトライ
      }
      if(res == 0x01){f_res = 0;}
      if(res == 0x05){f_res = 0;}
     }while(f_res);  //*要タイムアウト設定

     do{
      CSI00_CS = 1;   //同期を取る(以下3行)
      WriteSPI0(0xFF);
      CSI00_CS = 0;   //【10】
      WriteSPI0(0x7A);  //CMD58:初期化&状況確認
      WriteSPI0(0x00);   //引数1
         WriteSPI0(0x00);   //引数2
         WriteSPI0(0x00);   //引数3
         WriteSPI0(0x00);   //引数4
         WriteSPI0(0xFD);   //CRC7(実際にはSPIモードなので無視される)
      for(i=0; i<1000; i++) //レスポンスチェック(通常は数回でコマンドレスポンスが返る)
      {
       res = ReadSPI0();
       if (res != 0xFF) break; //レスポンス評価、ビジー(0xFF)検出ならリトライ
      }
     }while(res != 0x01);  //*要タイムアウト設定

     res = ReadSPI0();    //res = 0x00?
     res = ReadSPI0();    //res = 0xFF?
     res = ReadSPI0();    //res = 0x80?
     res = ReadSPI0();    //res = 0x00?

     f_res = 1;
     do{
      CSI00_CS = 1;   //同期を取る(以下3行)
      WriteSPI0(0xFF);
      CSI00_CS = 0;   //【13】
      WriteSPI0(0x77);  //CMD55:初期化&状況確認
      WriteSPI0(0x00);   //引数1
         WriteSPI0(0x00);   //引数2
         WriteSPI0(0x00);   //引数3
         WriteSPI0(0x00);   //引数4
         WriteSPI0(0x65);   //CRC7(実際にはSPIモードなので無視される)
      for(i=0; i<1000; i++) //レスポンスチェック(通常は数回でコマンドレスポンスが返る)
      {
       res = ReadSPI0();
       if (res == 0x01) break; //レスポンス評価、ビジー(0xFF)検出ならリトライ
      }

      res = ReadSPI0();  //ダミーREADこれが必要!
      res = ReadSPI0();  //ダミーREADこれが必要!

      WriteSPI0(0x69);  //CMD41:初期化&状況確認
      WriteSPI0(0x40);   //引数1
         WriteSPI0(0xFF);   //引数2
         WriteSPI0(0x80);   //引数3
         WriteSPI0(0x00);   //引数4
         WriteSPI0(0x17);   //CRC7(実際にはSPIモードなので無視される)
      for(i=0; i<1000; i++) //レスポンスチェック(通常は数回でコマンドレスポンスが返る)
      {
       res = ReadSPI0();
       if(res == 0x00){f_res = 0;}
       if(res != 0xFF) break;
      }
     }while(f_res);  //*要タイムアウト設定


     do{
      CSI00_CS = 1;   //同期を取る(以下3行)
      WriteSPI0(0xFF);
      CSI00_CS = 0;   //【10】
      WriteSPI0(0x7A);  //CMD58:初期化&状況確認
      WriteSPI0(0x00);   //引数1
         WriteSPI0(0x00);   //引数2
         WriteSPI0(0x00);   //引数3
         WriteSPI0(0x00);   //引数4
         WriteSPI0(0xFD);   //CRC7(実際にはSPIモードなので無視される)
      for(i=0; i<1000; i++){ //レスポンスチェック(通常は数回でコマンドレスポンスが返る)
       res = ReadSPI0();
       if (res != 0xFF) break; //レスポンス評価、ビジー(0xFF)検出ならリトライ
      }
     }while(res != 0x00);  //*要タイムアウト設定

     res = ReadSPI0();    //res = 0xC0?
     res = ReadSPI0();    //res = 0xFF?
     res = ReadSPI0();    //res = 0x80?
     res = ReadSPI0();    //res = 0x00?

        //(8)通信速度再設定         ボーレート変更!!
     ST0 |= 0x0001;    //ch0を停止
     SOE0 &= ~0x0001;   //シリアル通信動作による出力禁止
     SDR00 = 0x0200;    //ボーレート分周(1/?)
            //153600bps=0xCE00
            //312500bps=0x6400
            //2500000bps=0x0600
            //★5000000bps=0x0200
     SOE0 |= 0x0001;    //シリアル通信動作による出力許可
     SS0 |= 0x0001;    //ch0を開始

     }
     else
     {
      res = 0xFF;
     }

        error_code = res;
     
     __EI();      //割り込み 許可☆070801
     
        return error_code;
    }

    こんな感じでブロック書き込みします。

    /****************************************************/
    /* MicroSD 1ブロック書込み       */
    /*  あらかじめd_SD_WR_BUF[]に書かれたデータを  */
    /* MicroSDに書き込む。        */
    /* 戻り値: 書き込みまで行った場合はデータレスポンスを返す。それ以外はコマンドレスポンスを返す  */
    /* 0xFF:コマンド発行中ビジーのまま終了    */
    /* 0x?5:データは受け入れられた      */
    /* 0x?B:CRCエラーで拒否された      */
    /* 0x?D:ライトエラー        */
    /****************************************************/
    unsigned char CMD24(long dataAddress)
    {
     unsigned char a1,a2,a3,a4;
     unsigned short i;
     unsigned char cmd24_res;

     //(1)ブロック数を4バイトの引数に変換
     a1 = (unsigned char)((dataAddress&0xFF000000)>>24);
     a2 = (unsigned char)((dataAddress&0x00FF0000)>>16);
     a3 = (unsigned char)((dataAddress&0x0000FF00)>>8);
     a4 = (unsigned char)(dataAddress&0x000000FF);
     
     __DI();         //割り込み 禁止☆070801

     //(2)CMD発行~レスポンス
     cmd24_res = CMD(24,a1,a2,a3,a4,0xFF); //CMD24発行、レスポンス取得
     if(cmd24_res != 0x00)     //レスポンスが0x00(エラーなし)以外だったら即終了。
     {
      WriteSPI0(0xFF);     //終了処理
         CSI00_CS = 1;      //終了
      return cmd24_res;
     }
     //(3)データトークンスタートバイト(0xFE)書き込み
     WriteSPI0(0xFE);
     //(4)データ書き込み
     for (i=0; i<512; i++)     //WRバッファの前半を書く
     {
      WriteSPI0(d_SD_WR_BUF[i]);   //データ書き込みxブロック長
     }

     //(5)CRC送信
     WriteSPI0(0x00);      //CRCを2バイト書き込み(SPIモードなので意味なし)
     WriteSPI0(0x00);

     //(6)データレスポンス受信
     cmd24_res = ReadSPI0();     //データレスポンス

     //(7)ビジー待ち

     for(i=0; i<10; i++){     //すぐにビジーが解除されない場合があるので多めに判定。呼び出し側で書き込み後すぐに読み込んでもデータが反映されない場合はココでビジーが解除されなかった可能性が高い。
      if(ReadSPI0() != 0x00) break;  //デフォルトは i<10000 だった!
     }

     //(8)終了処理
     WriteSPI0(0xFF);      //ダミークロック送信
        CSI00_CS = 1;       //終了
     
     __EI();         //割り込み 許可☆070801

     return cmd24_res;      //CMD27のレスポンス結果を返信
    }

  • NoMayさん,こんにちは。

    丁寧に1から教えてくださり,本当にありがとうございます。

    他の方もありがとうございます。

    まずは,デモプログラムの読み込みまでやっていきたいと思います。

  • こんにちは。NoMaYです。

    NAKAさんがFATファイルシステムを使わずSDカードにアクセスする話を書いていましたが、RXスマートコンフィグレータのデモプログラムにもそのようなものがありました。RX72Mのみです。以下、主な手順の画面コピーです。(すみません、この際ですので、今回もe2 studioの画面コピーにします。なお、前回の分も、CS+の画面コピーは後日とろうかと思います。)









     

  • こんにちは。NoMaYです。

    すみません、CS+と単体RXスマートコンフィグレータの組み合わせにはデモプログラムダウンロード機能が無かったことを理解しました。ごめんなさい、いろいろ考え直します。

    以下、単体RXスマートコンフィグレータの画面コピーです。



     

  • こんにちは。NoMaYです。

    CS+の場合は、スマートブラウザー経由でルネサスさんのウェブサイトをオープンしてデモプログラムをダウンロードすることになりそうですね。難点は、以下のスマートブラウザーの画面コピーのように、どれをダウンロードすれば良いのかとっさには分からないことでしょうか、、、




    以下、その他の手順の画面コピーです。注意点は、mtpjファイルではなくrcpcファイルをオープンすることかと思います。