8-900-374-94-44
[email protected]
Slide Image
Меню

Распиновка карты сд – Работа с SD картой. Подключение к микроконтроллеру. Ч1

Работа с SD картой. Подключение к микроконтроллеру. Ч1

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

Всем доброго дня! Сегодня мы поговорим о подключении карты памяти SD к микроконтроллеру STM32.

Казалось бы, памяти полно у контроллеров STM32F10x, зачем там еще дополнительная, но это впечатление обманчиво ) Вот, например, надо нам на дисплей вывести пару-тройку разных изображений – формат 320*240 – то есть 76800 пикселей, каждому из которых соответствует целых 2 байта. Вот и получаем около 150 кБ на одну картинку. А это немало по меркам микроконтроллера, и не факт, что две разные картинки удастся запихать в его Flash память. Или надо нам хранить большие объемы информации, данные с какого-нибудь датчика, к примеру. Да еще так, чтобы эти данные были доступны и после отключения питания. Вот тут то нам и пригодится внешняя память. И отличным решением будет

SD карта памяти или MMC. К слову в этой статье мы будем проводить опыты над картой micro SD.

Для начала пара слов о самой карте памяти, точнее о ее распиновке. Выглядит все это дело следующим образом:


Итак, что тут у нас? Ну сразу видно, что выводов у нее целых восемь штук. Назначение выводов следующее (слева направо):


Колонка 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 и MicroSD карт

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

Восстановление монолитных SD карт памяти

Примечательно, что внешне не понять, — это "классическая" SD карточка, с платой текстолита, NAND памятью и контроллером, или монокристалл. До тех пор, пока не вскроется пластиковый корпус. Чаще всего выход таких карт памяти из строя обусловлен сбоем в таблицах трансляции. Реже — электромеханическими повреждениями.

Для восстановления файлов с такой карточки первым делом надо вычитать дампы с кристалла. Для этого механическим (очисткой и шлифованием) путем удаляется защитный лак, скрывающий дорожки и контактные площадки монолита. После чего флешка начинает выглядеть так:

Дорожки и распиновка монолитной SD карты

Видны контактные площадки, к которым подключены шина данных, chip enable, read/write busy, питание и т.п. Разумеется ничего не промаркировано, и даташитов, в которых подробно расписано, что куда подключать, в свободном доступе так же нету. Распиновку можно отыскать либо взяв точно такую же исправную флешку (а их великое множество типов, и найдя такой же по виду условный SD Kingston, можно получить внутри совершенно по другому сделанный девайс) и вооружившись логическим анализатором кропотливо изыскивать что куда и зачем. Либо купив распиновку у человека/конторы, которые такую работу за тебя уже сделали.

Дальше, сверяясь с полученной схемой вывода контактов, под микроскопом монолит распаивается тонкими проводниками на монтажную плату. Работа кропотливая и небыстрая.

В итоге получается нечто такое:

Или такое:

Теперь можно читать дампы. После прочтения, примерно пол-дела считай что сделано.

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

а когда нужная маска XOR подобрана и применена, то сектор приобретает осмысленный вид:

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

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

Безусловно, многие операции достаточно автоматизированы, но тем не менее объем работ при восстановлении данных с монолитов (монокристаллов) весьма велик. Далеко не каждый инженер или компания, восстанавливающая информацию, горит желанием с такими работами связываться. И ценник на такого рода восстановление весьма далёк от понятия "бюджетный".

Вот еще один случай на примере восстановления SD Sandisk — такой же монолит, только внутри чуть по-другому сделан:

Не определяется флешка Sandisk (Сандиск)

Готово для чтения

Восстановление MicroSD флешек

А вот как выглядят контактные площадки на Micro SD карточке. Сразу нужно оговориться, что это только несколько примеров из множества вариантов компоновки.

Ещё вот такой SD монолит

А вот вариант распиновки монолитной карты памяти Memory Stick Pro Duo

Процесс восстановления монолитной USB флешки

Вот — не сказать что монолит, но и не обычная USB флешка. Микросхема памяти (кристалл) залита компаундом (клеем).

А вот как выглядит монолитная карта памяти Olympus XD Picture card, с которой потребовалось восстановить фотоснимки:

Восстановление поломанных Микро СД

Отдельно стоит упомянуть об успешном выполнении задач по восстановлению информации с MicroSD флешек, сломанных на части, с отломанным куском, с трещинами на корпусе и т.п. Несколько примеров на картинках ниже:

Во всех случаях, когда речь идет о флешке разломанной на куски, с отломанной частью и т.п. есть возможность восстановления информации если остался цел кристалл NAND. Например в микро-флешке Сандиск из примера ниже в результате неаккуратной эксплуатации откололся кусок с повреждением дорожек, отмеченных красным овалом.

Лаборатория "Хардмастер" одна из немногих, имеющих опыт и квалификацию в восстановлении данных с монолитных USB, SD, microSD, Memory Stick и т.п. карт памяти. Если на вашей монолитной поломанной флешке остались важные файлы которые хотелось бы вернуть — обращайтесь к нам!

www.hardmaster.info

Secure Digital (SD) card распиновка и описание @ pinouts.ru

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:

  • Copyright protection mechanism with the SDMI standard (Secure Digital Music Initiative)
  • Integrated CPRM file protection and encryption system (CPRM is a Content Protection for Recordable Media)

pinouts.ru

SD/MMC карта памяти и микроконтроллер AVR (часть 1) Базовые операции.

Как-то давно хотел себе сделать логгер температуры, возникла необходимость использовать внешнюю 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, а потом считаем этот же блок и посмотрим, записались ли наши данные. Для этого была написана небольшая программка :

  1. #include <avr/io.h> //Cтандартная библиотека ввода/вывода

  2. #include <string.h> //Библиотека для работы с строками

  3.  

  4. #define DI 0

  5. #define DO 1

  6. #define CLK 2

  7. #define CS 3

  8. #define INS 4

  9. #define WP 5

  10.  

  11. char buffer [512]={}; //Буфер данных для записи/чтения

  12.  

  13. //Программа инициализации UART

  14. void uart_init(void)

  15. {

  16. UBRRH = 0x00; //256000 битрейт, 1 стоп бит, без проверки четности

  17. UBRRL = 0x01;

  18. UCSRA = 0x00;

  19. UCSRB = (1<<RXEN)|(1<<TXEN); //Прием и передача разрешена

  20. UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);

  21. }

  22.  

  23. //Программа передачи байта по UART

  24. void uart_transmit(unsigned char data)

  25. {

  26. while ( !( UCSRA & (1<<UDRE)) );

  27. UDR = data;

  28. }

  29.  

  30. //Программа приема байта по UART

  31. unsigned char uart_receive (void)

  32. {

  33. while ( !(UCSRA & (1<<RXC)) );

  34. return UDR;

  35. }

  36.  

  37. //Программа передачи строки по UART

  38. void uart_transmit_message(char* msg)

  39. { unsigned char i;

  40. i=0; //Начальное значение переменной

  41.  

  42. //Цикл до перебора всех элементов строки

  43. while ((i<256)&(msg[i]!=0x00) )

  44. {

  45. //Отправка поэлементно символов строки

  46. uart_transmit(msg[i]);

  47. i++; //Увеличиваем номер элемента строки

  48. }

  49. }

  50.  

  51. //Программа передачи байта карте SD|MMC

  52. void spi_transmit (unsigned char data)

  53. {

  54. unsigned char i;

  55. for (i=0;i<8;i++) //Цикл перебора битов отправляемого байта

  56. {

  57. if ((data&0x80)==0x00) //Если все данные переданы

  58. PORTB&=~_BV(DI); //Выставить бит данных

  59. else

  60. PORTB|=_BV(DI);

  61. data=data<<1;

  62. PORTB|=_BV(CLK); //Импульс

  63. asm("nop"); //Пауза в 1 такт

  64. PORTB&=~_BV(CLK);

  65. }

  66. }

  67.  

  68. //Программа приема байт от карты SD|MMC

  69. unsigned char spi_receive (void)

  70.  

  71. {

  72. //Декларация переменных

  73. unsigned char i, res=0;

  74. for(i=0;i<8;i++)

  75. {

  76. PORTB|=_BV(CLK); //Фронт импульса

  77. res=res<<1;

  78. if ((PINB&_BV(DO))!=0x00)

  79. res=res|0x01; //Считать бит данных

  80. PORTB&=~_BV(CLK); //Спад испульса

  81. asm("nop");

  82. }

  83. return res;

  84. }

  85.  

  86. unsigned char sd_cmd(char b0, char b1, char b2, char b3, char b4, char b5)

  87. //Отправка команды карте SD|MMC

  88. { unsigned char res;

  89. long int count;

  90. spi_transmit (b0); //Передать индекс команды

  91.  

  92. spi_transmit (b1); //Передать аргумент

  93. spi_transmit (b2);

  94. spi_transmit (b3);

  95. spi_transmit (b4);

  96.  

  97. spi_transmit (b5); //Передать CRC

  98. count=0;

  99. do { //Подождпть R1 ответа

  100. res=spi_receive();

  101. count=count+1;

  102. } while ( ((res&0x80)!=0x00)&&(count<0xffff) );

  103. return res;

  104. }

  105.  

  106. unsigned char sd_card_init(void)

  107. { unsigned char i,temp;

  108. long int count;

  109.  

  110. if ((PINB&_BV(INS))!=0x00) return 1; //Проверка карты в слоту

  111.  

  112. for (i=0;i<10;i++) //80 импульсов

  113. spi_transmit (0xff);

  114. PORTB&=~_BV(CS); //CS опустить

  115.  

  116. temp=sd_cmd (0x40,0x00,0x00,0x00,0x00,0x95); //CMD0

  117. if (temp!=0x01) return 3; //Выйти, если ответ не 0х01

  118. spi_transmit (0xff);

  119.  

  120. count=0;

  121. do{

  122. temp=sd_cmd (0x41,0x00,0x00,0x00,0x00,0x95); //CMD1

  123. spi_transmit (0xff);

  124. count=count+1;

  125. } while ( (temp!=0x00)&&(count<0xffff) ); //Ждем 0x01 ответа R1

  126.  

  127. if (count>=0xffff) return 4;

  128. return 0;

  129. }

  130.  

  131. unsigned char read_block (char* buff, unsigned char a1, unsigned char a2, unsigned char a3, unsigned char a4)

  132. { unsigned char temp;

  133. long int count;

  134.  

  135. if ((PINB&_BV(INS))!=0x00) return 1; //Проверка карты в слоту

  136.  

  137. temp=sd_cmd (0x51,a1,a2,a3,a4,0x95); //CMD17

  138. if (temp!=0x00) return 5; //Выйти, если ответ не 0x00

  139. spi_transmit (0xff);

  140. count=0;

  141. do{ //Ждем начала пакета данных

  142. temp=spi_receive();

  143. count=count+1;

  144. } while ( (temp!=0xfe)&&(count<0xffff) );

  145.  

  146. if (count>=0xffff) return 5;

  147.  

  148. for (count=0;count<512;count=count+1) //Сохраняем данные

  149. buff[count]=spi_receive();

  150. spi_receive(); //Сохраняем CRC

  151. spi_receive();

  152. return 0;

  153. }

  154.  

  155. unsigned char write_block (char* buff, unsigned char a1, unsigned char a2, unsigned char a3, unsigned char a4)

  156. { unsigned char temp;

  157. long int count;

  158.  

  159. if ((PINB&_BV(INS))!=0x00) return 1; //Проверка карты в слоту

  160. if ((PINB&_BV(WP))!=0x00) return 2; //Проверка write protect

  161.  

  162. temp=sd_cmd(0x58,a1,a2,a3,a4,0x95); //CMD24

  163. if (temp!=0x00) return 6; //Выйти, если ответ не 0x00

  164. spi_transmit (0xff);

  165.  

  166. spi_transmit (0xfe); //Начало пакета данных

  167. for (count=0;count<512;count=count+1) //Отослать данные

  168. spi_transmit(buff[count]);

  169. spi_transmit (0xff); //Отослать CRC

  170. spi_transmit (0xff);

  171. temp=spi_receive();

  172. if ((temp&0x05)!=0x05) return 6; //Выйти, если данные не приняты

  173.  

  174. count=0;

  175. do { //Ждем окончания busy состояния

  176. temp=spi_receive();

  177. count=count+1;

  178. }while ( (temp!=0xff)&&(count<0xffff) );

  179. if (count>=0xffff) return 6;

  180. return 0;

  181. }

  182.  

  183. int main(void)

  184. { unsigned char temp;

  185. int i;

  186.  

  187. PORTB=_BV(CS)|_BV(DO)|_BV(DI)|_BV(WP)|_BV(INS); //Инициализация портов

  188. DDRB=_BV(CS)|_BV(DI)|_BV(CLK);

  189.  

  190. uart_init(); //Инициализация UART

  191.  

  192. temp=sd_card_init(); //Инициализация карты

  193. if (temp==0x00)

  194. {

  195. uart_transmit_message("sd_card_init: initialization succes\r\n");

  196. for (i=0;i<512;i=i+1)

  197. buffer[i]=0x30+(i%10); //Заполнить буфер 12345...

  198.  

  199. temp=write_block(buffer,0x00,0x00,0x02,0x00);//Записать буфер

  200. if(temp==0x00) uart_transmit_message("write_block: block writte succes\r\n");

  201. else if (temp==1) uart_transmit_message("write_block: fail, no card in the slot\r\n");

  202. else if (temp==2) uart_transmit_message("write_block: fail, card write protected\r\n");

  203. else uart_transmit_message("read_block: CMD24 fail\r\n");

  204. temp=read_block(buffer,0x00,0x00,0x02,0x00); //Считать буфер

  205. if(temp==0x00) {

  206. uart_transmit_message("read_block: data block read succes:\r\n");

  207. for (i=0;i<512;i=i+1) //Выслать буфер по UART

  208. uart_transmit(buffer[i]);

  209. }

  210. else if (temp==0x01) uart_transmit_message("read_block: fail, no card in the slot\r\n");

  211. else uart_transmit_message("read_block: CMD17 fail\r\n");

  212. }

  213. else if (temp==0x01) uart_transmit_message("sd_card_init: fail, no card in the slot\r\n");

  214. else if (temp==0x03) uart_transmit_message("sd_card_init: CMD0 fail\r\n");

  215. else uart_transmit_message("sd_card_init: CMD1 fail\r\n");

  216.  

  217. while (1);

  218.  

  219. return 1;

  220. }


Код программы прост, название функций говорит само за себя. Вначале инициализируем UART, посредством которого будем связываться с компьютером на скорости 256кбод/с, с одним стоп битом, без проверки четности (если такая скорость покажется большой по ряду причин, то ее легко подредактировать в строке 16). Функция void uart_init(void) инициализирует UART; void uart_transmit(unsigned char х) – пересылает байт х по UART; unsigned char uart_receive(void) – принимает байт; void uart_transmit_message(char * msg) – пересылает строку, на которую ссылается msg по UART. Подключение карты к микроконтроллера определяется директивами define в начале программы. Рассмотрим функции работы c картой SD/MMC. Функции void spi_transmit(unsigned char x), unsigned char spi_receive(void) отвечают за пересылку байт по SPI; unsigned char sd_cmd(unsigned char b0, unsigned char b1, unsigned char b2, unsigned char b3, unsigned char b4, unsigned char b5) – отвечает за пересылку команды карте памяти.

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 на USB — распиновка адаптера микро сд

Подключение 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 картой никак не связаны и их можно не подключать. Однако, если они нужны, их можно подключить как обычную тактовую кнопку — один вывод на землю, другой через резистор к плюсу питания. Или вместо внешнего резистора использовать подтягивающий резистор микроконтроллера.

t-31.ru

4a4ik: Как работать с SD / MMC картой через SPI

SD карты (Secure Digital) - это формат карт флэш памяти. Был представлен в 1999 как улучшенный MMC. Стандарт SD регулирует "SD Association" (SDA).  На их сайте можно найти документацию на стандарт.

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

Рис.1 SD карты различных размеров
По стандарту, у SD карт есть 3 возможных физических размера: стандартный, mini и micro:
Рис.2 различные типы размеров SD карт с замерами
Есть 4 поколения карт памяти, которые отличаются друг от друга размером хранимой информации, считыватели карт младших поколений не работают с более поздними версиями.
  • SD 1.0 — от 8 МБ до 2 ГБ;
  • SD 1.1 — до 4 ГБ;
  • SDHC — до 32 ГБ;
  • SDXC — до 2 ТБ.

Есть 3 способа общения с SD картой:
  • Шина SPI
  • Однобитовый режим шины SD
  • Четырёх битовый режим шины SD

Шина SD намного быстрее, но для того чтобы ими пользоваться нужна лицензия, тем более в большинство цифровых устройств уже заложена поддержка SPI. Так что я рассмотрю только 1 способ.
Рис.3 Распиновка различных карт памяти
Режим SPI
MMCSDminiSDmicroSDИмяВход/ВыходОписание
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 . Зарезервировано

Если использовать SPI то SD карта питается от 3.3 В, может потреблять от 20 до 100 мА при передаче данных. В режиме покоя потребляет меньше 1 мА. Максимальная скорость передачи 12 мб/с (Частота CLK 25 МГц). Теперь мы знаем как подключить карту, осталось разобраться как с ней общаться.

В сети есть несколько открытых библиотек для работы с FAT (16/32), к примеру: FatFs, в таком случае можно считывать данные с компьютера, проверяются повреждённые блоки, память и ресурсы карты расходуются разумнее, ведь файловая система используется не просто так.

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

Можно создать текстовый документ, записать в него нужную информацию, открыть SD карту с помощью Hex-редактора, (к примеру: HxD) посмотреть в каком блоке (кластере) находится информация, (может быть она записана в нескольких блоках) считать её.

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

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

SPI используется всего лишь как интерфейс, данные передаются по "урезанной" версии стандартного протокола SD карты.

Протокол передачи данных
К примеру мы хотим считать блок данных, это будет выглядеть следующим образом:
Рис.4 Считывание 1 блока данных (512 байт)
Рассмотрим что здесь изображено. Сперва хост по линии DataIn (MOSI) посылает команду карте. Рассмотрим из чего состоит "команда":
Рис.5 Формат команды
Команда состоит из 48 бит, начальный бит = "0", затем "1" означает, что это команда от хоста.
Биты передаются, начиная со старших разрядов.
Content - содержимое команды вместе с адресом или параметром (38 бит). Первые 6 бит определяют команду, остальные 32 это параметр команды, к примеру, ячейку с каким адресом прочитать из памяти.
CRC (Cyclic Redundancy Code) - помогает избегать ошибок при передаче, у каждой команды есть свой CRC код (контрольная сумма).
Стоп бит = "1".

Response - это ответ карты на команду, если он есть (есть команды без ответа), то он может быть 1 из 4 видов (R1, R2, R3, R6):

Рис.6 Формат ответа
Ответ может состоять из 48 или 136 бит. Передаются, также начиная со старших разрядов. Сперва начальный бит = "0". Затем "0" означающий, что это команда от карты. В содержимом может быть либо значение регистра, который мы хотели считать, стоит отметить, что регистр RCA не доступен в режиме SPI (R3), либо "зеркальный" код команды и информация о состоянии.

Data block - это 512 байт данных, которые мы хотели считать, после них идёт контрольная сумма (CRC) для проверки содержимого.

Команды


Теперь рассмотрим, какие команды доступны в режиме SPI, команда состоит из 6 бит и определяется её индексом, чтобы отправить SD карте команду CMD0 нужно передать "000000", для CMD39 это будет "100111" (передаётся, начиная со старшего разряда). Сразу скажу, что большинство команд для нас не имеет значения, если мы хотим только считать и записать несколько байт.
Индекс командыАргументОтветОписание
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


Вместе с командой нам нужно отправлять CRC код для проверки, он вычисляется с помощью алгоритма. Если использовать библиотеки для работы с SD картами и FAT, то там это уже всё реализовано. Если работать с нуля, нужно для каждой команды вычислять 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:

  • берём содержимое команды вместе с её индексом и битом, обозначающим от кого передача (0 в данном случае) получаем (индекс команды 0, аргумент 0):                                                          1 000000 00000000000000000000000000000000 
  • Сдвигаем число на 7 разрядов влево, получаем                                                                                                      1 000000 00000000000000000000000000000000 0000000
  • Полученное число делим на CRC7 полином "10001001" и берём остаток:                           1 000000 00000000000000000000000000000000 0000000 % 10001001 = 1001010

Согласно даташиту именно такой 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 Подсчёт остатка
Остаток 0x17.

Можно найти готовый код для подсчёта CRC7 значений, есть довольно много реализаций, к примеру: вот и вот.

Ответы "Responce"


Теперь рассмотрим, какие есть форматы ответов SD карты на команды (Responce).

Чаще всего используется ответ R1, он состоит из 8 бит, старший бит всегда выставлен в "0". Ошибка обозначается "1" в соответствующем бите. Структура R1 выглядит следующим образом:

Рис.8 Формат ответа R1
  • (0 бит) in idle state - карта в состоянии ожидания и проводит процесс инициализации.
  • (1) erase reset - команда отмены удаления данных из памяти пришла до того как удаление началось.
  • (2) illegal command - неизвестный код команды.
  • (3) com crc error - ошибка проверки CRC кода.
  • (4) erase sequence error - ошибка в последовательных командах удаления.
  • (5) address error - неверный адрес.
  • (6) parameter error - неверный параметр.
R1b формат такой же, как R1, но с дополнительной информацией о готовности карты, это информация может быть произвольного размера. "0" означает что карта "занята", любое значение отличное от 0 означает, что карта готова к следующей команде.

В ответ на CMD13, карта отправляет R2, в дополнении к ошибкам в R1 здесь добавлено несколько новых:

Рис.9 Формат ответа R2
  • (0 бит) Card is locked - карта заблокирована пользователем.
  • (1) Write protect erase skip | lock/unlock command failed - была попытка удалить блок, защищённый от записи, либо был введён неправильный пароль при блокировке/разблокировке карты.
  • (2) Error - стандартная или неизвестная ошибка произошла во время операции.
  • (3) CC error - ошибка контроллера карты.
  • (4) Card ECC failed - ECC код был использован, но не получилось восстановить данные.
  • (5) Write protect violation - была попытка записи в блок, защищенный от записи.
  • (6) Erase param - неправильно выбраны адреса для очистки блоков.
  • (7) Out of range - параметр выходит за границы карты.
Формат R3 состоит из 40 бит, первый байт это формат R1, затем следует значение регистра OCR.

Формат R7 используется когда мы меняем напряжение, но SPI может работать только при 3.3 В. В отличие от SD интерфейса, так что R7 можно не рассматривать.

При работе с блоками данных используются особые "маркеры" (token) для сообщении о ходе передачи данных.

Рис.10 Запись нескольких блоков в карту
На каждый записанный блок карта посылает ответный маркер:
Рис.11 Маркер записи блока данных
Значение битов "Status" следующее:
  • "010" - данные приняты.
  • "101" - данные отклонены из-за ошибки в CRC коде.
  • "110" - данные отклонены из-за ошибки в процессе записи.
Также есть маркеры определяющие начало и конец записи:
Рис.12 Маркер начала записи/считывания 1 блока, считывания нескольких блоков

Рис.13 Маркер начала записи нескольких блоков
При работе с несколькими блоками маркер посылается каждый раз перед передачей очередного блока данных.
Рис.14 Маркер обозначающий конец записи.
Последний маркер используется только при записи нескольких блоков, при считывании используется команда CMD12.

Если карта не сможет прочитать блок данных, она отправит маркер ошибки, там обозначены те же биты, что и в R2:

Рис.15 Маркер ошибки считывания.
Биты обозначающие ошибки как в маркерах так и в ответах R* очищаются после того как они были переданы хосту, их не нужно очищать вручную.

Внутренние регистры


В режиме SPI мы можем считать 3 регистра OCR CID и CSD. Рассмотрим, что в них хранится.

Регистр OCR отвечает за доступные режимы питания карты:

Рис.16 Содержимое регистра OCR.
В битах [23:15] единица означает, что карта поддерживает данное напряжение.

Регистр CID хранит информацию от производителя:

Рис.17 Содержимое регистра OCR
Регистр CSD состоит из 127 бит и хранит техническую информацию, максимальный ток, скорость записи, размер максимального блока для работы и т.д. Он может отличаться от карты к карте в зависимости от размера. Не буду его расписывать в документации на это потратили 11 страниц.

У карты больше регистров, но они не доступны в режиме SPI.

Заключение
Этой информации должно хватить, чтобы понять, как работать с SD картой. Но я рекомендую использовать готовые библиотеки для работы с FAT файловой системой, конечно нужно больше памяти и RAM, но зато не нужно разбираться с работой на низком уровне, остаётся лишь использовать готовые функции.

Популярная библиотека 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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *