Даже неверное решение, проведенное в жизнь с должной последовательностью и энергией, приводит к успеху
Для начала о том, чего в этом посте не будет. Здесь не будет рассказа о том, как легко написать программу для мигания светодиодами. Здесь не будет сведений о том, где и по какой цене Вы можете купить замечательные платы некоей чудесной фирмы. Здесь не будет рассказа о том, какое голубое небо было до появления этого исчадия ада, и как все теперь плохо. Здесь не будет также рассказа о том, в каком хаосе пребывала отрасль до появления такого чудесного решения, и как все стало хорошо. Здесь даже не будет картинок для привлечения внимания. За всем этим не сюда, подобных постов на Хабре хватает и без того (ни в коей мере не пытаюсь обидеть их авторов, но я пишу несколько о другом).
Здесь будет попытка понять, для чего нужна Ардуино (А), как именно она делалась, какими методами решались различные проблемы, и где их (методы решения) можно было бы постараться улучшить. Несомненно, тут будет большое количество оценочных суждений, субъективного взгляда, вкусовщины, и прочих прелестей, связанных с обсуждением неординарной проблемы. Ну и будут рассуждения на тему, почему А не всегда и не везде торт и как ее (А) в него (торт) превратить (если смотреть на это дело с правильной, то есть моей, стороны).
Для начала, сразу оговорюсь, что я не искал информацию на закрытых разделах специализированных форумов, не брал интервью у разработчиков А, не читал внутрифирменную документацию и не использовал иную инсайдерскую информацию. Все мысли, которые дальше изложены, есть попытка поставить себя на место разработчиков и размышления в стиле «Если бы министром был я». Ну и конечно, плод определенного опыта, приобретенного как во взаимодействии с А, так и с другими системами разработки встроенного программного обеспечения (В или Firmware), чем я занимаюсь на профессиональной основе. Ну, надеюсь, с преамбулой покончено, вопросы об ангажированности заранее отметаю с негодованием, можно перейти к делу.
Итак, для того, чтобы плодотворно (то есть делая хоть что-нибудь) работать в отрасли разработки В, необходимо (действительно необходимо, то есть без этого никак не получится) иметь следующие компоненты:
1) Аппаратную платформу, на которой В функционирует,
2) Программную платформу, которая позволяет подготовить В к функционированию на данной платформе,
3) Компоненту связи, которая позволяет разместить данное В на данной платформе,
4) Средства контроля процесса функционирования данного В на данной платформе.
Если с первыми тремя компонентами все вроде как очевидно, то четвертая обычно несколько выпадает из поля зрения, и это совсем не отладчик или монитор, хотя их наличие категорически приветствуется, но и просто элементарный процесс начала функционирования В либо же контроля зависания. Теперь, когда мы определились с необходимостями, начнем рассмотрение того, как система А позволяет нам их реализовывать, а также что можно было бы сделать лучше (естественно, на мой взгляд, потому что чужого у меня нет).
Прежде чем приступить к обсуждению, несколько привходящих обстоятельств, которые следует учитывать. Если верить информации из открытых источников, и все, что мне известно, ей не противоречит, первоначально А разрабатывалась с целью обучения основам программирования микроконтроллеров (МК). Поэтому основной задачей было получение максимально простого в использовании для обучаемых (то есть малоквалифицированным персоналом) устройства.
Разумеется, экономические факторы тоже были приняты во внимание, но не являлись определяющими. В настоящее же время область применения А существенно расширилась, и она активно применяется как в секторе DIY в качестве прототипа, где экономический фактор также не критичен, так и в готовых устройствах, где ситуация несколько иная. Именно с учетом данных аспектов и будем вести дальнейшее повествование.
1. Аппаратная платформа
А система представляет собой плату, которая содержит в своем составе ВСЕ необходимые компоненты для обеспечения полного цикла разработки (с некоторыми оговорками, рассмотрим их далее), за исключением источника питания. Последний реализуется вне системы А, подключение его не представляет особых трудностей, в ряде случаев достаточно прилагаемого к комплекту или приобретаемого самостоятельного стандартного соединительного кабеля (вот так наукообразно звучит USB кабель).
По этому пункту можно поставить твердую пятерку, то есть все необходимое присутствует и работать с устройством можно.
А теперь перейдем к улучшениям, ибо, как известно, совершенству нет предела. Основная компонента на плате А — это микроконтроллер (МК), и вот тут сразу возникают вопросы. По каким критериям данный МК должен выбираться?
Первое — прежде всего, необходимо наличие возможности модифицировать ПО с минимальными затратами, отсюда вытекает наличие на МК легко изменяемой (не ультрафиолетово-стираемой, тот, кто использовал, поймет) памяти программ, а это однозначно FLASH, причем не самого минимального объема, 1К или 2К вряд ли будут приемлемы — в А реализовано на 4+ (в свое время было 5, но время не стоит на месте).
Второе — это выбор архитектуры МК. Поскольку изначально планировалось использование языка программирования высокого уровня (скорее всего, С), особенности архитектуры выбранного МК не столь существенны, до тех пор, пока они не препятствуют эффективной работе компилятора. По этой причине неприемлемы системы с аппаратным ограниченным стеком типа i8048 (для них эффективная реализация стекового языка едва ли возможна).
Эти два соображения сужают пространство выбора даже в наше время, а 10 лет назад (с учетом доступности) практически стоял выбор между продукцией двух фирм — Atmel (семейство AVR) и MicroChip (семейство PIC) и выбор был сделан в пользу первой фирмы. Мое отношение в этому выбору нейтральное, фирма AVR делает неплохие микросхемы, хотя фирма PIC делает не намного худшие (или лучшие, это дело вкуса). А вот дальше стоял вопрос выбора конкретного семейства МК, и вот тут я все-таки предпочел бы 89 семейство, совместимое по командам с I8051, но авторам виднее, и они взяли кристалл из семейства MEGA AVR. У этого решения есть как плюсы, так и минусы, но обсуждение их является предметом более специализированного поста (и постоянных священных войн), мы же пробежимся только по верхушкам деревьев.
Третье необходимое условие — простота модификации ПО в МК, реализованная в виде ISP (In System Programming) технологии, которая позволяет осуществлять изменение ПО на МК в составе платы, не подвергая ее воздействиям, связанным с нарушением конструктивной целостности изделия (переводя на русский, без необходимости извлекать МК из платы). Этому требованию отвечают многие кристаллы, в том числе и выбранный разработчиками — твердая 5.
Тем на менее, МК стоит на плате в колодке ( я говорю про оригинальное решение), что, конечно, облегчает поиск возможных неисправностей путем замены (а данная проблема, несомненно, была актуальна, учитывая применение А в учебных целях и все связанные с этим обстоятельства), но в то же время, создает дополнительные возможности для возникновения неисправностей и увеличивает стоимость устройства. Поддержание подобного решения также наложило определенные ограничения на конструктивную реализацию выбранного МК, поскольку колодки для QFP корпусов по своей стоимости существенно превосходят аналогичные устройства для DIP и PLCC, а последние также требуют специальных приспособлений для извлечения МК из колодки, так что был выбран DIP вариант — 5-.
Какие компоненты еще расположены на плате А? Прежде всего, это стабилизатор питания со схемой защиты от переполюсовки (последовательный диод), который не позволяет так просто взять и убить МК завышенным или отрицательным напряжением, сначала придется убить стабилизатор (что, впрочем, не является особо трудной задачей и неоднократно реализовывалось). Учитывая, что подразумевалась в основном подача питания через USB разъем, такое решение является безусловно приемлемым.
Кварцевый (не керамический) резонатор с конденсаторами позволяет задать вполне себе стабильную (в разумных рамках) частоту, по сравнению с керамическим резонатором, хуже которого может быть только встроенный генератор, который известен крайне высокими отклонениями от номинала (смотрите документацию).
Схема запуска в виде времязадающей RC цепочки (но почему то без разрядного диода, хотя учитывая особенности питания в режиме обучения, он не особо нужен, а вот для реализации устройств, постоянно находящихся под питанием, совершенно необходим и клоны А его, как правило, имеют) с дополнительной кнопкой, позволяющей перезапустить устройство без отключения питания и с дополнительный сигналом сброса от программатора через конденсаторную развязку (о последнем поговорим чуть позже).
Колодки для подключения дополнительных устройств (шилдов), на которые выведены все контакты МК (кроме служебных) плюс сигналы питания и сброса.
Светодиоды для индикации наличия питания и активности разных узлов платы А, а также светодиод общего назначения, которым и предлагается помигать в многочисленных руководствах.
В общем и целом, почти все, что есть, нужно, так что ставим 5-.
А вот теперь перейдем к последней по порядку, но не по значимости, аппаратной составляющей — программатору. Прежде всего несколько слов о методике программирования в общем.
Загрузка ВПО в МК может осуществляться либо при помощи аппаратного загрузчика (или назовем его еще встроенным) либо при помощи программного (назовем его внешним). Вопрос терминологии здесь отнюдь не простой и не однозначный, но мы должны договориться, о чем ведем речь.
Основным отличием встроенного загрузчика является то, что возможность его функционирования обеспечивается на этапе производства МК и не может быть модифицирована пользователем (вернее, может, но этот процесс нетривиален и потенциально обратим). Это может быть настоящий аппаратный модуль, либо программный модуль, расположенный в особой области памяти программ. В любом случае, в процессе функционирования встроенного загрузчика обычная работа МК (выполнение программ пользователя) невозможна. Если мы будет рассматривать чисто аппаратные загрузчики, то они могут реализовываться на основе следующих интерфейсов (в порядке уменьшения количества необходимых контактов) JTAG, (4/5+1(0)), SPI (3/4+1), SWD (2+1), DebugWire (1), конечно, не считая землю и учитывая вход Reset(+1). Все эти интерфейсы обеспечивают полный доступ к ресурсам МК, а некоторые еще могут быть использованы и для управления выполнением В (для отладки).
Возможна также реализация встроенного программного модуля (так называемый Boot-Loader), который по функционированию ближе к внешнему загрузчику, с рядом отличий, но встречаются они реже, нежели аппаратные ( это было справедливо для времен, когда создавали А, сейчас ситуация не столь однозначна).
Внешний (программный) загрузчик представляет собой специальное программное обеспечение, которое неотличимо от В с точки зрения функционирования, и которое использует специальные аппаратные возможности МК для доступа к ресурсам МК с целью модификации памяти программ. При этом необходимая информация получается посредство какого-либо стандартного интерфейса — UART, USB, Ethernet, Wireless интерфейсы, входящие в состав МК. При реализации такого варианта возникает ряд проблем, которые не то чтобы нерешаемы, просто о их существовании надо знать. Среди них обеспечение совместного функционирования В и процесса модификации памяти программ, контроль целостности и восстановление информации о программе при сбоях в процессе программирования, и вопрос о передаче управления от загрузчика к основной программе. Последний вопрос рассмотрим подробнее чуть позже, а пока о плюсах и минусах двух подходов.
Какие преимущества у встроенного загрузчика:
1) он неубиваем, то есть пользователь не может сделать невозможным его использование без специальной нетривиальной процедуры. Некоторые пользователи в своих вопросах утверждали, что им это удавалось, но я склонен считать, что это возможно только в силу ограниченности имеющегося у них в распоряжении оборудования. Лично я достаточно долго работал с МК фирмы Atmel и должен заявить со всей ответственностью, что убить кристалл в целом, хоть и нелегко, но возможно, но «окирпичить» отладочный интерфейс мне не удалось ни разу (случаи физического повреждения мы не рассматриваем).
2) он стандартизован фирмой изготовителем, как правило, весьма подробно прописан в документации, поэтому имеется значительная номенклатура программирующих устройств и программ загрузки, как от производителя кристалла, так и третьих фирм. Если они Вас не устраивают, то Вы можете изготовить свою собственную систему программирования, как я в свое время и сделал на основе устройства ByteBaster и самописных программ.
3) помимо функций загрузки В, он может быть использован и для других целей, в частности мониторинга состояния целевой программы, а также отладки В, хотя данная возможность реализована далеко не везде.
4) он расположен в специальной секции программной памяти и может предоставлять доступ целевой программе к своим функциям на правах библиотеки (как сделано вCube), тут есть определенные трудности с точки зрения линкера, но они вполне решаемы.
Теперь немного о недостатках — их немного, но они есть, а именно:
1) он неубиваем и, соответственно, немодифицируем, минусы, из этого проистекающие, очевидны, хотя и не столь значимы. Если Вам действительно нужен свой загрузчик, то Вы всегда можете прибегнуть к двойной загрузке — сначала при помощи встроенного загрузчика загружаете и запускаете вторичный (свой) загрузчик, а уж он делает все необходимое. Правда, в случае Flash памяти со страничной организацией Вам может потребоваться двойное стирание, что уменьшит ресурс МК, но он довольно таки значителен и данное обстоятельство не должно иметь существенного значения, кроме того, Вы можете пользоваться результатами работы встроенного загрузчика по стиранию соответствующей страницы. Резюмируя, я бы такой путь не рекомендовал, предпочтительнее выглядит метод с внешней программой, которая переводит Ваш формат в формат встроенного загрузчика и затем передают полученные данные в стандартном режиме.
3) он может быть использован для мониторинга, но при этом интерфейс становится недоступен для связи с устройвами пользователя, если не принять специальных мер, в А они не приняты, поскольку перемычки лично я не считаю решением.
4) он расположен в памяти программ и следовательно отнимает место у целевой программы, что может оказаться проблемой в определенных обстоятельствах.
Второй интересный вопрос — взаимодействие загрузчика с целевой программой с точки зрения передачи управления, ведь не всегда же Ваш МК будет запускаться с загрузкой нового содержимого. Решение данного вопроса лежит в рамках выбраной парадигмы использования загрузчика. Водораздел проходит по линии начального включения — либо Вы выбираете в момент включения, что именно начинает функционировать — основная пограмма или загрузчик, а для этого потребуются некоторые аппаратные ресурсы, например, конфигурационная ножка МК, либо после запуска функционирует загрузчик (тут без вариантов) и тогда он должен принять решение о передаче управления целевой программе, либо под управлением опять таки внешнего сигнала, либо при достижении определенного условия, как правило, периода неактивности внешнего интерфейса. Оба эти метода не свободны от недостатков и представляют собой выбор между плохим и не лучшим и свойственны только внешнему загрузчику.
Теперь, когда мы осознали наличие проблемм, можем посмотреть, как их решают в А, здесь принят вариант внешнего загрузчика с переходом на пользовательскую программу после задержки неактивности, цепочка прохождения информации начинается с USB, который превращается в UART, поступает в МК и обрабатывается загрузчиком в перепрограммируемой памяти МК. Рассмотрим данное решение подробнее.
Выбор интерфейса USB несомненно является удачей разработчиков, поскольку он к настоящему моменту является де-факто стандартным периферийным интерфейсом и им оснащены практически все возможные устройства, также удачное решение с точки зрения организации питания А модуля (5+).
Преобразователь в интерфейс программирования на микросхеме FTDI — тут у меня отношение несколько более сложное. Конечно, в свое время этот кристалл задал тон на данном сегменте рынка, но фирменный вариант не отличался низкой ценой, а многочисленные клоны конфликтовали с фирменными драйверами (если кто то понимает, чем именно фирму не устроил стандартный драйвер Serial из состава ОС, поделитесь инфой, я просто не могу понять такое решение). А вот дальше покатилось по наклонной — режим побитового манипулирования никак нельзя отнести к достоинствам данного кристалла, а последовательный порт делался легко, что и привело к следующей реализации.
При этом всплывает недостаток опоры на фирменный драйвер — для обеспечения старта загрузчика из любого состояния МК используется перезапуск системы путем подачи сигнала сопровождения информации из состава UART, а он реализован нестандартным образом, в силу чего клоны А на других преобразователях работают нестабильно (строго говоря, вообще не работают, но им можно помочь кнопкой сброса на плате).
Другой недостаток реализации — после перзапуска всегда начинает работать загрузчик, а выход из него наступает по истечении времени ожидания, на протяжении которого все пины, не задействованные непоредственно в загрузке, находятся в третьем состоянии, что может привести (и приводит) к определенным проблемам в функционировании подключенных устройств, если при проектировании чувствительных к уровню цепей не были заложены внешние подтягивающие резисторы.
Последовательный порт в качестве устройства обмена для программирования — задействован стандартный интерфейс, что позволяет реализовать канал связи с целевой программой через одно устройство с загрузчиком (+), но затрудняет использование данного интерфейса для связи с внешними устройствами (-).
Теперь, когда мы рассмотрели имеющуюся реализацию, можно предложить улучшеную. При этом сохраняем интерфейс USB (от добра добра не ищут), реализуем возможность использовать стандартные драйвера ОС,
организовываем взаимодействие с МК как минимум с двумя интерфейсами — SPI для целей загрузки (используем в МК встроенный загрузчик) и UART для взаимодействия с целевой программой, оба с возможностью отключения драйверов покманде пользователя, совсем неплохо будет выглядеть реализация дополнительных интерфейсов типа I2C, 1wire, SWD (всех тех, кто не требуют дополнительной аппаратной обвязки). Для все реализованных интерфейсов крайне желательна функция мониторинга, что превращает нашу плату (назовем ее И) в основу микро-лаборатории. Реализовать все эти хотелки на кристалле стандартного преобразователя интерфейсов едва ли возможно, поэтому интерфейс к ПК основывается на недорогом контроллере с встроенным USB (подобные реализации на одном МК уже есть, но они сохраняют А стиль интерфейса и только его).
Альтернативой данному варианту является реализация внешнего загрузчика, идентичного существующему, но на одном кристалле, который является одновременно преобразователем интерфейса и целевым МК, что позволяет улучшить массо-габаритные и стоимостные харакеристики платы, но тут нужно учесть минусы, свойственные такому загрузчику и максимально их ослабить, реализация мониторинга стандартных интерфейсов также затрудняется.
Что мне не очень нравится в А, так это присутствие на плате не всегда востребованных в процессе самостоятельного функционирования (имеется в виду бевая работа) компонент, связанных с функцией 3 и 4. Такие компоненты будут всегда (ну почти всегда), поскольку необходимо обеспечить физический контакт с внешним программирующим устройством, но в данном случае лично мне они представляются несколько избыточными (микросхема FTDI), что приводит к увеличению стоимости, размеров платы и потребления устройства. Тогда и наличие на плате разъема мини-USB будет под большим вопросом — только для подачи питания, но тут надо подумать.
Если говорить в принципе, я бы все-таки программатор сделал в виде отдельного устройства, что позволило бы уменьшить стоимость и размеры платы, за счет определенного уменьшения удобства эксплуатации. Кстати, многие другие системы разработки В реализуют некий гибрид — имеется расширенная версия платы со встроенным устройством программирования и усеченные версии плат, для контроля над которыми используется расширенная версия. Так, в частности, делает TI в своих оценочных наборах. Наверное, такой вариант был бы неплох, но только для варианта с использованием платы, как основы реальных устройств, для целей обучения такой подход явно неудобен.
Ну вроде рассмотрение аппаратуры закончили (если я что забыл, напомните в комментах), теперь немного о программной среде разработки А. Она построена в виде оболочки над GCC компилятором и изначально предназначалась для целей облегчения работы слабо подготовленного пользователя. Оболочка реализует немного синтаксического сахара, устраняя необходимость некоторых рутинных действий, которые действительно имеют место в написании программы на языке С, но в то же время ограничена использованием стандартного препроцессора и компилятора со всеми его недостатками. Кроме того, в распоряжение пользователя предоставляются стандартные библиотеки, облегчающие взаимодействи с аппаратурой МК, и описан интерфейс к ним. Замечу мимоходом, что качество данных библиотек может быть предметом дискуссии (смотри мой пост на тему управления пинами, но они есть и позволяют кое-что делать, так что требования назначения реализованы, ставим 4.
Встречающееся мнение о том, что в А есть некоторый свой язык программирования Wiring не более чем заблуждение, вызванное недобросовестными заявлениями маркетологов, есть только интерфейс к библиотекам. А жаль, между прочим, введение своего препроцессора с развитыми возможностями мета-программирования было бы весьма кстати, да и некоторые особенности работы с аппаратурой реализовывались гораздо проще и надежнее, чем в стандартном С, так что по этой позиции 4--.
Весьма полезны в этой надстройке над языком были бы средства обобщенного описания настройки аппаратуры с генерацией необходимого кода для конкретного МК со средствами визуализации такого описания (что то вроде ST Cube), но создание такого продукта явно выходило за рамки намерений (а может и возможностей) разработчиков платформы. Дело в том, что в последние годы появляются А совместимые системы на кристаллах различных фирм — это и STM и TI, и экзотика вроде ESP и даже Intel. И если с последней для меня все ясно — ну нет для нее рынка, не нужна А совместимая плата с таким разъемом и ТАКОЙ ценой, хотя и с ТАКИМИ возможностями, то остальные упомянутые выгодно отличаются от оригинальных А кристаллов в плане встроенных аппаратных блоков и их возможностей (сохраняя невысокую стоимость), но за все в этом мире надо платить и правильное применение таких блоков требует внимательного изучения документации (отметаем данный вариант как фантастический) либо библиотек совсем иного, нежели А, уровня.
Взаимодействие среды разработки с железом — собственно процесс программирования сдела неплохо (с учетом замечаний о драйверах), есть возможность кастомизации загрузчика, с учетом принятой парадигмы — 5-, причем минус за недостаточную информативность сообщений об ошибках и отсутствие в стандартной поставке проверки типа программируемого устройства.
А вот с управлением работой программы достаточно плохо — реализована только возможность перезагрузки в любой момент, независимо от состояния целевой программы МК и минимальные средства отладки в виде отладочной печати через UART интерфейс, причем встроенный монитор отладки отсутствует как класс, отладочный вывод в случае занятости последовательного канала не предусмотрен, стандартные отладочные интерфейсы не задействованы. В общем, в таких случаях я из вежливости говорю, что отладочные средства в составе комплекса присутствуют — твердая 3-- (все оценки даются по пятибальной шкале).
Ну и в заключение поста (пора закругляться, а то и так получилось больше, чем я планировал) хотел бы ответить на вопрос, который наверняка возник у читателя — я за А или против. Вроде бы в самом начале я как бы намекнул, что постараюсь сохранить объективность, но в чью сторону она будет? Так вот, я не отношусь ни к ненавистникам, ни к секте почитателей А. С одной края мы видим заявления о том, что использование А несовместима с профессионализмом (вообще то профессионал как раз и способен оперировать любыми инструментами, любить их или ненавидеть не входит в его обязанности), с другой встречаем заявления, что человек, написавший скетч для считывания данных с термодатчика (как правило, не написавший, а использовавший готовое решение) не нуждается в дальнейшем совершенствовании своих навыков в области программирования вообще и встроенных систем в частности.
Истина, как всегда, лежит посередине, есть у нее такое милое свойство и заключается она в том (опять таки, по моему мнению) что А неплохой комплект начального уровня, который позволяет быстрее построить устройства определенной сложности, отличная площадка для начала освоения предметной области, но надо хорошо понимать ограниченность данной платформы и ни в коей мере не останавливаться на первой ступеньке довольно таки длинной лестницы.
PS. Подумываю о создании курса по встроенному программированию, составной частью которого (начальным курсом) была бы модифицированная Ардуино плата, каково Ваше отношение к подобному проекту, выразите его в опросе.
Автор: GarryC