ESP32 ( ESP-WROOM-32 ) で micro SDHC メモリカードを使う場合の注意点

記事公開日:2017年4月20日
最終修正日:2017年5月24日

スポンサーリンク

こんばんは。

今回は、ESP32 ( ESP-WROOM-32 ) で micro SDHC  メモリカードを使う場合の注意点を自分なりにまとめてみました。

Twitter上 で micro SDHC カードが読み込めないというツイートを見て、いろいろ調べたり、実験したりしてみました。
以下、Arduino IDE でコンパイルした場合で説明します。

私はアマチュアなので、SD カード規格にはあまり詳しくありません。
ですから、誤っていた場合はコメント欄等でご連絡いただけると助かります。

SD ( SDHC ) カード規格について

SDHC ( SD ) カード規格についてはいろいろ調べてみたのですが、詳細な技術仕様書はなかなか拝見できませんでした。
それは、どうやら、SDアソシエーションという団体に入会しないと、詳細な技術仕様書が手に入らないようです。
その件については、以下のページを参照してください。

https://www.sdcard.org/jp/developers/overview/

要するに、企業がその団体に会費を払って入会しているみたいですね。
技術仕様書には恐らく、接続ピンをプルアップするべきなどと書いてあるのでしょうか・・・。

ザッと私なりに調べたところによると、SPIモードのような低速のデータ通信はライセンスが不要っぽく、HD動画などの高速大容量通信には、ライセンス料を払わないといけないみたいです。

そもそも、マイコンの SD , SDHC ホストコントローラーを使って、SDカードスロット付きデバイスを販売する場合は、ライセンス料が必要みたいです。
販売に関しては、SPIモードも対象かどうかは良く分かりません。
MMC カードの場合はライセンス不要という情報もありました。
このライセンス料はかなり高額のようで、独りメーカーで販売しようとするにはハードルが高すぎますね。

MMCカードよりも SD カードの方が高速で、SPIモードのクロック最高周波数の理論値は 24MHz 程度らしいです。
でも、最近の micro SDHC カードでは、それ以上でも読み込める場合があります。
SDアソシエーション会員になれば、更に高速の通信が使えるみたいです。

現在の電子工作では、HD動画を再生したいということも有るかも知れないので、SPIモードでは限界を感じることもありますね。
高速化時代の電子工作家にとっては、これはなかなか厳しい現実ですね。

使用したデバイス等

では、実際に micro SDHC カードの読み書き実験に使ったものを紹介します。

ESP32-DevKitC

日本の電波法をクリアした技適認証済み Wi-Fi & Bluetooth マイコン ESP-WROOM-32 ( ESP32 )を搭載した開発ボードです。
現在、秋月電子通商さんや Amazon.co.jp で販売されています。

SparkFun micro SDカードスロット

micro SDカードスロットは、何も付属品が無いシンプルな物を使いました。

ブレッドボード SAD-101 ( サンハヤト )

サンハヤトさんのこのブレッドボードは使用できるピン列が多く、複数連結できるのでお勧めです。

その他、ジャンパーワイヤー等

動作確認済み micro SDHC カード

以下の micro SDHC カードは動作確認しました。
SD カードや SDXC カードは試していません。
他の種類や他メーカーのカードでは動作しない場合がありますのでご注意ください。

因みに、常識かと思いますが、静電気で一発で壊れますので、素手で触るときには十分ご注意ください。

Transcend micro SDHC カード 32GB Class10 UHS-I対応

Twitter の@robo8080さんによれば、これの 16GB は動作しなかったという情報がありました。
私は16GB は持ち合わせていないので、試しに 32GB を購入して確かめてみたら、特に問題無く動作しました。
これにはデータ転送中のエラーを修正する EEC 機能というものがあるらしく、それが影響するのかとも思いましたが、今のところ問題無しです。

Transcend microSDHCカード 8GB Class10

TOSHIBA microSDHCカード 8GB Class10 UHS-I対応

これは、SDカードアダプターがありませんのでご注意ください。

TDK microSDHCカード 4GB Class4 SDアダプター付き

SDHC カードの初期化(フォーマット)

現在販売している micro SDHC カードは殆ど FAT32 で初期化(フォーマット)されていると思いますので、そのままパソコンでファイル転送できると思います。
初期化されていない場合は、以下の記事を参照してください。

micro SD 、micro SDHC カードの初期化(フォーマット)方法

ただし、SDカードやSDXC カードはフォーマット方法が異なります。
SDカードは最大2GB までで、FAT16 または FAT12 です。
SDXC カードは32GB以上の大容量カードで、exFAT というシステムです。
当方では、SDHC カードしか試していませんので、ご了承ください。

カードの種類による容量の違いや、ファイルシステムの違いについては以下のサイトをご参照ください。

https://www.sdcard.org/jp/developers/overview/capacity/index.html

ESP32-DevKitC との接続

いろいろと調べた結果、SDカード規格によると、データ線は10kΩ前後でプルアップしなければいけないそうです。
ただ、その中でも MOSI ( Master Out Slave In )ラインはプルアップ抵抗が必須という情報がありました。

確かに、4GB の micro SDHC カードで、スピードクラスが class 4 の場合はプルアップしなくても読み込めましたが、8GB以上の class 10 のmicro SDHC カードは読み込めませんでした。
ということで、最低 MOSI ラインにはプルアップが必要だということが分かりました。

その他の、SLCK、MISO、CS ラインに必要かどうかはハッキリしたことは分かりません。
ただ、秋月電子通商さんで販売している以下の製品
http://akizukidenshi.com/catalog/g/gK-05818/
でも、電源ライン以外は全てプルアップしていますので、おそらく必要なのかと思われます。
MISO と MOSI だけで良いという情報もありました。

結局のところ、SDカード仕様書がネットで見当たらないので分かりませんが、エラーになった場合はデータ線全てをプルアップしてみてはいかがでしょうか。
私の環境の場合はMISO だけでOKでした。

ESP32_microSDHC_01

サンプルスケッチの入力

では、まず、Arduino core for the ESP32 をインストールしていない方は以下のページを参照してください。

Arduino core for the ESP32 のインストール方法

また、重要なのは、今まで Arduino core for the ESP32 を使っていた方は、最新版をインストールし直してみて下さい。
古いライブラリでは micro SDHC カードを読み込まない場合があります

では、実際に Arduino IDE にスケッチを書きこんで、読み書きできるか試してみます。
サンプルスケッチで確認しても良いのですが、ここでは、同時に開くことが出来るファイル数を確認するためのスケッチを入力してみたいと思います。

#include <SD.h>

const uint8_t cs_SD = 5;

const char* fname1 ="/test1.txt";
const char* fname2 ="/test2.txt";
const char* fname3 ="/test3.txt";
const char* fname4 ="/test4.txt";
const char* fname5 ="/test5.txt";
const char* fname6 ="/test6.txt";
const char* fname7 ="/test7.txt";
const char* fname8 ="/test8.txt";
const char* fname9 ="/test9.txt";
const char* fname10 ="/test10.txt";

File f1, f2, f3, f4, f5, f6, f7, f8, f9, f10;

void setup() {
  Serial.begin(115200);
  SD.begin(cs_SD, SPI, 24000000, "/sd");

  Serial.println("\r\n--------正常な書き込み(ファイルは4つまで同時オープン)");
  f1 = SD.open(fname1, FILE_WRITE);
  f2 = SD.open(fname2, FILE_WRITE);
  f3 = SD.open(fname3, FILE_WRITE);
  f4 = SD.open(fname4, FILE_WRITE);
  serial_print_Fwrite(f1, 1, "このファイルはテスト1\r\n");
  serial_print_Fwrite(f2, 2, "このファイルはテスト2\r\n");
  serial_print_Fwrite(f3, 3, "このファイルはテスト3\r\n");
  serial_print_Fwrite(f4, 4, "このファイルはテスト4\r\n");
  f1.close(); f2.close(); f3.close(); f4.close();
  delay(1);
  
  f5 = SD.open(fname5, FILE_WRITE);
  f6 = SD.open(fname6, FILE_WRITE);
  f7 = SD.open(fname7, FILE_WRITE);
  f8 = SD.open(fname8, FILE_WRITE);
  serial_print_Fwrite(f5, 5, "このファイルはテスト5\r\n");
  serial_print_Fwrite(f6, 6, "このファイルはテスト6\r\n");
  serial_print_Fwrite(f7, 7, "このファイルはテスト7\r\n");
  serial_print_Fwrite(f8, 8, "このファイルはテスト8\r\n");
  f5.close(); f6.close(); f7.close(); f8.close();
  delay(1);
  
  f9 = SD.open(fname9, FILE_WRITE);
  f10 = SD.open(fname10, FILE_WRITE);
  serial_print_Fwrite(f9, 9, "このファイルはテスト9\r\n");
  serial_print_Fwrite(f10, 10, "このファイルはテスト10\r\n");
  f9.close();  f10.close();
  Serial.println("\r\n--------10ファイル読み込み同時オープン");
  
   Serial.println("");
  f1 = SD.open(fname1, FILE_READ);
  f2 = SD.open(fname2, FILE_READ);
  f3 = SD.open(fname3, FILE_READ);
  f4 = SD.open(fname4, FILE_READ);
  f5 = SD.open(fname5, FILE_READ);
  f6 = SD.open(fname6, FILE_READ);
  f7 = SD.open(fname7, FILE_READ);
  f8 = SD.open(fname8, FILE_READ);
  f9 = SD.open(fname9, FILE_READ);
  f10 = SD.open(fname10, FILE_READ);

  serial_print_Fread(f1, 1);
  serial_print_Fread(f2, 2);
  serial_print_Fread(f3, 3);
  serial_print_Fread(f4, 4);
  serial_print_Fread(f5, 5);
  serial_print_Fread(f6, 6);
  serial_print_Fread(f7, 7);
  serial_print_Fread(f8, 8);
  serial_print_Fread(f9, 9);
  serial_print_Fread(f10, 10);

  f1.close(); f2.close(); f3.close(); f4.close();  f5.close();
  f6.close(); f7.close(); f8.close(); f9.close();  f10.close();
  
  Serial.println("\r\n---------ファイルを4つ毎に読み込む");
  f1 = SD.open(fname1, FILE_READ);
  f2 = SD.open(fname2, FILE_READ);
  f3 = SD.open(fname3, FILE_READ);
  f4 = SD.open(fname4, FILE_READ);
  serial_print_Fread(f1, 1);
  serial_print_Fread(f2, 2);
  serial_print_Fread(f3, 3);
  serial_print_Fread(f4, 4);  
  f1.close(); f2.close(); f3.close(); f4.close();
  delay(1);
  
  f5 = SD.open(fname5, FILE_READ);
  f6 = SD.open(fname6, FILE_READ);
  f7 = SD.open(fname7, FILE_READ);
  f8 = SD.open(fname8, FILE_READ);
  serial_print_Fread(f5, 5);
  serial_print_Fread(f6, 6);
  serial_print_Fread(f7, 7);
  serial_print_Fread(f8, 8);
  f5.close(); f6.close(); f7.close(); f8.close();
  delay(1);

  f9 = SD.open(fname9, FILE_READ);
  f10 = SD.open(fname10, FILE_READ);  
  serial_print_Fread(f9, 9);
  serial_print_Fread(f10, 10);
  f9.close(); f10.close();
/*  
  Serial.println("\r\n------------ファイル削除");
  Delete_File(fname1);
  Delete_File(fname2);
  Delete_File(fname3);
  Delete_File(fname4);
  Delete_File(fname5);
  Delete_File(fname6);
  Delete_File(fname7);
  Delete_File(fname8);
  Delete_File(fname9);
  Delete_File(fname10);
*/ 
}

void serial_print_Fwrite(File ff, byte num, const char *message){
  if(ff.print(message)){
    Serial.printf("f%d Message wrote. Good!\r\n", num);
  }else{
    Serial.printf("f%d write failed\r\n", num);
  }
}

void serial_print_Fread(File ff, byte num){
  size_t len = ff.size();
  uint8_t buf[256];
  
  if (ff.read(buf, len)) {
    Serial.printf("f%d File found OK!!\r\n", num);
    for(int i=0; i<len; i++){
      Serial.write(buf[i]);
    }
  }else{
    Serial.printf("f%d File not found\r\n", num);
  }
}

void Delete_File(const char *fname){
  if(SD.remove(fname)){
      Serial.printf("%s File deleted\r\n", fname);
  } else {
      Serial.printf("%s Delete failed\r\n", fname);
  }
}

void loop() {
}

【解説】

◆1行目:
Arduino core for the ESP32 標準の SD ライブラリをインクルードします。

◆3行目:
micro SDHC カードの CS ( Chip Select )ピンを定義します。
GPIO #5 に接続しています。

◆5-14行:
micro SDHC カードに出力するファイル名を定義します。
ルートに書き込む場合は必ずスラッシュを入れてください。

◆16行:
ファイルハンドル名を定義

◆20行:
単なる、SD.begin(); でも良いのですが、その場合、周波数は1MHz で固定されてしまいます。
上で述べたように、SDカードのSPIモード通信の最大周波数を24MHz と変更する場合にはこうします。
CSピンは、”SS” としても良いです。
“SS” とした場合は、CSピンは自動的に GPIO #5 にアサインされます。

◆23-49行:
まず、最初に micro SDHC カードにファイルを書き込まなければいけないので、正常に書き込みできる方法にします。
Arduino core for the ESP32 ライブラリを使った場合、同時に開けるファイル数は4つまででしたので、この様に4つ書き込んだ後は必ずクローズしておきます。
クローズしないと次のファイルを開けません。

27-30行では、自作した関数121-127行で定義しています。
要するに、ファイル書き込めたかどうかをシリアルモニターに出力するものです。

◆53-76行:
実験のために、10個のファイルを同時に開いて読み込んでみます。
結果は後述します。

◆79-105行:
正常にファイルを読み込むためにはこのように記述します。
要するに、ファイルは4つまでしか同時に開けません。
書込みも同様です。

◆106-118行:
ファイルを削除したい場合は、このコメントを解除してください。

◆121-127行:
micro SDHC にファイルを書き込めたかどうかをシリアルモニターに出力するものです。

◆129-141行:
256バイトまでのファイルを読み込む関数です。
Arduino IDE 1.8.2 からUTF-8コードの日本語文字列をシリアルモニターに直接出力することができるようになりました。

◆143-149行:
micro SDHC カード内の指定ファイルを削除する関数です。

同時に開けるファイル数のチェック

では、スケッチをコンパイル書き込み実行させてみてください。

すると、シリアルモニターには以下のように表示されると思います。
因みに、シリアルモニターの転送レートは 115200 bps にしておいてください。

ESP32_microSDHC_02ESP32_microSDHC_03

いかがでしょうか。

私は自作ライブラリ等で、micro SDHC カードからファイルを複数同時に開くことがあるのですが、4つまでしか開けないことを知らずに、永遠とエラーに悩まされていたことがありました。
こうすると、Arduino core for the ESP32 標準ライブラリでは、同時に4つまでしか開けないことが分かりますね。
要注意です。
これについては、おそらく SD.h ライブラリを修正すれば開ける数は変えられると思いますが、あくまで標準使用ということで、そこは手を付けないでおきます。

因みに、SD.begin の周波数を 40MHz にしても、上記の動作確認済みカードの場合は読み込めました。
ただ、これは動作保証外だと思われます。

現在の Arduino core for the ESP32 では、ESP32 のCPU周波数が最大80MHz ですので、理論値では、SPI周波数は40MHz までクロックを出力できます。
しかし、いずれにしても安全動作はその4分の1周の20 MHz を最大周波数としておいた方が良いような気がします。
(自作ライブラリでは 40MHz としていますが・・・)
あとは、個人の判断でいろいろと試してみて下さい。

まとめ

まとめると、こんな感じになるでしょうか。

◆micro SDHC カードには相性がある。

◆ESP32 ( ESP-WROOM-32 )でmicro SDHC カードを使う場合には、MISO ピンは必ずプルアップしておく。
エラーがある場合はその他のデータ線もプルアップしておく。

◆SPIモードの周波数は最大20MHz を目安とした方が良さそう。

◆Arduino core for the ESP32 の SD.h ライブラリでは、同時に開けるファイル数は4つまで。

以上です。
何か間違い等ありましたら、コメント等でご連絡いただけると助かります。

早く Arduino core for the ESP32 がアップデートされて、240MHz まで使えるようになってほしいものです。
(実は、初めからCPUは 240MHz モードだったようです。失礼しました。)

では、今回はここまでです。
ではまた・・・。

mgo-tec電子工作 関連コンテンツ ( 広告含む )

スポンサーリンク

Amazon.co.jp 当ブログのおすすめ








投稿者:

mgo-tec

Arduino, ESP8266, ESP-WROOM-02 等を使って、主にスマホと連携した電子工作やプログラミング記事を書いてます。ライブラリも作ったりしてます。趣味、独学でやってますので、動作保証はしません。 電子回路やプログラミングの専門家ではありません。 畑違いの仕事をしてます。 でも、少しだけ電気の知識が必要な仕事なので、電気工事士や工事担任者等の資格は持ってます。

コメントを残す

メールアドレスが公開されることはありません。

*画像の文字を入力してください。(スパム防止の為)