Логгер для водозабора на даче я собирал за вечер, а карту к нему выбирал минуту: взял в магазине самую дешёвую на 64 ГБ — «с запасом, вдруг логов много». Модуль засветился, скетч из первого урока про логирование залился, Serial напечатал «SD initialization failed» — и всё, стена. Я полвечера переставлял провода, менял питание, подозревал модуль и даже припаял заново контакт MISO. Карта была исправная: телефон читал её без вопросов. Виноват оказался формат — exFAT, в котором SDXC-карта приезжает из коробки, а библиотека SD его не понимает.
Полгода назад та же история была с картой на 2 ГБ — только там всё завелось с первого раза. Разница не в качестве карт и не в моей сноровке: разница в разметке. Старые маленькие карты продают в FAT16 или FAT32, новые большие — в exFAT, и для Arduino Uno это ровно граница между «работает» и «вечер насмарку».
Здесь разберём, что такое файловая система FAT и зачем она карте, чем FAT16 отличается от FAT32, почему карта на 64 ГБ — худший выбор для логгера, и как разметить карту, чтобы она завелась с первой попытки. В симуляторе в конце прогоним проверку карт по объёму — тем же правилом, которым я теперь пользуюсь в магазине.
Что такое FAT и почему Arduino понимает только её
FAT — file allocation table, таблица размещения файлов. Разметка родом с дискет восьмидесятых, и именно она — причина живучести: простая структура, которую может переварить даже двухкилобайтная программа. Карта физически разбита на сектора по 512 байт, а сектора собираются в кластеры — минимальные порции, которыми файловая система выдаёт место файлу. Файл — это цепочка кластеров, и таблица FAT хранит эту цепочку: здесь начало, следующий — там, конец — тут. Копий таблицы две: основная и запасная на случай сбоя питания посреди записи.
Для Arduino это означает две вещи. Первая: библиотека SD умеет читать и писать именно эту структуру — FAT16 на маленьких картах и FAT32 на картах от 2 до 32 ГБ. Вторая: кластер — мельчайшая единица выдачи места, поэтому даже файл из одной строки занимает его целиком. Сколько именно — зависит от объёма карты, и это в таблице ниже.
| Система | Типы карт | Раздел до | Кластер (типично) | Библиотека SD на Uno |
|---|---|---|---|---|
| FAT16 | SD, до 2 ГБ | 2 ГБ | 2-32 КБ | да |
| FAT32 | SDHC, 2-32 ГБ | 32 ГБ | 4-32 КБ | да |
| exFAT | SDXC, от 32 ГБ | 2 ТБ и выше | 128 КБ и выше | нет |
| NTFS | любая | не важно | не важно | нет |
Почему exFAT не читается, если карта живая и провода целые? exFAT — разметка для больших носителей: другая структура таблиц, кластеры от 128 КБ, расчёт на терабайты. Библиотека SD, встроенная в Arduino IDE, выросла из старой версии сторонней библиотеки SdFat, и поддержка exFAT туда никогда не входила. Симптом всегда одинаковый: SD.begin() возвращает false, а вы мучаете провода. Дорогой путь наверх существует: свежая библиотека SdFat из менеджера библиотек (ставится через урок про библиотеки в IDE) понимает exFAT — но у неё другой API, и код из этого раздела придётся переписывать. Мой путь дешевле: я держу пул старых карт на 4-16 ГБ, оставшихся от фотоаппаратов.
Вторая ловушка прячется в Windows. Для карт больше 32 ГБ родное окно форматирования не предлагает FAT32 вообще — только exFAT и NTFS. Это не значит, что FAT32 на такую карту физически не влезает: сторонние утилиты вроде Rufus или GUI Format размечают её спокойно. Но для логгера на Uno в этом нет смысла: 32 ГБ — это сотни миллионов строк текста, и переплачивать за объём, который вы никогда не выберете, странно. Я беру карты на 2-16 ГБ — и place-боюсь за лишнее место в последний раз.
Кластеры: сколько места съедает одна строка лога
Вернёмся к кластерам с числами. Стандартная разметка Windows: карта на 8 ГБ в FAT32 получает кластеры по 8 КБ, карта на 16-32 ГБ — по 16 КБ. Строка моего лога — около 12 байт. Она занимает один кластер целиком: на карте 32 ГБ это 16 КБ на каждые 12 байт данных, тысяча лишних раз. Пока у вас один длинный файл лога, беды нет: строки дописываются в кластеры подряд, и впустую пропадает только хвост последнего. Беда начинается, когда файлов становится много: лог на каждый день, лог на каждый запуск скетча — и на каждый файл в среднем один недозаполненный кластер в конце.
Прикинем на цифрах: лог раз в минуту, новый файл каждые сутки, строка 12 байт. За год — 365 файлов, данные съедят примерно 2,2 МБ, а хвосты недозаполненных кластеров по 8 КБ — ещё 2,9 МБ. Потеря заметная, но не смертельная. А вот заводить по файлу на каждый перезапуск скетча с датой в имени я перестал после того, как карта на 8 ГБ кончилась за месяц от одних хвостов.
Класс скорости — отдельное честное слово. Шина SPI на Uno в реальности перекачивает сотни килобайт в секунду, поэтому Class 4 хватает за глаза, и Class 10 или UHS-III через модуль за 150 рублей никакого выигрыша не дадут. Скорость упирается в провода и питание: короткие перемычки и стабильные 5 вольт важнее любого класса — про просадки питания у меня отдельный разбор в уроке про общий провод и ошибки макетки.
#include <SPI.h>#include <SD.h> const int chipSelect = 10; void setup() { Serial.begin(9600); Serial.print("Проверка карты... "); if (!SD.begin(chipSelect)) { Serial.println("нет ответа. Формат (нужен FAT16/FAT32), питание или провода."); while (true) { } } Serial.println("карта отвечает, файловая система смонтирована"); if (SD.exists("probe.txt")) { SD.remove("probe.txt"); // чтобы тест был честным } File f = SD.open("probe.txt", FILE_WRITE); if (!f) { Serial.println("Файл не открылся: защита от записи или карта заполнена"); while (true) { } } f.println("probe"); f.close(); File check = SD.open("probe.txt", FILE_READ); if (check) { Serial.print("Читаем обратно, байт: "); Serial.println(check.size()); // 7 - значит запись дошла до карты check.close(); } SD.remove("probe.txt");} void loop() { }Смысл скетча — не в печатах, а в порядке вопросов. Сначала SD.begin() отвечает «жива ли карта вообще»: при exFAT он падает здесь, и дальше можно не идти. Потом запись и обязательный close, о котором целиком следующий-следующий урок, и чтение обратно с проверкой size(): если записано 7 байт, а читается 7 байт — карта не только форматом, но и физикой записи исправна. Такой тест я прогоняю на каждой карте перед установкой в устройство, которое поедет на дачу: там разбирать корпус и подключать монитор будет некогда. Ещё быстрее проверка без Arduino: вставьте карту в кардридер, откройте свойства диска — Windows напишет FAT32 или exFAT прямо там. Это десять секунд и часто весь диагноз: половина моих «сломанных модулей» оказывалась картой из телефона, пересобранной в exFAT. Старые фотоаппаратные карты на 2 ГБ — честный FAT16, они заводятся всегда, и именно их я советую новичкам для первых опытов: меньше соблазна накупить гигабайтов, которые Uno всё равно не выберет.
Что делать с исправной картой дальше — материал урока про режимы открытия File: там FILE_READ, FILE_WRITE и честная перезапись. Если карта уже крутится в работающем устройстве, посмотрите, как оформить её содержимое в CSV-лог с шапкой и чтением конфига — формат карты от этого не зависит, а пользы от лога вдвое больше. Теперь симулятор. Настоящую карту памяти он не подключает, поэтому проверка карт эмулируется печатью в Serial: каждому объёму печатается пара формат и вердикт ok=0 или ok=1. Логика та же, по которой вы будете выбирать карту в магазине: до 32 ГБ — FAT32, берём; больше — exFAT, оставляем на телефоне.
- 1. Что вернёт SD.begin(), если карта размечена в exFAT?
- 2. Самый большой раздел FAT32, который создаёт родное окно форматирования Windows?
- 3. Сколько места на карте 32 ГБ (FAT32) займёт строка лога в 12 байт в собственном файле?
- 4. Нужна FAT32 на карте 64 ГБ, а Windows не даёт. Что делать?
- 5. Какой класс скорости карты нужен для модуля microSD на Uno?
- SD.h понимает только FAT16 и FAT32; exFAT, в котором приезжают все SDXC-карты от 32 ГБ, — гарантированный «SD initialization failed»
- Windows не предлагает FAT32 для карт больше 32 ГБ; для логгера берите карту 2-16 ГБ и не платите за объём, который не выберете
- Кластер — минимальная порция места: строка 12 байт занимает 8-16 КБ; много маленьких файлов = карта кончается от хвостов
- Класс скорости выше 4 на Uno ничего не добавляет: сотни КБ/с по SPI — потолок модуля
- Форматируйте на компьютере, полный формат; «внутренняя память» в телефоне зашифрует карту под этот телефон
- Перед установкой в устройство прогоняйте скетч-диагностику: begin, запись, close, чтение обратно
Частые вопросы по теме урока
- Что вернёт SD.begin(), если карта размечена в exFAT?
- exFAT — другая структура таблиц и кластеры от 128 КБ; встроенная SD.h выросла из старой версии SdFat без поддержки exFAT, поэтому begin() падает. false — библиотека SD структуру exFAT не понимает
- Самый большой раздел FAT32, который создаёт родное окно форматирования Windows?
- Для карт больше 32 ГБ Windows предлагает только exFAT и NTFS. FAT32 на больший объём ставят сторонние утилиты вроде Rufus, но логгеру это не нужно. 32 ГБ
- Сколько места на карте 32 ГБ (FAT32) займёт строка лога в 12 байт в собственном файле?
- Кластер — минимальная порция выдачи места. На карте 16-32 ГБ в FAT32 кластер 16 КБ, и даже файл из одной строки займёт его целиком. весь кластер — 16 КБ
- Нужна FAT32 на карте 64 ГБ, а Windows не даёт. Что делать?
- FAT32 технически влезает, просто Windows прячет опцию. Сторонние утилиты размечают. Но для Arduino разумнее взять карту 2-16 ГБ. Взять стороннюю утилиту: Rufus или GUI Format
- Какой класс скорости карты нужен для модуля microSD на Uno?
- SPI на Uno перекачивает сотни килобайт в секунду — Class 4 покрывает с запасом. Узкие места логгера: провода, питание и формат карты. Class 4 достаточно: ограничение в шине SPI и модуле