Подключаем SD карту памяти к STM32 по SPI. Подключение sd карты к микроконтроллеру Работа с sd картой подключение к микроконтроллеру

Мы выводили картинку на дисплей с sd карточки, но в ней были упущены некоторые моменты, первый - подключение самой карточки, второй - была рассмотрена лишь часть функций библиотеки Petit FatFs , давайте остановимся на этих моментах подробнее.

Общение с карточкой возможно по одному из двух интерфейсов, SPI или SD .



Надо сказать, что SD интерфейс может работать в однобитном и четырёхбитном режимах.

Схема подключения карточки по SPI стандартная и выглядит следующим образом, не используемые выводы карточки нужно с помощью резистора 10К подтянуть к питанию.


Но в любительских конструкциях зачастую пренебрегают подтягивающими резисторами, упрощая схему подключения.

Надо отметить, что при подключении по SPI карточка очень требовательна к напряжению питания и небольшая просадка питающего напряжения приводит к неработоспособности карточки, это проверено на личном опыте, по поводу SD интерфейса сказать нечего, ещё не пробовал. Это всё писал к тому, что по питанию обязательно ставить конденсаторы . Что касается дросселя, он должен быть рассчитан на ток до 100мА, но ставить его необязательно.

На схемах, изображённых выше видно, что для работы карточке необходимо 3.3 вольта, соответственно, в линиях передачи данных напряжение не должно выходить за диапазон 0 – 3.3 вольт и тут возникает вопрос, что делать если МК питается от 5 вольт?
Ответ прост, надо согласовать линии передачи данных, а сделать это можно с помощью обычного резистивного делителя.


На схеме видно, что линию MISO согласовывать не надо так, как по этой линии данные передаются от карточки к МК .
На самом деле, мало кто подключает карточку напрямую к МК, гораздо удобнее подключить к МК разъём для карточки или купить шилд с разъемом и всей необходимой обвязкой.

С подключением разобрались, давайте теперь рассмотрим как пользоваться библиотекой Petit FatFs , которая предназначена для 8-битных микроконтроллеров с малым размером памяти.

Библиотека состоит из 5 файлов:
integer.h - заголовочный файл в котором описаны основные типы данных.

diskio.h - заголовочный файл в котором объявлены прототипы низкоуровневых функций для работы с диском и статусные коды, которые они возвращают.

diskio.c - в этом файле должны быть реализованы низкоуровневые функции, изначально там "заглушки".

pffсonf.h - конфигурационный файл.

pff.h - заголовочный файл в котором объявлены прототипы функций взаимодействия с файловой системой диска.

pff.c - файл содержит реализации функций для взаимодействия с файловой системой диска.

Видно, что для того чтобы библиотека заработала необходимо реализовать низкоуровневые функции. Но если речь идет о AVR или PIC, для них сайте можно скачать пример работы с библиотекой, в котором есть файл mmc , в нем уже реализованы низкоуровневые функции. Также необходимо задать конфигурацию библиотеки в файле pff.h и написать функции необходимые для работы SPI.

Функции Petit FatFs.

FRESULT pf_mount (FATFS*) - функция монтирует/демонтирует диск. Эту функцию необходимо вызывать до начала работы с диском, если вызвать функцию с нулевым указателем диск демонтируется. Функция может быть вызвана в любой момент времени.

Параметры
FATFS* fs - указатель на объект типа FATFS, описание этой структуры можно посмотреть в файле pff.h. Нам надо всего лишь объявить переменную такого типа.

Возвращаемые значения:
FR_OK (0)
FR_NOT_READY - устройство не может быть инициализировано
FR_DISK_ERR - возникла ошибка во время чтения с диска
FR_NO_FILESYSTEM - на диске нет правильного раздела FAT

FATFS fs;//объявляем объект типа FATFS //монтируем диск if (pf_mount(&fs) == FR_OK) { //диск смонтирован, работаем с ним //демонтируем диск pf_mount(NULL); } else { //не удалось смонтировать диск }

FRESULT pf_open (const char* path) - функция открывает существующий файл. После того как файл открыт с ним можно работать, то есть читать из него и записывать в него. С открытым файлом можно работать до тех пор, пока не будет открыт другой файл. Функция может быть вызвана в любой момент времени.

Параметры
const char* path - указатель на строку, указывающую путь к файлу. Путь надо указывать полностью относительно корневой директории, разделяя директории слэшем.

Возвращаемые значения:
FR_OK (0) - возвращается в случае успешного выполнения функции
FR_NO_FILE - файл не найден
FR_DISK_ERR - ошибка диска
FR_NOT_ENABLED - диск не был смонтирован

FATFS fs;//объявляем объект типа FATFS //монтируем диск if (pf_mount(&fs) == FR_OK) { //открываем файл лежащий в корневой директории if(pf_open("hello.txt") == FR_OK) { //делаем что-то } //открываем файл лежащий в папке new if(pf_open("new/hello.txt") == FR_OK) { //делаем что-то } //демонтируем диск pf_mount(NULL); } else { //не удалось смонтировать диск }

FRESULT pf_read(void* buff, WORD btr, WORD* br) - функция читает указанное количество байт из файла и сохраняет их в буфер. Если количество прочитанных байт меньше чем указано, значит был достигнут конец файла.
#define _USE_READ 1

Параметры:
void* buff - указатель на буфер, в котором сохраняются прочитанные данные
WORD btr - количество байт, которые нужно прочитать
WORD* br - указатель на переменную, в которой хранится количество прочитанных байт.

Возвращаемые значения:
FR_OK (0) - возвращается в случае успешного выполнения функции
FR_DISK_ERR - ошибка диска
FR_NOT_OPENED - файл не был открыт
FR_NOT_ENABLED - диск не был смонтирован

FATFS fs;//объявляем объект типа FATFS BYTE buff;//буфер для чтения файла WORD br; //счетчик прочитанных байт //монтируем диск if (pf_mount(&fs) == FR_OK) { //открываем файл лежащий в корневой директории if(pf_open("hello.txt") == FR_OK) { //читаем из него 10 байт pf_read(buff, 10, &br); if(br != 10) { //если br не равно 10 //значит мы достигли конца файла } } }

FRESULT pf_write(const void* buff, WORD btw, WORD* bw) - функция позволяет записывать данные в открытый файл. Для того чтобы функция работала в файле pffconf.h надо записать
#define _USE_WRITE 1

Параметры:
void* buff - указатель на буфер, который хотим записать, нулевое значение финализирует запись
WORD btw - количество байт, которые хотим записать
WORD* bw - указатель на переменную, хранящий количество байт, которые удалось записать. Анализируя, эту переменную можно узнать был ли достигнут конец файла.

Возвращаемые значения:
FR_OK (0) - возвращается в случае успешного выполнения функции
FR_DISK_ERR - ошибка диска
FR_NOT_OPENED - файл не был открыт
FR_NOT_ENABLED - диск не был смонтирован

Из-за того, что библиотека рассчитана на микроконтроллеры с малым объемом памяти, эта функция имеет ряд ограничений:

  • нельзя создавать новые файлы, а записывать можно только в существующие
  • нельзя увеличивать размер файла
  • нельзя обновить временную метку
  • операцию записи можно начать/остановить только на границе сектора
  • файловый атрибут "только для чтения" не может запретить запись

Для того чтобы понять предпоследний пункт, надо знать, что память карточки разбита на блоки(сектора) по 512 байт и запись можно начать только с начала сектора . Таким образом если мы хотим записать 1000 байт, то первый сектор запишется полностью, а во второй запишется только 488 байт, а оставшиеся 24 байта заполнятся нулями.

Для записи в открытый файл надо выполнить следующие действия:

  • установить указатель на границу сектора, если установить не на границу, то указатель будет округлен до нижней границы сектора
  • вызвать функцию записи нужное количество раз
  • финализировать запись, вызвав функцию с нулевым указателем

Для того, чтобы привести пример работы функции записи необходимо рассмотреть ещё одну функцию.

FRESULT pf_lseek(DWORD offset) - устанавливает указатель чтения/записи в открытом файле. Устанавливать указатель можно абсолютным или относительным смещением, для абсолютного смещения необходимо передать в функцию число
pf_lseek(5000);
для относительного, передать значение указателя на текущую позицию fs.fptr и величину смещения
pf_lseek(fs.fptr + 3000);
Для того чтобы функция работала в файле pffconf.h надо записать
#define _USE_LSEEK 1

Параметры:
DWORD offset - количество байт, на которые нужно сместить указатель.

Возвращаемые значения:
FR_OK (0) - возвращается в случае успешного выполнения функции
FR_DISK_ERR - ошибка диска
FR_NOT_OPENED - файл не был открыт

Записать данные в файл можно следующим образом.
FATFS fs;//объявляем объект типа FATFS BYTE buff;//буфер для чтения файла WORD br; //счетчик прочитанных байт //монтируем диск if (pf_mount(&fs) == FR_OK) { //открываем файл лежащий в корневой директории if(pf_open("hello.txt") == FR_OK) { //устанавливаем указатель на первый сектор pf_lseek(0); //записываем pf_write(buff, 10, &br); //финализируем запись pf_write(0, 0, &br); } }

Также оставляю тут кусок реально работающего кода, в котором используются все выше описанные функции.
#define F_CPU 8000000UL #define buff_size 10 #include #include #include "diskio.h" #include "pff.h" #include "spi.h" FATFS fs;//объявляем объект типа FATFS BYTE read_buff;//буфер для чтения файла BYTE write_buff = "hello word";////буфер для записи в файл UINT br; //счетчик прочитанных байт int main(void) { //монтируем диск if (pf_mount(&fs) == FR_OK) { //открываем файл лежащий в папке new if(pf_open("new/hello.txt") == FR_OK) { //устанавливаем указатель записи pf_lseek(0); //записываем pf_write(write_buff, buff_size, &br); //финализируем запись pf_write(0, 0, &br); //устанавливаем указатель чтения pf_lseek(0); //читаем то, что записали pf_read(read_buff, buff_size, &br); if(br != buff_size) { //если br не равно buff_size //значит мы достигли конца файла } } //демонтируем диск pf_mount(NULL); } while(1) { } }

FRESULT pf_opendir(DIR* dp, const char * path) - функция открывает существующую директорию и создает указатель на объект типа DIR, который будет использоваться для получения списка файлов открытой директории.
Для того чтобы функция работала в файле pffconf.h надо записать
#define _USE_DIR 1

Параметры:
DIR *dp - указатель на переменную типа DIR.

const char * path - указатель на строку, которая содержит путь к директории, директории разделяются слэшем

Возвращаемые значения:
FR_OK (0) - возвращается в случае успешного выполнения функции
FR_NO_PATH - не удалось найти путь
FR_NOT_READY - не удалось инициализировать диск
FR_DISK_ERR - ошибка диска
FR_NOT_ENABLED - диск не был смонтирован

//объявляем переменные FATFS fs; DIR dir; //монтируем диск pf_mount(&fs); //открываем директорию pf_opendir(&dir, "MY_FOLDER");

FRESULT pf_readdir(DIR* dp, FILINFO* fno) - функцию позволяет прочитать содержимое директории. Для этого нужно открыть директорию с помощью функции pf_opendir() и вызывать pf_readdir(). Каждый раз при вызове функция будет возвращать название объекта(папки/файла) лежащего в указанной директории. Когда она пройдется по всем объектам, вернет нулевую строку в элементе массива fno.fname.
Для того чтобы функция работала в файле pffconf.h надо записать
#define _USE_DIR 1

Параметры:
DIR *dp - указатель на переменную типа DIR, которая должна быть предварительно объявлена

FILINFO *fno - указатель на переменную типа FILINFO, которая должна быть предварительно объявлена.

Возвращаемые значения:
FR_OK - успешное завершение функции
FR_DISK_ERR - ошибка диска
FR_NOT_OPENED - не открыта директория

FATFS fs; FRESULT res; FILINFO fno; DIR dir; //монтируем диск pf_mount(&fs); //открываем директорию res = pf_opendir(&dir, MY_FOLDER); //читаем содержимое директории for(;;){ res = pf_readdir(&dir, &fno); //проверяем не возникло ли ошибок при чтении // и есть ли еще файлы в указанной директории if ((res != FR_OK) || (fno.fname == 0)){ break; } //выводим удобным способом fno.fname usart_sendStr(fno.name); usart_sendStr(/r); }

Ну и напоследок оставлю тут рабочий проект

Скачал исходник.
Вывалились ошибки:
stm32 nok1100 disp.axf: Error: L6218E: Undefined symbol USART_Cmd (referred from main.o).
stm32 nok1100 disp.axf: Error: L6218E: Undefined symbol USART_GetFlagStatus (referred from main.o).
stm32 nok1100 disp.axf: Error: L6218E: Undefined symbol USART_Init (referred from main.o).
stm32 nok1100 disp.axf: Error: L6218E: Undefined symbol USART_ReceiveData (referred from main.o).
stm32 nok1100 disp.axf: Error: L6218E: Undefined symbol USART_SendData (referred from main.o).

Добавил в проект библиотеку для работы с USART — скомпилилось (неплохо было бы все же об этом упомянуть в статье, а?), но карта не инициализируется. Пробовал менять местами выводы MISO и MOSI — результат нулевой…

В проекте использую Standard Peripheral Library + заметно упоминание в тексте и коде об UART’е, думал это само собой влечет использование USART библиотеки. Используемые библиотеки из SPL перечислил. Чуть позже думаю выложить проект целиком.
Есть ли диалог по UART? Что за карта? Она живая? Пробовали ли другие карты?

Ситуация — человек, ни разу ДО того не сталкивавшийся с STM32, находит в интернете Ваши статьи, начинает их читать. Ставит необходимый софт и читает Ваши статьи, последовательно одну за другой, попутно компилируя примеры и проверяя работоспособность на плате STM32VL Discovery (как это у Вас в первой статье сказано). В первом примере все разжевано и разложено по полочкам — какие файлы библиотек куда положить, как структуру проекта оформить, какие опции в свойствах проекта включить/выключить. Все понятно, все прекрасно. Статья для новичков. В статье про подключение SD-карт — полная противоположность, как в той песне — «догадайся, мол, сама…». Мало того — на схеме подключения карты указаны пины процессора, хотя по идее должны быть указаны пины разъемов платы STM32VL Discovery (коли уж повествование началось на ее базе). Думаю, что в статьях должна прослеживаться некая преемственность, раз уж начали опираться с первой статьи на STM32VL Discovery — на ее базе и остальное повествование продолжайте. Так будет намного проще для читающих Ваши статьи.

По УАРТу данные в терминалку падают, в обратную не пробовал.

В процессе написания ответа взял другую карту — не инитится. Поменял местами выводы MISO и MOSI на разъеме дискавери — заработало. Так что в схемке ошибочка наблюдается. Кстати, вот тут http://mycontroller.ru/stm32-sd-card-podklyuchenie/ схема подключения правильная. Подключение карты к плате STM32VL Discovery получается таким: карта пин 1 — PA4, карта пин 2 — PA7, карта пин 5 — PA5, карта пин 7 — PA6. Заработала одна старая карточка (16 Мб) и новая (2 Гб). Старая карточка 8 Мб (раритет, однако 😉) от видеокамеры JVC инициализироваться не захотела.

Пожелание: если не затруднит, описывайте подробнее добавления/изменения в проекте и т.п.. Опытным товарищам это можно и не читать, а неопытным будет ясно и не будут возникать всякие глупые вопросы. 🙂

ЗЫ. Блоки данных пишутся/читаются на/с карты. Спасибо за статью!

Там идет специальная обучающая серия и она пронумерована, вот в ней пытаюсь максимально разжевать. Обычные же статьи могу быть, как обзорные/поверхностные, т.е. самое основное, т.к. материала очень много и всего не упомянуть, а могут быть так же развернутыми. К примеру: эта статья появилась раньше, чем рассказал об UART’е и SPI, не откладывать же материал на потом? да и когда будет этот потом и будет ли вообще?

За замечание насчёт перепутанных выводов спасибо, как выйду на работу с больничного перепроверю (SD карты у меня там остались).

Ответ на пожелание — постараюсь.

В схеме ошибка подтвердилась, вечером информацию обновлю. Спасибо, что заметили.

Спасибо, все отлично работает на F103RB, кингстон сдхц на 4гб скушалась без приреканий. Правда я не сразу заметил, что у меня на плате PA4 — это слейв-селект не для карточки, отладка слегка затянулась))

Вы написали что: SD_init() – инициализация SPI и карты памяти
в случае неудачи возвращает 0.
Разве не наоборот, в случае успешной инициализации, возвращается ноль, иначе - единица?

Ошибся, исправим. Спасибо, что заметили.

А вы пробовали SDHC карту? Она инициализируется но не получается не прочитать не записать, плюс не понятно как ее адресовывать,что то в интернете толком ни чего не нашел

Пробовал SDHC Qumo 8GB — чтение успешно, запись не помню проверял ли. Другие карты не пробовал.

странно, у меня кингстон SDHC на 2гб не пишется и не читается

Ещё может от карточки зависеть, т.е. повезет — не повезет.

Скажите, пожалуйста, а можно ли как-то прочитать данные, записанные на sd карту (без файловой системы), с компьютера. Я имею ввиду использование каких-либо программ для восстановления данных с флешек и пр? Дело в том, что с FatFS постоянно возникают проблемы (с низкоуровневыми функциями, скорее всего). Или чинить их или искать программы.

Такого ПО не искал — на примете нечего нет.

Там в инструкциях к библиотеки есть описание и замечания по её критическим участкам, например, на время каких операций лучше запретить прерывания и прекращение каких приведет к повреждению данных.

Было бы куда интереснее найти/сочинить универсальный драйвер для картридеров которые есть сейчас в любом буке для использования слотов CD/MMC вкачестве универсального SPI интерфейса / программатора, естественно с эмуляцией СОМ порта потому как практически весь софт программаторов работает через СОМ/LPT и практически все железки теперь имеют биос/загрузчики через SPI или общается через него, вот тогда бы вам народ памятник поставил (хотя бы виртуальный).
Удивляюсь почему до сих пор никто такого драйвера не написал, не думаю что это невозможно или архи сложно — «хардвару обходим сфтварой а софтвару — хардварой» , однако сколько не рыл в инете такого драйвера не нашел, а самому писать — слабо.

Хорошая статья! Можно увидеть весь проект с описанной инициализацией карточки?

А к статье разве он не прикреплен?

Хм… думал все основные файлы проекта выложил, вечерком постараюсь добавить.
На счёт сайта — да, печаль, хороший был ресурс, но уже, как с год помер и полноценной копии материалов с того ресурса нигде найти не могу.
Тот сайт, по библиотеке FatFS, на самом деле занимался переводом аналогичного ресурса, библиотеку можете скачать от туда — FatFs — Generic FAT File System Module , плюс там есть ещё её обновление от 14 ноября текущего года.

Все основные файлы проекта выложены, остаётся только standard peripheral library поставить.

Добрый вечер!
Интересует вопрос создания и записи данных в текстовый файл на флешке с периодичностью в 100кГц.

Есть камера DCR-DVD203E ПИШИТ на мини сд диск …задача убрать сд и установить блок записываюший на флеш карту 32-64 ГБ.. ЕСТЬ ВНАЛИЧИИ НО КАК СДЕЛАТЬ???? ВОПРОС— СМОГЛИ БЫ СДЕЛАТЬ И ЦЕНА ВОПРОСА

По обоим вопросам не чем помочь не смогу.

«Если вы обнаружили, что обратная связь не работает, просьба сообщить об этом через комментарии».
Сообщаю 😉

Сайт работает исправно, всё что приходит вижу. Это меня завалило работой по всем фронтам. И поэтому уже с пару недель на сайт не отвечаю. Скоро одни дела завершу и на недели со временем должно будет быть чуть посвободнее, отвечу на всё, что накопилось.
1. В идеале лучше использовать простые карты памяти, не HD. Но статистики по картам у меня нет.
2. Перепроверьте распиновку карты памяти по другим ресурсам в интернете, кто-то когда то замечал у меня ошибку, не помню подтвердил её и исправил или нет.

Понятно, извиняюсь за нетерпение 🙂
Спасибо за ответ, если найду ошибку — напишу в чем было дело.

Хм, проблема оказалась в интересном месте. На одном форуме нашел статью человека, у которого была схожая проблема. На ножках, задействованных в SPI1, также висит JTAG. Так вот оказалось, что он включается автоматически после Reset, несмотря на то, что я нигде его не включаю как альтернативную функцию. В статье предлагалось решение этой проблемы (), я же просто использовал другой SPI. После чего стало возможным отослать 74 синхроимпульса.
P.S. Правда дальше все равно не заработало 🙂 После отсылки запроса на программный сброс(с пустым аргументом) ответа на команду не приходит 🙁 Будем искать еще ошибки.

И это снова я. И опять ошибка возникала из-за неправильной работы ножки. В качестве ножки SlaveSelect я выбрал ту, которая указана в ДШ как NSS для SPI2. Настроил ее на ее на управление программно. Сброс/установку ножки осуществлял с помощью функции SPI_NSSInternalSoftwareConfig() (так написано в библиотеке SPL). Так вот ножка не изменяла своего значения! Более того, когда я перестал использовать эту функцию и стал напрямую менять бит через регистр порта BSRR, то ножка все равно постоянно была выставлена! Причины я не знаю. Возможно, что все дело в режиме программного управления NSS. Поэтому когда я стал использовать для SlaveSelect другой пин, то все заработало — ответы стали приходить.
P.S. Правда дальше все равно не заработало….Опять… 🙂
Поэтому снова обращение за советом к уважаемому автору (когда он разгребётся с работой) 🙂
Ситуация такая: на команду SEND_IF_COND приходит ответ 0x01 — значит флешка v2 — вроде бы логично — флешка куплена неделю назад и навряд ли она v1. Идем дальше: отсылаю ACMD41, т.е. APP_CMD (получаю ответ 0x01 — вроде тоже все норм) и APP_SEND_OP_COND — получаю ответ 0x05. Имеем illegal command error, значит флешка не воспринимает такую команду. Решил попробовать отослать просто CMD1(вдруг карта версии v1), т.е. SEND_OP_COND — получаю ответ 0x01. Т.е. карточка никак не хочет инициализироваться, т.к. ждем 0x00. Может ли быть еще другие варианты последовательности инициализации?

Решил проблему 🙂 Долго гуглил, находил различные решения (причем некоторые были противоположны друг другу:О) но ничего не помогало. Увидел вот эту ссылку http://stackoverflow.com/questions/2365897/initializing-sd-card-in-spi-issues — решил что это не поможет и стал дальше искать, а зря…. Так как позже, отчаявшись, решил пробовать все решения и добавил несколько команд spi_read(); в начале функции SD_sendCommand() и карточка наконец инициализировалась 🙂
P.S. В той же ссылке есть другой совет — «send ACMD41 with the bit set for the voltage you’re supplying the card with», и этот человек утверждает, что ему это помогло, хотя в Physical Layer Simplified Specification Version 4.10 говорит про аргумент ACMD41 так:
Argument Reserved bit HCS Reserved bits
Command Description — Sends host capacity support information and activates the card’s initialization process. Reserved bits shall be set to ‘0’
что явно противоречит выше сказанному. Так что не всем советам стоит верить. Возможно, что и моим тоже 🙂

И снова здравствуйте! 🙂 В ходе использования карточкой возник вопрос: а как отследить что мы пишем в неверный сектор? Я имею ввиду, например, на карте 1000000 секторов, а мы пытаемся записать в 1000001. Карта это спокойно воспринимает — присылает valid-ный R1-response на команду (0x00) и valid-ный Data-response после приема данных (0xE5, но это тоже самое что 0x05, ведь значимые только младшие 7 бит).
P.S. Причем при попытке считать из неверного сектора R1-response 0x40, т.е. Parameter Error.

stm32f103 контроллер? У них столкнулся с подобной проблемой, только в другом ключе и использовал не SPI. Решение проблемы нашел, в рамках одного из будущих материалов опишу его на сайте.
По остальным вопросам отправил Вам письмо.

Alex_EXE, благодарю за письмо. Всеми ссылками, которые Вы указали, активно пользовался и до этого 🙂 Кроме первой 🙂 Но она тоже выглядит полезной и ее стоит добавить в закладки. Я так понимаю Вы давали ссылку в этой статье на нее, но только на нерабочую версию, поэтому решил добавить ее в комментарии: http://mycontroller.ru/old_site/category/vneshnie-ustroystva/karta-pamyati-sd/default.htm
Теперь по поводу чем дело кончилось:) К сожалению, ответа на него я не нашел 🙁 Нет, проблему-то я решил, правда другим способом, но мне кажется что это лишние действия и было бы лаконичнее и красивее, если бы карта выдавала Parameter Error на попытку записать в неверный сектор. Возможно, где-то в закоулках даташита, все-таки скрывается ответ и его нужно просто очень внимательно прочитать 🙂 А вот об этом речь пойдет дальше, в следующем комменте 🙂

Так вот. Как я думал решить проблему. Чтобы не писать в несуществующий сектор нужно просто знать их количество и проверять не вышли ли мы за предел 🙂 Знаю, банально, но решать проблему как-то надо 🙂
Есть такой регистр CSD (The Card-Specific Data register) В нем определенные биты отвечают за размер карты C_SIZE, при чём: memory capacity = (C_SIZE+1) * 512KByte. Т.е. отсюда можно посчитать количество секторов. Читается он с помощью CMD9 (SEND_CSD). Нашел наверно с десяток ссылок (например https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Attachments/18065/stm32_eval_spi_sd.c) в которых был написан один и тот же(по смыслу, а не скопипащенный 🙂) алгоритм чтения этого регистра. Суть сводилась к следующему:
Reading the contents of the CSD register in SPI mode is a simple read-block transaction (при чем в даташите есть точно такая же строка, но абзац на этом не заканчивается, но видимо дальше никто не читает 🙂). В итоге, во все ссылках такая последовательность действий:
CS в ноль -> шлем команду CMD9 с пустым аргументом -> ждём R1(0x00) -> ждём Data Token(0xFE) -> читаем 16 байт регистра -> читаем 2 байта CRC -> CS в единицу. Всё, данные получили, осталось только их распарсить.
ОК, пишу код, запускаю. На команду отвечает R1(0x00), всё норм. Вместо Data Token(0xFE) приходит 0x7F, а дальше идут 0xFF. Приехали. Начинаю гуглить, искать что означает 0x7F и кто с этим сталкивался. Вообщем потратил кучу времени и всё в пустую. Потом смотрю на свой код команды чтения сектора и стоп! — в CMD17 сначала шлем команду, а потом CS в ноль, а тут наоборот почему-то, хотя везде сказано что что CMD9 та же самая CMD17. Думаю дай-ка попробую так. Ииии…нет 🙁 всё равно не получаем 0xFE. НО, если раньше дальше шли 0xFF, то теперь какие-то непонятные байты. Странно, непонятно…И тут у меня появилась мысль и полез я в даташит. И что же я там увидел, в следующей части абзаца, после строки про simple read-block transaction. А вот что:
The card will respond with a standard response token followed by a data block of 16 bytes suffixed with a 16-bit CRC.
Т.е. в даташите для команды CMD9 ни про какой Data Token не сказано! Т.е. сразу после R1(0x00) идут байты регистра! Вот что значат эти непонятные байты. Проверил — действительно, 18 байт (16 + CRC), а потом уже пошли 0xFF. Распарсил байты и проверил провел по даташиту все сходится, это он — CSD. И размер карты тоже сошелся. Ну дальше дело техники посчитать количество секторов.
Так что вот, мой так сказать опыт по этому вопросу, может кому пригодится, чтобы не трать (как мне дурачку) такое количество времени на поиски ошибок на пустом месте 🙁Alex_EXE пишет 22.10.2016 в 20:28

Кто знает, эта библиотека подойдет чтобы подключить к discovery флешку от mxic 25l на 32Мб?

Михаил Русских

Приводится краткая информация о SD-картах, даются основы принципа работы шины SD, поясняется порядок использования драйвера stm324xg_eval_sdio_sd, предназначенного для упрощения связи микроконтроллеров семейства STM32 с SD-картами

Некоторые встраиваемые системы должны иметь возможность хранения больших объемов информации. Например, регистраторы различных физических величин и параметров (ток, напряжение, температура, географические координаты) должны сохранять полученные с датчиков показания на определенном носителе, который впоследствии можно было бы извлечь из устройства и подключить к компьютеру для просмотра данных в удобном для пользователя виде. Для решения такой задачи наиболее очевидным кажется использование USB флеш-накопителей. Они широко распространены на рынке и позволяют хранить большие объемы информации. Но для некоторых малых встраиваемых систем первостепенным фактором является компактность, и габариты этих накопителей могут оказаться чрезмерными. Кроме того, не все микроконтроллеры оснащены модулем USB, и разработчик системы может довольно долго разбираться с USB-стеком, что может увеличить время работы над проектом. В связи с этим хорошей альтернативой USB является использование SD-карт, которые очень компактны и позволяют обмениваться данными с помощью распространенного интерфейса SPI или специального интерфейса для SD-карт.

Карты памяти SD (Secure Digital) разработаны, в основном, для применения в портативных устройствах. Сегодня на рынке существует большое количество моделей, предоставляемых такими компаниями как SanDisc, и способных записывать с зависящей от класса скоростью данные объемом от 8 МБ до 2 ТБ. SD-карты, в отличие от MMC-карт, помимо обычной области хранения данных имеют специальную защищенную область, которая недоступна обычному пользователю. Для того чтобы устройство смогло прочитать записанную на SD-карту информацию в виде файлов, эта карта должна иметь определенную файловую систему. Наиболее предпочтительной в данном случае является система FAT, поскольку количество циклов записи/чтения для SD-карт ограничено, а системы вроде NTFS и ext являются журналируемыми, то есть предполагающими частые опросы.

Передача и прием данных осуществляется по интерфейсу SPI или по шине SD. На Рисунке 1 показано расположение выводов SD-карт различных типов, а в Таблице 1 представлено функциональное назначение этих выводов.

Таблица 1. Функциональное назначение выводов SD-карт

Интерфейс SPI

Интерфейс SD

Карты SDC

Карты miniSD

Карты microSD

Хотя с помощью SPI организация связи хост-контроллера с картой не вызывает затруднений, все же шина SD предоставляет больше возможностей и позволяет пересылать информацию с большей скоростью за счет наличия четырех линий передачи данных. Поэтому ниже более подробно рассмотрим именно этот способ работы с SD-картой.

Передача данных по шине SD

Связь с SD-картой осуществляется по 6 информационным линиям: 4 линиям данных (DAT0, DAT1, DAT2, DAT3), линии синхронизации (CLK), линии передачи команд (CMD). При подключении к контроллеру линии данных и линия передачи команд должны быть подтянуты к питанию, как показано на Рисунке 2.

Запись и чтение данных выполняются поблочно. Обычно блок состоит из 512 байтов. Передача данных и служебной информации основана на модели взаимодействия «команда-ответ». Перед передачей или приемом данных хост-контроллер должен отправить соответствующую команду по линии CMD. По этой же линии от SD-карты должен прийти ответ, после которого может быть осуществлено требуемое действие. Стандарт SD поддерживает присутствие нескольких ведомых на шине, в таком случае хост-контроллер может посылать команды широковещательно. Команда имеет четкую структуру, состоящую из 48 бит: 1 стартовый бит, 1 бит передачи (установлен в 1), 6 бит для индекса команды, 32 бита для аргумента, 7 бит для контрольной суммы и 1 стоповый бит. Ответ может иметь такую же 48-битную структуру (в этом случае бит передачи установлен в 0) или состоять из 136 битов (т. н. формат длинного ответа): 1 стартовый бит, 1 бит передачи (установлен в 0), 6 зарезервированных битов, 127 битов содержимого регистров CID (Card Identifiction Register) или CSD (Card Specific Data Register) и контрольной суммы, 1 стоповый бит.

В начале работы с картой хост-контроллер перезагружает карту с помощью команд GO_IDLE_STATE (CMD0) и IO_RW_DIRECT (CMD52) . Полный список команд с описанием можно найти в (приложение A). После перезагрузки карта восстановит свои настройки по умолчанию, и ее адрес будет равен RCA = 0x0001. Если к хосту подключено несколько карт, то с помощью команды SET_RELATIVE_ADDR (CMD3) он задает каждой карте собственный адрес. Также в начале работы выполняется проверка поданного на карту напряжения. Напряжение карты должно быть в строго установленном диапазоне от 2.7 до 3.6 В. В связи с этим хост-контроллер с помощью команды SEND_OP_COND (CMD1 или ACMD41 ) обязан узнать текущее напряжение на карте и прекратить с ней работу, если оно не входит в требуемый диапазон. Таков общий принцип инициализации карты, для выполнения которой, в зависимости от типа карты (MMC, SD, SD I/O), могут использоваться другие команды и выполняться дополнительные шаги, поэтому при реализации низкоуровневого интерфейса нужно внимательно прочитать документацию на карту и изучить команды CMD.

Во время записи хост передает карте один или несколько блоков, используя команду WRITE_BLOCK (CMD24) или WRITE_MULTIPLE_BLOCK (CMD25) , соответственно, при этом в конце каждого блока хост записывает контрольную сумму. Карта, запись данных для которой разрешена, всегда будет в состоянии принять блок(и), но если контрольная сумма не совпадет, то карта сообщит об ошибке и не запишет текущий блок в свою память, а в случае пакетной передачи следующие блоки будут проигнорированы.

Передать информацию хосту, то есть выполнить чтение, также можно одним блоком с помощью команды READ_SINGLE_BLOCK (CMD17) или пакетом из нескольких блоков с помощью команды READ_MULTIPLE_BLOCK (CMD18) . В случае пакетной передачи хост может прервать чтение в любое время, отправив команду STOP_TRANSMISSION (CMD12) . Если в ходе передачи нескольких блоков внутренний контроллер карты зафиксирует ошибку, то он остановит передачу данных хост-контроллеру, но оставит карту в режиме передачи данных. В таком случае хосту придется принудительно завершить чтение с помощью команды CMD12 , при этом в ответе на эту команду карта сообщит об ошибке чтения.

Организация правильной работы шины SD является достаточно трудоемким процессом, поскольку помимо общих ситуаций, описанных выше, необходимо предусматривать различные нюансы в поведении карты и реализовывать дополнительные обработчики ошибок. Поэтому наиболее рациональным решением будет использование специальных библиотек, позволяющих разработчику не вдаваться в подробности передачи данных на аппаратном уровне и существенно сократить время разработки. Одной из таких библиотек, о которой пойдет речь ниже, является библиотека-драйвер stm324xg_eval_sdio_sd для популярных микроконтроллеров , позволяющая существенно упростить работу с модулем SDIO, предназначенным для взаимодействия с SD-картами.

Драйвер stm324xg_eval_sdio_sd

Этот драйвер представляет собой библиотеку функций, с помощью которых можно реализовать высокоуровневый интерфейс для обмена данными с SD-картой. Драйвер поставляется для работы с отладочной платой STM324VG (UtilitiesSTM32_EVALSTM3240_41_G_EVAL), но после изменения функций, связывающих эту библиотеку с низкоуровневым интерфейсом SDIO он может функционировать со многими микроконтроллерами семейства STM32, в составе которых имеется модуль SDIO. Из предыдущего предложения следует, что к проекту должны быть подключены файлы из стандартной библиотеки Standard Peripheral Library , обеспечивающие функционирование модуля SDIO на низком уровне. Например, для микроконтроллеров серии STM32F4xx это будут файлы stm32f4xx_sdio.c и stm32f4xx_sdio.h .

Перед использованием функций драйвера программист должен связать этот драйвер с аппаратной частью, то есть настроить линии модуля SDIO. Для этого ему нужно в основном файле своей программы main.c создать функции SD_LowLevel_Init() (для включения модуля SDIO) и SD_LowLevel_DeInit() (для отключения модуля SDIO), в которых необходимо выполнить конфигурирование этих линий. Если программист желает использовать модуль прямого доступа к памяти для увеличения скорости работы с SD-картой, то ему также нужно будет создать функции SD_LowLevel_DMA_TxConfig() и SD_LowLevel_DMA_RxConfig() , отвечающие за передачу и прием данных с помощью модуля ПДП. В качестве примера инициализации четырех указанных функций можно взять код, имеющийся в файле stm324xg_eval.c из (UtilitiesSTM32_EVALSTM3240_41_G_EVAL).

Теперь рассмотрим основные функции для работы с SD-картой, предоставляемые этим драйвером. Для того, чтобы инициализировать карту, нужно вызвать функцию SD_Init() , которая настраивает модуль SDIO, обращаясь к SD_LowLevel_Init() , проверяет тип SD-карты, получает служебную информацию из регистров CID и CSD, задает скорость передачи данных (по умолчанию 24 МГц) и устанавливает ширину шины (4 бита). Прочитать данные, полученные с карты, можно с помощью функций SD_ReadBlock() (для чтения одного блока) и SD_ReadMultiBlocks() (для чтения нескольких блоков). Чтобы записать данные на карту, используют функции SD_WriteBlock() (для записи одного блока) и SD_WriteMultiBlocks() (для записи нескольких блоков). Эти функции чтения и записи принимают три аргумента: buffer (переменная-буфер, в которую должны помещаться данные для чтения и записи), address (адрес ячейки памяти SD-карты) и block_size (всегда 512, поскольку эти функции работают только с блоками длинной 512 байтов). Для стирания определенной области памяти карты имеется функция SD_Erase() . В качестве аргументов она принимает startaddr и endaddr. В первом указывается адрес ячейки памяти, с которой начнется стирание, а во втором - адрес ячейки, на которой стирание будет завершено.

Передача данных между модулем SDIO и памятью микроконтроллера может осуществляться как обычным путем через центральный процессор, так и через блок прямого доступа к памяти. Для выбора необходимого режима нужно в файле stm324xg_eval_sdio_sd.h раскомментировать либо строчку #define SD_POLLING_MODE (обычный режим), либо строчку #define SD_DMA_MODE (режим ПДП). После любой операции записи или чтения необходимо с помощью функции SD_GetStatus() проверять, завершила ли карта текущую операцию, и готова ли она к приему или отправке новых данных. Если эта функция вернула значение SD_TRANSFER_OK, то передача завершена успешно, возврат SD_TRANSFER_BUSY означает, что канал передачи занят, а возврат SD_TRANSFER_ERROR сообщает об ошибке передачи. Все эти значения определены в структуре SDTransferState , записанной в stm324xg_eval_sdio_sd.h . Если передача информации выполнялась через блок ПДП, то дополнительно нужно проверять, завершил ли контроллер ПДП все операции по пересылке данных. Это делается с помощью функции SD_ReadWaitOperation() . Также стоит отметить, что передача через блок ПДП завершается прерыванием, поэтому программисту необходимо организовать вызов функции SD_ProcessIRQ() в обработчике прерываний модуля SDIO SDIO_IRQHandler() и вызов функции SD_ProcessDMAIRQ() в обработчике прерываний DMA2 DMA2_Streamx_IRQHandler() .

Для лучшего понимания принципа работы драйвера stm324xg_eval_sdio_sd можно воспользоваться рабочим примером из папки SDIOSDIO_uSDCard (ProjectSTM32F4xx_StdPeriph_ExamplesSDIO). С помощью этой тестовой программы можно выполнить стирание определенной области памяти карты, запись данных по определенному адресу, чтение данных по этому же адресу с последующим сравнением отправленной и принятой информации. Идентичность буфера приема и буфера отправки является свидетельством того, что модуль SDIO, шина передачи информации и SD-карта функционируют нормально.

Таким образом, можно сказать, что SD-карты являются достойными конкурентами USB флеш-накопителей, когда речь заходит о проектировании малых встраиваемых систем, требующих хранения больших объемов данных. Передавать информацию с карты и на карту можно с помощью интерфейса SPI или по шине SD, которая разработана для этих целей и обеспечивает высокую скорость передачи. Реализация связи с картой существенно упрощается при использовании специальных драйверов, облегчающих работу с аппаратной частью и предлагающих программистам простые в использовании функции. Но, к сожалению, записанные в произвольном порядке данные не будут восприняты какой-либо операционной системой, например, Windows, поэтому в следующей части будет рассмотрен порядок работы с SD-картой, имеющей файловую систему FAT.

Список источников

В устройствах на микроконтроллерах для хранения больших объемов данных используется внешняя память. Если требуется хранить единицы мегабайт, то подойдут микросхемы последовательной флэш памяти. Однако для больших объемов (десятки -сотни мегабайт) обычно применяются какие-нибудь карты памяти. В настоящий момент наибольшее распространение получили SD и microSD карты, о них я и хотел бы поговорить в серии материалов. В этой статье речь пойдет о подключении SD карт к микроконтроллеру, а в следующих мы будет разбираться как читать или записывать на них данные.

Распиновка SD и microSD карт

SD карты могут работать в двух режимах - SD и SPI . Назначение выводов карт и схема подключения зависит от используемого режима. У 8-и разрядных микроконтроллеров AVR нет аппаратной поддержки SD режима, поэтому карты с ними обычно используются в режиме SPI. В 32-х разрядных микроконтроллерах на ядре ARM, например AT91SAM3, интерфейс для работы с картами в SD режиме есть, поэтому там можно использовать любой режим работы.

Назначение контактов SD карты в SD режиме


Назначение контактов SD карты в SPI режиме

Назначение контактов microSD карты в SD режиме



Назначение контактов microSD карты в SPI режиме



Подключение SD и microSD карт к микроконтроллеру в SPI режиме

Напряжение питания SD карт составляет 2.7 - 3.3 В. Если используемый микроконтроллер запитывается таким же напряжением, то SD можно подключить к микроконтроллеру напрямую. Расово верная схема, составленная путем изучения спецификаций на SD карты и схем различных отладочных плат, показана на рисунке ниже. По такой схеме подключены карты на отладочных платах фирм Olimex и Atmel .

На схеме обозначены именно выводы SD карты, а не разъема.


L1 - феррит или дроссель, рассчитанный на ток >100 мА. Некоторые его ставят, некоторые обходятся без него. А вот чем действительно не стоит пренебрегать, так это полярным конденсатором C2. Потому что при подключении карты происходит бросок тока, напряжение питания "просаживается" и может происходить сброс микроконтроллера.

По поводу подтягивающих резисторов есть некоторая неоднозначность. Поскольку SD карты выпускаются несколькими производителями, на них существует несколько спецификаций. В одних документах четко указана необходимость подтягивающих резисторов (даже для неиспользуемых линий - 8, 9), в других документах этих указаний нет (или я не нашел).

Упрощенный вариант схемы (без подтягивающих резисторов) показан на рисунке ниже. Эта схема проверена на практике и используется в платах фирмы Microelectronika. Также она используется во многих любительских проектах, которые можно найти в сети.



Здесь сигнальные линии SD карты удерживаются в высоком состоянии микроконтроллером, а неиспользуемые линии (8, 9) никуда не подключены. По идее они должны быть подтянуты внутри SD карты. Далее я буду отталкиваться от этой схемы.

Если микроконтроллер запитывается напряжением отличным от напряжения питания SD карты, например 5 В, то нужно согласовать логические уровни . На схеме ниже показан пример согласования уровней карты и микроконтроллера с помощью делителей напряжения. Принцип согласования уровней простой - нужно из 5-и вольт получить 3.0 - 3.2 В.



Линия MISO - DO не содержит делитель напряжения, так как данные по ней передаются от SD карты к микроконтроллеру, но для защиты от дурака можно добавить аналогичный делитель напряжения и туда, на функционировании схемы это не скажется.

Если использовать для согласования уровней буферную микросхему, например CD4050 или 74AHC125, этих недостатков можно избежать. Ниже приведена схема, в которой согласование уровней выполняется с помощью микросхемы 4050. Это микросхема представляет собой 6 неинвертирующих буферов. Неиспользуемые буферы микросхемы "заглушены".

Подключение microSD карт аналогичное, только у них немного отличается нумерация контактов. Приведу только одну схему.



На схемах я рассматривал подключение SD карт к микроконтроллеру напрямую - без разъемов. На практике, конечно, без них не обойтись. Существует несколько типов разъемов и они друг от друга немного отличаются. Как правило, выводы разъемов повторяют выводы SD карты и также содержать несколько дополнительных - два вывода для обнаружения карты в разъеме и два вывода для определения блокировки записи. Электрически эти выводы с SD картой никак не связаны и их можно не подключать. Однако, если они нужны, их можно подключить как обычную тактовую кнопку - один вывод на землю, другой через резистор к плюсу питания. Или вместо внешнего резистора использовать подтягивающий резистор микроконтроллера.

Подключение SD и microSD карт к микроконтроллеру в SD режиме

Ну и для полноты картины приведу схему подключения SD карты в ее родном режиме. Он позволяет производить обмен данными на большей скорости, чем SPI режим. Однако аппаратный интерфейс для работы с картой в SD режиме есть не у всех микроконтроллеров. Например у Atmel`овских ARM микроконтроллеров SAM3/SAM4 он есть.



Шина данных DAT может использоваться в 1 битном или 4-х битном режимах.

Продолжение следует...

В большинстве проектов с Ардуино необходимо устанавливать вспомогательное хранилище для медиафайлов, будь это видео или аудио. Если возникает необходимость хранить и обрабатывать информацию, а стоковой флеш-памяти плат вам не хватает, то есть несколько решений.

Можно докупить специальную плату, обеспечивающую быстрый доступ к данным, но и стоящую не малых денег. Если же у вас нет желания тратиться, то расширить стоковую память платы можно и с arduino card SD, дабы не было проблем с записью и стиранием стоковых утилит с чипов. Однако далеко не все новички знают, как правильно подключать флешку к чипу и что для этого нужно. Давайте разберёмся во всех нюансах и узнаем, какие подводные камни такого решения вас поджидают.

Что необходимо знать при подключении SD card к Arduino

Прежде чем подсоединять что-либо, следует изучить нюансы, которые будут подстерегать вас на каждом шагу. Первое, с чем вам придётся столкнуться, это вольтаж карт памяти, ведь они рассчитаны на 3.3 В, что является стандартом.

Неудобство заключается в том, что для записи данных необходима и соответствующая сила тока, вплоть до 100 мА, если речь о действительно больших массивах информации. Соответственно, необходимо обеспечить всю систему хорошим источником питания, но основная проблема заключается в том, что карты крайне привередливы. Если вы будете пользоваться резисторами и длинными проводниками, то скорость записи и чтения может упасть в разы ниже средних показателей, поэтому следует обзавестись небольшими коннекторами и убрать, по возможности, всё сопротивление из цепочки для питания логики.

Чтобы не сжечь всю плату, достаточно прикупить преобразователи переменного и постоянного тока, лучше всего подойдут приборы под HEF4050 и 74FHC125 базу.

  1. SPI. Универсален, и подойдёт для любого микроконтроллера, а подключение требует всего четыре пина.
  2. SDIO. Хороший выбор, если необходима высокая скорость передачи информации, но с arduino microsd реализуется крайне тяжело.

Учитывайте и формат карты, он не влияет ровным счётом ни на что, кроме размера вашей конечной поделки. Если необходимо серьёзно урезать габариты, то хорошим выбором станет microSD.

Сама по себе флешка – это небольшой чип со специально выделенными секторами, а соответственно, структур, обязательных к использованию, вы здесь не найдёте. Такой подход удобен для быстрого форматирования и сохранения данных в подходящей файловой системе.

Большинство устройств на сегодняшний день пользуются форматами NTFS, FAT32 и FAT16. Но чем сложнее система, тем больше памяти для работы arduino SD придётся выделить, что чревато последствиями в виде подлагиваний и плохой скорости отклика.

Схема подключения SD card к Arduino

Предварительно отформатировав карту памяти, приступайте к её подключению.

Платы расширений облегчат задачу, ведь они позволят урегулировать напряжение до необходимых нам 3.3 В, а контроллеры уровня преобразуют питание логики в подходящие для флешки.

Плата расширений потребуется под микроконтроллеры до 5 В, учитывайте это при её выборе. Главное достоинство Ардуино – простота, и подключение вспомогательных модулей не стало исключением. Лучшим выбором станет именно структура запуска через hardware SPI пины, дабы не усложнять новичкам жизнь. Нам потребуются 13, 12 и 11 цифровые пины, а также четвёртые, чтобы наладить «chip\slave select» цепь. Под это, зачастую, берётся 10 пин, но если вы знаете, что делаете, можете выбрать и более подходящий.


Обратите внимание на то, что в зависимости от форм-фактора и типа платы Ардуино, точки подключения могут варьироваться. Например, для меги необходимо соединить цепь с 50, 51, 52 и 53 слотом.

В последующие разы вы можете поэкспериментировать с последними пинами на обеих картах, но поначалу лучше выбрать именно те, что указаны выше. Так вы сможете отработать код, избавившись от нежелательных поломок и осечек, что значительно упростит задачу в будущем. Оставшиеся 5 В и GND подсоединяйте к соответствующим портам, здесь никаких особых инструкций нет.

Еще один вариант наглядной схемы:

В конце процедуры необходимо замкнуть CD в заземление, так система не сможет инициализировать карту памяти. Но, в случае необходимости, всегда можно применить резисторы в 10 кОм и вспомогательные порты, однако мы не будем останавливаться на этом пине, так как сейчас он нам не нужен.

Загрузка библиотек и запуск SD card на Arduino

Чтобы подсоединиться к SD карте и свободно передавать на неё данные, потребуется написать немало кода, однако здесь нам поможет встроенная библиотека SD.

Библиотеку по работе с картами памяти можно найти на официальном сайте производителя микроконтроллера: https://www.arduino.cc/en/Reference/SD

Открыв подменю «образцов», найдите заготовку «cardinfo», именно её мы не будем использовать в качестве прописной функции при загрузке информации. Скетч пригодится лишь для проверки, опознаётся ли дополнительная память на устройстве. Проверяйте chipSelect, учитывая, что подключение идёт через 10 пин.

#include const int chipSelect = 4; void setup() { Serial.begin(9600); while (!Serial) { ; // wait for serial port to connect. } Serial.print(“Initializing SD card…”); pinMode(10, OUTPUT); //iniot SD card if (!SD.begin(chipSelect)) { Serial.println(“Card failed, or not present”); return; } Serial.println(“card initialized.”); } void loop() { String dataString = “”; // read three sensors and append to the string for (int analogPin = 0; analogPin < 3; analogPin++) { int sensor = analogRead(analogPin); dataString += String(sensor); if (analogPin < 2) { dataString += “,”; } } // open the file. File dataFile = SD.open(“data.txt”, FILE_WRITE); // if the file is available, write to it: if (dataFile) { dataFile.println(dataString); dataFile.close(); } // if the file isn’t open else { Serial.println(“error opening data.txt”); } }

Если всё прошло удачно, то на экран выведется информация о типе файловой системы и объёме вашей SD-карты. Если же производитель подсунул вам не лучший продукт, могут возникнуть ошибки. Здесь проще купить новую флешку, чем бороться с ошибками файловой системы, изначально заложенными в девайс.

Когда вы получите отклик от системы, можете начинать подгружать библиотеки и нужные вам файлы. SD-карта полностью работает и подключена, однако не забудьте протестировать несколько типов файловых систем, дабы подобрать оптимальный вариант по скорости и потреблению ресурсов. В каждом конкретном случае эти параметры будут разными, поэтому не бойтесь экспериментировать.

Заключение

SD-карта – необходимый элемент любой системы, в которой вы собираетесь использовать медиафайлы. Это будет хорошим решением как для приборов под «умный дом», так и для самодельных плееров. Однако не забывайте, что качество конечного продукта приравнивается к качеству его худшего компонента, и не стоит экономить на SD-картах.