Тестовая ферма для встраиваемых решений  (DevOps для Embedded, часть 2)

Можно ли автоматизировать тестирование платы не на уровне модульных тестов, а на уровне функционала? В предыдущей статье этой серии было рассказано о различных способах создания и использования многократно используемой среды для разработки на примере создания шаблонной прошивки для STM32F103. Сейчас будет рассказано, как настроить автоматизированное тестирование готового устройства в конвейере разработки после сборки прошивки
596
В избранное

В предыдущей статье этой серии было рассказано о различных способах создания и применения многократно используемой среды для разработки на примере создания шаблонной прошивки для STM32F103. Сам проект, то есть прошивка для STM32, на самом деле не имеет никакого значения и является просто эталонным проектом для работы с представленными примерами. Вместо этой прошивки у вас может быть что-то другое, более или менее сложное. В этой статье будет продемонстрировано, как можно создать и использовать тестовую ферму для тестирования готового функционального решения. 

Конечно, полное автоматическое тестирование встроенного решения скорее всего невозможно. Но этот процесс можно существенно автоматизировать.

Тестирование во встроенных решениях

Когда дело доходит до встраиваемых решений, есть очень важный этап, который было бы замечательно включить в автоматизацию - этап тестирования. При этом нужно понимать, что в разрабатываемой системе у вас может быть нестандартное оборудование, которое работает с нестандартным программным обеспечением и может быть подключено к более сложной системе или быть ее частью. Так что вы будете тестировать в этом случае? Аппаратное обеспечение? Программное обеспечение? Всю систему? Функциональность? Это может стать действительно сложным для осознания.

Сами встроенные проекты также могут быть очень сложными. Обычно система состоит из MCU или ЦП и некоторого оборудования вокруг него. Сложность заключается не только в периферийном оборудовании вокруг MCU, но и в общей функциональности аппаратного обеспечения. Поэтому, например, аппаратное обеспечение может быть довольно простым, но его может быть трудно проверить из-за его функциональности и/ или условий тестирования. Например, будет довольно сложно протестировать переключение встроенного светодиода на Arduino при невесомости или ускорении 100 g.

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

Юнит-тестирование

Обычно тестирование программного обеспечения заключается в выполнении тестов для определенных функций или модулей (модульное тестирование), и в большинстве случаев эти тесты изолированы, то есть тестируется только конкретный модуль, а не весь код. Юнит тестирование в настоящее время часто используется для тестирования прошивки.

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

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

Тестирование на макете (mock тестирование)

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

Есть несколько способов mock тестирования. Это может быть программа, встроенный аппаратный блок или внешнее оборудование. В большинстве случаев, тестирование выполняется в модульных тестах без внешнего оборудования, конечно, это «самый простой» случай, и он предпочтителен в большинстве случаев. Я использовал кавычки в предыдущем предложении, потому что иногда имитировать аппаратное обеспечение только с помощью ПО, встроенного в модуль, может быть очень сложно.

В образе единой среды разработки (CDE), который я использовал в предыдущей статье, есть еще одна роль Ansible – фреймворк cpputest ("provisioning/roles/cpputest/tasks/main.yml").
Образ можно найти в репозитории https://bitbucket.org/dimtass/stm32-cde-template/src/master/.

(Существует множество платформ тестирования для разных языков программирования, но поскольку в большинстве встроенных систем языки ограничены C/ C ++, я использовал cpputest. В вашем случае можно создать другую роль Ansible и установить необходимую среду тестирования. Обычно эти фреймворки просты в установке и, следовательно, их легко добавить в образ). 

Системное и функциональное тестирование

Как вы тестируете свою систему? Как вы тестируете функциональность? Обычно на получение ответов на эти вопросы тратится основная часть времени при проектировании тестов.

По сути, вам нужно ответить на два вопроса: «что» и «как». «Что» нужно проверить? «Как» это сделать максимально простым способом?

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

Фреймворки для тестирования

Вообще, доступно очень много фреймворков. Но проблема со всеми ними заключается в том, что они очень уневерсальны. Иногда это становится проблемой, особенно в тех случаях, когда можно было бы использовать несколько строк bash-скрипта.

Когда я упоминаю о тестовых фреймворках в этом разделе, я имею в виду не фреймворки модульного тестирования, а фреймворки более высокого уровня, такие как Robot FrameworkLAVAFuego Test Systemtbot и другие. Это отличные инструменты, и они разрабатываются людьми, которые хорошо знают, что такое тестирование. Но лично я предпочитаю простоту и инструменты, которые делают одну вещь и не имеют много зависимостей.

В этой статье я буду использовать robot framework только потому, что многие тестировщики используют его для своих тестов. 

Последовательное тестирование или распараллеливание

Платформы тестирования, которые я упомянул выше, обычно используются в конвейерах CI/ CD. В некоторых инструментах CI, таких как gitlab-ci, вы можете запускать несколько задач за этап, поэтому в случае этапа тестирования вы можете запускать несколько задач тестирования. Этими задачами может быть что угодно, например, модульные или функциональные тесты, но важно решить, какую архитектуру вы собираетесь использовать, и имеет ли это смысл для вашего конвейера. Также имейте в виду, что вы не можете запустить несколько задач на одном этапе, если эти задачи используют одно и то же оборудование (если это не предусмотрено прошивкой). Например, не стоит ждать корректных результатов от двух задач, одновременно отправляющих команды I2C одному датчику. 

Также давайте предположим, что у вас есть модульные и функциональные тесты, которые нужно запустить. Имеет ли смысл запускать функциональные тесты перед модульными тестами? Имеет ли смысл запускать их параллельно? Возможно, вы предположите, что в случае сбоя ваших модульных тестов запускать сложные и длительные функциональные тесты довольно бесполезно. Возможно, модульным тестам требуется меньше времени для работы, так почему бы не запустить их сначала, а затем запустить функциональные тесты? Кроме того, если вы выполняете их параллельно, то если модульный тест не пройдет, функциональный тест может работать длительное время, что означает, что gitlab-runner (или Jenkins и т. д.) будет занят выполнением теста на уже неудачной сборке.

С другой стороны, возможно их стоит запускать параллельно, даже если один из них даст сбой, вы будете знать, что другие тесты пройдены, и вам не нужно вносить в них изменения. Для распараллеливания тестов вам потребуется больше оборудования. Но вы можете уменьшить затраты, используя для сборки машины x86_64 с инструментами для этой платформы, а для функциональных тестов - ARM SBC, которым не нужно иметь наборы инструментов для сборки кода.

Пример проекта

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

Как и в предыдущей статье, я буду использовать gitlab-ci для запуска конвейеров CI/ CD). 

Простой тестовый сервер

Прежде чем перейти к CI/ CD, давайте посмотрим, что такое тестовый сервер. Тестовый сервер - это аппаратная платформа, которая может запускать тесты на тестируемом устройстве, а также готовить тестируемое устройство к этим тестам. Подготовка должна быть выполнена таким образом, чтобы на проверяемое устройство не влияли предыдущие тесты, которые выполнялись на нем. Это может быть достигнуто различными способами в зависимости от проверяемого устройства, гарантию может дать перепрошивка устройства, его сброс и установка выходов в заранее заданное состояние.

В статье в качестве DUT используется STM32F103C8T6 (blue-pill), но что нужно использовать в качестве тестового сервера? В общем случае – любой SBC с поддержкой Linux, я буду использовать Nanopi K1 Plus и Nanopi Neo2-LTS. Хотя это разные SBC, они имеют общий процессор Allwinner H5 SoC (ARM Cortex-A53). Основным отличием между платами является тактовая частота процессора и объем оперативной памяти, который составляет 2 ГБ для TK1 и 512 МБ для Neo2. Цена этих одноплатных компьютеров ниже 100 долларов, это достаточно дешево для строительства фермы. Также можно использовать Rapberry Pi и другие SBC.

Подобные SBC с поддержкой Linux обладают достаточным количеством периферии и большой гибкостью настройки.

Итак, какие пакеты должен иметь этот тестовый сервер? Это зависит от спецификаций вашего проекта, я буду использовать Python3, robot framework, Docker и несколько других инструментов. Важно просто понять, как все настроено, а инструменты можно подобрать для конкретного проекта. Это блок-схема того, как тестовый сервер подключен к DUT.

Блок-схема подключения тестового сервера к DUT

Тестовый сервер (SBC) имеет различные входы/ выходы и порты, такие как USB, I2C, SPI, GPIO, OTG и т. д. DUT (STM32) подключается к программатору ST-Link через интерфейс SWD, а ST-Link подключается через USB к SBC. Также STM32F1 подключен к SBC через интерфейс I2C и GPIO (GPIO A0).

Поскольку сейчас мы просто проверяем концепцию, схема не очень сложна, потом вы сможете масштабировать этот пример в той степени, в которой будет необходимо. В данном проекте STM32 будет реализовывать простой I2C => GPIO расширитель. Устройство будет иметь 8 GPIO и набор регистров, к которым можно получить доступ через I2C для программирования функций GPIO. Таким образом, тестовый сервер запустит тестирование, в ходе которого будет проверено, что устройство подключено, а затем сконфигурирует вывод в качестве выхода, установит высокий уровень, прочитает и проверит вывод, затем установит низкий уровень и снова прочитает и проверит вывод. Каждая из этих задач является отдельным тестом, и если все тесты пройдут, то тестирование будет успешным.

Итак, это наш простой пример. Сложность вашего проекта может быть гораздо больше, но, в конце концов, если вы разбиваете все на части, все сводится к аналогичным простым вещам. Конечно, есть вероятность, что ваше изделие не может быть автоматически протестировано на 100% по разным причинам, но даже если вы можете автоматизировать 40-50% тестов, это огромный выигрыш во времени и стоимости.

Теперь давайте посмотрим на две разные архитектуры тестовых ферм, которые мы собираемся использовать в этой статье.

Многоагентный конвейер

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

Dev_Ops_3.png (12 KB)

После успешного коммита gitlab-ci начнет выполнять конвейер. В этом конвейере есть этап сборки, который компилирует код и запускает модульные тесты на экземпляре AWS EC2, и если все идет хорошо, то артефакт (двоичный файл прошивки) загружается в gitlab. На самом деле не имеет значения, работает ли это на AWS или каком-либо другом сервере, который вы используете для сборки кода. Важно то, что процесс сборки и тестирования выполняется разными агентами.

Теперь давайте посмотрим плюсы и минусы этой архитектуры.

Плюсы:

  • Изоляция. Поскольку серверы сборки изолированы, их можно использовать для других задач, в то время как конвейер ожидает результатов тестирования, которое может занять довольно много времени.
  • Гибкость. При необходимости вы можете масштабировать свои серверы сборки.
  • Обработка ошибок. Если вы используете инструменты мониторинга или оркестратор (например, Kubernetes), то если ваш сервер сборки выйдет из строя, появится новый, и вы автоматически вернетесь к работе.
  • Скорость. Серверы сборки могут быть намного быстрее, чем тестовые серверы, что означает, что этап сборки закончится намного быстрее, и серверы будут доступны для других заданий.

Минусы:

  • Техническое обслуживание. Вам нужно будет поддерживать две разные инфраструктуры: серверы сборки и тестовые серверы.
  • Расходы. Одновременное использование обеих инфраструктур обходится дороже, но в сценариях реального использования затраты могут быть незначительными, особенно для компаний.

Одноагентный конвейер

В конвейере с одним агентом агент скомпилирует прошивку и затем выполнит тесты. 

Dev_Ops_2.png (11 KB)

На изображении выше вы можете видеть, что тестовый сервер (в данном случае nanopi-k1-plus) запускает клиент gitlab-runner, а затем выполняет задание сборки из gitlab-ci при новом коммите. Затем он загружает прошивку и запускает тесты на целевой плате. Это означает, что тестовый сервер должен иметь все необходимые инструменты, в том числе и STM32 toolchain (для архитектуры aarch64). Давайте посмотрим плюсы и минусы этого решения:

Плюсы:

  • Простота обслуживания. Только одна инфраструктура для обслуживания.
  • Стоимость. Низкие эксплуатационные расходы.

Минусы:

  • Скорость. Сборка на Cortex-A53 гораздо медленнее, чем на процессорах x86 (даже если это виртуальный процессор в облачном кластере).
  • Поддержка. В настоящее время существует несколько сборок gitlab для aarch64, но gitlab официально не поддерживается для этой архитектуры. Эта проблема может возникнуть и для других пакетов.

Образ тестового сервера

Есть два способа настроить ферму тестирования как IaC. Я коротко расскажу о первом, и далее в примерах будем использовать второй. Первый способ – использовать уже существующий образ для вашего SBC, например, дистрибутив Debian или Ubuntu (например, Armbian), а затем использовать, например, Ansible, для настройки образа. Давайте посмотрим на плюсы и минусы этого решения:

Плюсы:

  • Готовый APT-репозиторий, который можно использовать для установки всего, что нужно, с помощью Ansible. 
  • Вы можете обновить свои скрипты в любой момент и запустить их на всех агентах.
  • Легкость версионирования.
  • Скрипты могут использоваться на любом SBC с тем же дистрибутивом ОС.

Минусы:

  • Нужно хранить образ базовой ОС, поскольку в будущем он может стать недоступным, и из-за этого может произойти сбой инициализации.
  • Образ может содержать множество ненужных пакетов.
  • В большинстве образов необходимо предварительно вручную создать нового пользователя.
  • Нужны разные образы, если на ферме использованы разные SBC.

Самый сильный аргумент в пользу этого решения – это репозиторий APT. Вы сможете создать базовый образ, записать на SD-карту для каждого агента и запустить плату, подключенную к сети. Затем запустить ANSIBLE PlayBook и все будет готово.

Второй вариант, который я буду использовать в этой статье – это создание собственного дистрибутива ОС с использованием Yocto. Это означает, что ваш IaC является мета-слоем, который основан на слое Yocto BSP и использует дистрибутив Poky по умолчанию в качестве основы. Давайте посмотрим на общие плюсы и минусы этого варианта:

Плюсы:

  • Специфичный метаслой тестового сервера может поддерживать все BSP Yocto. Неважно, используете ли вы RPi или какой-либо из allwinner, образ, который вы получите в итоге, будет одинаковым.
  • Это статичный образ. Это означает, что все версии всегда будут одинаковыми, и вам будет сложнее нарушить вашу среду.
  • Это решение IaC, так как мета-слой Yocto можно разместить в git-репо.
  • Вы можете настроить образ во время сборки без необходимости инсталяции.
  • Вы по-прежнему можете использовать Ansible для управления образом, даже если вы не используете репозиторий пакетов (конечно, вы также можете создать свой собственный репозиторий пакетов с помощью Yocto).
  • Мета-слои Yocto можно использовать повторно

Минусы:

  • Хотя вы можете создать свой собственный репозиторий пакетов и собрать пакеты ipk, deb и rpm для своего образа, это не так просто, как использование Debian APT, и вам придется поддерживать эту инфраструктуру и в будущем. Хотя это дает вам больше контроля.
  • Если вы не используете диспетчер пакетов, то вы не сможете добавить новые функции на тестовую ферму, вам придется добавить эти функции в образ Yocto, а затем собрать и заново прошить все тестовые серверы. Обычно это случается не часто, но стоит сразу задуматься о собственном репозитории пакетов.
  • Создание образа с Yocto намного сложнее, чем просто использование Ansible для Debian.

В этом примере тестовой фермы я буду использовать Yocto. Конечно, для этого примера такой подход избыточен, но я считаю, что это гораздо лучшее решение в долгосрочной перспективе, это более правильный IaC, так как все является кодом и не нужны никакие двоичные образы или внешние зависимости. Это также хорошая отправная точка для интеграции Yocto в ваш рабочий процесс, так как он стал отраслевым стандартом, и это не зря. Поэтому интеграция этой технологии в вашу инфраструктуру полезна не только для этапа тестирования, а также для вашей общей инфраструктуры, поскольку она обеспечивает гибкость, объединяет широко используемые и хорошо зарекомендовавшие себя технологии и расширяет базу знаний.

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

Настройка SBC (nanopi-neo2 и nanopi-k1-plus)

Первым компонентом тестовой фермы является тестовый сервер. В этом случае я буду использовать два разных SBC allwinner для того, чтобы показать, насколько все гибко при использовании концепции IaC в DevOps. Для этого я создам собственный образ Linux с использованием Yocto, и в результате получу два идентичных образа для разных SBC.

Для сборки образа вам понадобится слой meta-allwinner-hx, который поддерживает все эти различные SBC. В любом случае, вам понадобится дополнительный слой, который будет располагаться поверх BSP со всеми необходимыми инструментами и поддержкой внешнего оборудования (например, stlink), требуемых служб и тестовой среды. Источник пользовательского мета-слоя Yocto тестового сервера, который я буду использовать, можно скачать здесь:

https://bitbucket.org/dimtass/meta-test-server/src/master/

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


1. mkdir -p yocto-testserver/sources

2. cd yocto-testserver/sources
3. git clone --depth 1 https://dimtass@bitbucket.org/dimtass/meta-test-server.git
4. cd ../

Далее вы можете действовать двумя способами. Во-первых, можно просто запустить скрипт из корневой папки.

1 ./sources/meta-test-server/scipts/setup-project.sh

Этот скрипт создаст образ Docker, необходимый для сборки образа Yocto. Это означает, что образ Yocto для BSP не будет использовать ваше хост-окружение, а он будет построен внутри контейнера Docker. Аналогичную операцию мы делали в предыдущей статье при сборке прошивки STM32, но на этот раз мы создаем собственный дистрибутив Linux для тестовых серверов.

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

Предположим, что вы создали образ Docker и находитесь в работающем контейнере, тогда вы можете выполнить следующие команды, чтобы настроить среду сборки и собрать образ:


1. DISTRO=allwinner-distro-console MACHINE=nanopi-k1-plus source ./setup-environment.sh build
2. bitbake test-server-image

После этого можно выйти из работающего контейнера, перенести образ на SD-карту и проверить, загружается ли тестовый сервер. Чтобы прошить образ, вам нужно сначала найти путь к вашей SD-карте (например, /dev/sdX), а затем запустить эту команду:

1. sudo MACHINE=nanopi-k1-plus ./flash_sd.sh /dev/sdX

Если эта команда не работает из-за отсутствия bmap-tool, установите его командой:

1. sudo apt install bmap-tools

После того, как вы запишите SD-карту и загрузите SBC (в данном случае nanopi-k1-plus), вы сможете войти в систему под именем root без пароля. 

Теперь для проверки работоспособности вы можете запустить команду "uname -a" и получить примерно следующие строки:


1. root:~# uname -a
2. Linux nanopi-k1-plus 5.3.13-allwinner #1 SMP Mon Dec 16 20:21:03 UTC 2019 aarch64 GNU/Linux

Это означает, что образ Yocto работает на ядре SMP 5.3.13 и имеет архитектуру aarch64. Вы также можете проверить наличие докера, gitlab-runner и набора инструментов STM32. Например, вы можете просто скопировать шаблон STM32, который я использовал в предыдущей статье, и собрать прошивку. Если это сработает, можно идти дальше:


1. git clone --recursive https://dimtass@bitbucket.org/dimtass/stm32f103-cmake-template.git
2. cd stm32f103-cmake-template
3. time TOOLCHAIN_DIR=/opt/toolchains/gcc-arm-none-eabi-9-2019-q4-major CLEANBUILD=true USE_STDPERIPH_DRIVER=ON SRC=src_stdperiph ./build.sh

В результате я получаю следующие строки:


1. Building the project in Linux environment
2. - removing build directory: /home/root/stm32f103-cmake-template/build-stm32
3. --- Pre-cmake ---
4. architecture : stm32
5. distclean : true
6. parallel : 4
7. ...
8. [ 95%] Linking C executable stm32-cmake-template.elf
9. text       data        bss        dec        hex    filename
10. 14924        856       1144      16924       421c    stm32-cmake-template.elf
11. [ 95%] Built target stm32-cmake-template.elf
12.Scanning dependencies of target stm32-cmake-template.hex
13. Scanning dependencies of target stm32-cmake-template.bin
14. [100%] Generating stm32-cmake-template.hex
15. [100%] Generating stm32-cmake-template.bin
16. [100%] Built target stm32-cmake-template.hex
17. [100%] Built target stm32-cmake-template.bin
18. 
19. real 816s
20. user 953s
21. sys 973s

Это означает, что nanopi-k1-plus создал шаблонную прошивку STM32, используя 4 потока и toolchain aarch64 GCC за 11,8 секунды. Увы, это реальная цифра. Nanopi с 4-ядерным процессором ARM-CortexA53 очень медленно собирает прошивку, даже по сравнению с AWS EC2. Насколько это критично для вас? Не знаю. В любом случае я опубликую результаты тестов ниже в этой статье.

Следующий тест должен проверить, сможет ли SBC прошить STM32. Сначала проверим st-link:


1. root:~/stm32f103-cmake-template# st-info --probe
2. Found 1 stlink programmers
3. serial: 513f6e06493f55564009213f
4. openocd: "\x51\x3f\x6e\x06\x49\x3f\x55\x56\x40\x09\x21\x3f"
5. flash: 65536 (pagesize: 1024)
6. sram: 20480
7. chipid: 0x0410
8. descr: F1 Medium-density device

Если вы видите аналогичный текст, значит st-link работает правильно. Теперь загрузим прошивку в целевую плату:


1. st-flash --reset write build-stm32/src_stdperiph/stm32-cmake-template.bin 0x8000000

Вы должны увидеть в терминале  что-то типа:


1. st-flash 5.1
2. 2019-12-20T23:56:22 INFO common.c: Loading device parameters....
3. 2019-12-20T23:56:22 INFO common.c: Device connected is: F1 Medium-density device, id 0x20036410
4. 2019-12-20T23:56:22 INFO common.c: SRAM size: 0x5000 bytes (20 KiB), Flash: 0x10000 bytes (64 KiB) in pages of 1024 bytes
5. 2019-12-20T23:56:22 INFO common.c: Attempting to write 15780 (0x3da4) bytes to stm32 address: 134217728 (0x8000000)
6. Flash page at addr: 0x08003c00 erased
7. 2019-12-20T23:56:24 INFO common.c: Finished erasing 16 pages of 1024 (0x400) bytes
8. 2019-12-20T23:56:24 INFO common.c: Starting Flash write for VL/F0/F3/F1_XL core id
9. 2019-12-20T23:56:24 INFO flash_loader.c: Successfully loaded flash loader in sram
10. 16/16 pages written
11. 2019-12-20T23:56:25 INFO common.c: Starting verification of write complete
12. 2019-12-20T23:56:25 INFO common.c: Flash written and verified! jolly good!

Это означает, что SBC смог прошить STM32. Вы можете проверить это, убедившись, что светодиод на gpio C13 переключается каждые 500 мс.

Отлично. Выполнив эти шаги, мы убедились, что мы создали образ Docker с Yocto для nanopi-k1-plus, содержащий все необходимые инструменты для сборки и прошивки STM32.

Последовательность действий, приведенная выше, может быть интегрирована в конвейер CI, который создает образ всякий раз, когда происходит изменение в слое meta-test-server. Поэтому, когда вы добавляете новые инструменты или что- то изменяете в образе, конвейер создает новый образ Linux, который вы можете перенести на SD-карту SBC. Параметр MACHINE в команде build может быть параметром в конвейере, поэтому вы можете создавать разные образы для разных SBC. Это упрощает и автоматизирует инфраструктуру вашей тестовой фермы (с точки зрения операционной системы).

Примечание: Конечно, к SBC можно подключаться через ssh, если вы знаете IP.В этом случае имеет смысл назначить статический IP-адрес в маршрутизаторе для SBC, используя его MAC-адрес.

Вы можете спросить здесь, почему я использовал Dockerfile для создания образа, который создает образ Yocto, вместо использования Packer и Ansible, как я делал в предыдущей статье? Единственная причина состоит в том, что Dockerfile уже включен в репозиторий meta-allwinner-hx, хорошо протестирован и готов к использованию. Вы можете также использовать Packer для создания своего собственного образа докера, но стоит ли игра свеч? 

Не всегда стоит создавать все с нуля, желательно использовать все, что доступно, что облегчает жизнь. DevOps - это не создание с нуля, а нахождение самого простого решения в конкретном случае.

Также обратите внимание на следующее. Для сборки ОС потребуется мощный компьютер -  более 16 ГБ ОЗУ и 50 ГБ дискового пространства, а также 8 ядер - это минимум.

Итак, в этом конкретном случае вам понадобится довольно мощный сервер сборки, если вы хотите интегрировать сборку образа Yocto в CI/ CD. В этой статье я буду использовать свою рабочую станцию для создания образа и пропущу детали создания конвейера CI/ CD для создания образа Yocto, поскольку он почти такой же, как и в любом другом случае CI/ CD, за исключением того, что вам понадобится более мощный агент.

Если вам нужно иметь образ докера Yocto в реестре, используйте Packer для создания этих образов и выгрузки их в реестр докеров или создайте конвейер CI/ CD, который просто создает образ компоновщика Yocto из Dockerfile (в данном случае в репозитории meta-allwinner-hx), а затем загружает этот образ в удаленный/ локальный реестр.

Настройка DUT

Теперь, когда вы настроили тестовый сервер, пришло время настроить DUT (stm32f103 blue pill в данном случае). В следующей таблице показаны соединения, которые необходимо выполнить (Распиновка для nanopi-neo2 здесь, а для nanopi-k1-plus здесь ).

SBC (nanopi-neo2 / k1-plus)
вывод: [функция]

STM32F103 (blue pill)

1: [SYS_3.3V]

3V3

3: [I2C0_SDA]

PB7

5: [I2C0_SCL]

PB6

6: [GND]

GND

7: [GPIOG11]

PA0

ST-LINK может быть подключен к любому доступному USB-порту SBC. К ST-LINK нужно подключить выводы RST, SWDIO, SWCLK и GND модуля STM32. Не подключайте питание 3V3 ST-LINK к STM32, так как плата уже получает питание от SYS_3.3V SBC.

Поскольку мы используем шину I2C, нам нужно использовать два внешних подтягивающих резистора на выводах PB7 и PB6. Просто подключите эти два резистора к выводам I2C и одному из доступных контактов 3V3 STM32.

Наконец, для целей отладки вы можете подключить последовательные порты SBC и STM32 к двум модулям USB-to-UART. Это полезно в тот момент, когда вы настраиваете свою ферму, а когда все заработает, последовательные порты можно будет отключить.

Для прошивки я буду использовать код из следующего репозитория:

https://gitlab.com/dimtass/stm32f103-i2c-io-expander

Эта прошивка заставит stm32f103 функционировать как расширитель I2C GPIO. MCU будет подключен к SBC через I2C и GPIO, затем SBC сможет настроить выводы stm32 с использованием протокола I2C и управлять GPIO. Протокол довольно прост и подробно объясняется в README файле.

Автоматизированные тесты

Теперь посмотрим на тесты в репозитории и как они используются. Давайте вернемся снова в репо прошивки:

https://gitlab.com/dimtass/stm32f103-i2c-io-expander

В нем вы увидите папку с именем tests, в которой расположены все тестовые сценарии, которые будет использовать конвейер CI. Файл yaml конфигурации конвейера находится в корневой папке репозитория и называется .gitlab-ci.yml. В этом файле вы увидите 3 этапа: сборка, прошивка и тестирование. На этапе сборки будет создана прошивка, на следующем этапе она будет загружена в контроллер, и, наконец, на этапе тестирования будет запущен тест с использованием роботизированной среды. Хотя я здесь использую robot-framework, это может быть любой другой фреймворк или даже скрипт.

Тестирование управляется файлом "tests/ robot-tests/ stm32-fw-test.robot". Если вы откроете этот файл, вы увидите, что он использует две библиотеки. Эти библиотеки просто классы Python, которые находятся в папке "tests /"и, в частности, они вызывают скрипты "tests/ STM32GpioExpander.py" и" tests/ HostGpio.py". "Tests/ STM32GpioExpander.py" реализует протокол I2C, который поддерживается прошивкой STM32 для настройки GPIO. Этот класс использует пакет Python smbus, который устанавливается из слоя Yocto meta-test-server. Вы можете увидеть, что этот объект поддерживает опрос I2C, чтобы определить наличие контроллера STM32 с готовой прошивкой. Это делается путем чтения регистров 0x00 и 0x01, которые содержат магическое слово 0xBEEF. Следовательно, эта функция будет считывать эти два регистра, и если 0xBEEF найден, это означает, что на плате установлена правильная прошивка. В этот опрос стоит также добавить версию прошивки.

Далее, класс "tests/ HostGpio.py" предоставляет интерфейс Python для настройки и управления GPIO SBC. Этот файл входит в слой meta-allwinner-hx BSP в "meta-allwinner-hx/ recipes-extended/ udev/ udev-python-gpio/ 60-python-gpio-permissions.rules". Остальные файлы python содержат вспомогательный код. Возвращаясь к сценарию тестирования, вы можете увидеть тестовые примеры, которые я перечислю здесь для удобства.


1. *** Test Cases ***
2. Probe STM32
3. ${probe} =     probe
4. Log  STM32GpioExpander exists ${probe}
5.  
6. Config output pin
7. ${config} =    set_config    ${0}  ${0}  ${0}  ${1}  ${0}  ${0}
8. Log  Configured gpio[0] as output as GPOA PIN0
9.   
10. Set stm32 pin high
11. ${pin} =  set_pin  ${0}  ${1}
12. Log  Set gpio[0] to HIGH
13.  
14. Read host pin
15. set_config     ${203}  ${0}  ${0}
16. ${pin} =  read_pin  ${203}
17. Should Be Equal     ${pin}  1
18. Log  Read gpio[0] value: ${pin}
19.  
20. Reset stm32 pin
21. ${pin} =  set_pin  ${0}  ${0}
22. Log  Set gpio[0] to LOW
23.   
24. Read host pin 2
25. set_config     ${203}  ${0}  ${0}
26. ${pin} =  read_pin  ${203}
27. Should Be Equal     ${pin}  0
28. Log  Read gpio[0] value: ${pin}

Первый тест называется «Probe STM32», и он просто проверяет наличие подключенного STM32 с нужной прошивкой. Эта строка на самом деле вызовет функцию STM32GpioExpander.probe(), которая возвращает True, если контроллер подключен, в противном случае False. Следующий тест «Config output pin» настроит выход PA0 STM32 как выход. При следующем тесте «Set stm32 pin high» PA0 будет установлен в HIGH. Следующий тест «Read host pin» настроит вход GPIOG11 (вывод № 203) SBC на вход, а затем прочитает уровень сигнала на этом выводе. Если на вход  подана «1», то тест пройден. При следующем тесте «Reset stm32 pin» PA0 будет установлен в LOW. Наконец, последний тест «Read host pin 2» снова прочитает вывод GPIOG11 и проверит, что он 0.

Если все тесты пройдены, это означает, что прошивка успешно загружена, шина I2C работает, протокол и GPIO работают должным образом.

Из файла .gitlab-ci.yml вы можете видеть, что команда запуска робота выглядит следующим образом:


1. robot --pythonpath . --outputdir ./results -v I2C_SLAVE:0x08 -v BOARD:nanopi_neo2 -t "Probe STM32" -t "Config output pin" -t "Set stm32 pin high" -t "Read host pin" -t "Reset stm32 pin" -t "Read host pin 2" ./robot-tests/

Она передает адрес подчиненного устройства I2C, плату и список с тестами для запуска в качестве параметров. Адрес I2C может быть опущен, поскольку он жестко задан в тесте для обратной совместимости, поскольку в версиях до 3.1.x все параметры передаются в виде строк, и это не будет работать с классом STM32GpioExpander. Команда вернет 0 (что означает отсутствие ошибок), если все тесты пройдены.

Обратите внимание, этот скрипт будет запускать все тесты последовательно независимо от результатов предыдущего. Вы можете изменить это поведение.

Тестирование фермы!

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

Dev_Ops_4.png (47 KB)

С левой стороны – nanopi-k1-plus, а с правой стороны - nanopi-neo2. Оба работают под одним и тем же образом Yocto, имеют подключение к Интернету, ST-LINK v2 подключен к USB-порту, а сигналы I2C и GPIO подключены между SBC и STM32. Также два порта UART SBC подключены к моей рабочей станции для отладки. Хотя на фотографии вы видите только два тестовых сервера, на ферме их может быть сколько угодно.

Следующий шаг – убедиться, что gitlab-runner работает на обеих SBC, и они зарегистрированы в репо. Обычно в этом случае gitlab-runner – это служба в образе Yocto, которая запускает сценарий, который автоматически проверяет и при необходимости регистрирует SBC в проекте. Чтобы это произошло, вам нужно добавить две строки в файл local.conf при создании образа Yocto.


1. GITLAB_REPO = "stm32f103-i2c-io-expander"
2. GITLAB_TOKEN = "4sFaXz89yJStt1hdKM9z"

Конечно, параметры должны соответствовать вашему проекту. Напоминаю, что GITLAB_REPO – это просто имя вашего репозитория, а GITLAB_TOKEN – токен, который можно получить на вкладке «Настройки -> CI / CD -> Агенты» в вашем репозитории Gitlab.

Если gitlab-runner по какой-либо причине не запускается в вашем SBC, просто запустите эту команду в терминале вашего SBC:


1. /usr/bin/initialize-gitlab-runner.sh

Если все работает нормально,  в проекте gitlab в «Настройки -> CI / CD -> Runners » будут видны активные агенты:

Dev_Ops_5.png (7 KB)

Первый агент - это nanopi-k1-plus, а второй - это nanopi-neo2. Вы можете проверить хеши в файле /etc/gitlab-runner/config.toml в каждом SBC в параметре token.

Теперь можно запустить конвейер вручную и посмотреть, что происходит. В веб-интерфейсе gitlab видно, что есть 3 этапа, и начался этап сборки. Вот часть журнала:

1 Running with gitlab-runner 12.6.0~beta.2049.gc941d463 (c941d463)
2   on nanopi-neo2 _JXcYZdJ
3 Using Shell executor... 00:00
5 Running on nanopi-neo2... 00:00
7 Fetching changes with git depth set to 50... 00:03
8 Reinitialized existing Git repository in /home/root/builds/_JXcYZdJ/0/dimtass/stm32f103-i2c-io-expander/.git/
9 From https://gitlab.com/dimtass/stm32f103-i2c-io-expander
10  * [new ref]         refs/pipelines/106633593 -> refs/pipelines/106633593
...
141 [100%] Built target stm32f103-i2c-io-expander.bin
142 [100%] Built target stm32f103-i2c-io-expander.hex
143 real    0m14.413s
144 user    0m35.717s
145 sys    0m4.805s
148 Creating cache build-cache... 00:01
149 Runtime platform                                    arch=arm64 os=linux pid=4438 revision=c941d463 version=12.6.0~beta.2049.gc941d463
150 build-stm32/src: found 55 matching files          
151 No URL provided, cache will be not uploaded to shared cache server. Cache will be stored only locally.
152 Created cache
154 Uploading artifacts... 00:03
155 Runtime platform                                    arch=arm64 os=linux pid=4463 revision=c941d463 version=12.6.0~beta.2049.gc941d463
156 build-stm32/src/stm32f103-i2c-io-expander.bin: found 1 matching files
157 Uploading artifacts to coordinator... ok            id=392515265 responseStatus=201 Created token=dXApM1zs
159 Job succeeded

Это означает, что сборка прошла успешно, прошло 14,413 с, и артефакт загружен. 

Следующим этапом является этап прошивки:


1 Running with gitlab-runner 12.6.0~beta.2049.gc941d463 (c941d463)
2   on nanopi-neo2 _JXcYZdJ
3 Using Shell executor... 00:00
5 Running on nanopi-neo2... 00:00
7 Fetching changes with git depth set to 50... 00:03
8 Reinitialized existing Git repository in /home/root/builds/_JXcYZdJ/0/dimtass/stm32f103-i2c-io-expander/.git/
9 Checking out bac70245 as master...
...
30 Downloading artifacts for build (392515265)... 00:01
31 Runtime platform                                    arch=arm64 os=linux pid=4730 revision=c941d463 version=12.6.0~beta.2049.gc941d463
32 Downloading artifacts from coordinator... ok        id=392515265 responseStatus=200 OK token=dXApM1zs
34 $ st-flash --reset write build-stm32/src/stm32f103-i2c-io-expander.bin 0x8000000 00:02
35 st-flash 1.5.1
36 2020-01-02T14:41:27 INFO common.c: Loading device parameters....
37 2020-01-02T14:41:27 INFO common.c: Device connected is: F1 Medium-density device, id 0x20036410
38 2020-01-02T14:41:27 INFO common.c: SRAM size: 0x5000 bytes (20 KiB), Flash: 0x10000 bytes (64 KiB) in pages of 1024 bytes
39 2020-01-02T14:41:27 INFO common.c: Attempting to write 12316 (0x301c) bytes to stm32 address: 134217728 (0x8000000)
40 Flash page at addr: 0x08003000 erased
41 2020-01-02T14:41:28 INFO common.c: Finished erasing 13 pages of 1024 (0x400) bytes
42 2020-01-02T14:41:28 INFO common.c: Starting Flash write for VL/F0/F3/F1_XL core id
43 2020-01-02T14:41:28 INFO flash_loader.c: Successfully loaded flash loader in sram
44  13/13 pages written
45 2020-01-02T14:41:29 INFO common.c: Starting verification of write complete
46 2020-01-02T14:41:29 INFO common.c: Flash written and verified! jolly good!
51 Job succeeded

Журнал показывает, что артефакт прошивки с помощью st-flash и ST-LINKv2 был успешно загружен в STM32.

Наконец, последний этап - это запуск робота для тестирования:


1 Running with gitlab-runner 12.6.0~beta.2049.gc941d463 (c941d463)
2   on nanopi-neo2 _JXcYZdJ
3 Using Shell executor... 00:00
5 Running on nanopi-neo2...
...
32 Downloading artifacts for build (392515265)... 00:01
33 Runtime platform                                    arch=arm64 os=linux pid=5313 revision=c941d463 version=12.6.0~beta.2049.gc941d463
34 Downloading artifacts from coordinator... ok        id=392515265 responseStatus=200 OK token=dXApM1zs
36 $ cd tests/ 00:02
37 $ robot --pythonpath . --outputdir ./results -v I2C_SLAVE:0x08 -v BOARD:nanopi_neo2 -t "Probe STM32" -t "Config output pin" -t "Set stm32 pin high" -t "Read host pin" -t "Reset stm32 pin" -t "Read host pin 2" ./robot-tests/
38 ==============================================================================
39 Robot-Tests                                                                  
40 ==============================================================================
41 Robot-Tests.Stm32-Fw-Test :: This test verifies that there is an STM32 board 
42 ==============================================================================
43 Probe STM32                                                           | PASS |
44 ------------------------------------------------------------------------------
45 Config output pin                                                     | PASS |
46 ------------------------------------------------------------------------------
47 Set stm32 pin high                                                    | PASS |
48 ------------------------------------------------------------------------------
49 Read host pin                                                         | PASS |
50 ------------------------------------------------------------------------------
51 Reset stm32 pin                                                       | PASS |
52 ------------------------------------------------------------------------------
53 Read host pin 2                                                       | PASS |
54 ------------------------------------------------------------------------------
55 Robot-Tests.Stm32-Fw-Test :: This test verifies that there is an S... | PASS |
56 6 critical tests, 6 passed, 0 failed
57 6 tests total, 6 passed, 0 failed
58 ==============================================================================
59 Robot-Tests                                                           | PASS |
60 6 critical tests, 6 passed, 0 failed
61 6 tests total, 6 passed, 0 failed
62 ==============================================================================
63 Output:  /home/root/builds/_JXcYZdJ/0/dimtass/stm32f103-i2c-io-expander/tests/results/output.xml
64 Log:     /home/root/builds/_JXcYZdJ/0/dimtass/stm32f103-i2c-io-expander/tests/results/log.html
65 Report:  /home/root/builds/_JXcYZdJ/0/dimtass/stm32f103-i2c-io-expander/tests/results/report.html
70 Job succeeded

Журнал показывает, что все тесты прошли успешно. Поэтому в gillab видна следующая картина:

Dev_Ops_5a.png (5 KB)

Тестирование фермы с облачными сборщиками

Теперь давайте реализуем первый вариант архитектуры со сборкой прошивки в облаке:

Dev_Ops_3.png (12 KB)

Как это сделать?

Gitlab CI поддерживает теги для агентов, так что вы можете указать, какой этап на каком из них нужно выполнять. У вас может быть несколько агентов с различными возможностями, и у каждого из них может быть свой собственный тег, который определяет его возможности. Поэтому я буду использовать отдельные теги для экземпляра AWS EC2 и SBC, и каждый этап в .gitlab-ci.yml будет выполняться для соответствующего тега. Это очень мощная функция, поскольку вы можете создавать агентов с различными возможностями, которые обслуживают несколько проектов.

Файл  .gitlab-ci.yml для такой конфигурации приведен ниже:


---
    image:
        name: dimtass/stm32-cde-image:0.1
        entrypoint: [""]
   
    variables:
        GIT_SUBMODULE_STRATEGY: recursive
   
    stages:
        - build
        - flash
        - test
   
    build:
        tags:
            - stm32-builder
        stage: build
        script: time TOOLCHAIN_DIR=/opt/toolchains/gcc-arm-none-eabi-9-2019-q4-major CLEANBUILD=true USE_STDPERIPH_DRIVER=ON USE_DBGUART=ON SRC=src ./build.sh
        cache:
            key: build-cache
            paths:
            - build-stm32/src         artifacts:
            paths:
            - build-stm32/src/stm32f103-i2c-io-expander.bin
            expire_in: 1 week
   
    flash:
        tags:
            - test-farm
        stage: flash
        script: st-flash --reset write build-stm32/src/stm32f103-i2c-io-expander.bin 0x8000000
        cache:
            key: build-cache
   
    run_robot:
        tags:
            - test-farm
        stage: test
        script:
            - cd tests/
            - robot --pythonpath . --outputdir ./results -v I2C_SLAVE:0x08 -v BOARD:nanopi_neo2 -t "Probe STM32" -t "Config output pin" -t "Set stm32 pin high" -t "Read host pin" -t "Reset stm32 pin" -t "Read host pin 2" ./robot-tests/

В нем видно, что на каждом этапе теперь определен tags, в котором перечислены агенты, которые могут выполнить каждый этап. Образ Yocto не имеет тегов для агентов, поэтому в этом тесте я удалю предыдущих агентов с помощью веб-интерфейса, а затем выполню эту команду на каждом тестовом сервере:


gitlab-runner verify --delete
gitlab-runner register

Затем вам нужно определить каждый параметр следующим образом:

Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
https://gitlab.com/
Please enter the gitlab-ci token for this runner:
4sFaXz89yJStt1hdKM9z
Please enter the gitlab-ci description for this runner:
[nanopi-neo2]: nanopi-neo2
Please enter the gitlab-ci tags for this runner (comma separated):
test-farm
Registering runner... succeeded                     runner=4sFaXz89
Please enter the executor: parallels, shell, ssh, virtualbox, docker+machine, docker-ssh+machine, docker, docker-ssh, kubernetes, custom:
shell
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!

То же самое можно повторить для второй платы. (Вообще эти шаги должны быть включены в образ Yocto. Я их привожу только для тестирования и демонстрации архитектуры).

Наконец, при создании экземпляра AWS EC2 нужно выполнить следующие команды:


git clone git@bitbucket.org:dimtass/stm32-cde-template.git
cd stm32-cde-template
packer build stm32-cde-aws-gitlab-runner.json
ln -sf Vagrantfile_aws Vagrantfile

 Теперь нужно отредактировать Vagrantfile и заполнить aws_keypair_name и aws_ami_name в соответствии с данными в консоли управления веб-EC2.


vagrant up
vagrant shh
ps -A | grep gitlab

Последняя команда отобразит запущенный экземпляр gitlab-runner. По аналогии с SBC нужно удалить старого агента и зарегистрировать нового, задав для него нужный тег ("stm32-builder"). 

Теперь можно проверить правильность настройки на странице «Настройки -> CI/ CD -> Агенты» в репозитории. Я там вижу следующую картину:

Dev_Ops_6.png (10 KB)

На изображении выше вы видите, что теперь у каждого агента есть описание и тег. Если теперь запустить конвейер, то сборка произойдет в облаке, а прошивка и запуск тестов на тестовой ферме.

Расскажу, как работает конвейер более подробно. После запуска конвейера сервер gitlab проанализировал файл .gitlab-ci.yml и обнаружил, что существует 3 этапа. Также выяснилось, что для каждого этапа определен тег. Поэтому конвейер остановился на первом этапе и ждет, чтобы любой агент с нужным тегом опросил сервер. Предположим, что в какой-то момент gitlab-runner на одном из SBC опрашивает сервер первым (это происходит по умолчанию каждые 3 секунды для всех участников). Когда SBC подключился к серверу, он опубликовал имя репо, токен и тег агента. Сервер проверил имя тега агента и этапа и обнаружил, что они отличаются, поэтому он не запускает этап на этом агенте и закрывает соединение.

Через 1-2 секунды gitlab-runner в экземпляре AWS EC2 с тем же тегом, что и на этапе сборки, подключается к серверу gitlab. Сервер проверяет тег агента, и затем начинает выполнять команды этапа через туннель. Сначала он клонирует репозиторий, выполняет сборку прошивки и загрузку полученного артефакта.

Теперь, когда этап сборки пройден успешно и артефакт находится на сервере, сервер инициирует следующий этап и теперь ожидает любого участника с тегом test-farm. В какой-то момент подключается один из SBC, и сервер получает контроль над SBC и выполняет этап flash, используя туннель.  Наконец, на этапе тестирования использует тот же агент, поскольку он имеет соответствующий тег. После выполнения всех тестов на сервер возвращается результат.

Производительность

Давайте посмотрим на время, требуемое для сборки на различных платформах. 

Платформа

Время, сек

AWS EC2 (t2.micro - 1 ядро)

5.345s

Nanopi-neo2 (4 ядра)

14.413s

Nanopi-k1-plus (4 ядра)

12.509s

Ryzen 2700X (8 ядер / 16 потоков)

1.914s

Как видно из приведенной выше таблицы, сборка в облаке ( t2.micro x86_64) выполняется гораздо быстрее, чем на SBC, а рабочая станция (Ryzen 2700X) работает еще быстрее. (Имейте ввиду, что это очень простая прошивка, и она собирается довольно быстро). Просто учтите этот момент при планировании архитектуры конвейера CI. 

Выводы

Наверное, эту длинную статью можно выразить в одном предложении - DevOps для встраиваемых – это сложно!

Конечно, большинство вещей, которые я продемонстрировал, одинаковы, независимо от сложности проекта. Но эта сложность относится не собственно к конвейеру CI/ CD или к используемым инструментам. Нет, сложность найти самый простой инструмент, который будет вас удовлетворять максимально долго.

Всегда выбирайте самое простое решение, которое кажется подходящим для ваших будущих потребностей. Рассчитывайте, что вам нужно будет масштабировать решение в будущем даже в рамках этого же проекта. Вот почему вам нужно следовать одной из лучших рекомендаций DevOps - IaC. Вся ваша инфраструктура должна быть кодом, чтобы вы могли легко и быстро вносить изменения и иметь возможность вернуться в известное рабочее состояние, если что-то пойдет не так. 

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

С другой стороны, облачные агенты не могут запускать тесты на реальном оборудовании и быть частью тестовой фермы. В этом случае вашей тестовой ферме нужно реальное оборудование, как в примерах, которые я продемонстрировал в этой статье. Запуск тестовой фермы - огромная и сложная задача, и чем больше ферма, тем больше вам нужно автоматизировать все. Автоматизация должна быть везде. Даже образ ОС должен быть частью IaC. Используйте Yocto или buildroot или любой другой дистрибутив (включите его в Ansible). Сделайте конвейер CI для образа  ОС.

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

Предыдущая глава:

  1. DevOps для встроенных систем (Часть 1)

Источник: https://www.stupid-projects.com

Производитель: STMicroelectronics
Наименование
Производитель
Описание Корпус/
Изображение
Цена, руб. Наличие
ST-LINK/V2
ST-LINK/V2
STMicroelectronics
Арт.: 684603 ИНФО PDF AN
Доступно: 160 шт. 2850,00
Внутрисхемный программатор/отладчик для микроконтроллеров серии STM8 и STM32 производства фирмы  STMicroelectronics.
ST-LINK/V2 2850,00 от 2 шт. 2590,00 от 4 шт. 2500,00 от 7 шт. 2380,00 от 18 шт. 2260,00
49 шт.
(на складе)
111 шт.
(под заказ)
ST-LINK/V2-ISOL
ST-LINK/V2-ISOL
STMicroelectronics
Арт.: 1107586 ИНФО PDF AN
Доступно: 47 шт. 9140,00
ST-LINK/V2-ISOL - внутрисхемный эмулятор для микроконтроллеров серии STM8 и STM32 производства фирмы STMicroelectronics
ST-LINK/V2-ISOL 9140,00 от 2 шт. 8710,00 от 5 шт. 8270,00 от 10 шт. 8230,00
36 шт.
(на складе)
11 шт.
(под заказ)
STLINK-V3SET
STLINK-V3SET
STMicroelectronics
Арт.: 3038905 ИНФО PDF AN
Доступно: 103 шт. 4360,00
Модульный автономный программатор/ отладчик для микроконтроллеров STM8 и STM32.
STLINK-V3SET 4360,00 от 2 шт. 4200,00 от 4 шт. 4000,00 от 11 шт. 3800,00 от 21 шт. 3780,00
58 шт.
(на складе)
45 шт.
(под заказ)
STLINK-V3MINI
STLINK-V3MINI
STMicroelectronics
Арт.: 3420352 ИНФО PDF AN
Доступно: 136 шт. от 1 шт. от 2910,39
Выбрать
условия
поставки
Компактный внутрисхемный программатор/ отладчик STLINK-V3 для МК STM32.
STLINK-V3MINI от 1 шт. от 2910,39
136 шт.
(под заказ)
Выбрать
условия
поставки
Производитель: Waveshare Electronics Ltd.
Наименование
Производитель
Описание Корпус/
Изображение
Цена, руб. Наличие
ST-LINK/V2 [mini]
ST-LINK/V2 [mini]
Waveshare Electronics Ltd.
Арт.: 2274149 ИНФО PDF
Доступно: 173 шт. 658,00
ST-LINK/V2 [mini] – крайне экономичное решение для внутрисхемного программирования и отладки микроконтроллеров STM8 и STM32
ST-LINK/V2 [mini] 658,00 от 7 шт. 598,00 от 14 шт. 576,00 от 29 шт. 549,00 от 77 шт. 521,00
138 шт.
(на складе)
35 шт.
(под заказ)

Сравнение позиций

  • ()