Распиновка слота карты памяти
Следует знать, что в режиме SPI поддерживаются только команды чтения/записи в режиме одного блока или нескольких блоков (в режиме MMC поддерживается режим последовательной чтения/записи). Размер блока для чтения/записи может быть размером в сектор карты памяти и размером в 1 байт. Поддержка операций частичного чтения/записи блока данных хранится в регистре CSD карты памяти.
Чуть не забыли поговорить о регистрах, которые содержит карта памяти стандарта MMC(SD). Этих регистров чуть больше, чем перечислю я, но те, которые я не укажу либо не особо нужны, либо не доступны в режиме SPI. Основными регистрами, которые представляют для нас интерес являются следующие:
— CID (Card identification data): содержит данные, по которым можно идентифицировать карту памяти (серийный номер, ID производителя, дату изготовления и т.д.)
— CSD (Card-specific data): содержит всевозможную информацию о карте памяти (от размера сектора карты памяти до потребления в режиме чтения/записи).
— OCR (Operation Conditions Register): содержит напряжения питания карты памяти, тип питания карты памяти, статус процесса инициализации карты.
Многие, наверное, заметили, что в таблице пропущены некоторые команды. Как я говорил ранее, в режиме SPI недоступны некоторые функции, которые доступны в режиме MMC. Поэтому некоторые команды так же не доступны. Так же из таблицы видно, что у всех команд в поле «Resp» присутствует аббревиатура R1(2, 3, 7 и др.). Это и есть так называемый ответ карты на посылаемую ей команду. Приведу небольшой пример обмена информацией с картой памяти для иллюстрации описанного выше.
Стоит отметить, что в протоколе MMC весь обмен данными завершается полем CRC, которое является необходимым. Что касается режима SPI, то по умолчанию при переходе в этот режим, контроль CRC отключен. Исключение составляют команды CMD0 и CMD8, поскольку они отправляются в карту, которая еще находится в режиме MMC, поэтому поле CRC для этих команд должно быть верным. Поскольку CMD0 отправляется единожды и все 6 байт этой команды известны заранее и не меняются, то в поле CRC для любой команды мы будем отправлять CRC для команды CMD0 (оно равняется 0x95). Что касается CMD8, то поле CRC в ней не является константой и зависит от передаваемых параметров. Хочу заметить, что проверку поля CRC можно активировать и в режиме SPI. Делается это при помощи соответствующей команды (CMD59).
Немного разобравшись с теорией, посмотрим на процесс инициализации карты памяти. Попробую представить это в виде блок-схемы. Вот что получилось у меня вымутить из datasheet’а (излагаю только суть, за вычетом некоторых моментов, которые я распишу после блок-схемы):
Ну вот, скажут некоторые, нарисовал не пойми чего, а вы тут разбирайтесь;) Но все не так уж и плохо. Первое, что необходимо пояснить в этой схеме это то, что карты как бы того не хотелось, бывают разные (поэтому наверное они и называются по разному). И на этой схеме мы видим, что бывает их ни много ни мало, а целых 4: MMC, SD версии 1.х стандартной емкости, SD версии 2.х стандартной емкости и карта SD версии 2.х повышенной емкости (SD карты расширенной емкости или SDHC). Все бы ничего, но все они требуют разной инициализации и это самое обидное. В принципе, есть общий способ инициализации всех их кроме SDHC, но он не есть правильный, поскольку работать с картой SD версии 2.х стандартной емкости и картой MMC как с одинаковыми картами неправильно (отличие в структурах CID и CSD). Конечно, можно построить алгоритм для работы с каждой картой по отдельности, но мы пойдем универсальной дорогой(и самой трудной на первый взгляд).
Из приведенной структуры намечается следующий путь работы (я буду указывать основные моменты, которые необходимо выполнять, но они не указаны на данной схеме). Мы определили, что в разъем картоприемника вставили какую-то фигню. Мы в свою очередь делаем следующее: подаем питание в пределах от 2.7-3.6 В, ожидаем ~1мс (точно не знаю сколько, но чтобы питание устаканилось). SPI настроен как полагается (я думаю все умеют это делать) и вывод _CS карты памяти выставлен в логическую “1”. После этого нам необходимо подать минимум 74 тактовых импульса на линию SCLK SPI. Выполнив все это мы выставляем логический “0” на вывод _CS карты памяти и отсылаем команду CMD0. Из таблицы команд видим, что ответом на CMD0 является R1, структуру которого мы знаем. Немного отступлю от мысли и обращу внимание на то, что все ответы содержат в себе первым байтом R1, 7-й бит которого всегда является 0. Таким образом, мы можем отличать ответы от идущий по линии MISO байтов 0xFF. Итак, приняв R1, проверяем бит «In idle state» на равенство «1». Если это так, то карта находится на этапе инициализации. А вот теперь пришел первый этап определения типа карты памяти. Посылаем команду CMD8, которая указывает карте поддерживаемые МК напряжения питания для ее и спрашивает у выбранной карты может ли она работать в данном диапазоне напряжений, дожидаемся ответа R7. Как видно из блок-схемы, карты памяти стандарта MMC и SD версии 1.х эту команду не поддерживают и, соответственно, в своем ответе будут содержать бит «illegal command». Если сказанное ранее верно, то установленная карта либо MMC, либо SD версии 1.х. Теперь пришло время распознать, какая именно из этих двух типов карт вставлена в картоприемник. Для этого отправим карте памяти команду ACMD41, которая инициирует процесс инициализации карты. Эта команда посылается в цикле либо для ее выполнения взводится таймер, по которому проверяется ответ на эту команду. В любом случае, карта MMC не поддерживает ACMD41 и вернет «illegal command» в своем ответе. В таком случае вставленная карта есть MMC и для ее инициализации потребуется команда CMD1 (так же посылается в цикле, пока ответ на нее не будет равен 0). Получив ответ на CMD1 равный 0х00 карта MMC готова к работе. Если ответ на ACMD41 не содержит никаких установленных битов (т.е. равен 0х00), то карта SD версии 1.х и она готова к работе. Теперь вернемся чуть выше и предположим, что в ответ на команду CMD8 не содержал бит «illegal command», т.е. у нас карта памяти формата SD версии 2.х стандартной емкости(SDSC версии 2.х) или SDHC. Следующим шагом в таком случае есть отправка команды ACMD41 с параметром, указывающим карте памяти, поддерживает ли наше устройство карты памяти SDHC. Вне зависимости от того, есть поддержка SDHC или ее нет, мы циклически отправляем эту команду карте то тех пор, пока она (карта) не закончит процесс инициализации. Когда ответ от ACMD41 будет равен 0х00, карта памяти проинициализирована и готова к работе. Но для того, чтобы узнать, какая у на карта, мы отправим ей команду CMD58. Ответом от этой команды есть R3, который в свою очередь содержит регистр OCR. Проанализировав OCR на установку бита CSS можно определить тип карты: CCS == 1 – карта SDHC или SDXC, CCS == 0 – карта SDSC. Чтобы не быть голословным, приведу мой участок кода инициализации карты памяти:
Закончив процесс идентификации(тип карты памяти) и инициализации, можно приступать к работе с картой памяти: вычисление объема, чтение и запись данных и т.д.Но это уже вопрос следующей статьи. Жду комментариев и вопросов. Критика и советы оч приветствуются!
P.S. Забегая немного вперед, пару скринов чтения информации с карты памяти:
В устройствах на микроконтроллерах для хранения больших объемов данных используется внешняя память. Если требуется хранить единицы мегабайт, то подойдут микросхемы последовательной флэш памяти. Однако для больших объемов (десятки -сотни мегабайт) обычно применяются какие-нибудь карты памяти. В настоящий момент наибольшее распространение получили SD и microSD карты, о них я и хотел бы поговорить в серии материалов. В этой статье речь пойдет о подключении 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-х битном режимах.
В устройствах на микроконтроллерах для хранения больших объемов данных используется внешняя память. Если требуется хранить единицы мегабайт, то подойдут микросхемы последовательной флэш памяти. Однако для больших объемов (десятки -сотни мегабайт) обычно применяются какие-нибудь карты памяти. В настоящий момент наибольшее распространение получили SD и microSD карты, о них я и хотел бы поговорить в серии материалов. В этой статье речь пойдет о подключении 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-х битном режимах.
На сегодняшний день карты памяти SD (microSD) стали очень дешевыми и доступными, являются хорошим вариантом для увеличения памяти в своих проектах на микроконтроллерах и встраиваемых системах. В этом проекте мы рассмотрим методы подключения данных типов карт к микроконтроллерам AVR ATmega8, ATmega32 компании Atmel. Основной целью является изучение интерфейса SD карт и понимание процесса передачи данных в «сыром» (без спецификации) формате и в формате файловой системы FAT32.
Как известно, карты памяти SD совместимы с интерфейсом SPI, поэтому их легко можно подключить к микроконтроллеру и наладить с ними обмен данными. Адаптеры для карт типа microSD также являются доступными, из такого адаптера мы можем изготовить слот для карты microSD для нашего макета. На фотографиях ниже показан внешний вид изготовленного адаптера для подключения к макетной плате.
В проект изначально использовалась карта памяти microSD объемом 1 ГБайт. Микроконтроллер – ATmega8 или ATmega32, работающий на частоте 8 МГц от внутреннего RC осциллятора. Кроме того, для подключения макета к персональному компьютеру для мониторинга данных использовался интерфейс RS-232. Для преобразования логических уровней интерфейса используется микросхема MAX232. Для питания схемы необходим стабилизированный источник питания 3.3 В (микросхема MAX232 рассчитана на напряжение питания 5 В, однако, как показала практика, сохраняет работоспособность при 3.3 В). Подключение карты памяти по 7-проводной схеме, согласно распиновке (см. рис).
Принципиальная схема для микроконтроллера ATmega8.
Подтягивающие резисторы R1, R2 номиналом 51 кОм интерфейса SPI придают лучшую стабильность при работе с различными картами. Стабилитроны D1, D2 предназначены для защиты карты памяти при работе внутрисхемного программатора (ISP). Выводы микросхемы MAX232 VCC и GND на схемах не указаны, но их необходимо подкличить к соответствующим точкам схемы.
Принципиальная схема для микроконтроллера ATmega32
Принципиальная схема для микроконтроллера ATmega32 (добавлены часы реального времени на микросхеме DS1307)
Как вы заметили, питание последнего варианта устройства осуществляется от источника 12 В, а на плате установлены два регулятора напряжения 5.0 В (LM7805) и 3.3 В (LM1117-3.3). Для питания интерфейса SD карты используется 3.3 В, вся остальная часть схемы питается от источника 5.0 В. Микросхема часов реального времени DS1307 в стандартном включении и подключена к интерфейсу I2C микроконтроллера.
Сперва был изучен «сырой» формат передачи данных, на примере операций чтения любого блока данных, чтения и записи нескольких блоков данных, стирания нескольких блоков, записи данных в любой блок памяти SD. Устройство, собранное на макетной плате, подключалось к компьютеру по интерфейсу RS-232. Для отображения прочитанных данных с карты памяти, а также для ввода и записи данных на карту используется программа HyperTerminal (или аналогичная) на компьютере.
После удачной реализации обмена данными без спецификации, карта памяти была отформатирована (FAT32) в операционной системе Windows XP, затем на карту были записаны несколько текстовых файлов, директорий и другие типы файлов (в корневую директорию карты). После этого были написаны подпрограммы и функции по работе с файловой системой FAT32 для чтения файлов, для получения списка файлов на карте памяти (с использованием HiperTerminal), для получения информации о полном и свободном объеме памяти.
Вид окна программы HiperTerminal с функциями по работе с картой памяти SD:
Пользователю предлагаются свыше 10 опций по работе с картой памяти (для варианта с часами).
Опции 0 – 4 – это низкоуровневые функции. Gосле использования опций 0 – 3 Вам необходимо переформатировать карту перед использованием FAT32 подпрограмм.
Опции 5 – 9 – относятся к файловой системе FAT32. На данный момент поддерживаются только короткие имена файлов (8 Байт - имя файла, 3 Байта – расширение файла). Если будут записаны файлы с длинными именами, то они будут отображены в терминальной программе в коротком формате. Для тестирования этих опций не забудьте отформатировать карту в файловой системе FAT32, записать несколько директорий и текстовых файлов.
Описание опций:
0 – Erase Blocks – стирание выбранного количества блоков начиная с указанного.
1 – Write Single Block - запись данных в блок с определенным адресом. Данные вводятся с клавиатуры в программе Hiperterminal;
2 – Read Single Block – чтение данных с блока с определенным адресом. Прочитанные данные отображаются в окне терминальной программы;
3 - Writing multiple blocks – запись нескольких блоков, начиная с определенного адреса;
4 - Reading multiple blocks – чтение нескольких блоков, начиная с определенного адреса.
5 – Get File List – отображает список доступных директорий и файлов с занимаемым ими объемом памяти (в корневой директории карты);
6 – Read File – чтение указанного файла и отображение содержимого в окне терминальной программы;
7 – Create File – создать/добавить файл с указанным именем;
8 – Delete File – удалить все файлы файл с указанным именем;
9 – Read SD Memory Capacity – информация о полном и свободном объеме карты памяти (используется FSinfo сектор SD карты).
В терминальной программе последовательный порт настраивается на скорость обмена 19200 бод, без контроля потока и без проверки четности.
Для версии с часами реального времени (DS1307) на микроконтроллере ATmega32 свойства создаваемых или обновляемых файлов привязываются к дате и времени (дата создания/изменения), эти свойства прописываются в файловой таблице и могут быть проверены с помощью компьютера, а также часы могут быть полезны при сборе данных. В меню опций в терминальной программе добавлены три опции:
a – Show Date&Time – по этой команде в окне терминальной программы отображается текущая дата и время;
b – Update Date – обновить дату;
с – Update Time – обновить время.
Также в верхней части отображается информация об определенной карте памяти:
Исходные файлы проекта:
Для разработки ПО и компиляции использовался Си компилятор WinAVR совместно с AVRStudio
Версия 2.4 (ATmega32, поддержка часов реального времени, поддержка SDHC) от 17 мая 2010 г..
Версия 2.3 (ATmega32, поддержка SDHC) от 09 мая 2010 г.
Версия 2.1 для микроконтроллера ATmega8, без поддержки SDHC:
Версии 2.3, 2.4 тестировались на микроконтроллере ATmega32, но могут быть адаптированы под любой контроллер с памятью SRAM не менее 1 КБайт и Flash-памятью программ не менее 16 КБайт.
Курс для новичков продолжается ознакомлением с SPI на примере работы с SD/MMC карточками. А поскольку USB-MSC мы уже проходили, то соорудим пародию на картридер. Пользоваться им я категорически запрещаю, т.к. размер карты зашит в коде и при установки другой карты вы можете потерять ваши данные.
Нам понадобится MMC либо SD карточка объемом до 2Гб. SDHC карточка нам не подойдет! С ней пример работать не будет.
Наиболее правильно было бы взять код FatFS от ChaN (У меня нашолся такой архив ffsample.zip, не помню какой свежести) в котором присутствует и определение размера, и работа с SDHC картами. Но код тяжел для начинающих. Желающие могут попробовать самостоятельно подключить правильную реализацию. Я же ограничусь более простой версией.
Так же отмечу, что это довольно сложный урок, и по-хорошему вы уже должны быть не начинающим.
Схема
Используем схему из прошлого урока с подключением USB разъема и добавляем подключение карточки. Для этого нам надо собрать следующую схему:
Можете подпаять проводки либо непосредственно к карточке, которую не жалко, либо как я воспользоваться слотом для карты. Приведённая схема одинакова как для SD так и для MMC карты. Все лишние (не показанные) выводы MMC карты остаются неподключенными.
Дорабатываем код
- Настройка SPI
- Код для работы с картой памяти
- Доработка функций чтения/записи USB-диска
Настройка SPI
В проекте (не библиотеке, т.к. здесь мы её не подключали) создаем файл ssp.h со следующим содержимым:
Поскольку карта памяти должна инициализироваться на скорости 400кГц, а работать может и на 20МГц, то функцию инициализации напишем с одним параметром, задающим медленный/высокоскоростной режим работы SPI.
Создаём файл ssp.c с реализацией функций. После подключения заголовочных файлов добавляем функции для выбора устройства.
Source File пишем ssp.c и жмем Finish.
Эти функции нам нужны, т.к. мы не будем использовать имеющийся аппаратный контроль, а будем выбирать карточку самостоятельно (ввиду некоторых ограничений в протоколе работы с картой памяти).
Далее реализуем функцию передачи. В ней мы просто заносим данные для передачи в регистр данных DR контроллера SPI. После этого контроллер SPI самостоятельно запускает цикл обмена. Нам же остается только ждать его завершения, о чём сообщит нам второй бит в регистре SR контроллера SPI. По окончании обмена мы извлекаем из регистра данных DR контроллера SPI принятые данные и возвращаем их как результат работы функции.
Теперь приступим к функции инициализации:
- установка в регистр SSPCLKDIV делителя тактовой частоты для контроллера SPI (задание частоты работы контроллера SPI) в 10 или 1, в зависимости от требуемого режима;
- установка в регистр CR0 формата пакета (подробно в документации к контроллеру) и дополнительного делителя (задание частоты тактовой линии SPI) в 8 либо 1, в зависимости от требуемого режима;;
- установка в регистр CPSR делителя частоты для опорной частоты тактовой линии SPI в минимальное значение 2;
- удаление «мусора» из приемного буфера SPI;
- установка в регистр CR1 работы контроллера в режиме «мастер» и разрешение тем самым работы контроллера SPI;
Работа с картой
Подробно рассматриваться не будет (Очень кстати, пока готовился курс, появилась статья от lleeloo). Функции расположены в файле sdcard.c и описаны в файле sdcard.h, которые требуется добавить к проекту.
Отмечу, что в файле sdcard.h содержится определение размера нашей карты памяти:
Всё имена те же, что были в примере. Укажите здесь количество блоков вашей карты памяти в MSC_BlockCount. Ещё раз напомню, что SDHC не поддерживаются и более 2Гб не может быть.
Так же добавился вызов инициализация карты памяти в функции main в файле usbmemrom_main.c:
Функция SetLed предназначена для целей диагностики. Так если при инициализации карты возникла ошибка, то будет зажжен светодиод на плате, индицируя ошибку.
Функции чтения/записи
В файле msccallback.c правим функции чтения и записи блока диска. Но так как размер блока на диске у нас 512 байт, а размер блока USB всего 64 байта, то для чтения одного блока диска функция чтения будет вызвана 8 раз подряд с разным смещением для одного и того же блока. И точно так же для записи. Что бы ни делать несколько чтений одного блока с диска (а тем более записей), добавим кэширование:
После этого функция чтения выглядит крайне просто:
И функция записи так же проста, только добавлен код записи буфера по достижение конца блока:
В коде присутствует вызов той же SetLed, на этот раз с целью индикации обращения к карте.
Запуск
Как обычно компилируем и исправляем ошибки.
После подключения добавленного разъема к компьютеру светодиод начнет мигать, а в системе появиться новый съемный диск.
Если светодиод постоянно ярко светится, что бывает, когда в начале был другой код, который «сбил» инициализацию карте, то обесточьте плату и снова подайте питание.
Если система предлагает вам диск отформатировать, то вероятно у вас в коде не верно указан размер. Хотя возможно просто карточка не была отформатирована.
Я повторно рекомендую не использовать карточки с важными для вас данными. Сам я при экспериментах указывал и меньшие и большие размеры, но кто знает как поведёт себя нестабильная система.
Статистика
Кода в Debug версии у меня получилось 4216 байт кода. Скорость чтения составила 194 кБайт/с, скорость записи 84 кБайт/с.
После переключения в Release версию код уменьшился до 2772 байта. Скорость чтения при этом выросла до 239 кБайт/с, а записи до 95кБайт/с.
Вместо заключения
С сожалением должен признать, что урок получился объемным и непонятным. При этом при всём непосредственно по теме (SPI) пара жалких абзацев. Даже исключение принципов работы с картой памяти хоть и сократило статью, но недостаточно.
Однако, буду надеяться, что изучение прошлых примеров научило вас разбираться в коде.
P.S.: Этот урок был написан до SPI. Подключаем дисплей от Nokia 3310., так что информация дублируются.
Читайте также: