Все эти профили получили реализацию в одном или нескольких ядрах Cortex, так, например, Cortex- A9 основан на профиле application и является частью процессора в i. Phone 4. S, а Cortex- M0 основан на профиле microcontroller. Железки! В качестве тестовых устройств я предлагаю вам LPC1. MCU производства NXP, схему на котором можно собрать буквально на коленке (нет, правда, вам нужен только сам MCU, FTDI- кабель на 3,3 В, несколько светодиодов и резисторов). LPC1. 11. 4 построен на базе Cortex- M0, так что это будет самый урезанный вариант платформы. В качестве альтернативного варианта мы будем работать с платформой mbed, а конкретно, с моделью на базе LPC1.
Cortex- M3, несколько более навороченный). Вариант уже не настолько бюджетный, но процесс заливки бинарников на чип и отладки упрощен максимально. Да и можно поиграться с самой платформой mbed (вкратце: это онлайн- IDE и библиотека, с помощью которой можно программить на уровне ардуины). Приступим. Интересной особенностью современных ARM- ов является то, что их вполне реально программировать целиком на С, без применения ассемблерных вставок (хотя ассемблер не так уж и сложен, у Cortex- M0 всего 5. Хотя некоторые команды в принципе не доступны из С, эту проблему решает CMSIS – Cortex Microcontroller Software Interface Standard.
Это драйвер для процессора, который решает все основные задачи управления им. Как же загружается процессор? Типична ситуация, когда он просто начинает выполнять команды с адреса 0x. В нашем случае процессор несколько более умный, и рассчитывает на специально определенный формат данных в начале памяти, а именно – таблицу векторов прерываний: Старт выполнения программы происходит следующим образом: процессор читает значение по адресу 0x. SP (SP – регистр, который указывает на вершину стека), после чего читает значение по адресу 0x.
PC (PC – регистр, который указывает на текущую инструкцию + 4 байта). Таким образом начинает выполняться какой- то код пользователя, при этом у нас уже есть стек, указывающий куда- то в память (т. С). В качестве тестового упражнения мы будем мигать светодиодом.
На mbed у нас их целых четыре, в схему с LPC1. Перед тем как непосредственно писать код, нам надо выяснить еще одну вещь, а именно – что где должно располагаться в памяти. Поскольку мы не работаем с какой- то «стандартной» ОС, то компилятор (вернее, компоновщик) не может узнать, где у него должен быть стек, где сам код, а где — куча. К счастью для нас, у семейства ядер Cortex стандартизированная карта памяти, что позволяет относительно просто портировать приложения между разными процессорами этой архитектуры. Работа с периферией, конечно, остается процессорозависимой. Карта памяти для Cortex- M0 выглядит вот так: (изображение из Cortex. Проблема тут в том, что у NXP есть свой, отдельный взгляд на этот вопрос, так что проверяем карту памяти в документации на процессор: (изображение из LPC1.
LPC1. 1Cxx User manual)На самом деле, SRAM у нас начинается с 0x. Вот так, одни стандарты, другие стандарты, а все равно надо тома документации листать. Вооружившись этими знаниями, идем писать код.
Для начала – таблица прерываний. Тут, фактически, только одна ассемблерная вставка – функция hang, которая устраивает процессору бесконечный цикл. Все прерывания, кроме reset, указывают на нее, так что в случае непредвиденной ситуации процессор просто зависнет, а не пойдет выполнять непонятный участок кода. Сама таблица должна бы быть длиннее, но на самом деле мы могли бы закончить ее еще после вектора Reset, остальные у нас не сработали бы в этом примере.
Но, на всякий случай, мы заполнили таблицу почти целиком (кроме пользовательских прерываний). Теперь напишем реализацию функции main: #if defined(!
Одни и те же пины могут выполнять разные функции, эти по умолчанию работают именно как GPIO (General Purpose I/O – линии ввода/вывода общего назначения). Код относительно прямолинеен, если держать под рукой LPC- шный User manual (один и второй). Для начала мы указываем режим работы GPIO через регистр GPIO.
Потом мы запускаем бесконечный цикл, в котором пишем в порт попеременно значения 0 и 1 (0 В и 3,3 В соответственно). Функция для «паузы» у нас работает наугад, просто прокручивая относительно долгий цикл (volatile int не дает компилятору выоптимизировать этот цикл целиком). Наконец, все это нужно правильно скомпоновать.
После определения карты памяти мы указываем, какие сегменты куда копировать, . Помимо этого мы задаем два символа, которые использовали в boot.
Чексумма рассчитывается по формуле: дополнительный код (2's compliment) от суммы полей выше (т. Хотя утилиты для прошивки (см. В качестве тулчейна мы будем использовать GCC, позже, возможно, я покажу как делать то же с LLVM. Пользователям OS X я советую взять тулчейн у Linaro – в самом конце списка: Bare- Metal GCC ARM Embedded.
Пользователям других ОС я советую взять тулчейн там же : -) (разве что гентушникам будет проще сэмержить crossdev и скомпилить GCC). O2 - nostdlib - nostartfiles - ffreestanding - Wall - mthumb - mcpu=cortex- m. O2 - nostdlib - nostartfiles - ffreestanding - Wall - mthumb - mcpu=cortex- m. T mem. ld boot. o main- c. T mem. ld boot. o main- c. D blink- c. 0. elf > blink- c.
D blink- c. 3. elf > blink- c. O binary. arm- none- eabi- objcopy blink- c. O binary. Интересный момент тут — это отключение использования всех стандартных библиотек у GCC. Действительно, весь код, который попадет в итоговый бинарник – это код, который написали мы сами. Вопрос: как компоновщик знает, куда надо засунуть таблицу прерываний?
А он и не знает, там не написано : -). Он просто линкует подряд, начиная с нулевого адреса, так что порядок файлов (boot.
Попробуйте слинковать наоборот или слинковать boot. Хорошая идея – посмотреть на итоговый листинг (файл lst) или закинуть бинарник в дизассемблер.
Пишем драйвер для самодельного USB устройства / Geektimes. Целью этой статьи является пошаговая демонстрация процесса разработки всего набора программного обеспечения необходимого для организации связи самодельного устройства с компьютером посредством USB. На данный момент, большинство радиолюбителей реализуют такой тип подключения используя чипы переходники USB в RS2. COM порта поставляемого с чипом переходником. Минусы такого подхода думаю понятны. Это как минимум лишний чип на плате и ограничения накладываемые этим чипом и его драйвером.
Мне же хочется осветить весь процесс организации такого взаимодействия так как оно и должно быть сделано, и как делается во всех серьезных устройствах. В конце концов, сейчас 2. USB есть почти во всех микроконтроллерах. Именно о том, как наиболее быстро воспользоваться этим модулем и будет эта статья. Так как для демонстрации процесса написания драйвера USB устройства нам необходимо собственно само устройство, то выберем одну из распространенных отладочных плат доступных в России. У меня это плата производства компании OLIMEX модель LPC- P2.
Основой платы является микроконтроллер LPC2. ARM7. TDMI производства компании NXP. Всю информацию по плате можно получить на сайте производителя по следующей ссылке.
Вот как она выглядит. Выбор контроллера и отладочной платы абсолютно не принципиален т. Среду разработки прошивки микроконтроллера будем использовать KEIL версии 4. В итоге, планируется реализовать только BULK тип передачи. Будем считывать массив данных из устройства в компьютер, а передавать на устройство будем состояние светодиодов, чтобы было видно, что плата реагирует на наши команды.
Для удобства понимания разделим дальнейшие действия на стадии и будем проходить их по- порядку. Адаптация готового примера USB устройства под нашу плату с целью убедиться, что плата работает и USB канал так же работоспособен. Это будет как бы наша стартовая точка. Изменение прошивки платы, чтобы она стала для Windows неизвестным устройством, требующее драйвер производителя.
Адаптация базового шаблона, пустого драйвера, чтобы Windows могла его корректно установить, для обслуживания нашего устройства. Реализация взаимодействия драйвера с пользовательским приложением. Написание консольного приложения Windows для работы с нашим драйвером, а следовательно и подключенным USB устройством.
Наполнение всей системы необходимыми функциями. Чего в этой статье не будет. Я не буду расписывать механизмы работы ОС, позволяющие находить и устанавливать нужный драйвер. Не будет описания, как собирать прошивку в среде KEIL.
Не будет описания параметров дескрипторов USB и вообще практически не будет ничего сказано про то, как работает прошивка. В конце я предоставлю ссылки на все источники информации, мои исходные коды и собранные бинарные файлы. Таким образом, описание любого момента не охваченного данной статьей, можно будет легко найти по указанным источникам. Поймите правильно, нереально вместить в одну статью подробную информацию по всем этим темам. Тем более, что есть более компетентные источники. Адаптация примера RTX.
Данный пример, когда успешно заработает, позволит нашу плату подключать к компьютеру и она будет там видна как обычная USB флешка. Таким образом мы получим прошивку, которая заведомо корректно настраивает USB модуль и всю необходимую процессору периферию. Кроссворды По Сказкам Шарля Перро на этой странице. Проект находится в папке ARM\Boards\Keil\MCB2.
RL\USB\. Пути здесь и далее я буду указывать относительно основной папки, куда установлена среда KEIL. Скопируем проект в отдельное место, загрузим его в KEIL и соберем. Собраться должен без ошибок. В итоге мы получили HEX файл, который можем прошить с помощью утилиты Flash. Magic. Правда можно пока его не прошивать так как очевидно, что он работать на нашей плате не будет. Если сравнить схему нашей платы и платы для которой написан пример, а это модель MCB2.
KEIL, то видно различия в подключении подтяжки линии D+. На плате MCB2. 14. В, а на LPC- P2. 14.
Схемы обеих плат доступны на сайтах www. Для простоты, мы немного изменим код инициализации, чтобы наша плата всегда при включении включала подтяжку линии D+, о чем будет сообщать светодиод USB. А так как на этом же транзисторе есть еще и светодиод USB. По- этому их назначение так же нужно переопределить. На данном этапе я их переназначил просто для индикации процессов чтения/записи.
Так как у нас нет индикаторов LED. Подключив плату к компьютеру, видно, что он ее распознает как внешний накопитель и в системе появляется еще один диск размером всего около 2. КБайт и с файлом readme. На этом первый этап можно считать законченным.
Переход от USB накопителя к уникальному устройству. Но нам требуется, чтобы Windows не знала, ким образом работать с нашим устройством и требовала драйвер. О том, что подключенное устройство относится ко классу накопителей, говорит параметр Interface class находящийся в дескрипторе интерфейса.
Если открыть файл usbdesc. USB. Дело в том, что Windows запомнив VID и PID нашего устройства в предыдущий раз, как относящиеся к устройству внешнего хранения, может продолжать ставить на него свой драйвер не обращая внимание на то, что класс устройства поменялся. Решение простое. Если плата по- прежнему определяется как накопитель, найдите ее в ветке USB диспетчера устройств и удалите драйвер вручную. После этого ОС должна начать просить драйвер. Создаем базовый драйвер. Драйвер будет иметь минимальный код, чтобы только корректно загрузиться и выгрузиться системой. Писать драйвер мы будем самым минималистическим методом.
Сам код будет редактироваться в блокноте, а собираться будет в командной строке. Для начала, нужно скачать с сайта Microsoft набор для разработки драйвером. Называется он Windows Driver Kit. Я использую версию WDK 7.
После установки, мы получим много примеров, окружение для сборки и документацию. В меню пуск, нужно найти раздел WDK и там Build Environments.
Это так называемые окружения для сборки. Фактически они предоставляют нам консоль, которая уже настроина так, чтобы собирать драйверы для нужной системы. Вы видите, что там для каждой ОС отдельная папке, где находится пара окружений Checked и Free.
Первое для так называемых Checked систем, собирает драйвер с дополнительной информацией полезной при отладке. Второе собирает релиз драйвера, который потом и используется.
Я буду использовать далее окружение «x. Checked Build Environment» от windows XP.
Это даст мне универсальный драйвер корректно работающий на системах от Windows XP и новее. Теперь займемся поиском шаблона, с которого было бы удобней всего начать. Самым подходящим кандидатом оказался пример к некой плате OSR USB- FX2 learning kit. Что это за плата я абсолютно не имею понятия, но нужный нам пример находится в WDK по пути src\usb\osrusbfx. Самое интересное, что это не просто пример, а пошаговое обучение, как сделать драйвер к этой плате. Как раз то, что нам и нужно. Зайдем глубже в директорию kmdf\sys и видим, что там все шаги и лежат по папочкам.
Подробнее о них можно почитать в описании примера, находящемся в файле osrusbfx. Тут я сделаю небольшое отступление, чтобы немножко сделать более понятней следующие действия.
Дело в том, что с момента появления Windows NT кое что изменилось в процессе написания драйвера. В те времена нам приходилось напрямую использовать функции ядра ОС и часто, просто чтобы сделать пустышку способную правильно загружаться, выгружаться, отвечать на события PNP и т. Потом Microsoft сделала модель, которую назвала Windows Driver Model и которая внесла некоторого рода стандарт что ли, как должен выглядеть драйвер. Особого облегчения, лично я от этого не почувствовал. А следующим шагом был сделан фреймворк, который называется Windows Driver Framework.
И вот благодаря этому жить стало намного проще. Теперь фреймворк берет на себя реализацию всех базовых действий необходимых для обслуживания основных событий, а нам останется только правильным образом добавить нужных нам функций.
Вот именно эту технологию мы и будем использовать. Начинаем с первого шага. Запускаем «x. 86 Checked Build Environment» и при помощи команды “cd” перемещаемся в папку Win.