В устройствах на микроконтроллерах для хранения больших объемов данных используется внешняя память. Если требуется хранить единицы мегабайт, то подойдут микросхемы последовательной флэш памяти. Однако для больших объемов (десятки -сотни мегабайт) обычно применяются какие-нибудь карты памяти. В настоящий момент наибольшее распространение получили SD и microSD карты, о них я и хотел бы поговорить в серии материалов. В этой статье речь пойдет о подключении SD карт к микроконтроллеру, а в следующих мы будет разбираться как читать или записывать на них данные.
SD карты могут работать в двух режимах — SD и SPI. Назначение выводов карт и схема подключения зависит от используемого режима. У 8-и разрядных микроконтроллеров AVR нет аппаратной поддержки SD режима, поэтому карты с ними обычно используются в режиме SPI. В 32-х разрядных микроконтроллерах на ядре ARM, например AT91SAM3, интерфейс для работы с картами в SD режиме есть, поэтому там можно использовать любой режим работы.
Назначение контактов SD карты в SD режиме
Назначение контактов SD карты в SPI режиме
Назначение контактов microSD карты в 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 карты к микроконтроллеру, но для защиты от дурака можно добавить аналогичный делитель напряжения и туда, на функционировании схемы это не скажется.
Резистивный делитель напряжения — это самый простой вариант согласования уровней, однако при высоких скоростях обмена или длинных проводах он может не подойти. Емкость входов SD карты, а также паразитная емкость линий, вместе с резисторами делителя образует RC фильтры, которые «заваливают» фронты передаваемых сигналов, а у SD карт есть определенные требования к этим фронтам.
Если использовать для согласования уровней буферную микросхему, например CD4050 или 74AHC125, этих недостатков можно избежать. Ниже приведена схема, в которой согласование уровней выполняется с помощью микросхемы 4050. Это микросхема представляет собой 6 неинвертирующих буферов. Неиспользуемые буферы микросхемы «заглушены».
Подключение microSD карт аналогичное, только у них немного отличается нумерация контактов. Приведу только одну схему.
На схемах я рассматривал подключение SD карт к микроконтроллеру напрямую — без разъемов. На практике, конечно, без них не обойтись. Существует несколько типов разъемов и они друг от друга немного отличаются. Как правило, выводы разъемов повторяют выводы SD карты и также содержать несколько дополнительных — два вывода для обнаружения карты в разъеме и два вывода для определения блокировки записи. Электрически эти выводы с SD картой никак не связаны и их можно не подключать. Однако, если они нужны, их можно подключить как обычную тактовую кнопку — один вывод на землю, другой через резистор к плюсу питания. Или вместо внешнего резистора использовать подтягивающий резистор микроконтроллера.
Ну и для полноты картины приведу схему подключения SD карты в ее родном режиме. Он позволяет производить обмен данными на большей скорости, чем SPI режим. Однако аппаратный интерфейс для работы с картой в SD режиме есть не у всех микроконтроллеров . Например у Atmel`овских ARM микроконтроллеров SAM3/SAM4 он есть.
Шина данных DAT[0..3] может использоваться в 1 битном или 4-х битном режимах.
Продолжение следует…
chipenable.ru
Всем доброго дня! Сегодня мы поговорим о подключении карты памяти SD к микроконтроллеру STM32.
Казалось бы, памяти полно у контроллеров STM32F10x, зачем там еще дополнительная, но это впечатление обманчиво ) Вот, например, надо нам на дисплей вывести пару-тройку разных изображений – формат 320*240 – то есть 76800 пикселей, каждому из которых соответствует целых 2 байта. Вот и получаем около 150 кБ на одну картинку. А это немало по меркам микроконтроллера, и не факт, что две разные картинки удастся запихать в его Flash память. Или надо нам хранить большие объемы информации, данные с какого-нибудь датчика, к примеру. Да еще так, чтобы эти данные были доступны и после отключения питания. Вот тут то нам и пригодится внешняя память. И отличным решением будет
Для начала пара слов о самой карте памяти, точнее о ее распиновке. Выглядит все это дело следующим образом:
Итак, что тут у нас? Ну сразу видно, что выводов у нее целых восемь штук. Назначение выводов следующее (слева направо):
Колонка SPI Mode нам намекает на то, что SD карта взаимодействует с микроконтроллером при помощи интерфейса SPI. НО! Мы пойдем по другому пути 😉 Все дело в том, что STM32 имеют на своем борту готовый периферийный модуль для работы именно с картами памяти, и называется он SDIO.
Вообще взаимодействие с картами памяти заключается в передаче им определенных команд. Некоторые команды требует наличия аргумента, некоторые нет. Команды можно найти в официальной документации на конкретную карту. Так вот встроенный модуль SDIO дает возможность значительно упростить процесс передачи команд, да и вообще процесс работы с внешними картами памяти. Например, вот регистр SDIO_CMD – туда мы просто напросто записываем код команды, которую хотим передать карте. Или вот статусный регистр SDIO_STA – там целых 24 флага на каждый чих, то есть для большого количества событий.
Кстати STM радует еще и добротной документацией на все это дело. Вот, к примеру, подробное описание инициализации для карты памяти SD (аналогично все описано для других типов карт):
Ну, собственно, пора перейти к практическому примерчику. Поковыряем-ка Standard Peripheral Library.
В файле stm32f10x_sdio.h по традиции находим структуры для всевозможной настройки – то есть для выбора источника тактового сигнала, частоты контроллера SDIO, настройки количества передаваемых байт. Там все так щедро откомментировано, что даже не хочется отдельно это повторять )) Просто смотрите:
typedef struct { uint32_t SDIO_ClockEdge; /* Specifies the clock transition on which the bit capture is made. This parameter can be a value of @ref SDIO_Clock_Edge */ uint32_t SDIO_ClockBypass; /* Specifies whether the SDIO Clock divider bypass is enabled or disabled. This parameter can be a value of @ref SDIO_Clock_Bypass */ uint32_t SDIO_ClockPowerSave; /* Specifies whether SDIO Clock output is enabled or disabled when the bus is idle. This parameter can be a value of @ref SDIO_Clock_Power_Save */ uint32_t SDIO_BusWide; /* Specifies the SDIO bus width. This parameter can be a value of @ref SDIO_Bus_Wide */ uint32_t SDIO_HardwareFlowControl; /* Specifies whether the SDIO hardware flow control is enabled or disabled. This parameter can be a value of @ref SDIO_Hardware_Flow_Control */ uint8_t SDIO_ClockDiv; /* Specifies the clock frequency of the SDIO controller. This parameter can be a value between 0x00 and 0xFF. */ } SDIO_InitTypeDef; typedef struct { uint32_t SDIO_Argument; /* Specifies the SDIO command argument which is sent to a card as part of a command message. If a command contains an argument, it must be loaded into this register before writing the command to the command register */ uint32_t SDIO_CmdIndex; /* Specifies the SDIO command index. It must be lower than 0x40. */ uint32_t SDIO_Response; /* Specifies the SDIO response type. This parameter can be a value of @ref SDIO_Response_Type */ uint32_t SDIO_Wait; /* Specifies whether SDIO wait-for-interrupt request is enabled or disabled. This parameter can be a value of @ref SDIO_Wait_Interrupt_State */ uint32_t SDIO_CPSM; /* Specifies whether SDIO Command path state machine (CPSM) is enabled or disabled. This parameter can be a value of @ref SDIO_CPSM_State */ } SDIO_CmdInitTypeDef; typedef struct { uint32_t SDIO_DataTimeOut; /* Specifies the data timeout period in card bus clock periods. */ uint32_t SDIO_DataLength; /* Specifies the number of data bytes to be transferred. */ uint32_t SDIO_DataBlockSize; /* Specifies the data block size for block transfer. This parameter can be a value of @ref SDIO_Data_Block_Size */ uint32_t SDIO_TransferDir; /* Specifies the data transfer direction, whether the transfer is a read or write. This parameter can be a value of @ref SDIO_Transfer_Direction */ uint32_t SDIO_TransferMode; /* Specifies whether data transfer is in stream or block mode. This parameter can be a value of @ref SDIO_Transfer_Type */ uint32_t SDIO_DPSM; /* Specifies whether SDIO Data path state machine (DPSM) is enabled or disabled. This parameter can be a value of @ref SDIO_DPSM_State */ } SDIO_DataInitTypeDef; |
Отметим как в SPL реализована передача команд карте памяти. Для этих целей отведена отдельная структура SDIO_CmdInitTypeDef. В поле SDIO_CmdIndex вводим код команды, в поле SDIO_Argument – аргумент команды, также заполняем остальные поля. Осталось как то эти данные запихать в карту micro SD 😉 А для этого нам приготовили функцию:
SDIO_SendCommand (SDIO_CmdInitTypeDef *SDIO_CmdInitStruct)
В качестве аргумента передаем ей как раз таки созданную нами структуру. Для записи данных есть функция – SDIO_WriteData(uint32_t Data). После вызова этой функции данные окажутся в специально предназначенном для этого регистре – SDIO_FIFO.
Вот так вот осуществляется работа с модулем SDIO в STM32F10x )
Теперь перейдем к практике наконец-то. Я снова буду работать с платой Mini STM32, поскольку добрые китайцы озадачились установкой на нее слота для карты памяти micro SD. Вот схема подключения разъема для карты к микроконтроллеру:
Для написания программы воспользуемся готовым примером для Keil’а – стащим оттуда два файла, в которых реализовано что-то вроде драйвера для работы с картами – это файлы sdcard.c и sdcard.h. Создаем новый проект, цепляем туда эти файлы, а кроме того, естественно, файлы CMSIS и SPL. Вот готовый проект, в который все уже добавлено – остается только написать код функции main() )
Проект для работы с SDIO
В файле sdcard.c реализованы всевозможные функции для работы с картой памяти, нам теперь остается их только использовать 😉 Пишем код! Для примера запишем на micro SD 512 байт тестовых данных, а затем попробуем их считать:
/*******************************************************************/ // Цепляем нужные файлы #include "stm32f10x.h" #include "sdcard.h" /*******************************************************************/ // Массивы входных и выходных данных и переменная для хранения данных // о нашей карте uint8_t writeBuffer[512]; uint8_t readBuffer[512]; SD_CardInfo SDCardInfo; /*******************************************************************/ int main() { // Тестовые данные для записи for (uint16_t i = 0; i < 512; i++) { writeBuffer[i] = i % 256; readBuffer[i] = 0; } // Иницилизация карты SD_Init(); // Получаем информацию о карте SD_GetCardInfo(&SDCardInfo); // Выбор карты и настройка режима работы SD_SelectDeselect((uint32_t) (SDCardInfo.RCA << 16)); SD_SetDeviceMode(SD_POLLING_MODE); // И вот наконец то запись и чтение SD_WriteBlock(0x00, writeBuffer, 512); SD_ReadBlock(0x00, readBuffer, 512); while(1) { } } /*******************************************************************/ |
Обратите внимание, что SD карта поддерживает запись блоками по 512 байт.
Если мы запустим программу под отладчиком, то увидим, что считанные данные соответствуют записанным =) Так что эксперимент можем считать удавшимся. На этом на сегодня заканчиваем, до скорых встреч!
microtechnics.ru
В последнее время всё чаще приносят на восстановление информации флешки, выполненные на монокристальной основе, так называемые монолиты. Сегодня речь пойдёт о процессе восстановления данных с такого монолита, — карты памяти SD которую прислал партнер из города Кемерово. На карточке была записана видеосъемка свадьбы, и когда торжество успешно окончилось и пора было приступать к монтажу и выпуску подарочных DVD, флешка приказала долго жить.
Примечательно, что внешне не понять, — это «классическая» SD карточка, с платой текстолита, NAND памятью и контроллером, или монокристалл. До тех пор, пока не вскроется пластиковый корпус. Чаще всего выход таких карт памяти из строя обусловлен сбоем в таблицах трансляции. Реже — электромеханическими повреждениями.
Для восстановления файлов с такой карточки первым делом надо вычитать дампы с кристалла. Для этого механическим (очисткой и шлифованием) путем удаляется защитный лак, скрывающий дорожки и контактные площадки монолита. После чего флешка начинает выглядеть так:
Дорожки и распиновка монолитной SD карты
Видны контактные площадки, к которым подключены шина данных, chip enable, read/write busy, питание и т.п. Разумеется ничего не промаркировано, и даташитов, в которых подробно расписано, что куда подключать, в свободном доступе так же нету. Распиновку можно отыскать либо взяв точно такую же исправную флешку (а их великое множество типов, и найдя такой же по виду условный SD Kingston, можно получить внутри совершенно по другому сделанный девайс) и вооружившись логическим анализатором кропотливо изыскивать что куда и зачем. Либо купив распиновку у человека/конторы, которые такую работу за тебя уже сделали.
Дальше, сверяясь с полученной схемой вывода контактов, под микроскопом монолит распаивается тонкими проводниками на монтажную плату. Работа кропотливая и небыстрая.
В итоге получается нечто такое:
Или такое:
Теперь можно читать дампы. После прочтения, примерно пол-дела считай что сделано.
Теперь в полученных дампах нужно устранить внутренние преобразования. Первым делом убрать маску XOR, которую накладывал при записи информации в ячейки NAND контроллер флешки. С этой маской сектор выглядит так:
а когда нужная маска XOR подобрана и применена, то сектор приобретает осмысленный вид:
После устранения XOR преобразований нужно выставить корректную геометрию сектора, описать маркеры и область ECC корректировки данных. С помощью алгоритма ECC поправить битовые ошибки. Выяснить, в какой последовательности были расположены блоки, их размер. Поскольку тип контроллера неизвестен (это ж монолит!), то надо определить, каким сборщиком пользоваться в данном конкретном случае. Будет ли это сборка финального образа по маркеру сектора или по остаткам таблиц трансляции.
После того, как образ собран, проверить конфликтные блоки, имеющие одинаковый маркер, на актуальность и подставить в образ те, с которыми итоговый результат будет наилучшим. Получив привычный образ с файловой системой можно открыть его в любом дисковом редакторе и выгрузить нужные пользователю файлы.
Безусловно, многие операции достаточно автоматизированы, но тем не менее объем работ при восстановлении данных с монолитов (монокристаллов) весьма велик. Далеко не каждый инженер или компания, восстанавливающая информацию, горит желанием с такими работами связываться. И ценник на такого рода восстановление весьма далёк от понятия «бюджетный».
Вот еще один случай на примере восстановления SD Sandisk — такой же монолит, только внутри чуть по-другому сделан:
Не определяется флешка Sandisk (Сандиск)
Готово для чтения
А вот как выглядят контактные площадки на Micro SD карточке. Сразу нужно оговориться, что это только несколько примеров из множества вариантов компоновки.
Ещё вот такой SD монолит
А вот вариант распиновки монолитной карты памяти Memory Stick Pro Duo
Процесс восстановления монолитной USB флешки
Вот — не сказать что монолит, но и не обычная USB флешка. Микросхема памяти (кристалл) залита компаундом (клеем).
А вот как выглядит монолитная карта памяти Olympus XD Picture card, с которой потребовалось восстановить фотоснимки:
Отдельно стоит упомянуть об успешном выполнении задач по восстановлению информации с MicroSD флешек, сломанных на части, с отломанным куском, с трещинами на корпусе и т.п. Несколько примеров на картинках ниже:
Во всех случаях, когда речь идет о флешке разломанной на куски, с отломанной частью и т.п. есть возможность восстановления информации если остался цел кристалл NAND. Например в микро-флешке Сандиск из примера ниже в результате неаккуратной эксплуатации откололся кусок с повреждением дорожек, отмеченных красным овалом.
Лаборатория «Хардмастер» одна из немногих, имеющих опыт и квалификацию в восстановлении данных с монолитных USB, SD, microSD, Memory Stick и т.п. карт памяти. Если на вашей монолитной поломанной флешке остались важные файлы которые хотелось бы вернуть — обращайтесь к нам!
www.hardmaster.info
SD cards are based on the older Multi Media Card (MMC) format, but most are physically slightly thicker than MMC cards. They also boast higher data transfer rates. DRM features are available but are little-used. SD cards generally measure 32 mm × 24 mm × 2.1 mm, but can be as thin as 1.4 mm, just like MMC cards.
There are different speed grades available. They are referred to with the same nx notation as CD-ROMs; a multiple of 150 kB/s. Devices with SD slots can use the thinner MMC cards, but the standard SD cards will not fit into the thinner MMC slots. MiniSD and MicroSD cards can be used directly in SD slots with an adapter. There are readers which allow SD cards to be accessed via many connectivity ports such as USB, FireWire.
Pin | SD Mode | SPI Mode | ||||
Name | Type | Description | Name | Type | Description | |
1 | CD/DAT3 | I/O/PP | Card detection / Connector data line 3 | CS | I | Chip selection in low status |
2 | CMD | PP | Command/Response line | DI | I | Data input |
3 | Vss1 | S | GND | VSS | S | GND |
4 | Vdd | S | Power supply | VDD | S | Power supply |
5 | CLK | I | Clock | SCLK | I | Clock |
6 | Vss2 | S | GND | VSS2 | S | GND |
7 | DAT0 | I/O/PP | Connector data line 0 | DO | O/PP | Data output |
8 | DAT1 | I/O/PP | Connector data line 1 | RSV | ||
9 | DAT2 | I/O/PP | Connector data line 2 | RSV |
SD cards interface is compatible with standard MMC card operations. All SD memory and SDIO cards are required to support the older SPI/MMC mode which supports the slightly slower four-wire serial interface (clock, serial in, serial out, chip select) that is compatible with SPI ports on many microcontrollers. Many digital cameras, digital audio players, and other portable devices probably use MMC mode exclusively. MMC mode does not provide access to the proprietary encryption features of SD cards, and the free SD documentation does not describe these features. As the SD encryption exists primarily for media producers, it is not of much use to consumers who typically use SD cards to hold unprotected data.
There are three transfer modes supported by SD: SPI mode (separate serial in and serial out), one-bit SD mode (separate command and data channels and a proprietary transfer format), and four-bit SD mode (uses extra pins plus some reassigned pins) to support four bit wide parallel transfers. Low speed cards support 0 to 400 kbit/s data rate and SPI and one-bit SD transfer modes. High speed cards support 0 to 100 Mbit/s data rate in four-bit mode and 0?25 Mbit/s in SPI and one-bit SD modes.
SD cards security features includes:
pinouts.ru
Как-то давно хотел себе сделать логгер температуры, возникла необходимость использовать внешнюю EEPROM память. Прикинув, что в наличие имеется 512кб память с i2c интерфейсом, сделал на ней экспериментальный логгер. Но когда возникла необходимость скинуть данные на компьютер для последующей обработки, то вылезли трудности с написанием софтины, которая бы считывала данные с EEPROM и писала бы их в текстовый файл.
Софтину я написал, только работала она как-то корявенько и медленно, для меня сойдет, а вот для массового производства корявости недопустимы. Захотелось писать данные на карту памяти, которую можно потом вставить в карт-ридер и через проводник перекинуть на компьютер, где их уже можно обрабатывать чем удобно. Для этого нужно уметь собственно писать данные на карту памяти, и знать файловую систему FAT, чтобы карточка распозналась компьютером. С этого вступления хочу начать небольшой цикл из 3-х статей, в котором я напишу про то, как работать с SD/MMC картой памяти и файловой системой FAT.
Карточку SD я выбрал из-за того, что внутри ее есть встроенный контроллер и что с ней можно работать в SPI 0 режиме (положительный синхроимпульс, защёлкивание по переднему фронту, сдвиг по заднему фронту), с которым довольно просто совладать. Посмотрим на распиновку(цоколевку) SD карты:
Видно, что карточка имеет 9 контактов, предназначение их следующее.
При работе с микроконтроллерами режима SPI за глаз хватает по скорости, потому использовать родной режим работы карты памяти будет нецелесообразно. Нам понадобятся пины DI, DO, CLK, CS для передачи данных и VSS, VDD для питания. Теперь немного про питание, SD карта требует от 2,7В до 3,6В, и тока до 100мА. Также если планируется горячее подключения, нужно предусмотреть просадку питающего напряжения при подсоединении карты. Иначе питание может просесть до такого уровня, когда BOD детектор сработает и ресетнет микроконтроллер. Этого можно избежать, налепив по питания конденсаторов и индуктивность. Учитывая все это, была слеплена стендовая платка для работы с SD картой:
Схема платки показана ниже:
Для питания карты памяти предусмотрен стабилизатор на 3,3В — LP2980-3.3. Его обвязка из конденсаторов C1,C3 – 100мкф, танталовые; C2,C4 – 0,1мкф, керамика; L1 – индуктивность на 22мкГн. Для сопряжения TTL уровней сигналов предусмотрены резистивные делители R2-R4 по 5,6кОм; R5-R7 по 10кОм. Светодиод D1 – сигнальный, для него ограничивающий резистор R1 – 470 Ом. Также на разъеме оказались выводы WP и INS, отслеживая состояния которых можно понять, защищена ли карта от записи механической защелкой, и присутствует ли карта в разъеме соответственно. Далее дело за подключением, все сигналы с карты подключил к PortB микроконтроллера. Нежелание использовать аппаратный SPI микроконтроллера буду аргументировать плохой переносимостью кода на разные модели микроконтроллеров. Для работы с SD картой сразу буду использовать ATmega32 (при работе с FAT нам понадобится около 20кб флеша). Хотя можно использовать хоть Atmega8, благо код для этого переделывать не нужно. Схема подключения к микроконтроллеру показана ниже:
Тактовый генератор – встроенный RC на 8Мгц, хотя можно использовать любой, но с 8Мгц работает шустро. Конденсаторы C5,C7 – по 100мкФ, электролиты, С4,С6 – 0,1мкф, керамика. Так как мы будем передавать большие объемы данных (стандартный блок – 512 байт), то выводить их будем по UART на компьютер в программу Terminal 1.9. Про сопряжение UART микроконтроллера с компьютером я писал уже неоднократно вот здесь, здесь и даже здесь.
Теперь у нас есть все железо для экспериментов с картой памяти. Но прежде чем перейти к программной части, упомянем, что карта типа MMC также может работать в SPI режиме. Для ее управления также стоит использовать выводы DI, DO, CLK, CS. Схемотехнические рассуждения для MMC такие же, как и для SD карты. Распиновка MMC карты показана ниже:
Перейдем к программной части. Рассмотрим, как инициализировать карту, и писать/читать из нее. Для перехода в режим SPI нужно дождаться, пока питающее напряжения на карте достигнет 3В (несколько миллисекунд, после включения) и подать более 74 импульса на выводе CLK, при высоком уровне на CS и DI выводах.
После нужно выставить на CS нулевой уровень, далее карта входит в режим SPI, теперь для успешной работы следует подать команды сброса и инициализации CMD0, CMD1 прежде, чем мы сможем писать/читать данные из карты. Команд для карты довольно много, часть из них приведена в таблице ниже:
Команд много, но основанная масса работы производится командами CMD0, CMD1 (сброс и инициализация) CMD17 (чтение), CMD24 (запись). Весь перечень команд и как с ними работать, можно просмотреть в родной спецификации SD карты на английском.
Рассмотрим формат команды для SD карты.
Сперва идет индекс команды. Индекс команды в десятичном виде определяется как 64+имя команды. Далее следует 4 байта аргументов (данные, адрес), после следует 7-ми битная контрольная сумма. После успешной отправки команды следует послать байтовую паузу из 8*N тактовых импульсов (N — целое), после чего карта ответит. Ответ может быть типа R1,R2,R3. В нашем случае, ответы будут только типа R1. Поэтому рассмотрим только его.
Старший бит R1 всегда равен 0. Назначения остальных битов хорошо видно с рисунка.
Рассмотрим процесс инициализации карты памяти командами CMD0,CMD1. Сперва, при высоком уровне на выводах CS и DI подаем 80 тактовых импульсов на вывод CLK. Далее на все время работы с картой сажаем CS на землю, подаем команду CMD0, контрольная сумма для которой равнa 0x95 (контрольная сумма в нашем случае нужна только для команды CMD0, в остальных случаях она не проверяется, поэтому все время будем использовать 0х95 как контрольную сумму). Далее, после байтовой паузы, карточка должна ответить 0х01, что означает, что она вошла в SPI режим и готова принимать команды. Теперь подаем команды CMD1, и после паузы ожидаем от карточки ответа 0х00, которые говорит о том, что карта готова к обмену данными.
Обмен данными между картой памяти и микроконтроллером будет производиться стандартными блоками по 512 байт. Адресация карты побайтная, начиная с нуля, но считывать данные можно только блоками. Адресом блока служит первый его байт. То есть 0-й блок имеет адрес 0х0000, 1-й блок — 0х0200, 2-й блок – 0х400 и т.д. (справедливо для размера блока 512 байт). В SDHC картах адресация поблочная, адресом блока служит его номер. Операция чтения блока производится в следующем порядке. Подается команда CMD17, байтовая пауза, если принимается ответ 0х00, то после еще одной байтовой паузы принимается блок данных, структура которого показана ниже.
Некое подобие временной диаграммы операции чтения можно посмотреть на рисунке ниже
Как видно, блок начинается с байта 0хFE (для команд CMD17/18, CMD24), далее идет 512 байт информации и 2 байта контрольной суммы (которая по умолчанию не используется). Операция записи производиться похоже, команда CMD24, пауза, ответ карты 0х00, и блок данных (так как контрольная сумма не проверяется, то ее поле можно заполнить случайно ). Далее следует ответ карты про прием блока данных.
После чего busy состояние, когда карта записывает полученные данные. Временная диаграмма операции записи приведена ниже.
Для подтверждения вышесказанного хочу привести пример работы с картой. Запишем в блок под номером 1 (адрес 0х0200) какие-то циклически повторяющиеся данные, например чередующиеся цифры от 0 до 9, а потом считаем этот же блок и посмотрим, записались ли наши данные. Для этого была написана небольшая программка :
#include <avr/io.h> //Cтандартная библиотека ввода/вывода
#include <string.h> //Библиотека для работы с строками
#define DI 0
#define DO 1
#define CLK 2
#define CS 3
#define INS 4
#define WP 5
char buffer [512]={}; //Буфер данных для записи/чтения
//Программа инициализации UART
void uart_init(void)
{
UBRRH = 0x00; //256000 битрейт, 1 стоп бит, без проверки четности
UBRRL = 0x01;
UCSRA = 0x00;
UCSRB = (1<<RXEN)|(1<<TXEN); //Прием и передача разрешена
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
}
//Программа передачи байта по UART
void uart_transmit(unsigned char data)
{
while ( !( UCSRA & (1<<UDRE)) );
UDR = data;
}
//Программа приема байта по UART
unsigned char uart_receive (void)
{
while ( !(UCSRA & (1<<RXC)) );
return UDR;
}
//Программа передачи строки по UART
void uart_transmit_message(char* msg)
{ unsigned char i;
i=0; //Начальное значение переменной
//Цикл до перебора всех элементов строки
while ((i<256)&(msg[i]!=0x00) )
{
//Отправка поэлементно символов строки
uart_transmit(msg[i]);
i++; //Увеличиваем номер элемента строки
}
}
//Программа передачи байта карте SD|MMC
void spi_transmit (unsigned char data)
{
unsigned char i;
for (i=0;i<8;i++) //Цикл перебора битов отправляемого байта
{
if ((data&0x80)==0x00) //Если все данные переданы
PORTB&=~_BV(DI); //Выставить бит данных
else
PORTB|=_BV(DI);
data=data<<1;
PORTB|=_BV(CLK); //Импульс
asm("nop"); //Пауза в 1 такт
PORTB&=~_BV(CLK);
}
}
//Программа приема байт от карты SD|MMC
unsigned char spi_receive (void)
{
//Декларация переменных
unsigned char i, res=0;
for(i=0;i<8;i++)
{
PORTB|=_BV(CLK); //Фронт импульса
res=res<<1;
if ((PINB&_BV(DO))!=0x00)
res=res|0x01; //Считать бит данных
PORTB&=~_BV(CLK); //Спад испульса
asm("nop");
}
return res;
}
unsigned char sd_cmd(char b0, char b1, char b2, char b3, char b4, char b5)
//Отправка команды карте SD|MMC
{ unsigned char res;
long int count;
spi_transmit (b0); //Передать индекс команды
spi_transmit (b1); //Передать аргумент
spi_transmit (b2);
spi_transmit (b3);
spi_transmit (b4);
spi_transmit (b5); //Передать CRC
count=0;
do { //Подождпть R1 ответа
res=spi_receive();
count=count+1;
} while ( ((res&0x80)!=0x00)&&(count<0xffff) );
return res;
}
unsigned char sd_card_init(void)
{ unsigned char i,temp;
long int count;
if ((PINB&_BV(INS))!=0x00) return 1; //Проверка карты в слоту
for (i=0;i<10;i++) //80 импульсов
spi_transmit (0xff);
PORTB&=~_BV(CS); //CS опустить
temp=sd_cmd (0x40,0x00,0x00,0x00,0x00,0x95); //CMD0
if (temp!=0x01) return 3; //Выйти, если ответ не 0х01
spi_transmit (0xff);
count=0;
do{
temp=sd_cmd (0x41,0x00,0x00,0x00,0x00,0x95); //CMD1
spi_transmit (0xff);
count=count+1;
} while ( (temp!=0x00)&&(count<0xffff) ); //Ждем 0x01 ответа R1
if (count>=0xffff) return 4;
return 0;
}
unsigned char read_block (char* buff, unsigned char a1, unsigned char a2, unsigned char a3, unsigned char a4)
{ unsigned char temp;
long int count;
if ((PINB&_BV(INS))!=0x00) return 1; //Проверка карты в слоту
temp=sd_cmd (0x51,a1,a2,a3,a4,0x95); //CMD17
if (temp!=0x00) return 5; //Выйти, если ответ не 0x00
spi_transmit (0xff);
count=0;
do{ //Ждем начала пакета данных
temp=spi_receive();
count=count+1;
} while ( (temp!=0xfe)&&(count<0xffff) );
if (count>=0xffff) return 5;
for (count=0;count<512;count=count+1) //Сохраняем данные
buff[count]=spi_receive();
spi_receive(); //Сохраняем CRC
spi_receive();
return 0;
}
unsigned char write_block (char* buff, unsigned char a1, unsigned char a2, unsigned char a3, unsigned char a4)
{ unsigned char temp;
long int count;
if ((PINB&_BV(INS))!=0x00) return 1; //Проверка карты в слоту
if ((PINB&_BV(WP))!=0x00) return 2; //Проверка write protect
temp=sd_cmd(0x58,a1,a2,a3,a4,0x95); //CMD24
if (temp!=0x00) return 6; //Выйти, если ответ не 0x00
spi_transmit (0xff);
spi_transmit (0xfe); //Начало пакета данных
for (count=0;count<512;count=count+1) //Отослать данные
spi_transmit(buff[count]);
spi_transmit (0xff); //Отослать CRC
spi_transmit (0xff);
temp=spi_receive();
if ((temp&0x05)!=0x05) return 6; //Выйти, если данные не приняты
count=0;
do { //Ждем окончания busy состояния
temp=spi_receive();
count=count+1;
}while ( (temp!=0xff)&&(count<0xffff) );
if (count>=0xffff) return 6;
return 0;
}
int main(void)
{ unsigned char temp;
int i;
PORTB=_BV(CS)|_BV(DO)|_BV(DI)|_BV(WP)|_BV(INS); //Инициализация портов
DDRB=_BV(CS)|_BV(DI)|_BV(CLK);
uart_init(); //Инициализация UART
temp=sd_card_init(); //Инициализация карты
if (temp==0x00)
{
uart_transmit_message("sd_card_init: initialization succes\r\n");
for (i=0;i<512;i=i+1)
buffer[i]=0x30+(i%10); //Заполнить буфер 12345...
temp=write_block(buffer,0x00,0x00,0x02,0x00);//Записать буфер
if(temp==0x00) uart_transmit_message("write_block: block writte succes\r\n");
else if (temp==1) uart_transmit_message("write_block: fail, no card in the slot\r\n");
else if (temp==2) uart_transmit_message("write_block: fail, card write protected\r\n");
else uart_transmit_message("read_block: CMD24 fail\r\n");
temp=read_block(buffer,0x00,0x00,0x02,0x00); //Считать буфер
if(temp==0x00) {
uart_transmit_message("read_block: data block read succes:\r\n");
for (i=0;i<512;i=i+1) //Выслать буфер по UART
uart_transmit(buffer[i]);
}
else if (temp==0x01) uart_transmit_message("read_block: fail, no card in the slot\r\n");
else uart_transmit_message("read_block: CMD17 fail\r\n");
}
else if (temp==0x01) uart_transmit_message("sd_card_init: fail, no card in the slot\r\n");
else if (temp==0x03) uart_transmit_message("sd_card_init: CMD0 fail\r\n");
else uart_transmit_message("sd_card_init: CMD1 fail\r\n");
while (1);
return 1;
}
b0 – индекс команды, b1-b4 – аргумент команды, b5 – контрольная сумма, функция возвращает ответ R1 от карточки. Пользовательские функции: unsigned char sd_card_init(void) служит для инициализации карты командами CMD0, CMD1, при успешном выполнении возвращает результат 0х00. Функции unsigned char read_block (char* buff, unsigned char a1, unsigned char a2, unsigned char a3, unsigned char a4) и unsigned char write_block (char* buff, unsigned char a1, unsigned char a2, unsigned char a3, unsigned char a4) служат для чтения/записи блока, на который указывает buff, по адресу a1-a4, в случае выполнения возвращают 0х00. Во всех пользовательских функция предусмотрена проверка наличия карты в слоте и режима Write Protect, который устанавливается механическим ползунком на самой карте памяти.
При внутрисхемном программировании следует вынимать карту из слота, иначе программатор не сможет залить прошивку в микроконтроллер (сигналы WP, INS при вставленной карте садят на землю выводы нужные для внутрисхемного программирования). Выполнение приведенной выше программы приведет к тому, что целостность файловой системы (существовавшей до этого на карточке) будет нарушена, так что перед экспериментами не забудьте скопировать с карточки всю важную информацию.
Вот что я увидел в Terminal 1.9 при запуске программы:
Решил перепроверить с помощью утилиты WinHex содержание первого блока карты памяти:
Результаты совпадают. Запись чтение удалось. Теперь смело можно писать/читать данные на карту. Про то, как писать данные в файлы и про файловую систему FAT я напишу чуть позже.
Cледующая статья цикла: «SD/MMC карта памяти и микроконтроллер AVR (часть 2) Система FAT, Petit FatFs.»
Последняя стать цикла: «SD/MMC карта памяти и микроконтроллер AVR (часть 3) Система FAT, FatFs.»
Код программы в формате проекта для AVR Studio 4.
Разводка печатной платы в формате .lay для программы Sprint Layout 5
avrlab.com
Напряжение питания 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 карты к микроконтроллеру, но для защиты от дурака можно добавить аналогичный делитель напряжения и туда, на функционировании схемы это не скажется.
Резистивный делитель напряжения — это самый простой вариант согласования уровней, однако при высоких скоростях обмена или длинных проводах он может не подойти. Емкость входов SD карты, а также паразитная емкость линий, вместе с резисторами делителя образует RC фильтры, которые «заваливают» фронты передаваемых сигналов, а у SD карт есть определенные требования к этим фронтам.
Если использовать для согласования уровней буферную микросхему, например CD4050 или 74AHC125, этих недостатков можно избежать. Ниже приведена схема, в которой согласование уровней выполняется с помощью микросхемы 4050. Это микросхема представляет собой 6 неинвертирующих буферов. Неиспользуемые буферы микросхемы «заглушены».
Подключение microSD карт аналогичное, только у них немного отличается нумерация контактов. Приведу только одну схему.
На схемах я рассматривал подключение SD карт к микроконтроллеру напрямую — без разъемов. На практике, конечно, без них не обойтись. Существует несколько типов разъемов и они друг от друга немного отличаются. Как правило, выводы разъемов повторяют выводы SD карты и также содержать несколько дополнительных — два вывода для обнаружения карты в разъеме и два вывода для определения блокировки записи. Электрически эти выводы с SD картой никак не связаны и их можно не подключать. Однако, если они нужны, их можно подключить как обычную тактовую кнопку — один вывод на землю, другой через резистор к плюсу питания. Или вместо внешнего резистора использовать подтягивающий резистор микроконтроллера.
t-31.ru
Я постараюсь вкратце расписать, как использовать эту карту для хранения и считывания информации с помощью SPI. О том как работать с SPI расписано здесь.
Рис.1 SD карты различных размеров |
Рис.2 различные типы размеров SD карт с замерами |
Рис.3 Распиновка различных карт памяти |
MMC | SD | miniSD | microSD | Имя | Вход/Выход | Описание |
---|---|---|---|---|---|---|
1 | 1 | 1 | 2 | nCS | Вх | Выбор режима SPI (негативная логика) |
2 | 2 | 2 | 3 | DI | Вх | Ввод данных SPI [MOSI] |
3 | 3 | 3 | VSS | . | Земля | |
4 | 4 | 4 | 4 | VDD | . | Питание |
5 | 5 | 5 | 5 | CLK | Вх | тактовый сигнал [SCLK] |
6 | 6 | 6 | 6 | VSS | . | Земля |
7 | 7 | 7 | 7 | DO | Вых | Вывод данных SPI [MISO] |
8 | 8 | 8 | NC | . | Не используется | |
9 | 9 | 1 | NC | . | Не используется | |
10 | NC | . | Зарезервировано | |||
11 | NC | . | Зарезервировано |
В сети есть несколько открытых библиотек для работы с FAT (16/32), к примеру: FatFs, в таком случае можно считывать данные с компьютера, проверяются повреждённые блоки, память и ресурсы карты расходуются разумнее, ведь файловая система используется не просто так.
Но если всё это не так важно, можно не много памяти, которые выглядят как простой набор бит, то можно обойтись и без файловой системы, напрямую считывая и записывая данные. Только нужно помнить, что в SD картах информация хранится в блоках по 512 байт. Нужно считывать и записывать информацию блоками.
Можно создать текстовый документ, записать в него нужную информацию, открыть SD карту с помощью Hex-редактора, (к примеру: HxD) посмотреть в каком блоке (кластере) находится информация, (может быть она записана в нескольких блоках) считать её.
Считать байт можно и без файловой системы и специальных библиотек, но скорей всего нельзя записать информацию не повредив файловую систему, после неправильной записи компьютер может не распознать SD карту и предложит её отформатировать.
Можно попробовать создать текстовый документ на компьютере, записать в него что-то, затем найти блок с этой информацией и менять его. Не знаю какие в файловой системе реализован проверки, возможно нельзя изменить хранящиеся данные (там могут быть контрольные суммы для проверки).
SPI используется всего лишь как интерфейс, данные передаются по «урезанной» версии стандартного протокола SD карты.
Рис.4 Считывание 1 блока данных (512 байт) |
Рис.5 Формат команды |
Response — это ответ карты на команду, если он есть (есть команды без ответа), то он может быть 1 из 4 видов (R1, R2, R3, R6):
Рис.6 Формат ответа |
Data block — это 512 байт данных, которые мы хотели считать, после них идёт контрольная сумма (CRC) для проверки содержимого.
Команды
Индекс команды | Аргумент | Ответ | Описание |
---|---|---|---|
CMD0 | [31:0] мусор | R1 | Перезагрузка карты памяти |
CMD1 | [31] Зарезервировано [30] HCS [29:0] Зарезервировано | R1 | Карта отправляет хосту информацию о ёмкости и включает процесс инициализации. HCS работает после команды CMD8. Если хост поддерживает карты SDHC и SDXC выставить «1», иначе «0». Зарезервированные биты должны быть выставлены в ‘0’. |
CMD6 | [31] Режим 0:Проверить функцию 1:Изменить функцию [30:8] Зарезервировано (все ‘0’) [7:4] функциональная группа 2 для системных команд [3:0] функциональная группа 2 для режима доступа | R1 | Смотреть в даташите. |
CMD8 | [31:12] Зарезервировано (все ‘0’) [11:8] Напряжение питания (VHS) [7:0] проверочный образец | R7 | Отправляет карте напряжение питания и спрашивает может ли она работать при таком питании. |
CMD9 | [31:0] мусор | R1 | Спрашивает у карты её информацию «о карте» (CSD) . |
CMD10 | [31:0] мусор | R1 | Спрашивает у карты её ID (CID). |
CMD12 | [31:0] мусор | R1b | Заставляет карту прекратить передавать данные в режиме считывания нескольких блоков. |
CMD13 | [31:0] мусор | R2 | Просит карту отправить её статус. |
CMD16 | [31:0] Длина блока | R1 | Для карт SDSC, длина блока выставляется этой командой. Для SDHC и SDXC карт, длина блока фиксирована и равна 512 байт. Длина команды CMD42 выставляется этой командой. |
CMD17 | [31:0] адрес данных | R1 | Считывает блок размером выставленным командой CMD16. |
CMD18 | [31:0] адрес данных | R1 | Передача блоков данных из карты хосту до тех пор, пока хост не отправит команду CMD12. |
CMD24 | [31:0] адрес данных | R1 | Записывает блок данных размером выставленным командой CMD16. |
CMD25 | [31:0] адрес данных | R1 | Непрерывно записывает блоки данных до тех пор пока карта не отправит байт «stop tran» |
CMD27 | [31:0] мусор | R1 | Программирует биты регистра CSD. |
CMD28 | [31:0] адрес данных | R1b | Если у карты есть функции защиты от записи, эта команда выставляет бит защиты для выбранной адресной группы,\. Свойства защиты от записи прописаны в данных карты (WP_GRP_SIZE). SDHC и SDXC карты не поддерживают эту команду. |
CMD29 | [31:0] адрес данных | R1b | Если у карты есть функции защиты от записи, эта команда очищает бит защиты выбранной адресной группы. SDHC и SDXC карты не поддерживают эту команду. |
CMD30 | [31:0] адрес для защиты от записи | R1 | Если у карты есть функции защиты от записи, эта команда просит карту отправить бит защиты выбранной адресной группы. SDHC и SDXC карты не поддерживают эту команду. |
CMD32 | [31:0] адрес данных | R1 | Выставляет адрес первого блока, который нужно стереть. |
CMD33 | [31:0] адрес данных | R1 | Выставляет адрес последнего блока, который нужно стереть. |
CMD38 | [31:0] мусор | R1b | очистка всех блоков от первого до последнего выбранных предыдущими командами. |
CMD42 | [31:0] Зарезервировано (все ‘0’) | R1 | Используется для выставления/сброса пароля или блокировки/разблокировки карты. Размер блока определяется командой CMD16. |
CMD55 | [31:0] мусор | R1 | Сообщает карте что следующая команда, это команда особого назначения. |
CMD56 | [31:1] мусор [0]: RD/WR | R1 | Используется для записи или считывания блока данных для стандартных или дополнительных команд. В случае SDSC карт, размер блока определяется командой CMD16. Для SDHC и SDXC карт длина блока фиксирована и равна 512 байт. |
CMD58 | [31:0] мусор | R3 | Считывает регистр OCR. CCS бит, выставлен в OCR[30]. |
CMD59 | [31:1] мусор [0:0] CRC настройка | R1 | Включает «1» или выключает «0» CRC. |
CRC
В SD картах используются CRC7 и CRC16 проверки, 16 редко используется, но смысл там тот же что и в 7, так что рассмотрим её, если нет желания возиться с CRC кодами их можно отключить командой CMD59.
В алгоритме используется что-то похожее на деление многочленов столбиком. Нам нужно взять содержимое посылки и бит определяющий от кого идёт передача (хост- карта или наоборот), у нас есть двоичное число из 39 бит, это число сдвигаем влево 7 раз (дописываем 7 нулей справа), т.к. CRC7. В различных версиях CRC нужно сдвигать на разное число бит. Теперь у нас есть число из 46 бит, его нужно разделить (по правилам двоичной арифметики) на полином данной CRC версии. У CRC это x^7 + x^3 + 1. В двоичном коде — «10001001». Полученный после деления остаток и будет нашим CRC7 кодом, который нужно передать вместе с сообщением.
Для того чтобы проверить результат нельзя использовать стандартный калькулятор Windows. Если перевести в десятичный код, то он даёт правильный ответ, но это не по правилам двоичной арифметики. Для проверки можно использовать, к примеру, этот калькулятор.
Подсчитаем CRC код для команды CMD0:
Согласно даташиту именно такой CRC код у команды CMD0.
На самом деле деление затратно выполнять в цифровых устройствах, но в данном случае его легко реализовать как программно, так и аппаратно, при делении с остатком нужно реализовать лишь сдвиги и логическую операцию XOR, что выполняется быстро и не занимает много места.
Нам нужно записать наше число, сдвинуть его на 7 разрядов влево, затем сдвинуть наш полином таким образом, чтобы его крайняя левая «1» была под крайней левой «1» нашего большого числа. Затем произвести между двумя числами XOR (если разные значения в 1 разряде выставить 1, иначе 0). С полученным числом проделать то же самое (сдвинуть под крайнюю единицу полином, XOR) до тех пор пока у изначального числа (пока мы его не сдвигали влево на 7 разрядов) не будут все 0, иначе до тех пор пока биты [max : 8] не будут равны «0». Оставшиеся 7 бит и есть наш остаток.
Рассмотрим это на примере:
CRC-7 полином = [1 0 0 0 1 0 0 1]
Сообщение (после сдвига на 7 разрядов) = [1 1 0 0 0 0 0 1] [1 0 0 0 0 0 0 0] 0 0 0 0 0 0 0
Рис.7 Подсчёт остатка |
Можно найти готовый код для подсчёта CRC7 значений, есть довольно много реализаций, к примеру: вот и вот.
Ответы «Responce»
Чаще всего используется ответ R1, он состоит из 8 бит, старший бит всегда выставлен в «0». Ошибка обозначается «1» в соответствующем бите. Структура R1 выглядит следующим образом:
Рис.8 Формат ответа R1 |
В ответ на CMD13, карта отправляет R2, в дополнении к ошибкам в R1 здесь добавлено несколько новых:
Рис.9 Формат ответа R2 |
Формат R7 используется когда мы меняем напряжение, но SPI может работать только при 3.3 В. В отличие от SD интерфейса, так что R7 можно не рассматривать.
При работе с блоками данных используются особые «маркеры» (token) для сообщении о ходе передачи данных.
Рис.10 Запись нескольких блоков в карту |
Рис.11 Маркер записи блока данных |
Рис.12 Маркер начала записи/считывания 1 блока, считывания нескольких блоков |
Рис.13 Маркер начала записи нескольких блоков |
Рис.14 Маркер обозначающий конец записи. |
Если карта не сможет прочитать блок данных, она отправит маркер ошибки, там обозначены те же биты, что и в R2:
Рис.15 Маркер ошибки считывания. |
Внутренние регистры
Регистр OCR отвечает за доступные режимы питания карты:
Рис.16 Содержимое регистра OCR. |
Регистр CID хранит информацию от производителя:
Рис.17 Содержимое регистра OCR |
У карты больше регистров, но они не доступны в режиме SPI.
Популярная библиотека FatFs. Также у них есть версия меньшего размера для 8 битных МК Petit FAT.
Источники:
en.wikipedia.org
ru.wikipedia.org
sdcard.org — Документация
my-cool-projects.blogspot.com — CRC7
users.ece.cmu.edu/~koopman — CRC7
www.pololu.com — CRC7
4a4ik.blogspot.com