[SD] Драйвер SDHC карты памяти для Stm32f4

Hardware issues, electronic components, schemas, Arduino, STM32, Robots, Sensors
Post Reply
Administrator
Site Admin
Posts: 81
Joined: 26-Feb-2014, 17:54

[SD] Драйвер SDHC карты памяти для Stm32f4

Post by Administrator » 11-Apr-2014, 17:54

Полнофункциональный драйвер SDHC карты памяти для Stm32f4

Для чего эта статья?
Все эмбеддеры, рано или поздно, сталкиваются с проблемой нехватки ПЗУ микроконтроллера для своих проектов. Решений масса, начиная от приобретения и подключения микросхем EEPROM и заканчивая подключением стандартной USB флешки. Ну, а для хэнд-майд проектов, отличным вариантом будет самая, что ни на есть классическая SD’шная карта памяти. Они бывают разного типа, имеют различные механизмы инициализации и передачи данных и подключаются к хосту через различные интерфейсы (их, правда, только три, но об этом позже). Более того, многие современные микроконтроллеры имеют на своем борту аппаратные модули этих интерфейсов, и работа разработчика сводится лишь к их конфигу и посылу карточке нужных команд в соответствии с протоколом. Ну и еще карты памяти имеют приятное свойство элементарно покупаться на каждом шагу.

О Secure Digital (SD) картах
Secure Digital формат – популярный (пожалуй, самый популярный на сегодняшний день) формат flash памяти для использования, в основном, в портативных устройствах. Внутри каждой такой карточки имеется, собственно, микросхема flash памяти (Memory Core) и, связывающий ее с внешним миром контроллер, имеющий 8 регистров. Задачи последнего – аппаратная реализация внешних интерфейсов, поддержка информации о карте (тип, емкость, класс скорости еще куча других характеристик), контроль электропитания, и, конечно, управление самой микрухой памяти (адресация, чтение, запись, очистка и оганизация порядка 80 команд управления).
SDHC_regs_contacts.png
SDHC_regs_contacts.png (33.09 KiB) Viewed 30355 times
Формат SD был основан компаниями Panasonic, SanDisk и Toshiba на основе MMC карт. Позже эти компании создали организацию SD Card Association, в настоящее время занимающуюся разработкой и продвижением технологии SD. Основной документ, в котором досконально описан интерфейс, протокол, команды, регистры карточек — Physical Layer Simplified Specification (©Copyright 2001-2006 SD Group (Panasonic, SanDisk, Toshiba) and SD Card Association). Именно эту информацию используют всякие R&D центры при разработки аппаратного и программного обеспечения своих будущих девайсов. Сам файлик благополучно лежит в свободном доступе в инете, и скачать его не предоставляется никаких сложностей. Так вот, в соответствии с этим документом, существуют следующие типы карт памяти:
SD карты (или еще SDSC (Secure Digital Standard Capacity) ) – первое поколение карт памяти. Ограничение по объему – 2 Гб. Минимальный размер адресуемого пространства – 1 байт.
SDHC карты (Secure Digital High Capacity) – карты памяти повышенной емкости (до 32 Гб). Имеют существенное отличие от первого типа, а именно, адресация происходит блоками по 512 байт. Еще у SDHC карт дугой процесс инициализации, о котором поговорим позже.
SDXC (Secure Digital eXtended Capacity) – карты памяти расширенной емкости – теоретически до 2Tб памяти. Адресация тоже по 512 байт. Вот оно и получается при 32-битном пространстве: (2^32)*512 = 2 Тб.

На каждое поколение карт существуют спецификации, и при этом в каждом документе на более новое поколение описывается инфа о старых – то есть они «толстеют» с каждым обновлением продукта. Так что скачиваем Physical Layer Simplified Specification самой последней версии и находим там все, что надо для работы со всеми поколениями карт. Кроме этого, карты памяти делятся на несколько классов по скорости чтения/записи данных. Ну, а что касается всяких там mini-, microSD, microSDXC и т.д. – это всего лишь другой размер корпуса и распиновка – никаких внутренних отличий от карточек стандартных габарит.

А теперь важно: ВНЕ зависимости от типа карты, емкости, ее производителя, типа корпуса, цвета и магазина, где вы ее купили – все Security Digital карты имеют одинаковые интерфейсы взаимодействия с внешним миром. Команды, механизмы инициализации – разные, да, но интерфейсы – ОДИНАКОВЫЕ. Именно это позволяет напофиг воткнуть в фотик как SD, так и SDHC карту памяти. Ну, вот и пришел момент обсудить язык карточки, а точнее аж три: SD и UHS-II (нэйтив спикер) и «язык универсальной микропроцессорной коммуникации, который сейчас знает каждый микроконтроллер» — SPI.

Administrator
Site Admin
Posts: 81
Joined: 26-Feb-2014, 17:54

Re: [SD] Драйвер SDHC карты памяти для Stm32f4

Post by Administrator » 11-Apr-2014, 18:15

Интерфейс карты памяти
Как было сказано выше, Security Digital карты имеют три внешних интерфейса: SD, UHS-II и SPI. Первые являются «родными» каналами обмена данными с хостом, и, как следствие, позволяют реализовать полнофункциональное, полноскоростное взаимодействие. SPI же не поддерживает ряда команд и не дает максимальной скорости обмена данными, зато он есть во всех микроконтроллерах (и в современных и в старых моделях), что делает возможным без особых проблем приконнектить карточку ко всему, что плохо лежит. Существует масса статей о том, как это сделать. Но, с развитием микропроцессорной техники, с уменьшением нанометров в технологическом процессе производства камней, SPI интерфейс, как средство коммуникации с SD картой постепенно отмирает. Действительно, если ваш МК поддерживает аппаратную реализацию SD протокола, будите ли Вы связываться с менее функциональной альтернативой? Судьба послала мне на проект камень Stm32f4 от STMicroelectronics, в котором как раз таки и имеется периферийный модуль SDIO (Security Digital Input Output), аппаратно реализующий и интерфейс, и протокол карточки.

Так что же такое SD протокол и с чем его едят? Ключевых понятий тут три:
команда – последовательность битов, воспринимаемых контроллером карточки и призывающих его к тому или иному действию;
отклик – ответ контроллера карты на команду. Он может содержать как общую информацию (статус карты, текущее состояние различных внутренних модулей и т.д.), так и, собственно, ожидаемую хостом информацию (запросили в команде идентификатор карты – получили его в отклике);
данные – ну тут без комментариев.

Но прежде, чем посмотрим на логику протокола, обратимся к физике интерфейса (очень обзорно).
SDHC_contacts.jpg
SDHC_contacts.jpg (11.16 KiB) Viewed 30354 times
Pin 4 – питание карточки;
Pin 3, 6 – земля;
Pin 5 – тактовый сигнал;
Pin 2 – линия команд и откликов;
Pin 1, 7, 8, 9 – линии 4-битной шины данных.

Все посылки карточке и обратно есть последовательности битов, строго синхронизированные с тактовым сигналом, передаваемым по линии CLK. Рекомендуемые частоты описаны в спецификации на карту и имеют различное значение, в зависимости от её типа и класса скорости. Отмечу только, что для любой карты инициализация проходит на очень малой (по сравнению с передачей данных) частоте. Шина данных может быть 1-битной (работает только D0) или 4-битной – это конфигурируется при инициализации. Важно, что для SD карт со стороны хоста линии данных и команд должны быть Push-Pull и быть подтянуты к питанию через резисторы 4.5 – 10 кОм. Тактовую шину тоже нужно подтянуть к питанию.

SD-протокол
Бывает несколько вариантов обмена информацией хост – карта.

1) Команды без данных.
Все команды делятся на требующие и не требующие отклик.

Если нам (хосту) нужно послать команду, не требующую отклика – просто посылаем ее. Если же, команда подразумевает некий ответ, посылаем, а затем ждём ответа. Почти все команды и отклики проверяются контрольной суммой, как со стороны хоста, так и со стороны карты. Ну, посмотрим на формат команды:
SDHC_cmd_diagram.png
SDHC_cmd_diagram.png (23.25 KiB) Viewed 30354 times
Кадр состоит из 48 бит. Первый – старт бит – всегда нуль. Затем, говорим, что данные направляются от хоста к карте и посылаем команду с аргументом. Да, да, команда состоит из индекса и аргумента. После команды обязательно шлем 7-битную контрольную сумму, вычисляемую по алгоритму циклически избыточного кода (CRC) и завершаем посылку стоп битом. Команды бывают двух типов: CMD (базовые команды) и ACMD (Application-Specific Command). Они могут быть с аргументом и без, иметь отклик и не иметь. Всего существует порядка 80 команд и каждая из них подробно описана в спецификации. Мы остановимся лишь на некоторых, необходимых для основной работы с карточкой (инициализация, чтение, запись). Индекс команды – это та цифра, которая идет после символов CMD или ACMD. Под него отведено 6 бит и 32 бита аргумента команды, если таковой требуется.

Важное пояснение по поводу ACMD: пространство их индексов пересекается с индексами CMD команд, поэтому, чтобы контроллер воспринял команду именно, как Application-Specific, ей должна предшествовать CMD55!

Отклик (если требуется) – тоже целая тема, хотя бы, потому что их пять типов.

R1 (normal response command) – длина 48 бит. Пожалуй, самый популярный отклик.
SDHC_normal_resp.png
SDHC_normal_resp.png (28.68 KiB) Viewed 30354 times
Содержит в себе старт бит, бит направления передачи (от карты к хосту), 6 битов индекса команды, побудившей на генерацию отклика, статус карты и, конечно же, контрольную сумму со стоп битом. Всю информацию в отклике этого типа несет 32 битное поле статуса карты. В спецификации тщательно и добросовестно расписано, что означает каждый бит этого статуса (карта занята/свободна, блокирована/разблокирована, текущее состояние автомата передачи данных, готовность к тому или иному действию и многое другое).

/skipped some commands/

2) Данные.
Мы рассмотрели посыл команд и получение отклика от карты. Теперь самое время разобраться с тем, как же передавать данные. Повторюсь, делается это блоками по 512 байт (для SDHC карт) — все адресное пространство карты разбито на 512 байтовые ячейки. Посылке данных всегда должна предшествовать специальная команда, говорящая контроллеру карты о том, что данные вот-вот уже пойдут. А идут они, как я уже говорил – по 1- или 4-битной шине. Посмотрим на формат посылки данных к хосту от карты (чтение).
SDHC_data_diagram.png
SDHC_data_diagram.png (42.92 KiB) Viewed 30354 times
Возможны два режима передачи данных: одним блоком (block read operation) и несколькими блоками сразу (multiple block read operation). В любом случае, старт передачи и её завершение происходят по специальной команде, обратите внимание, с откликом.

Обратная процедура (запись) осуществляется аналогичным образом, только между пачками обязательно присутствует busy, сигнализирующий о неготовности карты принять следующий блок (данные еще не записались во флэш карты).
SDHC_datawrite_diagram.png
SDHC_datawrite_diagram.png (48.88 KiB) Viewed 30354 times

Administrator
Site Admin
Posts: 81
Joined: 26-Feb-2014, 17:54

Re: [SD] Драйвер SDHC карты памяти для Stm32f4

Post by Administrator » 11-Apr-2014, 18:35

Инициализация SD Карты памяти
Всё надо инициализировать, поэтому SD карта не является исключением из этого великолепнейшего правила. Нужно проверить поддерживаемые напряжения, назначить адреса и убедиться, что мы можем работать с данной картой. Посмотрим на алгоритм инициализации, вытащенный из спецификаии и пройдемся по нему по порядку, блок за блоком, дабы понять, что нужно сделать с девайсом перед использованием по назначению.
SDHC_Init.png
SDHC_Init.png (131.38 KiB) Viewed 30354 times
ВАЖНО : инициализация проводится на низкоскоростном режиме! Частота клока карты не более 400 кГц!

ЕЩЕ ВАЖНО: после подачи питания, не спешим грузить карту командами, дадим напряжению устаканиться, подождем 250 миллисекунд (в зависимости от числа карт, подключенных к одной шине, ширины линии данных и параметров источник питания). Как только вольтаж вышел на необходимый уровень, зарядились все паразитные емкости и т.д. и т.п., можно творить процесс инициализации. А начинается он с обнуления всех карт и перевода их в Idle State.
• Шлем CMD0, обратим внимание, без аргумента и не ждем ничего в отклике. В результате все карты на линии передут в холостой режим.
• Помните, я говорил, что напряжение нужно валидировать? Правильно! Нужно сказать карте, на каком вольтаже мы работаем и выслушать от нее все по этому поводу. Шлем CMD8 с аргументом, в котором биты 11:8 означают напряжение хоста и биты 7:0 – check pattern (проверочный шаблон) – любой, спецификация рекомендует слать 10101010. Биты напряжения ставятся в соответствии с таблицей:
SDHC_voltage.png
SDHC_voltage.png (29.34 KiB) Viewed 30354 times
У нас всё очень даже определено и далеко не Low Voltage Range. Stm32f4 выдает как раз напряжение в диапазоне 2.7 – 3.6 V, так что ставим 1 на восьмом бите аргумента. Итого, имеем команду с аргументом 110101010. Отправили. Проверили, что всё отправилось хорошо и ждём ответа, он не заставит нас делать это долго. В спецификации увидели, что ответ на эту команду – R7 типа.
Если мы его так и не дождались, то дальнейшая команда ACMD41 решит, как именно нас надули – подсунули карту версии 1.X стандартной емкости или вообще не SD карту.
Если с напряжением все хорошо, карта довольна, мы довольны, ответ будет содержать в себе всё то, что мы отправили в аргументе, то есть 110101010. Это называется valid response. Если так, то переходим к дальнейшему шагу, иначе – опять же – либо надули, либо где-то косяк.

• Дождались 110101010, и пришло время непосредственной инициализации – команды ACMD41. Чтобы сказать карточке, что команда не простая, а ACMD, отправим сперва CMD55. В аргументе обязательно указываем, адрес той карты, для которой эта команда предназначена. Но стоп, у нас, ведь, пока нет адреса, мы его не знаем. Ничего, узнаем, а пока пишем нули.
• Далее шлем CMD2 — без аргумента и смотрим на ответ R2. В этом случае он будет нести информацию о содержимом CID регистра, и мы сможем вычитать ID производителя, серийный номер карты и прочую информацию.
• И, наконец, заключительный шаг – получение адреса карты (RCA — relative address). Как оно уже упоминалось, к одной шине может быть подключено несколько карт, поэтому каждая должна иметь свой уникальный локальный адрес. Шлем CMD3 и получаем ответ типа R6, в котором в младших 16 битах содержится статус карты, а в старших – новый RCA адрес. Отныне, для доступа к нашей карточке, мы должны будем звать ее по имени, то есть по RCA адресу.
• Опциональный пункт. По умолчанию карта работает с 1-битной шиной данных, что, ясное дело, медленнее, чем с 4-х битной. Если мы хотим достичь максимального быстродействия – шлем ACMD6, с предшествующей CMD55, конечно же. Но прежде, нужно перевести карту в состояние Transfer State (см. ниже) командой CMD7 с RCA в качестве аргумента. В аргументе ACMD6 на месте самого первого бита пишем 1 – если хотим включить 4-битный мод и 0 – для отключение. Ответ R1 скажет об успешном проведении операции.

Пример инициализации SDHC карты
В данном примере используется самодельная функция посылки команды, написанная под периферию Stm32F4.
char SDIO_send_command(char index, unsigned int arg, char resp_type, unsigned int *resp);
• index – индекс команды;
• arg — аргумент;
• resp type – тип отклика (0 – без отклика, 1 – короткий (48 бит) отклик, 2 – длинный (136 бит) отклик);
• resp — массив откликов (в случае короткого отклика информацию несет первый элемент массива, в случае длинного – 4 элемента).
• Команда возвращает 0, в случае успешной операции посыла команды и приема ответа и код ошибки в противном случае.

Code: Select all

char SDHC_card_initialization(unsigned int *RCA)
{
    char result;
    unsigned int RESP[4];
    result = SDIO_send_command(0, 0, 0, RESP);     //Посылаем CMD0, дабы обнулить карты
    if (result != 0) return result;      //Чекаем на успех
    result = SDIO_send_command(8, 0x1AA, 1, RESP);      //Посылаем CMD8 с аргументом 110101010
    if ( (result != 0) || (RESP[0] != 0x1AA) ) return 4;      //Чекаем на успех
    while( !(RESP[0]&(1<<31) ) )      //Ждем, пока флаг бизи не слезет
    {
        result = SDIO_send_command(55, 0, 1, RESP);      //Шлем CMD55, тем самым, говоря, что потом будет ACMD
        if (result != 0) return result;
        result = SDIO_send_command(0x29, 0x40020000, 1, RESP);     //Шлем ACMD41
        if (result != 0) return result;
    }
       result = SDIO_send_command(2, 0, 3, RESP);     //Шлем CMD2 и получаем инфу о карте
    if (result != 0) return result;
    result = SDIO_send_command(3, 0, 1, RESP);     //Шлем CMD3 и получаем RCA номер
    if (result != 0) return result;
    SDIO->CLKCR = (0x02<<0)|(1<<11)|(1<<8)|(1<<14);     //Наращиваем клок (в части 2 - подробнее)
    *RCA = ( RESP[0] & (0xFFFF0000) );      //Маскируем отклик и получаем RCA
    result = SDIO_send_command(7, *RCA, 1, RESP);     //Выбираем нашу карту                
    if (result != 0) return result;
    result = SDIO_send_command(55, *RCA, 1, RESP);      //Шлем CMD55, тем самым, говоря, что потом будет ACMD
    if (result != 0) return result;
    result = SDIO_send_command(6, 0x02, 1, RESP);      //Шлем ACMD6 c аргументом 0x02, установив 4-битный режим
    if (result != 0) return result;
    if (RESP[0] != 0x920) return 1; else return 0;    //Убеждаемся, что карта находится в готовности работать с трансфером
    return 0;
}
Запускаем код, убеждаемся, что в ответе пришел НУЛЬ и завершаем инициализацию. Все, можем работать с памятью и писать/считывать информацию.

Запись данных на карту
Итак, после успешной инициализации мы находимся в состоянии tran, во всяком случае, должны находиться. Смотрим по диаграмме: для того, чтобы перейти на состояние rcv, нужно послать команду CMD24 с адресом 512 байтной ячейки, которую хотим записать. Послали. Карта перешла в режим ожидания данных. Далее начинаем кидать ей информацию по шине данных, пока не перекинем все 512 байт или не пошлем команду CMD12 (стоп передачи). После завершения акта, карточка сама переедет в состояние prg и пробудет там некоторое время (пока данные запишутся). Ждем.… Как имено ждем? А посылаем ей в цикле CMD13 с адресом карты в аргументе, до тех пор, пока не вернется в отклике R1 типа статус tran. Когда это, наконец, случилось можно слать очередную пачку данных, вновь послав CMD24. Кроме того, существует еще режим записи несколькими блокам сразу (CMD25) и другие режимы – за подробностью – в спецификацию.

Чтение данных
Дабы выполнить обратную процедуру, в первую очередь, убеждаемся, что карта стоит в tran. Шлем CMD17 с адресом RCA в аргументе. Если все пройдет успешно – карточка перейдёт в состояние data и начнет выдавать на линии данных информацию, опять же 512 байтным блоком. Задача хоста в это время внимательно слушать линию и считывать данные. Как только посылка закончится, карта сама переедет в статус tran. Думаю, не стоит и говорить о том, что считывание так же как и запись возможна несколькими блоками сразу.

Post Reply