- •Перечень сокращений
- •Предисловие
- •Введение
- •Часть 1. Архитектура и аппаратные средства микроконтроллера LPC214x
- •1.1 Общие сведения о микроконтроллерах LPC214x
- •1.2 Программистская модель процессорного ядра ARM7TDMI
- •1.2.1 Режимы работы ядра ARM7
- •1.2.2 Система регистров
- •1.2.3 Слово состояния программы
- •1.2.4 Организация памяти
- •1.3 Система команд
- •1.3.1 Команды арифметической и логической обработки
- •1.3.2 Команды умножения
- •1.3.3 Команды регистровой пересылки
- •1.3.4 Команды загрузки и сохранения регистров
- •1.3.5 Команды пакетного обмена с памятью
- •1.3.6 Команды передачи управления
- •1.3.7 Команды обращения к слову состояния программы
- •1.4 Методы адресации
- •1.4.1 Непосредственная адресация
- •1.4.2 Регистровая адресация
- •1.4.3 Косвенная адресация
- •1.4.4 Индексная адресация
- •1.5 Процедура начальной загрузки и режимы отображения памяти
- •1.6 Обработка исключительных ситуаций
- •1.7 Система тактирования
- •1.7.1 Выбор тактовой частоты микроконтроллера
- •1.7.2 Настройка тактирования периферийных устройств
- •1.8 Модуль ускорения памяти
- •1.9 Внешние выводы микроконтроллера
- •1.9.1 Служебные контакты
- •1.9.2 Программно-управляемые линии ввода-вывода
- •1.9.3 Альтернативные функции линий ввода вывода
- •1.10 Цифровые порты ввода-вывода
- •1.10.1 Управление портом через низкоскоростную шину
- •1.10.2 Управление портом через высокоскоростную шину
- •1.11 Система прерываний
- •1.11.1 Назначение системы прерываний
- •1.11.2 Процесс обработки прерываний IRQ
- •1.11.3 Процесс обработки быстрых прерываний FIQ
- •1.11.4 Регистры управления системой прерываний
- •1.11.5 Порядок настройки прерывания IRQ
- •1.11.6 Порядок настройки быстрого прерывания FIQ
- •1.11.7 Процедура обработки прерывания
- •1.11.8 Задержка обработки прерывания
- •1.12 Внешние прерывания
- •1.12.1 Регистры управления блоком внешних прерываний
- •1.12.2 Порядок настройки блока внешних прерываний
- •1.13 Таймеры-счетчики
- •1.13.1 Режим таймера и схема совпадения
- •1.13.2 Режим счетчика
- •1.13.3 Схема захвата
- •1.13.4 Управляющие регистры
- •1.13.5 Формирование интервалов времени через систему прерываний
- •1.13.6 Измерение периода и длительности импульса с помощью устройства захвата
- •1.13.7 Подсчет числа импульсов в единицу времени
- •1.14 Широтно-импульсный модулятор
- •1.14.1 Основы функционирования
- •1.14.2 Дополнительные возможности
- •1.14.3 Регистры управления ШИМ
- •1.14.4 Порядок настройки ШИМ
- •1.15 Аналого-цифровые преобразователи
- •1.15.1 Краткие сведения о встроенных АЦП
- •1.15.2 Общие рекомендации по использованию АЦП
- •1.15.3 Управляющие регистры
- •1.15.4 Порядок настройки АЦП
- •1.15.5 Программный запуск аналого-цифрового преобразователя
- •1.15.6 Запуск аналого-цифрового преобразователя по таймеру
- •1.15.7 Программный опрос готовности АЦП
- •1.15.8 Опрос готовности АЦП по прерыванию
- •1.15.9 Считывание и масштабирование результата АЦП
- •1.16 Цифро-аналоговый преобразователь
- •1.16.1 Регистр управления ЦАП
- •1.16.2 Рекомендации по применению ЦАП
- •1.17 Последовательный синхронный приемо-передатчик SPI
- •1.17.1 Назначение и основы функционирования интерфейса SPI
- •1.17.2 Управляющие регистры
- •1.17.3 Передача и прием данных в режиме ведущего
- •1.17.4 Передача и прием данных в режиме ведомого
- •1.18 Последовательный синхронный приемо-передатчик I2С
- •1.18.1 Назначение и основы функционирования интерфейса I2С
- •1.18.2 Управляющие регистры
- •1.18.3 Настройка модуля I2C
- •1.18.4 Типовые циклы обмена данными по шине I2C
- •1.19 Последовательный асинхронный приемопередатчик UART
- •1.19.1 Назначение и основы функционирования порта UART
- •1.19.2 Управляющие регистры
- •1.19.3 Настройка порта UART
- •1.19.4 Прием байта с опросом флага
- •1.19.5 Передача байта с опросом флага
- •1.19.6 Прием и передача данных с использованием прерываний
- •1.19.7 Прием и передача пакетов данных
- •1.19.8 Диагностика ошибок
- •1.19.9 Автоматическая настройка скорости
- •1.20 Часы реального времени
- •1.20.1 Основные возможности часов реального времени
- •1.20.2 Управляющие регистры
- •1.20.3 Рекомендации по применению
- •1.21 Управление питанием и идентификация источников сброса
- •1.21.1 Краткие сведения о мониторе питания
- •1.21.2 Управляющие регистры
- •Часть 2. Разработка и отладка программ с помощью современных инструментальных средств
- •2.1 Форматы представления чисел
- •2.1.1 Основные коды представления целых чисел
- •2.1.2 Форматы представление целых чисел, приятные в языке Си
- •2.1.3 Форматы чисел c плавающей точкой стандарта IEEE754
- •2.2 Основы программирования на языке Си
- •2.2.1 Структура программы
- •2.2.2 Числовые константы
- •2.2.3 Переменные и именованные константы
- •2.2.4 Оператор присваивания, выражения и операции
- •2.2.5 Условный оператор
- •2.2.6 Приведение и преобразование типов
- •2.2.7 Массивы
- •2.2.8 Строки символов
- •2.2.9 Структуры
- •2.2.10 Объединения
- •2.2.11 Указатели
- •2.2.12 Ветвление
- •2.2.13 Множественное ветвление
- •2.2.14 Цикл со счетчиком
- •2.2.15 Циклы с предусловием и постусловием
- •2.2.16 Функции
- •2.2.17 Некоторые директивы компилятора
- •2.2.18 Библиотека математических функций MATH.h
- •2.2.19 Функция создания форматированных строк SNPRINTF
- •2.2.20 Ассемблер в Си-программах
- •2.3 Интегрированная среда разработки Keil µVision 4
- •2.3.1 Создание проекта
- •2.3.2 Создание файла программы
- •2.3.3 Настройка проекта
- •2.3.4 Набор текста программы
- •2.3.5 Компиляция программы
- •2.3.6 Отладка программы
- •2.3.7 Основные отладочные инструменты среды Keil µVision 4
- •2.3.8 Управление распределением памяти
- •2.4 Методика отладки программ
- •2.4.1 Быстрый поиск ошибок
- •2.4.2 Ввод и вывод дискретных сигналов
- •2.4.3 Таймер-счетчик. Формирование интервалов времени
- •2.4.4 Таймер-счетчик. Формирование внешних сигналов совпадения
- •2.4.5 Таймер-счетчик. Счетчик внешних событий
- •2.4.6 Таймер-счетчик. Устройство захвата
- •2.4.7 Широтно-импульсный модулятор
- •2.4.8 Аналого-цифровой преобразователь
- •2.4.9 Цифро-аналоговый преобразователь
- •2.4.10 Приемопередатчик SPI
- •2.4.11 Приемопередатчик I2C
- •2.4.12 Приемопередатчик UART
- •2.4.13 Часы реального времени
- •2.5 О программировании ARM7 на ассемблере
- •2.5.1 Основные правила записи программ на ассемблере
- •2.5.2 Псевдокоманды
- •2.5.3 Директивы ассемблера
- •2.5.4 Макросы
- •2.5.5 Пример простой программы
- •2.6 Распространенные средства разработки и отладки
- •2.6.1 Демонстрационные платы EA-EDU-001 и EA-EDU-011
- •2.6.2 Внутрисхемный отладчик J-Link
- •2.6.3 Утилиты программирования ПЗУ LPC Flash Utility и FlashMagic
- •2.6.4 Программа-терминал 232Analyzer
- •2.6.5 Низкоуровневый редактор диска DMDE
- •Часть 3. Решение типовых задач локального управления
- •3.1 Формирование временной задержки с помощью цикла
- •3.1.1 Задание
- •3.1.2 Общие рекомендации
- •3.1.3 Алгоритм программы
- •3.1.4 Отладка
- •3.1.5 Дополнительные сведения о формировании временной задержки
- •3.2 Формирование дискретного сигнала с помощью таймера
- •3.2.1 Задание
- •3.2.2 Общие рекомендации
- •3.2.3 Алгоритм программы
- •3.3 Опрос дискретного датчика или кнопки
- •3.3.1 Задание
- •3.3.2 Общие рекомендации
- •3.3.3 Алгоритм программы
- •3.3.4 Отладка
- •3.4 Опрос состояния механических контактов с подавлением дребезга
- •3.4.1 Задание
- •3.4.2 Общие рекомендации
- •3.4.3 Алгоритм программы
- •3.4.4 Отладка
- •3.5 Опрос клавиатуры с автоповтором
- •3.5.1 Задание
- •3.5.2 Общие рекомендации
- •3.5.3 Алгоритм программы
- •3.5.4 Отладка
- •3.6 Формирование импульсного управляющего сигнала с помощью модуля ШИМ
- •3.6.1 Задание
- •3.6.2 Общие сведения
- •3.6.3 Алгоритм программы
- •3.6.4 Отладка
- •3.6.5 Синхронизация внешним сигналом
- •3.7 Формирование сигналов специальной формы с помощью ЦАП
- •3.7.1 Задание
- •3.7.2 Основы
- •3.7.3 Алгоритм программы
- •3.7.4 Повышение точности генерирования частоты
- •3.7.5 Выбор числа дискрет
- •3.8 Управление двухфазным шаговым двигателем
- •3.8.1 Задание
- •3.8.2 Общие сведения
- •3.8.3 Алгоритм программы
- •3.9 Применение ШИМ для формирования низкочастотных аналоговых сигналов
- •3.9.1 Задание
- •3.9.2 Основные сведения
- •3.9.3 Алгоритм основной программы
- •3.9.4 Алгоритм процедуры обработки прерывания
- •3.10 Управление символьным жидкокристаллическим индикатором
- •3.10.1 Задание
- •3.10.2 Управление модулем жидкокристаллической индикации
- •3.10.3 Разработка функции управления ЖКИ с ожиданием готовности
- •3.10.4 Функция вывода строки символов
- •3.10.5 Разработка функции инициализации модуля ЖКИ
- •3.10.6 Разработка тестовой программы
- •3.10.7 Управление ЖКИ с опросом флага готовности
- •3.10.8 Программирование произвольных символов
- •3.11 Управление матричным светодиодным индикатором
- •3.11.1 Задание
- •3.11.2 Основные рекомендации
- •3.11.3 Алгоритм основной программы
- •3.11.4 Алгоритм процедуры обработки прерывания
- •3.11.5 Реализация движения строки
- •3.12 Управление матричным жидкокристаллическим дисплеем
- •3.12.1 Управление дисплеем на основе контроллера PCF8833
- •3.12.2 Построение простейших геометрических фигур
- •3.13 Измерение постоянного напряжения
- •3.13.1 Задание
- •3.13.2 Основные рекомендации
- •3.13.3 Алгоритм основной программы
- •3.13.4 Алгоритм процедуры обработки прерывания от АЦП
- •3.13.5 АЦП с циклическим опросом нескольких каналов
- •3.13.6 Автоматический выбор пределов измерения
- •3.14 Измерение параметров уровня переменного напряжения
- •3.14.1 Задание
- •3.14.2 Основные рекомендации
- •3.14.3 Алгоритм основной программы
- •3.14.4 Алгоритм процедуры обработки прерывания
- •3.15 Измерение ускорения с помощью трехосевого акселерометра
- •3.16 Измерение интервалов времени с помощью таймера
- •3.16.1 Задание
- •3.16.2 Общие рекомендации
- •3.16.3 Алгоритм основной программы
- •3.16.4 Алгоритм процедуры обработки прерывания
- •3.16.5 Повышение разрешающей способности путем усреднения
- •3.16.6 Введение поправок
- •3.17 Измерение частоты с помощью счетчика
- •3.17.1 Задание
- •3.17.2 Основные рекомендации
- •3.17.3 Алгоритм программы
- •3.17.4 Повышение точности измерений
- •3.18 Опрос цифрового датчика температуры. Интерфейс I2C
- •3.18.1 Задание
- •3.18.2 Общие рекомендации
- •3.18.3 Алгоритм программы
- •3.20 Обмен данными с электрически перепрограммируемым ПЗУ
- •3.20.1 Задание
- •3.20.2 Общие сведения о микросхемах EEPROM
- •3.20.3 Адресация в микросхемах EEPROM
- •3.20.4 Порядок чтения EEPROM
- •3.20.5 Порядок записи EEPROM
- •3.20.6 Разработка программы чтения EEPROM
- •3.20.7 Разработка функции записи блока данных в EEPROM
- •3.21 Интерфейс RS-232. Прием и передача простых команд
- •3.21.1 Задание
- •3.21.2 Алгоритм программы
- •3.21.3 Автоматическая настройка скорости
- •3.22.1 Задание
- •3.22.2 Основные рекомендации
- •3.22.3 Алгоритм программы
- •3.23 Интерфейс RS-232. Прием пакета переменной длины
- •3.23.1 Задание
- •3.23.2 Основы реализации
- •3.23.3 Алгоритм программы
- •3.24 Обмен данными с картой памяти Secure Digital
- •3.24.1 Задание
- •3.24.2 Общие сведения о карах FLASH-памяти SD/MMC
- •3.24.3 Команды SD/MMC
- •3.24.4 Процедура инициализации карты
- •3.24.5 Чтение и запись данных
- •3.24.6 Обработка ошибок
- •3.24.7 Комментарии к алгоритму и программе
- •Алфавитный указатель управляющих регистров
- •Список литературы
- •Содержание
Команда чтения обозначается CMD17 (код 0x51), команда записи — CMD24 (код 0x58). Четырехбайтным аргументом команд служит адрес начала блока. Блок целиком должен помещаться в пределы сектора 512 байт. Значит, например, нельзя считывать более одного байта с адреса 0x1FF (511), потому что граница секторов окажется «накрыта» блоком. По той же причине при записи адрес должен быть кратным 512.
Разумеется, необходимо учитывать и объем карты памяти. Установка адреса, превышающего физический объем, приведет к ошибке. Следует принимать во внимание, что реальная емкость меньше заявленной. Так, например, карта microSD фирмы Transcend c маркировкой «2GB» содержит ровно 1886 мегабайт.
Очевидно, что 32-х разрядная адресация позволяет работать с объемом до 4 Гбайт. В картах большей емкости используется не побайтная, а посекторная адресация. В адресной части передается номер сектора, размер которого всегда равен 512 байтам.
После ответа на команду по шине SPI передается пакет данных заранее оговоренной длины (установленной CMD16). Пакет начинается с маркера 0xFE, последовательности байтов данных и двух байт циклического кода CRC16. Формат пакета одинаков независимо от того, в каком направлении он передается. Если пакет направлен карте памяти, она подтвердит прием байтом в формате, обозначенном как «подтверждение пакета» (рисунок 3.24.1). Безошибочная передача сопровождается кодом подтверждения 0x05. Пакет, принятый от карты ни в каком подтверждении не нуждается.
Процедура чтения на этом завершается; но для завершения записи потребуется еще некоторое время. При этом на линии MISO (контакт DO карты) будет удерживаться низкий уровень (рисунок 3.24.2), что при чтении байта с шины SPI даст код 0x00. После завершения записи установится высокий логический уровень, соответственно, будут считываться коды 0xFF. Отметим, что активный уровень сигнала CS может быть снят, не дожидаясь окончания записи. Сигнал «занят» в этом случае также снимается картой и устанавливается снова только при появлении активного уровня выбора ведомого (CS).
3.24.6 Обработка ошибок
До сих пор считалось, что взаимодействие с картой памяти выполняется без ошибок и ответ равен 0x00. Коротко рассмотрим диагностику возможных ошибок.
Прежде всего, необходимо всякий раз при вызове функции WaitFor задать маску 0x80. Тогда за удовлетворительный ответ будет приниматься любой байт с нулем в старшем разряде. Далее потребуется проанализировать значение, возвращаемое функцией. Нулевой результат говорит об отсутствии ошибки, ненулевой требует соответствующей обработки. Если же старший байт результата оказался не равен нулю, значит, ответ вообще не был принят в течение отведенного времени.
243
Далее, в процедуре записи блока следует изменить ожидаемый байт подтверждения пакета с 0x05 на 0x01 и задать маску 0x11. Под это правило попадают все три возможные значения кода подтверждения (см. рисунок
3.24.1 в центре).
Если в процессе чтения данных с карты возникает ошибка, то вместо маркера пакета 0xFE высылается сообщение об ошибке (см. рисунок 3.24.1 справа). Маркер не имеет ни одного общего бита с сообщением об ошибке, поэтому простого наложения маски здесь недостаточно. Потребуется отдельная функция ожидания пакета, которая принимала бы как ответ 0xFE, так и 0x00 с маской 0x1F.
do { ... } while ((B!=0xFE)&&(B&0x1F>0)&&(N>0));
Отметим, что картами поддерживается команда CMD13, которая может использоваться для выявления ошибок, возникших в процессе записи. Карта высылает обычный ответ, за которым следует еще один байт, содержащий в основном те же флаги, что и «Сообщение об ошибке».
В ответственных случаях можно гарантировать успешное завершение сравнения каждого записанного блока.
Для проверки программы можно рекомендовать использовать устройство для чтения Flash-карт персонального компьютера и программу
DMDE 2.0
3.24.7 Комментарии к алгоритму и программе
Схемы алгоритмов подпрограмм и основной программы показаны на рисунках 3.24.3–3.24.5. Поскольку ниже приведен полный листинг программы, подробные комментарии излишни. Разъясним лишь назначение отдельных подпрограмм.
В состав программы входят шесть три функции низкоуровневого управлении и три высокоуровневого.
Функция SPIByte выполняет передачу одного байта с ожиданием окончания и прием байта, который одновременно передавался ведомым.
Функция MMCCommand передает по шине SPI 6-байтную команду карты. Функция имеет три параметра: код команды, 4-байтный аргумент и код CRC7. Каждый байт передается с помощью SPIByte. Аргумент разделяется на байты операциями сдвига.
Функция WaitFor предназначена для циклического опроса шины SPI и ожидания определенного байта (передается через параметр функции). На принятый байт накладывается маска операцией «И», результат сравнивается с байтом-параметром. Операция повторяется до тех пор, пока не зафиксировано совпадение, но не более N раз. Число возможных повторов тоже передается через параметр. Функция возвращает значение принятого байта. Если выход функции не совпадает с ожидаемым значением, значит, оно так и не было принято за N попыток.
Высокоуровневая функция MMCInit выполняет весь набор действий по настройке портовых линий, приемопередатчика SPI и инициализации карты. После ее завершения карта полностью готова к работе.
244
|
Начало |
|
|
Начало |
|
|
|
|
|
||||
1 |
|
|
|
1 |
|
|
|
|
|
|
|
||
|
Ввод Byte |
|
Ввод Byte, Mask, N |
|
|
||||||||
2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
Передача по SPI Byte |
2 |
|
|
|
|
|
|
|
|||||
|
|
|
|
|
N = N – 1 |
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
||
3 |
|
|
|
3 |
|
|
|
|
|
|
|
||
|
|
Да |
|
Прием по SPI B |
|
|
|
|
|
||||
|
Передача ? |
|
|
|
|
|
|
|
|
|
|||
|
|
|
Нет |
|
|
4 N > 0 и |
|
Да |
|
|
|||
|
|
|
|
Byte ≠ B & Mask |
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|||
4 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Прием по SPI Byte |
|
|
Нет |
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
||
5 |
|
|
|
5 |
|
|
|
|
|
|
|
||
|
Возврат Byte |
|
|
Возврат B |
|
|
|
|
|
||||
|
|
Конец |
|
|
Конец |
|
|
|
|
|
|||
Рисунок 3.24.3 – Схема подпрограмм передачи байта по SPI (слева) |
|||||||||||||
|
и ожидания приема заданного байта (справа) |
|
|
||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Начало |
8 |
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
Линия CS = 1 |
|
|
|||
|
|
1 |
|
|
|
||||||||
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
Перевод порта 0 в |
9 |
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
высокоскор. режим |
|
|
|
|
Команда |
|
|
|||
|
|
2 |
|
|
|
|
(0x40, 0x00, 0x95) |
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
Настройка режима |
10 |
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
линий P0.4–P0.6 |
|
|
|
Ожидание 0x01 |
|
|
||||
|
|
3 |
|
|
|
|
10 попыток |
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
Режим вывода |
11 |
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
для линии P0.11 |
|
|
|
Передача 0xFF |
|
|
||||
|
|
4 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
Включить SPI; |
12 |
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
уст. частоту 300 кГц |
|
|
|
|
Команда |
|
|
|||
|
|
5 |
|
|
|
|
(0x41, 0x00, 0xFF) |
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
Линия CS = 0 |
13 |
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
Ожидание 0x00 |
|
|
|||
|
|
|
|
|
|
|
|
250 попыток |
|
|
|||
|
|
6 |
|
|
|
||||||||
|
Да |
|
|
Нет |
|
|
|
|
|
||||
|
|
k =0; k < 10; k++ |
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
14 |
Ответ 0x00 |
|
Нет |
|||||||
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
|
|
|
|
|
|||
7 |
|
|
|
|
|
|
|
|
принят? |
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Передача 0xFF |
|
|
|
|
|
|
Да |
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
Линия CS = 0 |
|
|
|||
|
|
|
|
|
16 |
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
Частота 7,5 МГц |
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
Конец |
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Рисунок 3.24.4 – Схема подпрограммы инициализации карты SD/MMC
245
Начало
1 Ввод Bytes, Addr, N
2
Линия CS = 0
3
Передача 0xFF
4
Команда
(0x50, N, 0xFF)
5 Ожидание 0x00
10 попыток
6
Передача 0xFF
7
Команда
(0x51, Addr, 0xFF)
8 Ожидание 0x00
10 попыток
9 Ожидание 0xFE
5000 попыток
Нет
Нет |
10 |
Да |
|
k =0; k < N+2; k++ |
|||
|
|
||
|
|
11 |
|
|
|
Прием Bytes[k] |
|
|
12 |
|
|
|
Линия CS = 1 |
|
|
|
Конец |
|
Начало
1 Ввод Addr
2
Линия CS = 0
3
Передача 0xFF
4
Команда
(0x50, 0x200, 0xFF)
5 Ожидание 0x00
10 попыток
6
Передача 0xFF
7
Команда
(0x58, Addr, 0xFF) |
|
|
8 |
|
|
Ожидание 0x00 |
|
|
10 попыток |
|
|
9 |
|
|
Передача 0xFE |
|
|
10 |
Да |
|
k = 0; k < 513; k++ |
||
|
||
|
11 |
|
|
Передача Bytes[k] |
|
12 |
|
|
Ожидание 0xX5 |
|
|
10 попыток |
|
|
13 |
|
|
Ожидание 0xFF |
|
|
5000 попыток |
|
|
14 |
|
|
Линия CS = 1 |
|
|
15 |
|
|
Ввод Bytes |
|
|
Конец |
|
Рисунок 3.24.5 – Схема подпрограммы чтения блока данных с карты SD/MMC (слева) и записи блока данных (справа)
Функции ReadBlock и WriteBlock выполняют чтение и запись блока данных (соответственно). Размер блока (только при чтении) и адрес передаются через параметры.
246
Укажем, что в большинстве случаев ответ будет получен со второй попытки. Поэтому параметр N в процедуре WaitFor с запасом принят равным десяти. Около 500 попыток требуется при чтении и записи карты. Там N увеличено до 5000. Подбор этих параметров осуществлялся экспериментально.
Время окончания записи одного блока (для карт Transcend) составляет около 2 мс. При этом оно случайно колеблется, иногда увеличивается до 10 мс и редко может достигать 250 мс.
Время, в течение которого карта занята, существенно сокращается при записи при пакетной записи. Порядок записи нескольких последовательно расположенных секторов аналогичен записи одного отдельного сектора. Код команды при этом 0x59, маркер кадра 0xFC. Если все сектора записаны, необходимо вместо маркера кадра передать маркер завершения записи 0xFD.
Последовательное чтение выполняется командой с кодом 0x52. Маркер кадра 0xFE будет передаваться картой в начале каждого блока. Остановка чтения выполняется командой 0x4C.
#include <LPC214x.h>
unsigned char Bytes[512];
/***** Передача и прием байта по SPI******************/
//Byte - передаваемый байт
//Возвращаемое значение содержит принятый байт unsigned char SPIByte(unsigned char Byte)
{
S0SPDR=Byte; while (!(S0SPSR & 0x80)) ; Byte=S0SPDR; return Byte;
}
/***** Передача команды ******************************/
//Com - код команды
//Arg - четырехбайтный аргумент
//Com - код CRC7
void MMCCommand(unsigned char Com, unsigned int Arg, unsigned char CRC)
{
SPIByte(Com); |
// Передать код команды |
SPIByte(Arg>>24); |
// Передать 3-ий байт аргумента |
SPIByte(Arg>>16); |
|
SPIByte(Arg>>8); |
|
SPIByte(Arg); |
// Передать 0-ой байт аргумента |
SPIByte(CRC); |
// Передать код CRC7 |
}
247
/***** Передача команды ******************************/
//Byte - ожидаемый байт
//Mask - маска принятого байта (через лог. умножение)
//N - число попыток приема
unsigned int WaitFor(unsigned |
char Byte, |
unsigned |
char Mask, |
unsigned |
int N) |
{ // Ждать требуемого байта
do N--; while ((Byte!=(SPIByte(0xFF)&Mask))&&(N>0));
return N; |
// |
Вернуть число оставшихся |
повторов |
} |
// |
Если N=0, значит байт не |
был принят |
/***** Инициализация MMС/SD **************************/ void MMCInit()
{
int k;
SCS|=1; |
// |
Высокоскорост. режим порта 0 |
PINSEL0|=0x00001500;// |
Настройка линий на режим SPI |
|
FIO0DIR|=0x800; |
// |
CS на вывод |
S0SPCR=0x820; |
// |
Настройка SPI (8 бит) |
S0SPCCR=200; |
// |
Скорость не более 400 кбит |
FIO0SET=0x00000800; // |
CS=1 |
|
|
// |
Не менее 74 тактов... |
for (k=0;k<10;k++) SPIByte(0xFF); //... пока CS=1 FIO0CLR=0x00000800; // CS=0 - активный уровень
MMCCommand(0x40,0x00,0x95); |
// Команда CMD0 |
WaitFor(0x01,0xFF,10); |
// Ждем ответа 0x01 |
SPIByte(0xFF); |
// Холостой байт |
do |
// Повторять... |
MMCCommand(0x41,0x00,0xFF); //...команду инициализ. while (WaitFor(0x00,0xFF,250)==0);// Ждать 0x00
FIO0SET=0x00000800; |
// CS=1 |
S0SPCCR=8; |
// Макс. скорость |
} |
|
/***** Чтение блока **********************************/
// |
Bytes |
- |
массив, в который помещаются данные |
// |
Addr |
- |
адрес начала блока |
248
// N - размер блока в байтах (1-512) void MMCRead(unsigned char *Bytes,
unsigned int Addr, unsigned int N)
{
int k; |
|
FIO0CLR=0x00000800; |
// CS=0 |
SPIByte(0xFF); |
// Холостой байт |
MMCCommand(0x50,N,0xFF); |
// Установка размера блока |
WaitFor(0x00,0xFF,10); |
// Ждать ответа 0x00 |
SPIByte(0xFF); |
// Холостой байт |
MMCCommand(0x51,Addr,0xFF); // Чтение блока |
|
WaitFor(0x00,0xFF,10); |
// Ждать ответа 0xFF |
WaitFor(0xFE,0xFF,5000); |
// Ждать маркера кадра 0xFE |
for (k=0;k<N+2;k++) |
// Прием пакета и CRC16 |
Bytes[k]=SPIByte(0xFF); |
|
FIO0SET=0x00000800; |
// CS=1 |
}
/***** Запись блока **********************************/
// Bytes |
- массив с данными для записи |
|
// Addr |
- адрес начала блока |
|
void MMCWrite(unsigned char *Bytes, |
||
|
unsigned int Addr) |
|
{ |
|
|
int k; |
|
|
FIO0CLR=0x00000800; |
// CS=0 |
|
SPIByte(0xFF); |
// Холостой байт |
|
MMCCommand(0x50,0x0200,0xFF);// Размер блока = 512 |
||
WaitFor(0x00,0xFF,10); |
// Ждать ответа 0x00 |
|
SPIByte(0xFF); |
// Холостой байт |
|
MMCCommand(0x58,Addr,0xFF); // Чтение блока |
||
WaitFor(0x00,0xFF,10); |
// Ждать ответа 0x00 |
|
SPIByte(0xFE); |
// Передать маркер кадра 0xFE |
|
for (k=0;k<511+2;k++) |
// Передать 512 байт и CRC16 |
|
SPIByte(Bytes[k]); |
|
|
WaitFor(0x05,0x0F,10); |
// Ждать подтверждения 0xX5 |
|
WaitFor(0xFF,0xFF,5000);// Ждать готовности (0xFF) |
||
FIO0SET=0x00000800; |
// CS=1 |
249
}
int main(void)
{
int k;
MMCInit();
for (k=0;k<512;k++) Bytes[k]=0x80 | (k>>4); MMCWrite(Bytes,0);
for (k=0;k<512;k++) Bytes[k]=0x88; MMCRead(Bytes,0,512);
while (1) ;
}
250