SD カード

SPI接続

サンプルスケッチがArduino IDEのスケッチの例ー>SDー>SD_Testに有ります。各CPUには各信号にデフォルトが有ります。

SPI Pin NameESP8266ESP32ESP32‑S2ESP32‑S3ESP32‑C3ESP32‑C6ESP32‑H2
CS (SS)GPIO15GPIO5GPIO34GPIO10GPIO7GPIO18GPIO0
DI (MOSI)GPIO13GPIO23GPIO35GPIO11GPIO6GPIO19GPIO25
DO (MISO)GPIO12GPIO19GPIO37GPIO13GPIO5GPIO20GPIO11
SCK (SCLK)GPIO14GPIO18GPIO36GPIO12GPIO4GPIO21GPIO10

デフォルト通りに配線し下記のスケッチを実行すればSDカードへの読み書きが出来ます。

sd.ino

#include "FS.h"
#include "SD.h"
#include "SPI.h"

void setup() {
  File file;
  String str;
  
    Serial.begin(115200);
    delay(1000);

    if (!SD.begin()) {
      Serial.println("Card Mount Failed");
      return;
    }

    file = SD.open("/test.txt",FILE_WRITE);
    file.println("test 123");
    file.clos();
  
    file = SD.open("/test.txt",FILE_READ);
    str = file.readStringUntil('\n');
    Serial.println(str);
}

void loop() {}

これを実行すればSDカードに”test.txt”といるファイル(内部は””test 123″)が出来、シリアルモニタに”test 123″と表示されます。

SPI用の信号ピンは任意に指定出来ます(デフォルト以外でもSPIを使える)。ピンの指定は SPI.begin()に引数を渡して行います。前回のスケッチの if (!SD.begin()) { をコメントアウトして以下の様に行います。

     Serial.begin(115200);
    delay(1000);

    SPI.begin(sck, miso, mosi, cs);
    
//    if (!SD.begin()) {
    if (!SD.begin(cs)) {
      Serial.println("Card Mount Failed");
      return;
    }

  • SPI.begin(sck, miso, mosi, cs);
    • この関数でSPIで使用するピンを指定出来る。
    • 各引数はSPIの信号線
  • SD.begin(cs);
    • CSピン(チップセレクト)をこの関数で設定出来る

SD_MMC接続

ESP32とESP32S3はSD_MMC接続を使ってSDカードとアクセス出来ます。信号線が4と1本の2方式が有り、信号線1本の方式でもSPIの2倍の速度で通信出来る様です。

下記はSPI信号とSD_MMC信号の対応表です。市販のSPI接続のSDカードソケットには通常接続端子にCS,DI,DO,CLK,Vs,GNDの6信号が出ています。MMC(1-Line)の接続はこれらの信号線で配線可能ですが、4−Line方式は端子に出ている信号では足らず新たに線を2本引き出す必要が有ります。新たに引き出すのは大変なので1−Line方式がお薦めです。

 SD -SPI  MMC (1-Line)  MMC(4-Line) 
CSRESD3
DI(MISO)CMDCMD
DO(MOSI)D0D0
CLKCLKCLK
VsVsVs
GNDGNDGND
D1
D2

各信号ですが、ESP32は固定(下記参照)。ESP32S3は任意に指定出来ます。

 MMC(1-Line)  ESP32(GPIO) 
CMD15
CLK14
D0

ESP32のGPIO2,15はコード書き込み、実行時に注意が必要は端子です。GPIOポート一覧(ESP32) 特にGPIO2はコード書き込み時はLowにする必要が有りますが、SD_MMCではこれをHighにしないといけません。SD_MMC libraryでは書き込み前後でスイッチ等でHigh/Lowを切り替える事を推奨しています。

また、各信号線は10KΩ位でPullupする必要が有ります。以下は1−Line方式の各CPUでの接続例

SD_MMCのサンプルプログラムは スケッチ例ー>SD_MMCー>SDMMC_Testに有ります。これを各CPUに合わせて書き換えてみます。

ESP32の場合

信号線が固定なので、指定通り配線して下記のスケッチを実行すればSPIと同じ動作をします。

SPIの時との違いは

  • 12行: GPIO2をHighに設定。
  • SD.begin()がSD_MMC.begin(“/sdcard”, true)に変更
    • 最初の引数”/sdcard”はmountpointを示している様です。良くわからないのですが、何か文字列を指定すればOK
    • 次の引数は、1または4−Line方式の選択。trueで1-Line、falseで4-Line方式となります。
  • その他、SD.xxの箇所をSD_MMC.xxに変更

上記の配線(ESP32の回路)で試したのですが、GPIO2をスイッチで切り替えなくても動作しました。

sd_mmc.ino

#include "FS.h"
#include "SD_MMC.h"
#define mmc_D0  2

void setup() {
  File file;
  String str;
  
    Serial.begin(115200);
    delay(1000);

    pinMode(mmc_D0, INPUT_PULLUP);
    if (!SD_MMC.begin("/sdcard", true)) {
      Serial.println("Card Mount Failed");
      return;
    }

    file = SD_MMC.open("/test.txt",FILE_WRITE);
    file.println("test 123");
    file.clos();
  
    file = SD_MMC.open("/test.txt",FILE_READ);
    str = file.readStringUntil('\n');
    Serial.println(str);
}

void loop() {}

ESP32S3の場合

こちらは信号線を指定する必要が有ります。回路は上記のサンプルの回路を使用しています。関数 SD_MMC.setPins(mmc_CLK, mmc_CMD, mmc_D0);で信号線を指定している以外はESP32と同じです。

sd_mmc_s3.ino

#include "FS.h"
#include "SD_MMC.h"
#define mmc_D0   16
#define mmc_CLK  17
#define mmc_CMD  18

void setup() {
  File file;
  String str;
  
    Serial.begin(115200);
    delay(1000);

    pinMode(mmc_D0, INPUT_PULLUP);
    SD_MMC.setPins(mmc_CLK, mmc_CMD, mmc_D0);
    if (!SD_MMC.begin("/sdcard", true)) {
      Serial.println("Card Mount Failed");
      return;
    }

    file = SD_MMC.open("/test.txt",FILE_WRITE);
    file.println("test 123");
    file.clos();
  
    file = SD_MMC.open("/test.txt",FILE_READ);
    str = file.readStringUntil('\n');
    Serial.println(str);
}

void loop() {}

<ESP32, ESP32S3 ともに、pinMode(mmc_D0, INPUT_PULLUP); が無くても動作する様でしたが念の為に入れています>

使用した感想

  • 1−Line方式でも確かにSPIより速い
    • 速度が2倍かどうかははっきりと言えませんが速いことは確かです。
    • 使用する信号が1本少なく転送が速いのでこの方式を使うメリットは有ります。
  • 信号線が長いとノイズが乗リ易い
    • SPIでもそうでしたが、信号線が長いとノイズが乗り易い様です。
    • SPIと同等(20CM目安)かそれより短くする方が良いと思います。

<<Before

Next>>