ARCAdaptor
Многие профессионалы-разработчики электроники часто «воротят нос» от семейства микроконтроллеров производства Atmel — фи, мол, эта ваша Атмега — только лампочками поморгать. Однако, это спорное утверждение.
Дешевизна, легкость программирования (как физической «заливки» прошивки, так и создания самих программ) превращают микроконтроллеры семейства AVR в универсальный инструмент, доступный начинающему радиолюбителю, а богатейшая линейка устройств — от самых простых ATTiny до устройств Mega256 с огромным количеством периферии «на борту» позволят реализовать самый смелый и амбициозный проект.
В этот раз мы рассмотрим конкретные примеры реализации одноплатных (и не очень) конструкторов на базе микроконтроллеров семейства ATMega. Все они вполне реализуемы в домашних условиях, а некоторые можно приобрести на сайте авторов. Для начала — небольшое отступление про «одноплатники» вообще.
Название говорит само за себя — все компоненты компьютера, необходимые для его базового функционирования размещены на одной плате. Совсем юные читатели сразу подумают о новинках вроде Raspberry Pi, а те, кто уже имеют понятие о мироустройстве — вспомнят РК-86, ZX-Spectrum и БК-0010, например.
Именно так — те самые «компьютеры в клавиатуре» были одноплатными. Да, допускались различные расширения, но кто о них помнит сейчас, тем более приобрести их в магазине было довольно проблематично. Да и нужды не было по большому счету.
И вот 21 век сдвинул «окно ностальгии» в нужную позицию и радиолюбители по всему миру не сговариваясь выпустили несколько проектов, которые по характеристиками ну очень напоминают те самые «эр-кашки» и «спектрумы» конца восьмидесятых годов прошлого века. А некоторые — в точности повторяют, но обо всём по порядку.
AVR Chip Basic
Первый персонаж нашего обзора — компьютер AVR Chip Basic, точнее это целое семейство компьютеров, различающееся по степени «навороченности» и наличию той или иной периферии.
Из под пера автора ( Jörg Wolfram ) вышла целая плеяда устройств:
- AVR-ChipBasic8 на базе ATMega8 или ATMega88 (та же микросхема используется в ARCAdaptor)
- AVR-ChipBasic на базе ATMega16
- AVR-ChipBasic32 на базе ATMega32
- AVR-ChipBasic2 на базе ATMega644
Все они имеют (как минимум) ТВ-выход и общаются с пользователем с помощью языка BASIC. В качестве устройства ввода используется стандартная PS/2 клавиатура.
Как уже говорилось, каждое из устройств обладает разными характеристиками, так например, AVR-ChipBasic8 имеет чёрно-белый видеовыход, может хранить программы на языке BASIC на подключаемой микросхеме EEPROM, ибо память самой микросхемы оставляет лишь 512 байт для хранения исходного текста.
Тем не менее — имеется и звуковой выход, и даже «свободные ножки», на которые можно повесить дополнительное оборудование.
Диалект бейсика очень сильно урезан, но позволяет вдоволь наиграться с этим языком программирования.
Из «фишек» интересное — прошивку можно собрать самостоятельно как под PAL развертку, так и под NTSC.
Остальные аппараты уже в состоянии выводить цветной видеосигнал через разъем SCART, и даже подключаться к совместимой TFT-матрице. Также к услугам пользователя возможность работы с периферией, последовательный интерфейс RS-232 с возможностью общения с «большим братом» и даже «картриджи памяти»! — съемные блоки памяти с записанными на них программами.
Более того, версии на ATMega16,32 и 644 используют одну и ту же плату, то есть достаточно поставить микросхему в панельку и загрузить нужную прошивку.
Остальные подробности можно почерпнуть на странице автора. К сожалению страничка на немецком языке, но онлайновые переводчики значительно облегчат жизнь.
Кстати, среди его проектов есть и эмулятор компьютера ZX-81 на микроконтроллерах AVR.
USB HID интерфейс для STM32 в STM32IDE
Ряд микроконтроллеров STM32 имеют на борту USB интерфейс для связи с компьютерами. Как правило, удобнее всего использовать предоставляемый компаний ST Microelectronics драйвер класса CDC (Communication Device Class ). Он позволяет использовать на стороне компьютера UART через USB и не требует установки драйверов. Со стороны STM32 при этом требуется только поменять операции вывода данных, остальное делается самостоятельно. Причём скорость такого соединения может быть практически любой, поддерживаемой компьютером.
Однако ряд разработок, особенно, когда приходишь в другую компанию, где используется HID Class (Human Interface Device), в случае разработки новой версии устройства требуется поддерживать ранее выбранный интерфейс. Что, собственно, и случилось. Примеры проектов от самой ST, которые они дают при загрузке STM32 Cube MX и IDE, как обычно, дали только минимальное понимание, но не раскрыли, что и как надо делать. Я когда-то разбирался с USB, даже писал собственный драйвер, но это было так давно… Остались только общие воспоминания. Посему пришлось искать дополнительную информацию, чтобы получить стартовую точку.
Первое найденное было видеороликом на youtube в стиле HID за 5 минут 🙂 Автор даёт доступ к своему коду на GitHub. Всё, типа круто, красиво, просто вставляйте к себе и всё будет чудесно. Судя по отзывам под роликом, некоторым этого хватило. Изучив исходники понял, что минимального прозрения не наступило, да и уровень полученной информации мал для того, чтобы решить поставленную задачу. Но закомство с этим материалом было явно полезным. Решение вопроса с использованием кубика (STM32Cube MX) мне лично импонирует больше, чем другие подходы, поскольку позволяет отвлечься от ряда низкоуровневых операций и генерация проекта всегда происходит в одном стиле. Соответственно, изучение этого примера показало, на какие файлы надо обратить внимание, где и что надо поменять или добавить, какие функции использовать для получения и отправки данных именно для нашей выбранной среды программирования.
Следующий поиск оказался весьма удачным. Хабр — известный сайт, на котором можно найти много полезного по разной электронной тематике. Нашлась там и статья STM32 и USB-HID — это просто. Я не являюсь постоянным клиентом Хабра и не знаю автора этой статьи RaJa, но на мой взгляд это очень хорошая статья, описывающая основные положения работы HID интерфейся. Без её прочтения читать дальше здесь бессмысленно, поскольку далее будут, в основном, комментарии для адаптации кода к среде разработки STM32IDE/STM32CubeMX + Atollic TrueStudio. (Далее STM32IDE). Да и столь популярный в 2014 году и реально очень неплохой проект EmBlocks, увы, умер.
Первое, что необходимо решить — как тестировать вновь создаваемое устройство. Лет… дцать назад я использовал для этого анализатор и синтезатор трафика USB — очень полезные, но дорогие игрушки 🙂 Сейчас у меня такой возможности нет, да и должен же быть более простой путь. Тем более для простого стандартного интерфейса без написания собственного драйвера. Авторы обоих рассмотренных выше проектов пошли самы простым для них путём — написание простой программы на известных им языках. Но автор статьи на Хабре сделал очень правильный шаг — он написал свой проект, совместимый с программой ST HID Demonstrator (ссылка есть в статье), позволяющей поуправлять нашим устройством, как графически, так и послать свои данные и посмотреть, что пришло от нашего устройства. Фактически программа может использоваться и в дальнейшем для отладки будущей программы на выбранном микроконтроллере.
Своё ознакомление с проектом для HID я осуществлял с платой STM32L476 Discovery. Плата, вообще говоря, может быть любой, где USB интерфейс микроконтроллера физически подключён к отдельному разъёму USB. Есть у меня и Nucleo 32 с STM32L4, но там один разъём USB тспользуется и для программирования/отладки, и для связи с хостом, что добавляет интриги в интерфейс и может служить источником дополнительных непоняток. Оно нам надо?
Итак, комментарии и дополнения к статье по привязке HID к STM32IDE примерно по тем же шагам, как и в хабровской статье.
Структура проекта
В STM32IDE структура всех проектов задаётся при генерации проекта из среды назначения функциональности пинов и пользователю о том заботиться не надо. В частности, в кубике (что отдельном STM32Cube MX, что в встроенном в STM32IDE) активируем USB, как Device, и добавляем Middleware USB Custom HID.
Рис.1 Выбор USB интерфейса Рис.2 Выбор и первичная настройка Middleware Надо заметить, что несмотря на установку размера буфера в 64 байта, эта величина не вносится по #define. Видимо баг текущей версии кубика. Далее покажем, где надо пофиксить. Указанный резмер дескриптора равный 79 — это значение для данного конретного стартового проекта
Заходим в Clock Configuration. Вполне вероятно, что могут быть проблемы с системными частотами, которые маркируются малиновым цветом.
Рис. 3 Возможные проблемы по установке частот
Если так, нажимаем Resolve Clock Issues и, скорее всего, всё будет настроено на максимальные частоты. Главное — USB Clock будет выставлен на 48 МГц. Надо заметить, что в семействе STM32L4 генератор на 48МГц имеет автоподстройку по SOF (Start Of Frame), что позволяет создавать USB устройства без внешнего кварца/генератора. Если, конечно, остальной дизайн допускает использование некварцованных генераторов. Для других семейств не проверял, поскольку для моего текущего проекта был выбран именно L4. Только надо отметить, что при использовании USB есть некоторая минимальная частота работы микроконтроллера. Я делал прикидку для другого проекта, где надо общаться с хостом и при этом потреблять минимум тока. Задачи простые, не требуют большой скорости и я хотел запустить МК на 8МГц. Оказалось, что меньше 14МГц при подключении USB ставить не могу, RCC не позволяет. Пришлось остановиться на следующем круглом значении 16МГц.
Собственно, настройка аппаратной части USB и выбор файлов, отвечающих за базовую функциональность этого интерфейса на на этом закончены. Вся остальная периферия, находящаяся на выбранной плате настраивается автоматически при её выборе на старте проекта. Сохраняем, генерим проект и переходим к «программированию» в сравнении с описанным на Хабре проектом.
Это страшное слово Descriptor
Стандартные массивы данных для передачи информации хосту, с чем он будет иметь дело. Для интереса можно посмотреть дескрипторы устройства и конфигурации. Сейчас их можно оставить такими, как получились, но в дальнейшем они наверняка потребуют редактирования. Впрочем, не исключено, что они будут генериться по тем параметрам, что ставятся в кубике. Что не может не радовать. А вот Report Descriptor стоит изучить получше — это фактически основное, что придётся в дальнейшем править ручками. Не знаю, откуда RaJa взял его дескрипторы, в нашём случае они генерируются кубиком и располагаются в следующих файлах проекта:
Дескриптор от Raja | Дескриптор от ST | Файл в проекте |
RHID_DeviceDescriptor | USBD_FS_DeviceDesc | usbd_desc.c |
RHID_ConfigDescriptor | USBD_CUSTOM_HID_CfgFSDesc | usbd_customhid.c |
RHID_ReportDescriptor | CUSTOM_HID_ReportDesc_FS | usbd_custom_hid_if.c |
Поскольку для простоты сейчас будем работать только с ST HID Demonstrator, то не мудрствуя лукаво я просто скопировал содержимое RHID_ReportDescriptor в соответствующее место моего проекта. Только подставил свои константы на место длины. Надо отметить, что надо точно посчитать количество байтов в этом дескрипторе (в этом проекте 79) и убедиться, что именно это значение стоит в Class Parameters. Не больше и не меньше. Иначе хост не опознает подключённое устройство. Проверено 🙂
Далее заходим в файл usbd_customhid.h и меняем значения CUSTOM_HID_EPIN_SIZE и CUSTOM_HID_EPOUT_SIZE на 0x40U. Честно говоря, немного напрягает то, что ST не даёт альтернатив смене значения по умолчанию 2 на другое значение и далее в коде с использованием этих констант стоит комментарий, что не более 2х байт. Но, с другой стороны, это было рекомендовано в первом найденном описании и, вообще говоря, установка такого значения выглядит достаточно логично. Иначе в чём отличие CustomHID от обычного? Проблема в том, что при регенерации проекта из кубика, что на этапе первичного кода происходит довольно часто, это значение не сохраняется и его надо восстанавливать ручками. Для этого я себе в main вывел строку warning, чтобы не забывать проверить эти константы. Возможно я ошибаюсь, и в дальнейшем всё окажется проще. Но в такой конфигурации работает 🙂
Цикл обмена (пишем/читаем)
Для выдачи данных на хост всё достаточно аналогично описанию на Хабре. Только название функции другое: USBD_CUSTOM_HID_SendReport(). Все остальные реомендации из той статьи подходят по полной программе.
А вот чтение здесь интереснее, чем на Хабре. И на самом деле несколько проще. Обработка принятого массива происходит в usbd_custom_hid_if.c / static int8_t CUSTOM_HID_OutEvent_FS(uint8_t event_idx, uint8_t state).
В этом тестовом проекте я не заморачивался с обработкой входных параметров и следуя своей обычной практике минимальности времени обработки прерываний, просто копирую полученные данные в заранее определённый массив и устанавливаю флаг готовности данных от USB
Ну, а собственно «сбор данных» (нажатие кнопок джойстика) и реакция на полученные от хоста данные в этом прото проекте делаю внутри бесконечного цикла в main.c Всё просто 🙂 В этом прото проекте нет разделения реакции на SET_FEATURE и SET_REPORT, с этим надо будет разобраться далее, в реальном проекте. Компилируем, запускаем, подключаем к хосту и там должен появиться новый CustomHID от STMicroelectronics.
Звпускаем на хосте USB HID Demonstrator. На плате, с которой я запускал этот проект, не имеет органов для работы с Variable Inputs/Outputs, поэтому в разделе Graphic customization были убраны соответствующие назначениями, оставлено 5 кнопок и назначены ID, определённые в проекте: 1, 2 для Output report (входные данные для ST) и 4 для Input Report (выход от ST).
Рис. 4 Настройка демонстратора
Моей задачей для этого проекта было управлять парой светодиодов на плате, что стало работать сразу, как эта программа обнаружила подключенную плату, и включать «лампочки» этой платы при нажатии различных кнопок джойстика на плате, а вот здесь сразу не получилось. При указанных настройках все пять лампочек одновременно зажигались при нажатии на центр джойстика. Остальные кнопки не отображались. При этом, если перейти на Input/Otput transfer, то данные были вполне ожидаемы. Т.е. сам интерфейс работает, но отображение в программе на хосте не отвечает моим запросам. Слава богу ST предоставляетс исходники, а в соседнем кубике сидит программист нашей группы, пишущий в том числе и софт для компьютеров. В общем, он подправил одну функцию и сгенерил исполняемую программу. Всё стало работать, как хотелось. Конечно, можно было бы на каждую кнопку создать свой report с уникальным номером, что исходно и предусмотрено. В этом случае было бы достаточно посылать по одному байту для каждой кнопки, но мой проект предусматривает многобайтный отчёт. Исходник подправленной функции и подправленный исполняемый файл можно скачать по ссылке ниже.
На этом, пожалуй, всё. Если у Вас есть такая же плата 32L476GDISCOVERY, то для начала можно просто скачать мой прото проект, адаптированный для него демонстратор и исходник изменённой функции по этой ссылке. Исходный USB HID Demonstrator скачивается с сайта STM, инсталлируется и его исполняемый файл заменяется моим. Импортируете в STM32IDE мой проект, компилируете и должны получить работающую базу для своих проектов. Если у Вас другая плата, то адаптируете «сбор информации» и включение светодиодов под свою плату.
Для дальнейшей работы обязательно прочтите указанную статью RaJa с Хабра. Она даст понимание того, что и как должно быть сделано для других проектов с USB HID интерфейсом. А ещё лучше начать с неё 🙂
И при выборе класса устройства для Вашего проекта надо учитывать следующее: минимальный период опроса HID устройств — 1ms. И если я правильно помню, это скорее пожелание системе от внешнего устройства. В стандартном HID устройстве за один кадр (frame) передаётся только два байта, т.е. скорость обмена не более 2 кбайт/с. В Custom HID на
Full Speed (12 мбит/с) объём данных отчёта (report) — не более 64 байт, т.е. скорость обмена с Вашим HID не более 64 кбайт/с. Для High Speed (480 мбит/с) — максимальный объём данных 512 байт (512 кбайт/с). Не будь у меня ограничения совместимости с предыдущим софтом, используемым в компании, использовал хотя бы CDC.
У меня изучение статей и адаптация под мои хотелки заняло три дня. Описание заняло больше 🙂 Надеюсь, что у тех, кто воспользуется этой статьёй, аналогичный процесс займёт не более одного дня. Комментируйте, спрашивайте. Что смогу — отвечу. Что не смогу, вместе поищем решение.
↑ Настройка среды
После установки CooCox IDE нам нужно указать путь к компилятору, программе, которая собственно и превращает наш исходный текст программы в машинный код микроконтроллера. Для этого заходим во вкладку Project –> Select Toolchain Patch и выбираем путь к компилятору arm_2011.03_coocoxbin, жмём ОК.
Далее необходимо выбрать отладчик, в нашем случае это ST-LINK. Вкладка Debug –> Debug Configuration –> ST-Link, нажать Apply. Не забываем установить драйвера для этого отладчика с сайта производителя.
Если Вы не желаете собирать проект сами, можете открыть проект, который находится в приложении. Для этого вкладка Project –> Open Project и выбрать путь к файлу проекта — CooOStest.cob.
Далее подключить плату STM32VL-Discovery к Вашему компьютеру. Для прошивки микроконтроллера вкладка Flash –> Program Download. На плате при этом на пару секунд должен замигать красный светодиод, означающий, что идет обмен данными между компьютером и микроконтроллером. После этого на плате замигают два светодиода, зеленый и синий, с разными частотами мигания.
В случае самостоятельной сборки необходимо создать новый проект. Вкладка Project –> New Project.
Затем придумать имя проекту, например CooCoxOStest. Жмем Finish.
Перед вами в центре среды появится вкладка Repository.
Шаг 1. Выбираем фирму производителя микроконтроллера, в нашем случае для STM32VL-Discovery это ST.
Далее получаем следующий шаг.
Шаг 2. Выбираем контроллер STM32F100RB.
Шаг 3. В появившемся окне ставим галочку GPIO. Автоматически установятся еще три галочки CMSIS core, CMSIS Boot и RCC. Эти библиотеки необходимы для того чтобы включить периферию, те порты ввода вывода GPIO (ноги контроллера), тактирование внутренних шин (RCC) и вспомогательные библиотеки для работы с ядром.
Осталось подключить ядро ОС. Для этого прокруткой попадаем в самую нижнюю строку Repository и ставим галочку напротив CooCox OS.
Настройки готовы. Осталось в левом нижнем окошке Project открыть файл main.c
И в появившейся вкладке main.c написать текст программы, подобно тому, как будет описано дальше.
В исходном коде программы подключаем файлы ядра и стандартных CMSIS библиотек.
Определяем под каждую необходимую нам задачу размер оперативной
памяти под стек. Если ее выделить мало, задача не сможет быть выполнена до конца. Если слишком много, то, при увеличении числа задач, памяти может не хватить.
Независимо от того, насколько хороша наша операционная система, нам в первую очередь необходимо настроить внутреннюю периферию контроллера, для этого собственно мы и подключали выше стандартные библиотеки МК от производителя.
Основные моменты STM32F103C8T6
Теперь, когда мы немного узнали о плате Blue Pill, давайте теперь разберемся с некоторыми важными особенностями самой платы, то есть микроконтроллера STM32F103C8T6. Как упоминалось ранее, этот микроконтроллер содержит 32-битное ядро ARM Cortex-M3 с максимальной частотой 72 МГц.
Давайте теперь посмотрим, какие технические характеристики этого микроконтроллера реализованы на плате Blue pill.
Характеристики STM32F103C8T6
- Память: содержит 64 Кбайт Flash и 20 Кбайт SRAM
- GPIO Pins — 32 с возможностью внешнего прерывания
- Таймеры — 3 16-битных таймера, 1 16-битный ШИМ-таймер
- PWM Pins — 15
- Аналоговый — 10 каналов 12-битного АЦП
- I2C — 2 периферийных устройства I2C
- USART — 3 периферийных устройства USART с аппаратным управлением
- SPI — 2 SPI периферийных устройства
- Другие периферийные устройства — USB 2.0 Full Speed, CAN 2.0B
Это некоторые из основных моментов, и если вы хотите узнать больше информации о периферийных устройствах, вам следует обратиться к datasheet (настоятельно рекомендуется).
В качестве дополнительной темы позвольте мне рассказать вам о маркировке, используемое в микроконтроллерах STM32 на примере STM32F103C8T6. Каждая буква в названии микроконтроллера обозначает особую характеристику: