Дёшево и сердито! Азы работы с MMC
MMC карты имеют достаточно простое управление. Память разбита на сектора по 512 байт. Карты форматируются так же, как обычные винчестеры под DOS: с 1 разделом, файловая система - FAT16. Чтение возможно как отдельными байтами, так и блоками.
Напряжение питания карты должно быть в пределах +2.7В...+3.6В, скорость обмена до 20 мбит/с. При простое более 5мс карточка переводится в sleep режим с малым энергопотреблением, и выходит из него автоматически при возобновлении обмена.
Интерфейс карты
MMC карты могут работать в двух режимах обмена - MultiMediaCard protocol и SPI protocol.Первый более скоростной, а в пользу второго говорит то, что много контроллеров имеют встроенный SPI интерфейс. Ниже приведена разводка MMC именно для работы в режиме SPI:
|
PIN |
Имя |
Функция |
1 |
xCS |
Выбор кристалла |
2 |
DI |
Входные данные |
3 |
VSS |
Земля |
4 |
VDD |
Питание +3.3B |
5 |
SCLK |
Синхронизация |
6 |
VSS2 |
Земля |
7 |
DO |
Выходные данные |
Cигнал выборки имеет "0" активный уровень. SPI порт в управляющем контроллере (далее МК) должен быть настроен так, чтобы активным был передний фронт SCLK:
Сразу же напомню о том, что фактически передача байта из контроллера (DO) осуществляется параллельно с приёмом по другой линии (DI). Чтобы начать приём/передачу через SPI в PICе (в Master mode), в буффер приёмопередатчика SSPBUF нужно что-то записать, а после окончания пересылки из SSPBUF считать принятое. В простейшем случае обмен с картой имеет вид "команда - ответ":
Обозначения:
- 1 клетка - 8 бит;
- X - произвольно,
- Z - третье состояние,
- H - 0xFF,
- L - 0x00;
- Тр = 1ё8 байт, Тотв = 1ёmany байт.
Внимание! Рисунки поясняют принцип обмена, поэтому масштабы не соблюдены.
Обмен начинается с того, что МК выставляет сигнал 0 на xCS. Сначала посылаем 6 байт команды - последовательно пишем в вышеуказанный SSPBUF нужные байты, не забывая перед записью очередного дожидаться окончания передачи предыдущего (бит SSPSTAT,BF). Далее нужно дождаться ответа карты: пишем в SPI байт 0xFF и по окончании каждой передачи (контролируем SSPSTAT,BF) читаем принятое в SSPBUF. Первый байт, отличный от 0xFF, будет первым байтом ответа карточки (а для рассматриваемых ниже команд ответ всегда состоит из 1 байта).
Данные, если требуется, передаются после ответа блоком заданной ранее длины:
Начало блока данных "ловится" также: его первый байт отличен от 0xff (см. ниже).После окончания обмена нужно подать 1 на xCS.
Команды и ответы
Команда имеет длину 6 байт, передача всегда начинается со старшего бита. Пакет команды имеет следующий формат:
Позиция бита |
47 |
46 |
[45:40] |
[39:8] |
[7:1] |
0 |
Длина |
1 |
1 |
6 |
32 |
7 |
1 |
Значение |
'0' |
'1' |
x |
x |
x |
'1' |
Описание |
старт бит |
- |
номер команды |
аргумент |
CRC7 |
стоп бит |
При работе MMC в режиме SPI доступно около 15 команд, позволяющих во-первых получить полную информацию о типе и текущем состоянии карты, во-вторых производить запись и чтение данных. Рассмотрим всего лишь 4 команды, с помощью которых можно лишь читать данные с MMC блоками размером 1x512 байт (мне для плеера вполне хватает):
Номер комады |
Аргумент |
Описание |
CMD0 |
нет |
go_idle_state Сброс |
CMD1 |
нет |
send_op_cond Инициализация |
CMD16 |
[31:0] длина блока |
set_blocklen установить размер блока |
CMD17 |
[31:0] адрес блока |
read_single_block прочитать блок размером, указанным set_block_len |
Обратите внимание: все числа, аргументы и т.п. передаются начиная со старшего бита, а адрес блока - адрес первого байта блока.
Ответ на любую из вышеприведённых команд состоит из одного байта, старший байт всегда равен 0. Другие биты - флаги ошибок:
- В спящем режиме - карта находится в спящем режиме и выполняется процесс инициализации;
- Erase reset - стирание не выполнено, т.к операция прервана до исполнения;
- Недопустимая команда - обнаружен недопустимый номер команды;
- Ошибка CRC - последняя принятая команда не прошла проверку CRC;
- Erase_seq_error - ошибка в команде стирания;
- Ошибка адреса - блок пересекает границу физического сектора;
- Ошибка параметра - аргумент команды вне допустимых пределов для данной карты.
Ошибки №2,4,5 нам встречаться не должны. Для операции чтения CMD17 считываемый блок должен быть в пределах одного физического сектора: его размер не должен превышать 512 байт, а начало и конец располагаться в одном и том же секторе. Если это не выполнено, то появится ошибка №6.
Блок данных имеет длину от 4 до N+3 байт, где N - число, указанное в аргументе CMD16. Первый байт при передаче от MMC к МК равен 0xFE, далее следуют N байт запрашиваемой информации, а в конце - 2 байта CRC (их содержимое можно игнорировать, но прочесть нужно обязательно!). Если же при чтении произошёл сбой и карта не может предоставить данные, то вместо указанного блока передаётся 1 байт с флагом ошибки:
- Неизвестная ошибка - сбой по неизвестной причине;
- Ошибка СС - сбой внутреннего контроллера;
- Сбой ЕСС - алгоритм ЕСС не смог восстановить данные;
- Выход за границу - аргумент команды вне допустимых пределов;
- Карта блокирована - доступ не разрешён, т.к карта защищена паролем.
Инициализация карты
Перед работой карту необходимо правильно проинициализировать. Спустя несколько мс после подачи питания по SPI нужно отправить 0xFF 74 раза и подождать ещё 1мс. Всё это время на xCS должна быть лог. "1". Теперь карта готова к приёму команд. После включения карта находится в режиме MultimediaCard protocol. Для перевода её в режим SPI надо отправить команду Сброс (CMD0) (не забывайте про xCS). В режиме SPI проверка CRC отключена по умолчанию, поэтому содержимое поля CRC7 игнорируется. Однако для CMD0 поле CRC7 нужно указать правильно. Поскольку команда не имеет меняющихся в процессе работы аргументов, то и специально вычислять это поле не обязательно: правильная CMD0 имеет вид: 0x40, 0x0, 0x0, 0x0, 0x0, 0x95. Далее карту необходимо проинициализировать. Для этого посылаем команду CMD1 до тех пор, пока в ответе карты бит0 (в спящем режиме) не сменится с 1 на 0. Это будет означать, что карта готова к работе. Теперь можно посылать прочие команды (у нас это CMD16 и CMD17).
Файловая cистема
Самое интересное - это работа с файловой системой. Не буду сильно распространяться, т.к. в инете итак навалом информации о том, что такое FAT16 и с чем её едят. Кратенько расскажу о том, как использовать содержимое некоторых секторов в своих личных целях.
Структура диска:
MasterBootRecord |
резервировано |
PartitionBootRecord |
FAT1 |
FAT2 |
Корневой каталог |
кластер 002 |
кластер 003 |
*** |
MBR находится в нулевом секторе диска, позиции остальных частей будем вычислять. Стоит отметить, что если карточка была переформатирована Windows, структура диска могла измениться: Windows стирает MBR, и в нулевом секторе сразу начинается PBR. Чтобы различить содержимое нулевого сектора нужно считать его первые неск. байт. Если байты нулевые - это MBR, иначе - PBR.
Нулевой сектор, он же Master Boot Record диска, выглядит примерно так:
Позиция байта |
Длина (байт) |
Описание |
Содержимое |
0х0 |
446 |
- |
0x0 |
0x1BE 16 |
16 |
описание раздела |
см.ниже |
0x1CE |
16 |
описание раздела |
см.ниже |
0x1DE |
16 |
описание раздела |
см.ниже |
0x1EE |
16 |
описание раздела |
см.ниже |
0x1FE |
2 |
подпись |
0x55,0xAA |
Нам нужно описание первого раздела (то, что по смещению 0x1BE).Что там есть:
Позиция байта |
Длина (байт) |
Описание |
Содержимое |
0x4 |
1 |
тип файловой системы |
6=DOS 16-бит ФАТ (возм. др. варианты) |
0x8 |
4 |
позиция 1 сектора раздела |
номер сектора |
0xС |
2 |
число секторов в разделе |
от 1 до макс. числа секторов диска |
Это, конечно, не всё, но этого вполне хватит. Как пример привожу то, что написано в моей карточке:
Offset |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
A |
B |
C |
D |
E |
F |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
000001B0 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
01 |
................ |
000001C0 |
01 |
00 |
06 |
07 |
E0 |
D3 |
20 |
00 |
00 |
00 |
E0 |
D3 |
03 |
00 |
00 |
00 |
....аУ ...аУ.... |
Здесь позиция PBR - сектор номер 0x00000020, а число секторов 0x0003D3E0 (все длинные числа записаны с младшего байта), Offset - смещение байта от начала диска. Не стоит забывать, что физический адрес PBR равен pbr_adr = 0x00000020 * 0x200 =0x00004000 (0x200 - число байт на сектор). Идём в Partition Boot Record раздела:
Позиция байта |
Длина (байт) |
Описание |
Содержимое |
0хD |
1 |
секторов на кластер, Sectors_per_Cluster |
XX(1...64) |
0xE |
2 |
число резервированных под PBR секторов, Rezerv |
x |
0x10 |
1 |
число таблиц FАТ, Number_of_Fat |
2 |
0x11 |
2 |
число записей в корневом каталоге, Root_dir_entry |
512 |
0x16 |
2 |
секторов на FАТ, Sectors_per_FAT |
XXX |
0x20 |
4 |
всего секторов |
XXX |
Опять-же здесь в помощь моя карточка:
Offset |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
A |
B |
C |
D |
E |
F |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
00004000 |
EB |
00 |
90 |
20 |
20 |
20 |
20 |
20 |
20 |
20 |
20 |
20 |
02 |
04 |
01 |
00 |
л.ђ ..... |
00004010 |
02 |
00 |
02 |
00 |
00 |
F8 |
F5 |
00 |
20 |
00 |
08 |
00 |
20 |
00 |
00 |
00 |
.....шх. ... ... |
00004020 |
E0 |
D3 |
03 |
00 |
80 |
00 |
29 |
A9 |
3D |
30 |
FC |
4E |
4F |
20 |
4E |
41 |
аУ..Ђ.)©=0ьNO NA |
Мы видим 0x04 сектора на кластер, 0x00F5 секторов на каждую FAT, под PBR отведён 1 сектор, 512 записей в корневом каталоге. Этих четырёх чисел хватит, чтобы вычислить 3 важных смещения:
- Fat_base = pbr_adr+0x200*Rezerv; (0x4200)
- Root_base = Fat_base + Number_of_Fat * (Sectors_per_FAT * 0x200); (0x41600)
- Cluster_base = Root_base + Root_dir_entry * root_entry_size - 2 * (Sectors_per_Cluster * 0x200); (0x44600)
Fat_base - адрес нулевого байта FAT, Root_base - адрес нулевого байта корневого каталога, Cluster_base - адрес нулевого (не 002!!!) кластера (нулевого кластера нет, но так удобнее, см. ниже). В скобках - числа для моей MMC, root_entry_size - размер записи в корневом каталоге, равен 32 байта.
Все смещения есть, осталось совсем немного. Разберёмся с FAT. Во первых всё пространство диска (после Root Dir) поделено на т.н. кластеры по "Sectors_per_Cluster" секторов в каждом. Во вторых 2 копии FAT идентичны, поэтому будем работать с первой. А FAT состоит из последовательности 2-х байтных слов (МЛАДШИЙ байт впереди). N-ое слово соответствует N-ому кластеру (N>1), и может содержать следующую информацию:
Число |
Значение |
0002-FFEF |
номер следующего кластера в цепочке |
FFF7 |
это дефектный кластер |
FFF8-FFFF |
это последний кластер цепочки |
0000,0001,FFF0-FFF6 |
резервировано (и нам не интересно) |
Исходя из разбиения диска на кластеры файл, будь он больше размера одного кластера, естественно содержит их несколько штук. Последовательность номеров кластеров, в которых записан файл, образует цепочку кластеров. Цепочка строится так: номер первого читается из записи в каталоге; в соответствующем слове FAT при этом указан следующий кластер. В слове для следующего - номер третьего и т.д. пока не достигается конец цепочки.
Маленький организационный момент: первые 4 байта FAT - обязательная подпись, означает, что это начало FAT. Поэтому Нет нулевого и первого слова, Нет нулевого и первого кластеров, сразу за RootDir сидит кластер номер 0002.
И снова от теории к практике - придуманное мной для примера начало FAT:
Offset |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
A |
B |
C |
D |
E |
F |
|
00004200 |
F8 |
FF |
FF |
FF |
03 |
00 |
05 |
00 |
06 |
00 |
04 |
00 |
07 |
00 |
FF |
FF |
шяяя..........яя |
Первые 4 байта - подпись. Допустим, файл начинается со 2 кластера, Num = 2. Тогда адрес этого кластера adr = Cluster_base + Num * Sectors_per_cluster * 0x200. Кластер мы прочитали, а дальше читаем слово в FAT для этого кластера, 2 байта начиная с адреса adr = Fat_base + Num * 2 (0x4204). В нашем случае это 0003 - номер следующего кластера (см. таблицу). Расшифроывая таким образом содержимое Fat получим цепочку:
0002 - первый,0003,0005,0004,0006,0007 - последний.
Если разобраться - достаточно просто.
Наконец заглянем в корневой каталог - там кроме имени файла, даты, времени, атрибутов, указан первый кластер файла и его размер в байтах. Каждая запись в корневом каталоге состоит из 32 байт. Нам нужно прочитать байты со смещением 0x00,0x02,0x1A-0x1B,0x1C-0x1F. Если нулевой байт не равен 0xE5, второй не равен 0x00 или 0x04, то 0x1B:0x1A - первый кластер файла, а 0x1F:0x1E:0x1D:0x1C - его размер в байтах. Пока плеер без экрана, имя файла получать не обязательно...
P.S.: Как выяснилось, SD карты полностью совместимы с карточками MMC, в т.ч. в режиме SPI. "Лишние" выводы в этом режиме не используются:
|
PIN |
Имя |
Функция |
1 |
xCS |
Выбор кристалла |
2 |
DI |
Входные данные |
3 |
VSS |
Земля |
4 |
VDD |
Питание +3.3B |
5 |
SCLK |
Синхронизация |
6 |
VSS2 |
Земля |
7 |
DO |
Выходные данные |
8 |
RSV |
Резерв |
9 |
RSV |
Резерв |
Единственно что стоит сделать - поставить подтягивающие сопротивления на выв. 8 и 9 (в р-не неск. деятков кОм).
По материалам сайта SanDisk
Катичев А. mp3vkarmane.nm.ru
Кино афиша Москвы на InOut.ru
|