SD.begin() вернул false — и начинается блуждание: люди первым делом пересобирают весь скетч, хотя скетч тут ни при чём в девяти случаях из десяти. У меня такой вечер однажды съел часа три: я перетыкал провода, менял библиотеки и уже грел мысль про сгоревший модуль, а виноват оказался дупон, который сидел в CS-пине и на вид держался, а по тесту мультиметром не звонился. Список причин того, почему карта не поднимается, у меня давно собран — он есть в уроке про диагностику begin и в уроке про молчащий модуль; а здесь то, чего в них нет — порядок, в котором причины проверять, чтобы уложиться в десять минут, а не в три часа.
Принцип протокола простой: от электрики к софту, от вероятного к редкому. Софт, кстати, почти никогда не виноват: SD-библиотека либо поднимается, либо молча возвращает false, и никакой правкой кода вы не почините плохой контакт в проводе питания. Каждый шаг протокола заканчивается либо вердиктом, либо переходом к следующему — и это не созерцание, а конкретные действия с мультиметром, второй картой и заменой проводов.
Десять шагов: от провода к модулю
Шаги 1-3 — питание и шина. Первым делом мультиметр на гнёзда модуля: между VCC и GND должно лежать честное напряжение, 5 В на модулях с стабилизатором или 3,3 В на голых переходниках; просадка под запись — отдельная история, её разбирал урок про просадки питания, но уже на этапе begin заметна просадка постоянная — от слабого USB-порта или тонкого кабеля. Шаг 2 — сверка CS: в begin(CS) передан тот пин, куда физически воткнут провод? На шилдах с Ethernet и переходниках CS бывает 4 вместо 10 — классика, о которой писал урок про общую шину. Шаг 3 — дупонты: замените все шесть проводов на заведомо короткие, до 15-20 сантиметров; SPI на пайке у меня поднимался и в метре, на макетке с дупонтами выше двадцати сантиметров — уже лотерея.
Шаги 4-7 — карта и формат. Шаг 4 — вторая карта: заведомо рабочая, маленькая, 2-8 ГБ; клоны с приписанным объёмом и свежие 64+ ГБ — отдельные истории, там и exFAT, и приписанный «2 ТБ» на восьми гигабайтах. Шаг 5 — формат FAT32 в компьютере, не быстрым форматированием, а полным; карта, отформатированная телефоном, приходила ко мне в exFAT чаще, чем в FAT32. Шаг 6 — очистка шины: вытащите другие SPI-устройства (Ethernet, дисплей) и проверьте begin в одиночестве; конфликт шины диагностируется потом, но на этом шаге его надо исключить. Шаг 7 — CardInfo из примеров библиотеки: он печатает тип карты и объём и отличает «карта жива, но формат не тот» от «карта не отвечает вообще».
Шаги 8-10 — софт и железо последнее. Шаг 8 — частота SPI: на ESP32 и длинных проводах begin поднимается на пониженной частоте, на Uno это редко, но проверка стоит две минуты. Шаг 9 — другой пин CS и другая макетная линия: контакт макетки между рядами иногда хуже провода. Шаг 10 — замена модуля: клоны с ширпотреба умирают молча, begin просто false. И в каждом шаге пусть вам помогает LED-код: короткая вспышка на каждый пройденный шаг, три длинных — на провал. Плату без монитора порта этот код выручает не хуже Serial.
#include <SPI.h>#include <SD.h> const int CS_PIN = 10;const int LED_PIN = 12; void blinkStep(int n) { // n коротких вспышек - номер шага for (int i = 0; i < n; i = i + 1) { digitalWrite(LED_PIN, HIGH); delay(80); digitalWrite(LED_PIN, LOW); delay(120); } delay(600); // пауза между шагами} void blinkFail() { // три длинных - провал begin for (int i = 0; i < 3; i = i + 1) { digitalWrite(LED_PIN, HIGH); delay(500); digitalWrite(LED_PIN, LOW); delay(200); }} void setup() { Serial.begin(9600); pinMode(LED_PIN, OUTPUT); blinkStep(1); // питание: 5 В на пин модуля Serial.print("VCC на модуле проверьте мультиметром: "); Serial.println("5 В (с стабилизатором) или 3.3 В (голый переходник)"); blinkStep(2); // CS: пин в begin = пин с проводом Serial.print("begin(SD_CS) должен получить "); Serial.println("тот же пин, куда воткнут провод CS"); blinkStep(3); Serial.println("провода: 6 дупонтов короче 20 см, GND общий с платой"); blinkStep(4); Serial.println("карта: вторая заведомо рабочая, 2-8 ГБ"); blinkStep(5); Serial.println("формат: полное форматирование FAT32, не exFAT"); blinkStep(6); Serial.println("шина: другие SPI-устройства вытащены"); if (!SD.begin(CS_PIN)) { blinkFail(); Serial.println("[вердикт] begin false: шаги 7-10 - CardInfo, частота, модуль"); while (true) delay(1000); } blinkStep(7); Serial.println("begin поднялся: карта отвечает на CS"); File f = SD.open("test.txt", FILE_WRITE); if (!f) { blinkFail(); Serial.println("[вердикт] begin ок, но запись не идёт: формат или карта"); while (true) delay(1000); } f.println("probe"); f.close(); blinkStep(8); Serial.println("запись прошла: карта и модуль живы"); blinkStep(9); File r = SD.open("test.txt"); if (r) { Serial.print("[чтение] "); while (r.available()) Serial.write(r.read()); Serial.println(); r.close(); } SD.remove("test.txt"); Serial.println("[вердикт] всё поднялось - вина была в шагах 1-6");} void loop() {}Модель честно повторяет то, что я делаю руками: LED отстукивает номер шага, вердикты раскладываются по шагам, и к шагу семь уже понятно, в какой половине — карта или шина. Клавиша N двигает протокол так же, как кнопка: на живой плате монитора порта может не быть, и именно поэтому LED-код стоит вшивать в любой диагностический скетч — три длинных вспышки видно с другого конца комнаты.
После того как begin поднялся, не спешите праздновать: шаг записи и шаг чтения из скетча выше — обязательная часть протокола. Я видел платы, где begin проходил, а первая запись зависала намертво — карта отвечала на инициализацию, но падала на записи секторов. Такие экземпляры под протокол попадают на шаге девять: запись есть, чтение не совпадает, карта в утиль. Это же место в протоколе закрывает споры «а вдруг библиотека кривая»: скетч выше — четыре строки поверх begin, дальше только железо.
| Симптом | Вероятный виновник | Шаг протокола | Проверка |
|---|---|---|---|
| begin false сразу, LED даже не мигает | питание: слабый USB, тонкий кабель | 1 | мультиметр на VCC модуля под нагрузкой |
| begin false, но с другой картой поднимается | карта: клон, износ, приписанный объём | 4 | вторая заведомо рабочая карта 2-8 ГБ |
| begin false на 64 ГБ карте | exFAT вместо FAT32 | 5 | полное форматирование FAT32 в компьютере |
| begin false в связке с Ethernet/дисплеем | конфликт CS или шины | 2, 6 | begin в одиночестве, потом возвращать устройства |
| begin ок, запись падает | карта жива на init, мертва на записи | 9 | запись пробы и чтение обратно |
Протокол сознательно заканчивается заменой модуля, а не паяльником: ширпотреб-переходники на 74LVC125 у меня умирали молча и без причины, и двадцать минут поисков вышли бы дороже нового модуля за сотню рублей. Если же после десятого шага вы уверены, что модуль жив, а begin всё равно false — вернитесь к шагу один с осциллографом или логическим анализатором: такое бывает на нестандартных разводках и в связке с нестандартными блоками питания, и там уже без прибора никак.
Для связки с ESP32 протокол тот же, но с двумя поправками: питание модуля — только 3,3 В, и levels уровень логики тоже 3,3 В (о границах писал урок про уровни); и частоту SPI стоит понизить в первую очередь, если провода длиннее двадцати сантиметров. Разводку пинов SPI и её варианты по платам я раскладывал в уроке про распиновку — держите её под рукой, чтобы шаг второй не превратился в угадывание.
- 1. С чего начинается протокол поиска отказа SD.begin?
- 2. begin(CS) получает 10, а провод CS воткнут в пин 4. Что произойдёт?
- 3. Какой шаг подтверждает, что модуль и карта живы целиком, а не только на инициализации?
- Порядок поиска — от электрики к софту: питание, CS, провода, карта, формат, шина, софт, модуль.
- Пин в begin(CS) обязан совпадать с физическим пином провода — десять секунд проверки, три часа экономии.
- Дупонты на макетке держат SPI до 20 см; длиннее — лотерея, пайка — другой разговор.
- CardInfo отличает «карта не отвечает» от «карта жива, формат не тот».
- LED-коды шагов выручают без монитора порта: короткая вспышка на шаг, три длинных — на провал.
Частые вопросы по теме урока
- С чего начинается протокол поиска отказа SD.begin?
- Порядок — от электрики к софту: без честного напряжения на VCC все остальные шаги бессмысленны. Библиотека стоит последней: скетч виноват в 9 из 10 отказов лишь косвенно. С проверки питания на модуле мультиметром
- begin(CS) получает 10, а провод CS воткнут в пин 4. Что произойдёт?
- Библиотека стучится в пин 10, карта слушает пин 4 — ответа нет, begin false. Классика шилдов с Ethernet, где CS карты равен 4. begin вернёт false, будто карты нет
- Какой шаг подтверждает, что модуль и карта живы целиком, а не только на инициализации?
- Бывают карты, отвечающие на инициализацию и падающие на записи секторов. Проба «записал — прочитал — совпало» закрывает вопрос целиком. Проба записи и чтение обратно