RX72N Envision Kit での開発(その4)SDCARD 編

RX72N Envision Kit の再販が始まったようだ・・・

チップワンストップ:
2020-06-04 17:31:31 Thursday:
※在庫8個だったけど、1日たったら、完売してた・・・、まだまだ潤沢に流通していないようだ・・

SD-CARD 操作と、関係ユーティリティの使い方

組み込みマイコンでは、SDカードのアクセスは必須な機能となっています。

ChaN さんによる FatFs ライブラリがオープンソースとして公開されており、非常に簡単に利用する事が出来ます。
※FatFs ライブラリは、常に進化しており、なるべく最新版を使う事が望まれます、自分のフレームワークでは、ff13c を利用しています。

SDカードにアクセスするには、簡易的な SPI モードと、SD モードがあります。

このサンプルでは、以下のように、各デバイスで、SDカードのアクセスを行います。

RX24T RX64M DIY RX64M GR-KAEDE RX65N RX72N
RSPI0 Soft SPI RSPI SDHI SDHI

RX64M から搭載(RX64M/Rx71M はオプション)された SDHI インターフェースを使った、SD モードのネィティブモードドライバーも利用可能です。
SD モードでは、4ビットバスを使った高速な転送が可能となっています。
※RX64M は SDHI はオプションになっており、自分が実験したデバイスは、「SDHI なし」なので、Soft-SPI で利用しています。

SDカードのアクセスでは、なるべく、簡単で柔軟性のある宣言で、実装が出来るように工夫してあり、簡単に扱う事が出来ます。

SDCARD_sample プロジェクト

インターフェースの宣言

RX24T

    typedef device::rspi_io<device::RSPI0> SDC_SPI;
    typedef device::PORT<device::PORT6, device::bitpos::B5> SDC_SELECT; ///< カード選択信号
    typedef device::PORT<device::PORT6, device::bitpos::B4, 0> SDC_POWER;   ///< カード電源制御
    typedef device::PORT<device::PORT6, device::bitpos::B3> SDC_DETECT; ///< カード検出
    typedef device::NULL_PORT SDC_WPRT;  ///< カード書き込み禁止ポート設定
    typedef fatfs::mmc_io<SDC_SPI, SDC_SELECT, SDC_POWER, SDC_DETECT, SDC_WPRT> SDC;
    SDC_SPI sdc_spi_;
    SDC     sdc_(sdc_spi_, 20'000'000);
  • RX24T では、RSPI0 を使います。
  • RSPI では、MISO、MOSI、SCLK の3つの信号を利用します。
  • 「カード選択信号」は、PORT6、B5 を使います。
  • 「カード電源制御」は、PORT6、B4 で、アクティブ Low の信号としています。
  • 「カード検出信号」は、PORT6、B3 を使います。
  • 「書き込み禁止信号」は、使わない為「NULL_PORT」を指定します。
  • 「fatfs::mmc_io」クラスは、SPI 制御の為のインターフェースクラスです。
  • 上記のように、RSPI0 の定義を、mmc_io にパラメータとして定義し、インスタンスをコンストラクターに渡します。
  • RSPI の上限のクロック速度を指定します。

RX64M / GR-KAEDE

  #ifdef GR_KAEDE
    typedef device::rspi_io<device::RSPI> SDC_SPI;
    typedef device::PORT<device::PORTC, device::bitpos::B4> SDC_SELECT; ///< カード選択信号
    typedef device::NULL_PORT  SDC_POWER;   ///< カード電源制御(常に電源ON)
    typedef device::PORT<device::PORTB, device::bitpos::B7> SDC_DETECT; ///< カード検出
    typedef device::NULL_PORT SDC_WPRT;  ///< カード書き込み禁止
  #else
    typedef device::PORT<device::PORTC, device::bitpos::B3> MISO;
    typedef device::PORT<device::PORT7, device::bitpos::B6> MOSI;
    typedef device::PORT<device::PORT7, device::bitpos::B7> SPCK;
    typedef device::spi_io2<MISO, MOSI, SPCK> SDC_SPI;  ///< Soft SPI 定義
    typedef device::PORT<device::PORTC, device::bitpos::B2> SDC_SELECT; ///< カード選択信号
    typedef device::PORT<device::PORT8, device::bitpos::B2, 0> SDC_POWER;   ///< カード電源制御
    typedef device::PORT<device::PORT8, device::bitpos::B1> SDC_DETECT; ///< カード検出
    typedef device::NULL_PORT SDC_WPRT;  ///< カード書き込み禁止
  #endif
    SDC_SPI sdc_spi_;
    typedef fatfs::mmc_io<SDC_SPI, SDC_SELECT, SDC_POWER, SDC_DETECT, SDC_WPRT> SDC;
    SDC     sdc_(sdc_spi_, 25'000'000);
  • DIY ボードでは、ソフト SPI の定義をしています。
  • GR-KAEDE では RSPI の定義をしています。
  • GR-KAEDE の RSPI/SD カードインターフェースは、E1 デバッガー端子と共有になっておりプルダウン抵抗があります。
  • SD カードの初期化時、プルアップが必要なので、対策する必要があります。
  • 対策方法は、main.cpp の説明を参照して下さい。
  • ソフト SPI では、クロックの生成など、全てソフトウェアーで行う為、自由度がありますが、速度は RSPI に比べてかなり遅いです。
  • MISO、MOSI、SPCK のポートを定義して、ソフト SPI クラス (spi_io2) として宣言します。
  • spi_io2 クラスは、SD カードの SPI 制御向けに特化したクラスとなっています。
  • 「カード選択信号」は、PORTC、B2 を使います。
  • 「カード電源制御」は、PORT8、B2 で、アクティブ Low の信号としています。
  • 「カード検出信号」は、PORT8、B1 を使います。
  • 「書き込み禁止信号」は、使わない為「NULL_PORT」を指定します。
  • 「fatfs::mmc_io」クラスは、SPI 制御の為のインターフェースクラスです。
  • 上記のように、Soft-SPI の定義を、mmc_io にパラメータとして定義し、インスタンスをコンストラクターに渡します。
  • ソフト SPI の上限のクロック速度を指定していますが、目安程度でしかありません。

RX65N Envision Kit

    typedef device::PORT<device::PORT6, device::bitpos::B4, 0> SDC_POWER;  ///< 「0」でON
    typedef device::NULL_PORT SDC_WPRT;  ///< カード書き込み禁止ポート設定
    typedef fatfs::sdhi_io<device::SDHI, SDC_POWER, SDC_WPRT, device::port_map::option::THIRD> SDC;
    SDC     sdc_;
  • SDHI を使う場合、ポートは決められた組み合わせの中から選択する必要があります。
  • SDHI が使うポートの詳細は、RX65x/port_map.hpp を参照して下さい、「候補3」です。
  • 「カード電源制御」は、PORT6、B4 で、アクティブ「Low」です。
  • 「書き込み禁止信号」は、使わない為「NULL_PORT」を指定します。
  • RX65N Envision Kit では、SDカードインターフェースは未実装となっています。
  • 電源制御は、専用 IC を使わず、Pチャネルの MOS-FET をスイッチとして流用している為、アクティブ「Low」となっています。
  • クロック速度は、現在の実装では、30MHz となっており、ハードコードになっています。

RX72N Envision Kit

    typedef device::PORT<device::PORT4, device::bitpos::B2> SDC_POWER;
    typedef device::NULL_PORT SDC_WPRT;  ///< カード書き込み禁止ポート設定
    typedef fatfs::sdhi_io<device::SDHI, SDC_POWER, SDC_WPRT, device::port_map::option::THIRD> SDC;
    SDC     sdc_;
  • SDHI を使う場合、ポートは決められた組み合わせの中から選択する必要があります。
  • SDHI が使うポートの詳細は、RX72N/port_map.hpp を参照して下さい、「候補3」です。
  • 「カード電源制御」は、PORT4、B2 で、アクティブ「High」です。
  • 「書き込み禁止信号」は、使わない為「NULL_PORT」を指定します。
  • クロック速度は、現在の実装では、30MHz となっており、ハードコードになっています。
  • 実験では、60MHz での動作も確認しましたが、RX65N Envision Kit では、不安定だったので、余裕を持って 30MHz としています。
  • クロック信号における、インピーダンスのマッチングを行えば、60MHz でも安定して利用可能と思います。

FatFs とのインターフェース定義

  • FatFs は、初期化(マウント)、セクター単位の読出し、書き込みなどの API を用意するだけで良く、以下のように、API を宣言します。
  • FatFs は C のプログラムなので、「extern "C"」で、C から呼べるようにしておきます。
  • ファイル書き込み時、タイムスタンプで使う「時間」が必要です、このフレームワークでは、GMT を使っています。
extern "C" {

    DSTATUS disk_initialize(BYTE drv) {
        return sdc_.disk_initialize(drv);
    }

    DSTATUS disk_status(BYTE drv) {
        return sdc_.disk_status(drv);
    }

    DRESULT disk_read(BYTE drv, BYTE* buff, DWORD sector, UINT count) {
        return sdc_.disk_read(drv, buff, sector, count);
    }

    DRESULT disk_write(BYTE drv, const BYTE* buff, DWORD sector, UINT count) {
        return sdc_.disk_write(drv, buff, sector, count);
    }

    DRESULT disk_ioctl(BYTE drv, BYTE ctrl, void* buff) {
        return sdc_.disk_ioctl(drv, ctrl, buff);
    }

    DWORD get_fattime(void) {
        time_t t = 0;
#if defined( ENABLE_RTC) || defined(ENABLE_I2C_RTC)
        rtc_.get_time(t);
#else
        t = utils::str::make_time(nullptr, nullptr);
#endif
        return utils::str::get_fattime(t);
    }
}

初期化、及び、SDカード挿入の監視

  • このサンプルでは、1/100 秒のタイマーを使って、ループを行い、その中で、SD カードの監視を行います。
  • ループ間隔は、スイッチの状態をサンプリングしており、チャタリングを除去するフィルターとして働きます。
    while(1) {
        cmt_.at_task().sync_100hz();

        sdc_.service();

        command_();
    }

簡単なシェル(SDカード操作)

  • 1/100 のループ中、シリアル入力も監視しており、バッファリングしています。
  • これを利用して簡単なコマンド操作として機能するようにしています。
    -「help」と打つと簡単なヘルプが表示されます。
  • 簡易的な実装で、厳密な入力のチェックを行っていません。
コマンド オプション 機能
ls -l ディレクトリのリスティング
cd カレントディレクトリの移動
pwd カレントディレクトリパスの表示
free SDカードの全容量、空き容量の表示
Start SD-CARD Access sample for 'RX72N' 240[MHz]
# ls
SoftShut.wad    TFALL.WAD       TIMER.WAD       TOFF.WAD        TON.WAD
VSOFF.WAD       VSON.WAD        TEST.BIN        System Volume Information/
inv_roms/       inv_wavs/       Dragon_Quest2_fix.nes
DragonQuest_J_fix.nes           Galaga_J.nes    GALAXIAN.NES    GRADIUS.NES
kfont16.bin     NoImage.jpg     Pac-Man.nes     Solstice_J.nes
Super_mario_brothers.nes        XEVIOUS.NES     HRC_logo_s.bmp
Super Mario USA (Japan).nes     Audios/
/ # cd Audios
/Audios # ls
AlbumArtSmall.jpg               Folder.jpg      Thumbs.db       AlfredBrendel/
CarpentersBest/ Chopin_Recital/ Denim/          DRACULA/        GeorgeMichael/
Glenn Gould/    JAnime/         KNOCK ON MY DOOR/               Make It Big/
Michael Jackson/                Mornin' After/  NarcisoYepes/
Over The Top_ Original Motion Picture Soundtrack/               PRIMO/
Rachmaninov Symphonies No_1-3 L_Maazel&Berliner Philharmoniker/
Rachmaninov_ Piano Concertos #2 & 3/            SoundTrack/
The Best Of Mission_ Impossible/
THE ORIGINAL~Songs for Scheherazade~/           Vienna Recital/
うる星やつら ジュークボックス/  のだめカンタービレ Best 100/
もってけ! セーラーふく/         イーハトーヴ交響曲/
コンピレーション/               スペシャル/     ドラゴンクエスト/
ボーカロイド/   ラフマニノフ_ ピアノ協奏曲 #1 & #2/
ラフマニノフ_ ピアノ協奏曲 #3 & #4/
ラフマニノフ_ ピアノ協奏曲第1番 & 第2番/        リシッツァ/
ルパン三世’71 ME TRACKS/           今井美樹/       仲道郁代/
倉木麻衣/       國府田マリ子/   坂本真綾/       堀江由衣/       太田貴子/
奥慶一/         宇多田ヒカル/   宮里久美/       工藤静香/       庄司紗矢香/
林原めぐみ/     椎名へきる/     相川七瀬/       西山ギター課題/ 金月真美/
/Audios # cd ..
/ # ls -l
     16384 May  4 2018 06:08  SoftShut.wad
     16384 May  4 2018 06:08  TFALL.WAD
     16384 May  4 2018 06:08  TIMER.WAD
     16384 May  4 2018 06:08  TOFF.WAD
     16384 May  4 2018 06:08  TON.WAD
     16384 May  4 2018 06:08  VSOFF.WAD
     16384 May  4 2018 06:08  VSON.WAD
   1048576 Jan  1 1980 09:00  TEST.BIN
           Nov  1 2017 07:25 /System Volume Information
           Mar 10 2019 07:37 /inv_roms
           Mar 10 2019 07:37 /inv_wavs
    131088 Feb 16 2017 03:00  Dragon_Quest2_fix.nes
     65552 Feb 16 2017 02:56  DragonQuest_J_fix.nes
     24592 Jun 21 2000 07:56  Galaga_J.nes
     40976 Feb 28 1997 17:26  GALAXIAN.NES
     65680 Apr 26 1997 01:53  GRADIUS.NES
    249824 Jun 25 2018 18:14  kfont16.bin
     49785 Nov 14 2018 06:58  NoImage.jpg
     24592 Dec 24 1996 20:32  Pac-Man.nes
    131088 Sep 20 1999 10:59  Solstice_J.nes
     40976 Jul  8 2018 23:59  Super_mario_brothers.nes
     40976 Jul 17 1997 23:31  XEVIOUS.NES
     86072 Sep  5 2018 19:57  HRC_logo_s.bmp
    262160 Jul  1 2018 12:29  Super Mario USA (Japan).nes
           Nov 18 2019 01:56 /Audios
Total 25 files
/ # free
1335360/15629312 [KB] (8.5%)
/ # write test.bin
Write: 'test.bin'
Write Open:  280 [ms]
Write: 395 KBytes/Sec
Write Close: 4 [ms]
/ # read test.bin
Read: 'test.bin'
Read Open:  1 [ms]
Read: 1171 KBytes/Sec
Read Close: 0 [ms]
/ # help
    ls [-l] [file]      list current directory (-l: long)
    pwd                 current directory path
    cd [file]           change current directory
    free                list disk space
    write filename      test for write
    read filename       test for read
    time [yyyy/mm/dd hh:mm[:ss]]   set date/time
  • write コマンドは、書き込み速度を計測します。
  • read コマンドは、読み込み速度を計測します。
  • time コマンドは、RTC への時間設定を行います。
  • RX65N Envision Kit/RX72N Envision Kit では、RTC は無効になっており利用出来ません。
  • サンプルには、I2C 接続の RTC を扱う場合を実装してあります。

Makefile での FatFs 設定

  • Makefile で、「-DFAT_FS -DFAT_FS_NUM=2」を設定し、コンパイル時に渡す必要があります。
    -「FAT_FS_NUM」は、POSIX の open 関数で同時にオープン出来るファイル数です。
  • 大きくすると、管理領域としてメモリを消費します。

まとめ

  • C++ のテンプレートクラスは、強力で、C 言語では実現できないような柔軟性を提供しています。
  • SDカードのインターフェースは、それなりに複雑ですが、サンプルでは、RSPI、ソフトSPI、SDHI に対応する方法を提示しています。
  • 異なるハードウェアーでも、同じように扱う工夫は、まさにオブジェクト指向的な概念によるものです。
  • この例からも、C++ が組み込みマイコンのプログラムに向いている事が判ると思います。
  • 問題なのは、C++ を学ぶのは、実際にはそれ程簡単では無く、ある程度の修練が必要です。
  • C++ は C 言語から派生したので、C 言語を自由に扱えるレベルの人でも、判ったつもりになっている人が多いようです。
  • 「C++ は C 言語とは全く違うプログラム言語である」ここから始める必要があると思います。
  • ただ、学ぶハードルは、それなりに低くなっており、色々な勉強会や、講習会に参加する事もできます。
  • 学ぶには、ある程度の時間や、修練は必要でしょうが、そのメリットは十分にあるものと思います。