M5Stack CoreS3でmicroSDが認識しないのでカード相性とSPIクロックを切り分けた
目次

M5Stack CoreS3にmicroSDカードを挿したら、工場出荷ファームの時点で「SD Card initialization failed!」と言われた。
PCでは普通に読めるカードなのにCoreS3では何をしてもダメで、最終的にカード相性とSPIクロックの2段構えの問題だと分かるまでの切り分けを記録しておく。
検証環境は以下の通り。
| 項目 | 内容 |
|---|---|
| 本体 | M5Stack CoreS3 Development Kit (K128) |
| チップ | ESP32-S3 (QFN56) rev v0.2、フラッシュ16MB |
| microSD | LAZOS 16GB(FAT32)/ LAZOS 32GB |
| 開発環境 | Windows 11 + arduino-cli 1.5.1 |
| コア/ライブラリ | esp32:esp32 3.3.10 / M5Unified 0.2.17 |
開封と最初のつまずき
アキバのマルツでCoreS3 Development Kitを買ってきた。

CoreS3のDevelopment KitはDIN BASEという台座付き構成で、DC 9〜24V入力・電源スイッチ・スピーカーが台座側に付いている。
microSDスロットは本体左側面のプッシュ式(押し込むとカチッとロック、ロック状態でさらに押すと出てくる)。

USBで電源を入れると、工場出荷ファーム(UserDemo)がハードウェア構成のマップを表示する。
ESP32-S3、16Mフラッシュ、8M PSRAM、2インチIPS液晶(ILI9342D 320x240)、microSDスロットの存在もここに描かれている。

このUserDemoにはSD-CARDメニューがあり、カードの中身を表示できる。
未挿入だと「Please insert SD card…」と出る。

ここに手持ちのLAZOS 32GBを挿すと、こうなった。

「SD Card initialization failed! Please try reinsert SD card…」。
言われた通り抜き差ししても変わらない。
この時点ではコードを1行も書いていない。買ってきたままの状態で挿しただけなので、原因はカードかハードの側にある。
CoreS3の公式スペックはmicroSD最大16GBなので、互換性を考えてスペックに収まるLAZOS 16GB(FAT32フォーマット済み、PCでは正常に読み書きできる)を後日買ってきた。
それでも同じ画面だった。
自前のコードで試す
原因の切り分けにはシリアルログが欲しいので、まずarduino-cliで開発環境を作った。
winget install --id ArduinoSA.CLI
arduino-cli core update-index
arduino-cli core install esp32:esp32
arduino-cli lib install M5Unified
CoreS3のボード定義はEspressif公式のesp32コアに入っている。
FQBNは esp32:esp32:m5stack_cores3。
arduino-cli compile --fqbn esp32:esp32:m5stack_cores3 .\sdtest
arduino-cli upload -p COM5 --fqbn esp32:esp32:m5stack_cores3 .\sdtest
CoreS3のmicroSDはSPI接続で、ピンは以下の通り。液晶とSPIバスを共有していて、CSだけ別に持っている。
| 信号 | GPIO |
|---|---|
| CS | 4 |
| SCK | 36 |
| MISO | 35 |
| MOSI | 37 |
最小のマウント確認コードはこうなる。
#include <M5Unified.h>
#include <SD.h>
void setup() {
auto cfg = M5.config();
M5.begin(cfg);
Serial.begin(115200);
delay(2000);
SPI.begin(36, 35, 37, 4);
if (!SD.begin(4, SPI, 25000000)) {
Serial.println("SD.begin() FAILED");
return;
}
Serial.printf("Size: %u MB\n", (uint32_t)(SD.cardSize() / 1024 / 1024));
}
void loop() { M5.update(); delay(100); }
結果は工場出荷ファームと同じで SD.begin() FAILED。

ここからクロックを疑って、25MHz→15MHz→4MHz→400kHzと段階的に落として全部試したが、LAZOS 16GBは全滅だった。
さらに2秒おきにSD.begin()をリトライし続けるループに変えて、動作中に抜き差しもしてみた。
111回目まで回しても一度もマウントされない。

- クロックを400kHzまで落としてもダメ
- 抜き差し・挿し直してもダメ
- でもPCのカードリーダーでは正常に読める
ここまでやってカード自体を疑い始めた。
LAZOS 32GBに交換したらマウントは通った
開封日に初期化失敗していたLAZOS 32GBに差し替えたところ、リトライループが即座に反応してマウントされた。
工場出荷デモでダメだったカードが、自作コードだとあっさり通る。
互換性を考えてあえてスペック内の16GBを買い足したのに、そっちが全滅で「スペック外」の32GBが動くというオチ。
マウントは通ったが、ファイル書き込みテストを足すと今度は書き込みで失敗した。

SD.open("/hello.txt", FILE_WRITE) がファイルハンドルを返さない。
マウントと容量読み取り(30000MB / Total 29985MB)は通っているので、読み出し系は25MHzで動くが書き込みは通らない、という状態。
そこで書き込みテストもクロックを落としながら再試行するようにした。
// 25MHzで開けなければ10MHz→4MHzで再マウントして書き込みを試す
const uint32_t freqs[] = {25000000, 10000000, 4000000};
for (uint32_t f : freqs) {
if (f != 25000000) {
SD.end();
delay(200);
if (!SD.begin(4, SPI, f)) continue;
}
File w = SD.open("/hello.txt", FILE_WRITE);
if (!w) continue;
w.println("hello from CoreS3");
w.close();
// 読み返して検証...
}
結果、10MHzで書き込み成功。

open(W) fail @25MHz
write OK @10MHz: hello from CoreS3
--- root files ---
[D] System Volume Information
hello.txt
ソフトリセット後に再マウントできなくなる
切り分けの途中でもう1つ別の挙動を踏んだ。
一度マウントに成功した後、プログラムの書き込みやシリアルモニタ切断でソフトリセット(ログ上は rst:0x15 (USB_UART_CHIP_RESET))がかかると、次の起動では同じカードなのにSD.begin()が失敗し続ける。
カードが直前のセッションの通信状態を引きずったままになるのが原因のようで、ソフト側からの回復も試したが、このカードでは効かなかった。
- CS無効のままダミークロックを8192クロック送る → 効果なし
- CS有効でクロックを送って読みかけデータを吐き出させ、CMD12(転送停止)を直接発行 → 効果なし
- USBケーブルを抜いて完全に電源を切る → 次の起動で1回目に即マウント
結局、電源断だけが確実な回復手段だった。
開発中はプログラムを書き込むたびにこの状態になるので、「書き込み→USB抜き差し」がワンセットになる。
切り分けの結果
| カード | PC | 工場出荷デモ | 自前コード(マウント) | 書き込み |
|---|---|---|---|---|
| LAZOS 16GB (FAT32) | ○ | ✕ | ✕(全クロック・抜き差しも) | - |
| LAZOS 32GB | - | ✕ | ○ | 25MHz ✕ / 10MHz ○ |
調べてみると、CoreS3でmicroSDが認識されずカードを変えたら解決したという事例は他にもあった。
M5Stack CoreS3 UIFlow2でmicroSDカードが認識しない原因がSDカード相性だった話では、ESP_ERR_INVALID_RESPONSEで初期化に失敗し続け、キオクシア製に交換して解決している。
CoreS3でSDカードを使うなら、認識しないときにフォーマットやコードを疑う前に、別メーカーのカードを1枚試すのが早い。
動いた後も、書き込みが必要な用途ならSPIクロックは10MHz程度に落としておいたほうが安全。