Моя первая встраиваемая система под управлением Linux

в 13:00, , рубрики: attiny, DIY, linux, ruvds_перевод, spi nor flash, встраиваемые системы, микроконтроллеры, Программирование

Моя первая встраиваемая система под управлением Linux - 1


В этой статье я задокументировал историю создания своей первой системы под управлением Linux. Здесь я расскажу, как собрал печатную плату под эту ОС, не имея какого-либо опыта работы с печатными платами в принципе.

Первая часть статьи может показаться не совсем по теме, но в ходе прочтения вы поймёте, что она также имеет отношение к основному тексту. В общем, рекомендую терпеливо прочесть всю историю.

Содержание

Не пугайтесь!

Я, конечно, не утверждаю, что мою разработку можно прямиком отправлять в производство и использовать для управления больничным оборудованием, но созданный мной прототип, как минимум, обеспечивает загрузку и функционирование Linux. Думаю, если вы читаете эту статью, то для вас это наверняка и является основной целью. Реализовав этот фундамент, вы уже будете более чётко понимать дальнейшие шаги к этапу реального производства.

Я не являюсь экспертом по созданию печатных плат, поэтому наверняка наделал кучу ошибок, но главное, что задача была выполнена, и в целом всё оказалось проще, чем казалось изначально. Если вы знакомы с основами электротехники, достаточно дисциплинированы и можете выделить на проект пару часов ежедневно, то буквально за несколько дней соберёте аналогичный прототип, способный загружать Linux. Надеюсь, что это понимание вас вдохновит, а содержание статьи позволит ускорить процесс.

Необходимый минимум знаний

Если формула I = U/R для вас ничего не значит, то рекомендую сначала ознакомиться с основами работы электрических цепей. Для реализации этого проекта вам потребуется некоторое понимание таких понятий, как резисторы, конденсаторы и индукторы. В целом же для тех, кто обладает этими базовыми знаниями электроники, текст должен быть вполне понятен (да я и сам знаю не на много больше).

Готовые печатные платы

Существуют удобные и популярные платы вроде Raspberry Pi, но если просто использовать одну из таких, особенно по инструкциям производителя, мы не особо разберёмся в том, как всё работает. А это знание нужно нам для создания собственных плат. По своему опыту могу сказать, что это особенно актуально в случае микроконтроллеров, поэтому в качестве примера мы будем использовать именно его.

Но для начала уточню, что это будет означать в отношении Linux. Например, если для загрузки этой ОС использовать Raspberry Pi или иную аналогичную плату, то в определённый момент вы попадёте в знакомую рабочую среду. Неважно, работаете ли вы с полноценной системой Linux или же с крохотным образом для RPi, в любом случае вы будете встречать привычные элементы вроде /dev, выполнять знакомые команды вроде ls и так далее. Объясняется это стабильностью API (ABI?) системы Linux. В случае же микроконтроллеров подобной стандартизации не существует.

Когда вы загружаете нужный код на плату Arduino, то можете проходить совершенно иной процесс, нежели при его загрузке на плату STM32 Nucleo. И отличаться будет не только сам процесс загрузки кода, но и способ его написания. В итоге для создания, по сути, одинакового кода Си, чтобы помигать светодиодом, мы используем разные IDE и рабочие потоки. Как это ни печально, но производители зачастую вынуждают нас работать с их кастомными потоками (наверняка, чтобы привязать к себе потребителей; поэтому рекомендую опираться на собственный здравый смысл и скептицизм).

Первый прототип печатной платы (без поддержки Linux)

Взяв во внимание всё вышесказанное, я решил собрать свою первую печатную плату с программируемой цифровой логикой, причём сделать её максимально простой.

А что вообще значит, запрограммировать плату? Это означает, что мы пишем код, компилируем его, отправляем каким-то образом на микросхему, способную выполнять скомпилированный машинный код и наблюдаем результат. Здесь я не буду разбирать написание и компиляцию кода, а сделаю акцент на последующих стадиях.

▍ Загрузка микросхемы

Размышляя о самых простых микроконтроллерах, я задался вопросом: «А что происходит, когда я подаю питание на микросхему (неважно каким образом)? Откуда она считывает код? И как вообще этот код можно в неё загрузить?»

Несколько лет назад в процессе поиска дешёвого микроконтроллера я наткнулся на Atmel ATtiny (сейчас они вроде называются Microchip). Купить такие можно по $1 за штуку, если не дешевле. И далее возникает вопрос: как теперь, имея голый микроконтроллер, начать с ним работать? Естественно, в случае столь крохотного чипа это должно быть довольно просто.

По сути, при подаче на неё питания микросхема ATtiny проверяет состояние своих контактов. Если выполняются определённые условия, такие как высокий/низкий уровень сигнала на конкретных контактах, микросхема входит в режим программирования. Этот режим позволяет взаимодействовать с чипом посредством определённого протокола, например, SPI и загружать в его флэш-память нужный код. Затем можно перезапустить микросхему так, чтобы условия входа в режим программирования выполнены не были, и тогда она уже начнёт выполнение загруженного кода.

▍ Программаторы

Но у меня в компьютере нет никаких специальных выводов или проводов, чтобы проделать описанный выше процесс, не говоря уже о чём-то вроде протокола SPI. В нём есть несколько USB-портов, а поскольку многие готовые печатные платы подключаются для программирования именно таким образом, этот подход вполне должен сработать.

Однако платы у меня нет — есть только микросхема. Как же мне реализовать её программирование по USB? ATtiny можно запрограммировать только по SPI, значит потребуется некий посредник между USB и SPI.

В случае с ATtiny существует эмулятор-программатор AVR Dragon, который решит эту проблему.

Это устройство можно подключить к компьютеру по USB и провернуть описанную выше манипуляцию с сигналами через специальное ПО с компьютера. Получив команду на программирование ATtiny, AVR Dragon переведёт плату в нужный режим и по шине SPI зальёт во флэш-память микроконтроллера скомпилированный код.

В моём случае я запрограммировал ATtiny, подключив его и Dragon к макетной плате. Причём процесс программирования проваливался, пока я не понял, что нужно скорректировать один параметр, замедлив скорость загрузки кода на микроконтроллер. После этого всё прошло прекрасно. Мне потребовалось лишь соединить выводы SPI моей микросхемы и программатора.

▍ ПО для программирования: avrdude

Хорошо. Мы реализовали аппаратный переход между USB и SPI, но каким образом теперь выполнить само программирование через компьютер?

Должно быть приложение, которое будет управлять передачей сообщений на Dragon через USB-порт. В моём случае им оказалось avrdude. Это опенсорсное приложение, способное программировать различные микросхемы Atmel/Microchip, включая серию ATtiny. Один из параметров avrdude определяет конкретный способ программирования. Я установил этот параметр на avr_dragon.

Далее я уже мог загрузить на ATtiny нужный код, затем отключить микроконтроллер, подключить его к другой макетке и помигать светодиодами.

Отлично! Теперь я знаю кое-какую важную информацию, которая пригодится при программировании печатной платы с микросхемой ATtiny:

  • Подобные микросхемы можно программировать на отдельной плате и затем уже устанавливать в нужную рабочую среду. Либо…
  • Вывести контакты шины SPI, чтобы подключить к ним AVR Dragon.

Причём второй вариант предполагает очевидную возможность также подключить к выводам те же светодиоды, чтобы ими помигать. Но в данном случае это не особо важно.

▍ Что такое Dragon, и нужен ли он мне?

Теперь, когда мы разобрали весь поток программирования ATtiny, стало ясно, что AVR Dragon не делает ничего сверхсложного — если у нас есть какое-то устройство, которое может отправлять на микросхему сообщения по SPI, можно использовать это устройство в качестве программатора.
Интересно, а можно ли использовать avrdude, установив для параметра, где мы указали avr_dragon, другое значение. Это значение используется в Raspberry Pi и подразумевает программирование через контакты ввода-вывода. Подробно об этом написано здесь.

▍ Проектирование печатной платы для ATtiny

Итак, я нашёл простой способ запрограммировать ATtiny с помощью макетной платы и подключенного к компьютеру AVR Dragon, хотя при желании я мог из этой схемы Dragon исключить.

Теперь мне нужно было спроектировать печатную плату с гнездом, в которое можно будет вставить запрограммированный ATtiny. В итоге при подаче на эту плату питания она будет мигать светодиодами.

Это очень простая плата. Вам потребуется разместить на ней один сокет DIP-8 и проложить несколько дорожек, которые заменят соединительные провода, использованные на макетной плате. Моя схема будет запитываться через одну дорожку 5 В, уходящую в микроконтроллер, плюс 2 дорожки будут отходить от контактов ввода-вывода, подавая питание на светодиоды, а замыкать всю цепь будет дорожка GND. Вот как это будет выглядеть:

Моя первая встраиваемая система под управлением Linux - 2

А вот готовая плата:

Моя первая встраиваемая система под управлением Linux - 3

Получилось два этапа проектирования: создание схемы и её фактическая реализация. Схема представляет логическую модель всей платы. После её проектирования в программе нужно будет кликнуть по соответствующей кнопке, чтобы уже наглядно расположить все компоненты по поверхности платы и соединить их. Вся работа будет производиться на основе полученной схемы, и ваш инструмент EDA (Electronic Design Automation) сможет использовать её для исключения ошибок, например, если вы попытаетесь проложить соединение, которое на схеме отсутствует.

Роберт Феранек снял хорошее видео для новичков, где рассказал, как спроектировать свою первую печатную плату. И хотя ролик у него получился весьма длинный, с ним можно ознакомиться поверхностно, чтобы получить общее представление:

Теперь, когда я успешно завершил этот эксперимент, предлагаю пойти ва-банк и приступить к созданию встраиваемой платы, способной работать под управлением Linux.

Что нужно для проектирования встраиваемой системы с Linux?

У Джея Карлсона есть очень хорошая обзорная статья на эту тему.

Если вы уже прекрасно понимаете, зачем вам встраиваемый Linux, то можете пропустить вступительную часть статьи и сразу перейти к разделу, посвящённому проектированию. Мы же будем работать с более простым корпусом, нежели BGA и также пропустим сложные моменты вроде маршрутизации DDR, поскольку вся наша RAM-память будет встроена в SoC. Кроме того, мы не будем сильно заморачиваться в отношении целостности сигнала, так как все наши компоненты будут работать достаточно быстро (медленно?), простив возможные огрехи дизайна.

Учитывая всё это, можете прочесть статью Джея и рассматривать мою как более мягкое вступление к тому, о чём писал он.

Что меня на всё это вдохновило

Как я писал в посте, посвящённом запуску Linux на оборудовании за $5, к созданию первой встраиваемой системы меня подтолкнула собранная энтузиастом визитка под управлением Linux. Тот факт, что человек реализовал это в формате визитной карточки, говорил о том, что он использовал максимально простой дизайн, который достоин внимания.

Поскольку автор той статьи любезно поделился схемой и своими рассуждениями на эту тему, я использовал его опыт в качестве основы для реализации первого этапа.

Проектирование схемы

В схеме визитки с Linux использовано немного компонентов, и это кажется правильным решением. В конце концов, мы уже продемонстрировали, что Linux можно запустить, используя одну только встроенную флэш-память и Allwinner SoC. Далее мы детально разберём процесс проектирования схемы, выстроив его вокруг F1C100 SoC.

▍ Питание

Как писал Джей Карлсон, и как подтверждает дизайн визитки, для питания SoC с Linux потребуется два разных напряжения. Заглянем в спецификацию F1C100:

Моя первая встраиваемая система под управлением Linux - 4

Здесь мы видим, что используется несколько разных напряжений: VCC-IO, VDD-CORE и так далее.

Похоже, для некоторых компонентов рекомендуемым является 3,3 В — хорошо, отметим его как нужное. Кроме того, мы видим, что для VCC-DRAM требуется 2,5 В, что также вписывается в допустимый диапазон для AVCC. Значит, и это напряжение нам тоже потребуется. Наконец, у VDD-CORE диапазон довольно узкий, поэтому добавляем в список ещё и 1,1 В.

Плату с Linux можно запитать от USB-хоста, то есть наша плата будет подключаться через USB к другой машине и получать от неё 5 В. Если это для вас незнакомо, рекомендую прочесть одну из моих последних статей, посвящённую сборке USB-устройств. Это единственное напряжение, которое мы будем получать извне. При этом нам потребуется снарядить нашу плату компонентами, способными преобразовывать 5 В в те напряжения, которые мы отметили как нужные.

Для этого мы используем регуляторы напряжения, коих нам потребуется три, по одному для каждой целевой величины. Вокруг этих регуляторов мы также добавим конденсаторы. Чтобы понять, как это сделать, откройте спецификацию ваших регуляторов и найдите раздел с названием вроде «типичное применение» (typical application).

Моя первая встраиваемая система под управлением Linux - 5

▍ Тактовый генератор

Для того, чтобы F1C100s смогла работать на частоте 24 МГц, ей потребуется соответствующий тактовый генератор, рядом с которым также нужно будет добавить конденсаторы. К счастью, для этого есть известное решение, которое описано на этой странице (тактовый генератор + 2 конденсатора).

И да, в своём дизайне я также прикинул для Cstray ёмкость 5 пФ.

▍ Блокировочные конденсаторы

Нам потребуется разместить рядом с линиями подачи напряжения несколько разделительных конденсаторов. Поскольку мои знания в этой области довольно скудны, я просто дам ссылки на некоторые ролики, которые нашёл полезными.

Первый в общих чертах поясняет, зачем нужны эти конденсаторы:

Во втором Зак Петерсон демонстрирует практические случаи их использования:

И, наконец, третье видео я взял из EEVblog, и оно позволило мне лучше понять этот способ применения конденсаторов:

В итоге я использовал множество деталей ёмкостью 100 нФ.

▍ Коннекторы, контакты и ввод-вывод

Я запитал печатную плату через micro-USB, и это же подключение использовал для заполнения встроенной флэш-памяти и RAM (подробнее об этом ниже). Для данного проекта этого минимума будет достаточно.

На своё усмотрение можете добавить какие-то другие возможности подключения. Как вы хотите, чтобы ваша плата взаимодействовала с внешним миром? Возможно, через порт I2C или что-то иное? Тут уже решать вам.

Для облегчения отладки можете добавить несколько светодиодов, что не составит особой сложности.

▍ Кнопка FEL Mode

Ещё раз вернусь к статье о запуске Linux на оборудовании за $5: в случае с F1C100s режим FEL очень важен. Я вкратце расскажу о нём позже, а пока поясню лишь, что добавил кнопку, которая будет заземлять тактовый генератор SPI Flash, по сути, отключая эту память. Такое решение может показаться странным, но оно упрощает жизнь.

▍ SPI Flash

Вот здесь что-то пошло не так. Я хотел использовать флэш память объёмом 16 МБ, но в итоге получил всего 2 МБ. Не уверен, чья в том вина — то ли накосячил я, то ли производитель (в документации или как-то иначе). Но это и не важно, так как мне удалось выкрутиться. Изначальное вступление про программирование ATtiny в данном случае оказывается важным уроком.

Более того, на своём опыте я понял, что в отношении SPI Flash нужно учесть пару нюансов:

  • Объём микросхемы должен быть достаточным для образа Linux и, возможно, каких-то данных среды выполнения (по желанию).
  • В идеале запитывать её нужно напряжением, уже присутствующим на плате — 3,3 В будет вполне достаточно.

▍ Странность SVREF

У SoC был один очень странный контакт — SVREF. В спецификации про него ничего конкретно не сказано, кроме самого факта его существования. Поэтому я просто подсмотрел, что обычно с ним делают в других проектах, и повторил. По факту я добавил простой делитель напряжения на базе резистора (взгляните, например, на схему визитки с Linux).

▍ Конкретные компоненты

Всего вышеперечисленного должно быть вполне достаточно для сборки простейшей системы под управлением Linux. Хотя вам также потребуется решить, какие именно компоненты использовать. К примеру, вы можете взять разделительные конденсаторы на 100 нФ, но они представлены огромным числом моделей, каждая из которых имеет свои характеристики (в том числе цену). Кроме того, некоторые из этих компонентов могут отсутствовать в продаже. Лично я использовал ресурс JLCPCB, где эти «более простые в использовании» детали называются basic parts.

Собирая прототип, убедитесь, что все детали хорошо сочетаются. Например, если вы используете резистор, то проследите, чтобы он поддерживал ток, который вы будете через него пропускать. Также обратите внимание на типоразмер (footprint) деталей. Типоразмер определяет посадочное место и схему подключения компонента. Эта характеристика обозначается на деталях специальной маркировкой. Например, есть резисторы 0603, но они больше, чем их аналоги 0402. Я в основном использовал резисторы и конденсаторы с типоразмером 0402.

Наконец, есть веская причина, по которой мне понравилось использовать в этом проекте среду EasyEDA: она предлагает обширную библиотеку компонентов, которые можно разместить на печатной плате, вместе с их типоразмерами. Проектировщикам печатных плат довольно часто (как я понял, поскольку сам таковым не являюсь) приходится копаться в спецификациях компонентов, чтобы выяснить, какой у них типоразмер, и как согласовать эти детали друг с другом. В этом смысле EasyEDA очень хорошо сочетается с сервисом по производству плат JLCPCB.

▍ Компоновка схемы

Вот схема.

Моя первая встраиваемая система под управлением Linux - 6

Внимание. Не ожидайте, что схема будет очень понятной. Опытных проектировщиков при её виде наверняка передёрнет. Она весьма топорная и использовалась лишь для проверки работоспособности. Кроме того, я далеко не эксперт в разработке печатных плат и показывать кому-либо её не собирался. Просто всё же посчитал, что кому-то она может оказаться полезна.

Опишу в общих чертах, что конкретно на ней происходит:

  • Большинство контактов SoC не подключены. Сама SoC обозначена как U1.
  • U2, U3 и U4 — это регуляторы напряжения, с помощью которых я получил его разные уровни для запитывания SoC.
  • U5 — это микросхема памяти SPI NOR Flash. Опять же, можете прочесть статью про запуск Linux на оборудовании за $5, чтобы понять, как производить с неё загрузку системы. Эту память можно «отключить», удержав кнопку U6 — ту самую, которая заземляет сигнал тактового генератора. Это позволит перезапустить SoC, которая решит, что загружать нечего, и перейдёт в режим FEL.
  • U7 — это кнопка перезагрузки.
  • U8 и U9 — это драйверы светодиодов. Излишняя деталь, можете просто подключить светодиоды к контактам ввода-вывода.
  • Разделительные конденсаторы должны быть легко заметны (их множество).
  • USB1 — это коннектор micro-USB, который подаёт 5 В на регуляторы напряжения и предоставляет дифференциальную пару, которую можно подключить к SoC для USB-коммуникации. Происходящее здесь описано в статье, посвящённой сборке USB-устройств.
  • X — это тактовый генератор, который был подключен к микросхеме стандартным способом.
  • L1 — это ферритовое кольцо. Насколько я понимаю, при подключении USB-кабеля, например, в розетку с USB-портом, могут возникать шумы, и ферритовое кольцо их гасит.
  • Остальное — это преимущественно выводы гребёнки для передачи сигналов во внешний мир.

Вот, собственно, и всё!

Разводка печатной платы

Теперь, когда у нас есть схема, можно всё подключать.

Для меня серьёзным испытанием стало подключение разделительных конденсаторов. Желательно, чтобы они располагались максимально близко к контактам SoC (можете посмотреть ролики выше), но здесь корпус SoC создаёт сложности. Я думал, что проблема в моём недостаточном опыте, но потом нашёл видео от Phil’s Lab, где этот момент разбирается подробно.

В моём случае речь идёт о корпусе QFN, у которого выводы расположены очень тесно, и всё выполнено очень мелко. И хотя я использовал небольшие конденсаторы, они сильно загромоздили пространство вокруг SoC, затруднив подключение. Тогда я решил последовать примеру Фила из видео и использовать 4-слойную плату:

Ещё один сложный момент связан с прокладкой линии USB. Но поскольку мы будем довольствоваться лишь скоростью USB 2.0, это всё упрощает. Можете освежить свои знания по USB-устройствам здесь и особо на эту тему не волноваться. Я просто проложил от коннектора micro-USB к SoC дифференциальную пару. Также не обязательно излишне продумывать ширину и длину дорожек, главное следовать здравому смыслу (например, не делайте длину больше 5 сантиметров и не чудите с шириной). В этом случае всё вполне будет работать.

Всё остальное должно быть довольно просто. Я использовал такой стек слоёв: сигнальный-земля-питание-сигнальный.

  1. На верхнем сигнальном слое присутствует множество дорожек ввода-вывода, а также дифференциальная пара USB (насколько я понимаю, прокладку этой пары не следует делать через разные слои).
  2. GND — это просто земля, весь слой.
  3. На слое питания я проложил жирные линии для подачи на SoC разного напряжения.
  4. Нижний сигнальный слой в основном состоит из разделительных конденсаторов.

Не стану углубляться в подробности разводки, так как моих знаний недостаточно для качественного объяснения.

Создание образа ПО

В идеале я должен был создать для этой платы собственное дерево устройств (device tree), но поленился и захотел поскорее увидеть результат. В своём проекте по запуску Linux на оборудовании за $5 я создал образ для Lichee Pi, который тоже состоял лишь из SoC и флэш-памяти. Этот же образ я решил использовать и здесь — он вполне должен был сработать.

И сработал — но с одним подвохом. Как я уже говорил, у меня каким-то образом вместо 16 МБ памяти получилось всего 2 МБ. Урезание образа потребовало бы много работы, а я просто хотел уже всё запустить.

Здесь-то и пригодился режим FEL, подтвердив значимость той самой кнопки, которая легко отключает встроенную память. Для взаимодействия с SoC я использовал инструмент sunxi-fel, поскольку она была подключена напрямую к моему компьютеру через дифференциальную пару USB. Одна из особенностей этого инструмента в том, что он может заполнить RAM содержимым, а затем выполнить загрузку с сохранением этого содержимого. Именно поэтому я изначально отвлёкся на объяснение принципа программирования ATtiny и выяснение способов, которыми можно загрузить код на микросхему и выполнить его.

Поэтому вместо загрузки образа U-Boot FIT со встроенной флэш-памяти, я скачал его со своего компьютера в RAM и загрузил оттуда. Linux прекрасно запустился.

Чтобы дополнительно убедиться в подобающей работе флэш-памяти, я упаковал образ U-Boot и записал его в хранилище NOR Flash, но уместить туда ещё и Linux уже не получилось. Сам же U-Boot заработал отлично.

Заключение

Это был крайне сумбурный проект, но он прекрасно удовлетворил моё любопытство. Кроме того, было очень приятно видеть, как после длительного процесса изучения, проектирования и ожидания изготовления печатная плата, наконец, оживает. Надеюсь, вы испытаете те же чувства, когда соберёте свою первую встраиваемую систему под управлением Linux!

Удачи!

Telegram-канал со скидками, розыгрышами призов и новостями IT 💻

Автор: Дмитрий Брайт

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js